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