xref: /illumos-gate/usr/src/lib/sun_sas/common/event.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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