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