OpenSolaris_b135/lib/sun_sas/common/event.c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sun_sas.h>
#include <libsysevent.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <ctype.h>
/* Remove these 5 when the header containing the event names aver available. */
/*
* Event definitions
*/
/* Event Class */
#define EC_HBA "EC_hba"
#define EC_DR "EC_dr"
/* Event Sub-Class */
#define ESC_SAS_HBA_PORT_BROADCAST "ESC_sas_hba_port_broadcast"
#define ESC_SAS_PHY_EVENT "ESC_sas_phy_event"
#define ESC_DR_TARGET_STATE_CHANGE "ESC_dr_target_state_change"
/* Broadcast Event Types */
#define SAS_PORT_BROADCAST_CHANGE "port_broadcast_change"
#define SAS_PORT_BROADCAST_SES "port_broadcast_ses"
#define SAS_PORT_BROADCAST_D24_0 "port_broadcast_d24_0"
#define SAS_PORT_BROADCAST_D27_4 "port_broadcast_d27_4"
#define SAS_PORT_BROADCAST_D01_4 "port_broadcast_d01_4"
#define SAS_PORT_BROADCAST_D04_7 "port_broadcast_d04_7"
#define SAS_PORT_BROADCAST_D16_7 "port_broadcast_d16_7"
#define SAS_PORT_BROADCAST_D29_7 "port_broadcast_d29_7"
/* Phy Event Types */
#define SAS_PHY_ONLINE "port_online"
#define SAS_PHY_OFFLINE "port_offline"
#define SAS_PHY_REMOVE "port_remove"
/* Event payload */
#define SAS_DRV_INST "driver_instance"
#define SAS_PORT_ADDR "port_address"
#define SAS_DEVFS_PATH "devfs_path"
#define SAS_EVENT_TYPE "event_type"
#define HBA_PORT_MATCH 1
#define TARGET_PORT_MATCH 2
#define PHY_MATCH 3
#define REMOVED 1
#define ONLINE 2
#define OFFLINE 3
sysevent_handle_t *gSysEventHandle = NULL;
/* Calls the client callback function, if one is registered */
static HBA_STATUS
updateMatchingPhy(HBA_WWN portAddr, uint8_t phyId, int update, uint8_t linkRate)
{
const char ROUTINE[] = "updateMatchingPhy";
struct sun_sas_hba *hba_ptr;
struct sun_sas_port *hba_port_ptr;
struct phy_info *phy_ptr;
log(LOG_DEBUG, ROUTINE, "- phy matching");
/* grab write lock */
lock(&all_hbas_lock);
/* loop through HBAs */
for (hba_ptr = global_hba_head; hba_ptr != NULL;
hba_ptr = hba_ptr->next) {
/* loop through HBA ports */
for (hba_port_ptr = hba_ptr->first_port;
hba_port_ptr != NULL;
hba_port_ptr = hba_port_ptr->next) {
if (wwnConversion(hba_port_ptr->
port_attributes.PortSpecificAttribute.
SASPort->LocalSASAddress.wwn) ==
wwnConversion(portAddr.wwn)) {
/* loop through phys */
for (phy_ptr = hba_port_ptr->first_phy;
phy_ptr != NULL; phy_ptr =
phy_ptr->next) {
if (phy_ptr->phy.PhyIdentifier ==
phyId) {
if (update == REMOVED) {
phy_ptr->invalid =
B_TRUE;
} else if (update == OFFLINE) {
phy_ptr->phy.
NegotiatedLinkRate
= 0;
} else { /* online */
phy_ptr->phy.
NegotiatedLinkRate
= linkRate;
}
unlock(&all_hbas_lock);
return (HBA_STATUS_OK);
}
} /* for phys */
} /* wwn mismatch. continue */
} /* for HBA ports */
} /* for HBAs */
unlock(&all_hbas_lock);
return (HBA_STATUS_ERROR);
}
/* Event handler called by system */
static void
syseventHandler(sysevent_t *ev)
{
const char ROUTINE[] = "syseventHandler";
nvlist_t *attrList = NULL;
char *eventStr, *portAddrStr, *charptr;
int update;
uint64_t addr;
uint8_t phyId, linkRate;
HBA_WWN portAddr;
/* Is the event one of ours? */
if (strncmp(EC_HBA, sysevent_get_class_name(ev), strlen(EC_HBA)) == 0) {
/* handle phy events */
if (strncmp(ESC_SAS_PHY_EVENT, sysevent_get_subclass_name(ev),
strlen(ESC_SAS_PHY_EVENT)) == 0) {
if (sysevent_get_attr_list(ev, &attrList) != 0) {
log(LOG_DEBUG, ROUTINE,
"Failed to get event attributes on %s/%s",
EC_HBA, ESC_SAS_PHY_EVENT);
return;
} else {
if (nvlist_lookup_string(attrList,
"event_type", &eventStr) != 0) {
log(LOG_DEBUG, ROUTINE,
"Event type not found");
return;
} else {
if (strncmp(eventStr, "phy_online",
sizeof (eventStr)) == 0) {
update = ONLINE;
if (nvlist_lookup_uint8(
attrList, "link_rate",
&linkRate) != 0) {
log(LOG_DEBUG, ROUTINE,
"Link Rate not \
found");
return;
}
} else if (strncmp(eventStr,
"phy_offline",
sizeof (eventStr)) == 0) {
update = OFFLINE;
} else if (strncmp(eventStr,
"phy_remove",
sizeof (eventStr)) == 0) {
update = REMOVED;
} else {
log(LOG_DEBUG, ROUTINE,
"Invalid event type");
return;
}
}
if (nvlist_lookup_string(attrList,
"port_address", &portAddrStr) != 0) {
log(LOG_DEBUG, ROUTINE,
"Port SAS address not found");
return;
} else {
for (charptr = portAddrStr;
charptr != NULL; charptr++) {
if (isxdigit(*charptr)) {
break;
}
}
addr = htonll(strtoll(charptr,
NULL, 16));
(void) memcpy(portAddr.wwn, &addr, 8);
}
if (nvlist_lookup_uint8(attrList,
"PhyIdentifier", &phyId) != 0) {
log(LOG_DEBUG, ROUTINE,
"Port SAS address not found");
return;
}
}
if (updateMatchingPhy(portAddr, phyId, update,
linkRate) != HBA_STATUS_OK) {
log(LOG_DEBUG, ROUTINE,
"updating phy for the events failed.");
}
}
} else if (strncmp(EC_DR, sysevent_get_class_name(ev), 2) == 0) {
/* handle DR events */
log(LOG_DEBUG, ROUTINE,
"handle EC_dr events.");
} else {
log(LOG_DEBUG, ROUTINE,
"Found Unregistered event. - exit");
return;
}
log(LOG_DEBUG, ROUTINE, "- exit");
}
/* Registers events to the sysevent framework */
HBA_STATUS
registerSysevent() {
const char ROUTINE[] = "registerSysevent";
const char *hba_subclass_list[] = {
ESC_SAS_PHY_EVENT
};
const char *dr_subclass_list[] = {
ESC_DR_TARGET_STATE_CHANGE
};
gSysEventHandle = sysevent_bind_handle(syseventHandler);
if (gSysEventHandle == NULL) {
log(LOG_DEBUG, ROUTINE,
"- sysevent_bind_handle() failed");
log(LOG_DEBUG, ROUTINE, "- error exit");
return (HBA_STATUS_ERROR);
}
if (sysevent_subscribe_event(gSysEventHandle, EC_HBA,
hba_subclass_list, 1) != 0) {
log(LOG_DEBUG, ROUTINE,
"- sysevent_subscribe_event() failed for EC_HBA subclass");
log(LOG_DEBUG, ROUTINE, "- error exit");
sysevent_unbind_handle(gSysEventHandle);
return (HBA_STATUS_ERROR);
}
if (sysevent_subscribe_event(gSysEventHandle, EC_DR,
dr_subclass_list, 1) != 0) {
log(LOG_DEBUG, ROUTINE,
"- sysevent_subscribe_event() failed for DR subclass");
log(LOG_DEBUG, ROUTINE, "- error exit");
sysevent_unbind_handle(gSysEventHandle);
return (HBA_STATUS_ERROR);
}
log(LOG_DEBUG, ROUTINE, "- exit");
return (HBA_STATUS_ERROR);
}