xref: /illumos-gate/usr/src/lib/sun_sas/common/event.c (revision 00f453f4ebc211cb928f19a54d3f4edd61f43279)
19e86db79SHyon Kim /*
29e86db79SHyon Kim  * CDDL HEADER START
39e86db79SHyon Kim  *
49e86db79SHyon Kim  * The contents of this file are subject to the terms of the
59e86db79SHyon Kim  * Common Development and Distribution License (the "License").
69e86db79SHyon Kim  * You may not use this file except in compliance with the License.
79e86db79SHyon Kim  *
89e86db79SHyon Kim  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e86db79SHyon Kim  * or http://www.opensolaris.org/os/licensing.
109e86db79SHyon Kim  * See the License for the specific language governing permissions
119e86db79SHyon Kim  * and limitations under the License.
129e86db79SHyon Kim  *
139e86db79SHyon Kim  * When distributing Covered Code, include this CDDL HEADER in each
149e86db79SHyon Kim  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e86db79SHyon Kim  * If applicable, add the following below this CDDL HEADER, with the
169e86db79SHyon Kim  * fields enclosed by brackets "[]" replaced with your own identifying
179e86db79SHyon Kim  * information: Portions Copyright [yyyy] [name of copyright owner]
189e86db79SHyon Kim  *
199e86db79SHyon Kim  * CDDL HEADER END
209e86db79SHyon Kim  */
219e86db79SHyon Kim /*
229e86db79SHyon Kim  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239e86db79SHyon Kim  * Use is subject to license terms.
249e86db79SHyon Kim  */
25*00f453f4SRob Johnston /*
26*00f453f4SRob Johnston  * Copyright 2019 Joyent, Inc.
27*00f453f4SRob Johnston  */
289e86db79SHyon Kim 
299e86db79SHyon Kim #include	<sun_sas.h>
309e86db79SHyon Kim #include	<libsysevent.h>
319e86db79SHyon Kim #include	<sys/types.h>
329e86db79SHyon Kim #include	<netinet/in.h>
339e86db79SHyon Kim #include	<inttypes.h>
349e86db79SHyon Kim #include	<ctype.h>
359e86db79SHyon Kim 
369e86db79SHyon Kim 
379e86db79SHyon Kim /* Remove these 5 when the header containing the event names aver available. */
389e86db79SHyon Kim /*
399e86db79SHyon Kim  * Event definitions
409e86db79SHyon Kim  */
419e86db79SHyon Kim /* Event Class */
429e86db79SHyon Kim #define	EC_HBA		    "EC_hba"
439e86db79SHyon Kim #define	EC_DR		    "EC_dr"
449e86db79SHyon Kim /* Event Sub-Class */
459e86db79SHyon Kim #define	ESC_SAS_HBA_PORT_BROADCAST  "ESC_sas_hba_port_broadcast"
469e86db79SHyon Kim #define	ESC_SAS_PHY_EVENT	"ESC_sas_phy_event"
479e86db79SHyon Kim #define	ESC_DR_TARGET_STATE_CHANGE  "ESC_dr_target_state_change"
489e86db79SHyon Kim 
499e86db79SHyon Kim /* Broadcast Event Types */
509e86db79SHyon Kim #define	SAS_PORT_BROADCAST_CHANGE   "port_broadcast_change"
519e86db79SHyon Kim #define	SAS_PORT_BROADCAST_SES	    "port_broadcast_ses"
529e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D24_0    "port_broadcast_d24_0"
539e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D27_4    "port_broadcast_d27_4"
549e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D01_4    "port_broadcast_d01_4"
559e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D04_7    "port_broadcast_d04_7"
569e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D16_7    "port_broadcast_d16_7"
579e86db79SHyon Kim #define	SAS_PORT_BROADCAST_D29_7    "port_broadcast_d29_7"
589e86db79SHyon Kim 
599e86db79SHyon Kim /* Phy Event Types */
609e86db79SHyon Kim #define	SAS_PHY_ONLINE		"port_online"
619e86db79SHyon Kim #define	SAS_PHY_OFFLINE		"port_offline"
629e86db79SHyon Kim #define	SAS_PHY_REMOVE		"port_remove"
639e86db79SHyon Kim 
649e86db79SHyon Kim /* Event payload */
659e86db79SHyon Kim #define	SAS_DRV_INST		"driver_instance"
669e86db79SHyon Kim #define	SAS_PORT_ADDR		"port_address"
679e86db79SHyon Kim #define	SAS_DEVFS_PATH		"devfs_path"
689e86db79SHyon Kim #define	SAS_EVENT_TYPE		"event_type"
699e86db79SHyon Kim 
709e86db79SHyon Kim #define	HBA_PORT_MATCH		1
719e86db79SHyon Kim #define	TARGET_PORT_MATCH	2
729e86db79SHyon Kim #define	PHY_MATCH		3
739e86db79SHyon Kim 
749e86db79SHyon Kim #define	REMOVED		1
759e86db79SHyon Kim #define	ONLINE		2
769e86db79SHyon Kim #define	OFFLINE		3
779e86db79SHyon Kim 
789e86db79SHyon Kim sysevent_handle_t *gSysEventHandle = NULL;
799e86db79SHyon Kim 
809e86db79SHyon Kim /* Calls the client callback function, if one is registered */
819e86db79SHyon Kim static HBA_STATUS
updateMatchingPhy(HBA_WWN portAddr,uint8_t phyId,int update,uint8_t linkRate)829e86db79SHyon Kim updateMatchingPhy(HBA_WWN portAddr, uint8_t phyId, int update, uint8_t linkRate)
839e86db79SHyon Kim {
849e86db79SHyon Kim 	const char  ROUTINE[] = "updateMatchingPhy";
859e86db79SHyon Kim 	struct sun_sas_hba	*hba_ptr;
869e86db79SHyon Kim 	struct sun_sas_port	*hba_port_ptr;
879e86db79SHyon Kim 	struct phy_info		*phy_ptr;
889e86db79SHyon Kim 
899e86db79SHyon Kim 	log(LOG_DEBUG, ROUTINE, "- phy matching");
909e86db79SHyon Kim 	/* grab write lock */
919e86db79SHyon Kim 	lock(&all_hbas_lock);
929e86db79SHyon Kim 	/* loop through HBAs */
939e86db79SHyon Kim 	for (hba_ptr = global_hba_head; hba_ptr != NULL;
949e86db79SHyon Kim 	    hba_ptr = hba_ptr->next) {
959e86db79SHyon Kim 		/* loop through HBA ports */
969e86db79SHyon Kim 		for (hba_port_ptr = hba_ptr->first_port;
979e86db79SHyon Kim 		    hba_port_ptr != NULL;
989e86db79SHyon Kim 		    hba_port_ptr = hba_port_ptr->next) {
999e86db79SHyon Kim 			if (wwnConversion(hba_port_ptr->
1009e86db79SHyon Kim 			    port_attributes.PortSpecificAttribute.
1019e86db79SHyon Kim 			    SASPort->LocalSASAddress.wwn) ==
1029e86db79SHyon Kim 			    wwnConversion(portAddr.wwn)) {
1039e86db79SHyon Kim 				/* loop through phys */
1049e86db79SHyon Kim 				for (phy_ptr = hba_port_ptr->first_phy;
1059e86db79SHyon Kim 				    phy_ptr != NULL; phy_ptr =
1069e86db79SHyon Kim 				    phy_ptr->next) {
1079e86db79SHyon Kim 					if (phy_ptr->phy.PhyIdentifier ==
1089e86db79SHyon Kim 					    phyId) {
1099e86db79SHyon Kim 						if (update == REMOVED) {
1109e86db79SHyon Kim 							phy_ptr->invalid =
1119e86db79SHyon Kim 							    B_TRUE;
1129e86db79SHyon Kim 						} else if (update == OFFLINE) {
1139e86db79SHyon Kim 							phy_ptr->phy.
1149e86db79SHyon Kim 							    NegotiatedLinkRate
1159e86db79SHyon Kim 							    = 0;
1169e86db79SHyon Kim 						} else { /* online */
1179e86db79SHyon Kim 							phy_ptr->phy.
1189e86db79SHyon Kim 							    NegotiatedLinkRate
1199e86db79SHyon Kim 							    = linkRate;
1209e86db79SHyon Kim 						}
1219e86db79SHyon Kim 						unlock(&all_hbas_lock);
1229e86db79SHyon Kim 						return (HBA_STATUS_OK);
1239e86db79SHyon Kim 					}
1249e86db79SHyon Kim 				} /* for phys */
1259e86db79SHyon Kim 			} /* wwn mismatch. continue */
1269e86db79SHyon Kim 		} /* for HBA ports */
1279e86db79SHyon Kim 	} /* for HBAs */
1289e86db79SHyon Kim 
1299e86db79SHyon Kim 	unlock(&all_hbas_lock);
1309e86db79SHyon Kim 	return (HBA_STATUS_ERROR);
1319e86db79SHyon Kim }
1329e86db79SHyon Kim 
1339e86db79SHyon Kim /* Event handler called by system */
1349e86db79SHyon Kim static void
syseventHandler(sysevent_t * ev)1359e86db79SHyon Kim syseventHandler(sysevent_t *ev)
1369e86db79SHyon Kim {
1379e86db79SHyon Kim 
1389e86db79SHyon Kim 	const char	ROUTINE[] = "syseventHandler";
1399e86db79SHyon Kim 	nvlist_t	*attrList = NULL;
1409e86db79SHyon Kim 	char		*eventStr, *portAddrStr, *charptr;
1419e86db79SHyon Kim 	int		update;
1429e86db79SHyon Kim 	uint64_t	addr;
1439e86db79SHyon Kim 	uint8_t		phyId, linkRate;
1449e86db79SHyon Kim 	HBA_WWN		portAddr;
1459e86db79SHyon Kim 
1469e86db79SHyon Kim 	/* Is the event one of ours? */
1479e86db79SHyon Kim 	if (strncmp(EC_HBA, sysevent_get_class_name(ev), strlen(EC_HBA)) == 0) {
1489e86db79SHyon Kim 		/* handle phy events */
1499e86db79SHyon Kim 		if (strncmp(ESC_SAS_PHY_EVENT, sysevent_get_subclass_name(ev),
1509e86db79SHyon Kim 		    strlen(ESC_SAS_PHY_EVENT)) == 0) {
1519e86db79SHyon Kim 			if (sysevent_get_attr_list(ev, &attrList) != 0) {
1529e86db79SHyon Kim 				log(LOG_DEBUG, ROUTINE,
1539e86db79SHyon Kim 				    "Failed to get event attributes on %s/%s",
1549e86db79SHyon Kim 				    EC_HBA, ESC_SAS_PHY_EVENT);
1559e86db79SHyon Kim 				return;
1569e86db79SHyon Kim 			} else {
1579e86db79SHyon Kim 				if (nvlist_lookup_string(attrList,
1589e86db79SHyon Kim 				    "event_type", &eventStr) != 0) {
1599e86db79SHyon Kim 					log(LOG_DEBUG, ROUTINE,
1609e86db79SHyon Kim 					    "Event type not found");
1619e86db79SHyon Kim 					return;
1629e86db79SHyon Kim 				} else {
1639e86db79SHyon Kim 					if (strncmp(eventStr, "phy_online",
1649e86db79SHyon Kim 					    sizeof (eventStr)) == 0) {
1659e86db79SHyon Kim 						update = ONLINE;
1669e86db79SHyon Kim 						if (nvlist_lookup_uint8(
1679e86db79SHyon Kim 						    attrList, "link_rate",
1689e86db79SHyon Kim 						    &linkRate) != 0) {
1699e86db79SHyon Kim 							log(LOG_DEBUG, ROUTINE,
1709e86db79SHyon Kim 							    "Link Rate not \
1719e86db79SHyon Kim 							    found");
1729e86db79SHyon Kim 							return;
1739e86db79SHyon Kim 						}
1749e86db79SHyon Kim 					} else if (strncmp(eventStr,
1759e86db79SHyon Kim 					    "phy_offline",
1769e86db79SHyon Kim 					    sizeof (eventStr)) == 0) {
1779e86db79SHyon Kim 						update = OFFLINE;
1789e86db79SHyon Kim 					} else if (strncmp(eventStr,
1799e86db79SHyon Kim 					    "phy_remove",
1809e86db79SHyon Kim 					    sizeof (eventStr)) == 0) {
1819e86db79SHyon Kim 						update = REMOVED;
1829e86db79SHyon Kim 					} else {
1839e86db79SHyon Kim 						log(LOG_DEBUG, ROUTINE,
1849e86db79SHyon Kim 						    "Invalid event type");
1859e86db79SHyon Kim 						return;
1869e86db79SHyon Kim 					}
1879e86db79SHyon Kim 				}
1889e86db79SHyon Kim 				if (nvlist_lookup_string(attrList,
1899e86db79SHyon Kim 				    "port_address", &portAddrStr) != 0) {
1909e86db79SHyon Kim 					log(LOG_DEBUG, ROUTINE,
1919e86db79SHyon Kim 					    "Port SAS address not found");
1929e86db79SHyon Kim 					return;
1939e86db79SHyon Kim 				} else {
1949e86db79SHyon Kim 					for (charptr = portAddrStr;
1959e86db79SHyon Kim 					    charptr != NULL; charptr++) {
1969e86db79SHyon Kim 						if (isxdigit(*charptr)) {
1979e86db79SHyon Kim 							break;
1989e86db79SHyon Kim 						}
1999e86db79SHyon Kim 					}
2009e86db79SHyon Kim 					addr = htonll(strtoll(charptr,
2019e86db79SHyon Kim 					    NULL, 16));
2029e86db79SHyon Kim 					(void) memcpy(portAddr.wwn, &addr, 8);
2039e86db79SHyon Kim 				}
2049e86db79SHyon Kim 				if (nvlist_lookup_uint8(attrList,
2059e86db79SHyon Kim 				    "PhyIdentifier", &phyId) != 0) {
2069e86db79SHyon Kim 					log(LOG_DEBUG, ROUTINE,
2079e86db79SHyon Kim 					    "Port SAS address not found");
2089e86db79SHyon Kim 					return;
2099e86db79SHyon Kim 				}
2109e86db79SHyon Kim 			}
2119e86db79SHyon Kim 			if (updateMatchingPhy(portAddr, phyId, update,
2129e86db79SHyon Kim 			    linkRate) != HBA_STATUS_OK) {
2139e86db79SHyon Kim 				log(LOG_DEBUG, ROUTINE,
2149e86db79SHyon Kim 				    "updating phy for the events failed.");
2159e86db79SHyon Kim 			}
2169e86db79SHyon Kim 		}
2179e86db79SHyon Kim 	} else if (strncmp(EC_DR,  sysevent_get_class_name(ev), 2) == 0) {
2189e86db79SHyon Kim 		/* handle DR events */
2199e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE,
2209e86db79SHyon Kim 		    "handle EC_dr events.");
2219e86db79SHyon Kim 	} else {
2229e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE,
2239e86db79SHyon Kim 		    "Found Unregistered event. - exit");
2249e86db79SHyon Kim 		return;
2259e86db79SHyon Kim 	}
2269e86db79SHyon Kim 
2279e86db79SHyon Kim 	log(LOG_DEBUG, ROUTINE, "- exit");
2289e86db79SHyon Kim }
2299e86db79SHyon Kim 
2309e86db79SHyon Kim /* Registers events to the sysevent framework */
2319e86db79SHyon Kim HBA_STATUS
registerSysevent(void)232*00f453f4SRob Johnston registerSysevent(void)
233*00f453f4SRob Johnston {
2349e86db79SHyon Kim 	const char ROUTINE[] = "registerSysevent";
2359e86db79SHyon Kim 	const char *hba_subclass_list[] = {
2369e86db79SHyon Kim 		ESC_SAS_PHY_EVENT
2379e86db79SHyon Kim 	};
2389e86db79SHyon Kim 	const char *dr_subclass_list[] = {
2399e86db79SHyon Kim 		ESC_DR_TARGET_STATE_CHANGE
2409e86db79SHyon Kim 	};
2419e86db79SHyon Kim 
2429e86db79SHyon Kim 	gSysEventHandle = sysevent_bind_handle(syseventHandler);
2439e86db79SHyon Kim 	if (gSysEventHandle == NULL) {
2449e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE,
2459e86db79SHyon Kim 		    "- sysevent_bind_handle() failed");
2469e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE, "- error exit");
2479e86db79SHyon Kim 		return (HBA_STATUS_ERROR);
2489e86db79SHyon Kim 	}
2499e86db79SHyon Kim 
2509e86db79SHyon Kim 	if (sysevent_subscribe_event(gSysEventHandle, EC_HBA,
2519e86db79SHyon Kim 	    hba_subclass_list, 1) != 0) {
2529e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE,
2539e86db79SHyon Kim 		    "- sysevent_subscribe_event() failed for EC_HBA subclass");
2549e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE, "- error exit");
2559e86db79SHyon Kim 		sysevent_unbind_handle(gSysEventHandle);
2569e86db79SHyon Kim 		return (HBA_STATUS_ERROR);
2579e86db79SHyon Kim 	}
2589e86db79SHyon Kim 
2599e86db79SHyon Kim 	if (sysevent_subscribe_event(gSysEventHandle, EC_DR,
2609e86db79SHyon Kim 	    dr_subclass_list, 1) != 0) {
2619e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE,
2629e86db79SHyon Kim 		    "- sysevent_subscribe_event() failed for DR subclass");
2639e86db79SHyon Kim 		log(LOG_DEBUG, ROUTINE, "- error exit");
2649e86db79SHyon Kim 		sysevent_unbind_handle(gSysEventHandle);
2659e86db79SHyon Kim 		return (HBA_STATUS_ERROR);
2669e86db79SHyon Kim 	}
2679e86db79SHyon Kim 
2689e86db79SHyon Kim 	log(LOG_DEBUG, ROUTINE, "- exit");
2699e86db79SHyon Kim 
2709e86db79SHyon Kim 	return (HBA_STATUS_ERROR);
2719e86db79SHyon Kim }
272