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