1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sun_sas.h> 27 #include <libsysevent.h> 28 #include <sys/types.h> 29 #include <netinet/in.h> 30 #include <inttypes.h> 31 #include <ctype.h> 32 33 34 /* Remove these 5 when the header containing the event names aver available. */ 35 /* 36 * Event definitions 37 */ 38 /* Event Class */ 39 #define EC_HBA "EC_hba" 40 #define EC_DR "EC_dr" 41 /* Event Sub-Class */ 42 #define ESC_SAS_HBA_PORT_BROADCAST "ESC_sas_hba_port_broadcast" 43 #define ESC_SAS_PHY_EVENT "ESC_sas_phy_event" 44 #define ESC_DR_TARGET_STATE_CHANGE "ESC_dr_target_state_change" 45 46 /* Broadcast Event Types */ 47 #define SAS_PORT_BROADCAST_CHANGE "port_broadcast_change" 48 #define SAS_PORT_BROADCAST_SES "port_broadcast_ses" 49 #define SAS_PORT_BROADCAST_D24_0 "port_broadcast_d24_0" 50 #define SAS_PORT_BROADCAST_D27_4 "port_broadcast_d27_4" 51 #define SAS_PORT_BROADCAST_D01_4 "port_broadcast_d01_4" 52 #define SAS_PORT_BROADCAST_D04_7 "port_broadcast_d04_7" 53 #define SAS_PORT_BROADCAST_D16_7 "port_broadcast_d16_7" 54 #define SAS_PORT_BROADCAST_D29_7 "port_broadcast_d29_7" 55 56 /* Phy Event Types */ 57 #define SAS_PHY_ONLINE "port_online" 58 #define SAS_PHY_OFFLINE "port_offline" 59 #define SAS_PHY_REMOVE "port_remove" 60 61 /* Event payload */ 62 #define SAS_DRV_INST "driver_instance" 63 #define SAS_PORT_ADDR "port_address" 64 #define SAS_DEVFS_PATH "devfs_path" 65 #define SAS_EVENT_TYPE "event_type" 66 67 #define HBA_PORT_MATCH 1 68 #define TARGET_PORT_MATCH 2 69 #define PHY_MATCH 3 70 71 #define REMOVED 1 72 #define ONLINE 2 73 #define OFFLINE 3 74 75 sysevent_handle_t *gSysEventHandle = NULL; 76 77 /* Calls the client callback function, if one is registered */ 78 static HBA_STATUS 79 updateMatchingPhy(HBA_WWN portAddr, uint8_t phyId, int update, uint8_t linkRate) 80 { 81 const char ROUTINE[] = "updateMatchingPhy"; 82 struct sun_sas_hba *hba_ptr; 83 struct sun_sas_port *hba_port_ptr; 84 struct phy_info *phy_ptr; 85 86 log(LOG_DEBUG, ROUTINE, "- phy matching"); 87 /* grab write lock */ 88 lock(&all_hbas_lock); 89 /* loop through HBAs */ 90 for (hba_ptr = global_hba_head; hba_ptr != NULL; 91 hba_ptr = hba_ptr->next) { 92 /* loop through HBA ports */ 93 for (hba_port_ptr = hba_ptr->first_port; 94 hba_port_ptr != NULL; 95 hba_port_ptr = hba_port_ptr->next) { 96 if (wwnConversion(hba_port_ptr-> 97 port_attributes.PortSpecificAttribute. 98 SASPort->LocalSASAddress.wwn) == 99 wwnConversion(portAddr.wwn)) { 100 /* loop through phys */ 101 for (phy_ptr = hba_port_ptr->first_phy; 102 phy_ptr != NULL; phy_ptr = 103 phy_ptr->next) { 104 if (phy_ptr->phy.PhyIdentifier == 105 phyId) { 106 if (update == REMOVED) { 107 phy_ptr->invalid = 108 B_TRUE; 109 } else if (update == OFFLINE) { 110 phy_ptr->phy. 111 NegotiatedLinkRate 112 = 0; 113 } else { /* online */ 114 phy_ptr->phy. 115 NegotiatedLinkRate 116 = linkRate; 117 } 118 unlock(&all_hbas_lock); 119 return (HBA_STATUS_OK); 120 } 121 } /* for phys */ 122 } /* wwn mismatch. continue */ 123 } /* for HBA ports */ 124 } /* for HBAs */ 125 126 unlock(&all_hbas_lock); 127 return (HBA_STATUS_ERROR); 128 } 129 130 /* Event handler called by system */ 131 static void 132 syseventHandler(sysevent_t *ev) 133 { 134 135 const char ROUTINE[] = "syseventHandler"; 136 nvlist_t *attrList = NULL; 137 char *eventStr, *portAddrStr, *charptr; 138 int update; 139 uint64_t addr; 140 uint8_t phyId, linkRate; 141 HBA_WWN portAddr; 142 143 /* Is the event one of ours? */ 144 if (strncmp(EC_HBA, sysevent_get_class_name(ev), strlen(EC_HBA)) == 0) { 145 /* handle phy events */ 146 if (strncmp(ESC_SAS_PHY_EVENT, sysevent_get_subclass_name(ev), 147 strlen(ESC_SAS_PHY_EVENT)) == 0) { 148 if (sysevent_get_attr_list(ev, &attrList) != 0) { 149 log(LOG_DEBUG, ROUTINE, 150 "Failed to get event attributes on %s/%s", 151 EC_HBA, ESC_SAS_PHY_EVENT); 152 return; 153 } else { 154 if (nvlist_lookup_string(attrList, 155 "event_type", &eventStr) != 0) { 156 log(LOG_DEBUG, ROUTINE, 157 "Event type not found"); 158 return; 159 } else { 160 if (strncmp(eventStr, "phy_online", 161 sizeof (eventStr)) == 0) { 162 update = ONLINE; 163 if (nvlist_lookup_uint8( 164 attrList, "link_rate", 165 &linkRate) != 0) { 166 log(LOG_DEBUG, ROUTINE, 167 "Link Rate not \ 168 found"); 169 return; 170 } 171 } else if (strncmp(eventStr, 172 "phy_offline", 173 sizeof (eventStr)) == 0) { 174 update = OFFLINE; 175 } else if (strncmp(eventStr, 176 "phy_remove", 177 sizeof (eventStr)) == 0) { 178 update = REMOVED; 179 } else { 180 log(LOG_DEBUG, ROUTINE, 181 "Invalid event type"); 182 return; 183 } 184 } 185 if (nvlist_lookup_string(attrList, 186 "port_address", &portAddrStr) != 0) { 187 log(LOG_DEBUG, ROUTINE, 188 "Port SAS address not found"); 189 return; 190 } else { 191 for (charptr = portAddrStr; 192 charptr != NULL; charptr++) { 193 if (isxdigit(*charptr)) { 194 break; 195 } 196 } 197 addr = htonll(strtoll(charptr, 198 NULL, 16)); 199 (void) memcpy(portAddr.wwn, &addr, 8); 200 } 201 if (nvlist_lookup_uint8(attrList, 202 "PhyIdentifier", &phyId) != 0) { 203 log(LOG_DEBUG, ROUTINE, 204 "Port SAS address not found"); 205 return; 206 } 207 } 208 if (updateMatchingPhy(portAddr, phyId, update, 209 linkRate) != HBA_STATUS_OK) { 210 log(LOG_DEBUG, ROUTINE, 211 "updating phy for the events failed."); 212 } 213 } 214 } else if (strncmp(EC_DR, sysevent_get_class_name(ev), 2) == 0) { 215 /* handle DR events */ 216 log(LOG_DEBUG, ROUTINE, 217 "handle EC_dr events."); 218 } else { 219 log(LOG_DEBUG, ROUTINE, 220 "Found Unregistered event. - exit"); 221 return; 222 } 223 224 log(LOG_DEBUG, ROUTINE, "- exit"); 225 } 226 227 /* Registers events to the sysevent framework */ 228 HBA_STATUS 229 registerSysevent() { 230 231 const char ROUTINE[] = "registerSysevent"; 232 const char *hba_subclass_list[] = { 233 ESC_SAS_PHY_EVENT 234 }; 235 const char *dr_subclass_list[] = { 236 ESC_DR_TARGET_STATE_CHANGE 237 }; 238 239 gSysEventHandle = sysevent_bind_handle(syseventHandler); 240 if (gSysEventHandle == NULL) { 241 log(LOG_DEBUG, ROUTINE, 242 "- sysevent_bind_handle() failed"); 243 log(LOG_DEBUG, ROUTINE, "- error exit"); 244 return (HBA_STATUS_ERROR); 245 } 246 247 if (sysevent_subscribe_event(gSysEventHandle, EC_HBA, 248 hba_subclass_list, 1) != 0) { 249 log(LOG_DEBUG, ROUTINE, 250 "- sysevent_subscribe_event() failed for EC_HBA subclass"); 251 log(LOG_DEBUG, ROUTINE, "- error exit"); 252 sysevent_unbind_handle(gSysEventHandle); 253 return (HBA_STATUS_ERROR); 254 } 255 256 if (sysevent_subscribe_event(gSysEventHandle, EC_DR, 257 dr_subclass_list, 1) != 0) { 258 log(LOG_DEBUG, ROUTINE, 259 "- sysevent_subscribe_event() failed for DR subclass"); 260 log(LOG_DEBUG, ROUTINE, "- error exit"); 261 sysevent_unbind_handle(gSysEventHandle); 262 return (HBA_STATUS_ERROR); 263 } 264 265 log(LOG_DEBUG, ROUTINE, "- exit"); 266 267 return (HBA_STATUS_ERROR); 268 } 269