diff options
Diffstat (limited to 'usr/src/lib/sun_sas/common/event.c')
-rw-r--r-- | usr/src/lib/sun_sas/common/event.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/usr/src/lib/sun_sas/common/event.c b/usr/src/lib/sun_sas/common/event.c new file mode 100644 index 0000000000..a4030d5d1b --- /dev/null +++ b/usr/src/lib/sun_sas/common/event.c @@ -0,0 +1,268 @@ +/* + * 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); +} |