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
updateMatchingPhy(HBA_WWN portAddr,uint8_t phyId,int update,uint8_t linkRate)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
syseventHandler(sysevent_t * ev)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
registerSysevent(void)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