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