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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * PICL Ontario platform plug-in to message the SC to light
28 * or extinguish the hdd 'OK2RM' ready-to-service light in
29 * the event of a soft unconfigure or configure, respectively.
31 * Erie platforms (T1000) do not have ok-to-remove LEDs
32 * so they do not need handlers for the SBL events.
41 #include <libnvpair.h>
47 #include <sys/types.h>
50 #include <sys/param.h>
51 #include <sys/raidioctl.h>
52 #include <sys/utsname.h>
53 #include <sys/systeminfo.h>
59 #pragma init(piclsbl_register)
61 static void *pcp_handle
;
63 static char hba_devctl
[MAXPATHLEN
];
65 static int (* pcp_init_ptr
)();
66 static int (* pcp_send_recv_ptr
)();
67 static int (* pcp_close_ptr
)();
69 static int load_pcp_libs(void);
70 static void piclsbl_init(void);
71 static void piclsbl_fini(void);
72 static void piclsbl_register(void);
73 static void piclsbl_handler(const char *ename
, const void *earg
,
74 size_t size
, void *cookie
);
76 static picld_plugin_reg_t piclsbl_reg
= {
77 PICLD_PLUGIN_VERSION_1
,
78 PICLD_PLUGIN_CRITICAL
,
85 * called from init to load the pcp library
92 (void) snprintf(pcp_dl_lib
, sizeof (pcp_dl_lib
), "%s%s",
93 LIB_PCP_PATH
, PCPLIB
);
95 /* load the library and set up function pointers */
96 if ((pcp_handle
= dlopen(pcp_dl_lib
, RTLD_NOW
)) == NULL
)
99 pcp_init_ptr
= (int(*)())dlsym(pcp_handle
, "pcp_init");
100 pcp_close_ptr
= (int(*)())dlsym(pcp_handle
, "pcp_close");
101 pcp_send_recv_ptr
= (int(*)())dlsym(pcp_handle
, "pcp_send_recv");
103 if (pcp_init_ptr
== NULL
|| pcp_send_recv_ptr
== NULL
||
104 pcp_close_ptr
== NULL
)
111 * callback routine for ptree_walk_tree_by_class()
114 cb_find_disk(picl_nodehdl_t node
, void *args
)
116 disk_lookup_t
*lookup
= (disk_lookup_t
*)args
;
119 char path
[PICL_PROPNAMELEN_MAX
];
121 status
= ptree_get_propval_by_name(node
, "Path", (void *)&path
,
122 PICL_PROPNAMELEN_MAX
);
123 if (status
!= PICL_SUCCESS
) {
124 return (PICL_WALK_CONTINUE
);
127 if (strcmp(path
, lookup
->path
) == 0) {
129 lookup
->result
= DISK_FOUND
;
131 /* store the HBA's device path for use in check_raid() */
132 n
= strstr(path
, "/sd");
134 (void) snprintf(hba_devctl
, MAXPATHLEN
, "/devices%s:devctl",
137 return (PICL_WALK_TERMINATE
);
140 return (PICL_WALK_CONTINUE
);
144 * check a target for RAID membership
147 check_raid(int target
)
149 raid_config_t config
;
156 * hba_devctl is set to the onboard hba, so it will
157 * always house any onboard RAID volumes
159 if ((fd
= open(hba_devctl
, O_RDONLY
)) < 0) {
160 syslog(LOG_ERR
, "%s", strerror(errno
));
165 * look up the RAID configurations for the onboard
166 * HBA and check target against all member targets
168 if (ioctl(fd
, RAID_NUMVOLUMES
, &numvols
)) {
169 syslog(LOG_ERR
, "%s", strerror(errno
));
174 for (i
= 0; i
< numvols
; i
++) {
176 if (ioctl(fd
, RAID_GETCONFIG
, &config
)) {
177 syslog(LOG_ERR
, "%s", strerror(errno
));
182 for (j
= 0; j
< config
.ndisks
; j
++) {
183 if (config
.disk
[j
] == target
) {
194 * Ontario SBL event handler, subscribed to:
195 * PICLEVENT_SYSEVENT_DEVICE_ADDED
196 * PICLEVENT_SYSEVENT_DEVICE_REMOVED
199 piclsbl_handler(const char *ename
, const void *earg
, size_t size
,
203 char hdd_location
[PICL_PROPNAMELEN_MAX
];
204 nvlist_t
*nvlp
= NULL
;
207 pcp_sbl_req_t
*req_ptr
= NULL
;
208 pcp_sbl_resp_t
*resp_ptr
= NULL
;
211 disk_lookup_t lookup
;
215 * setup the request data to attach to the libpcp msg
217 if ((req_ptr
= (pcp_sbl_req_t
*)umem_zalloc(sizeof (pcp_sbl_req_t
),
218 UMEM_DEFAULT
)) == NULL
)
222 * This plugin serves to enable or disable the blue RAS
223 * 'ok-to-remove' LED that is on each of the 4 disks on the
224 * Ontario. We catch the event via the picl handler, and
225 * if the event is DEVICE_ADDED for one of our onboard disks,
226 * then we'll be turning off the LED. Otherwise, if the event
227 * is DEVICE_REMOVED, then we turn it on.
229 if (strcmp(ename
, PICLEVENT_SYSEVENT_DEVICE_ADDED
) == 0)
230 req_ptr
->sbl_action
= PCP_SBL_DISABLE
;
231 else if (strcmp(ename
, PICLEVENT_SYSEVENT_DEVICE_REMOVED
) == 0)
232 req_ptr
->sbl_action
= PCP_SBL_ENABLE
;
237 * retrieve the device's physical path from the event payload
239 if (nvlist_unpack((char *)earg
, size
, &nvlp
, NULL
))
241 if (nvlist_lookup_string(nvlp
, "devfs-path", &devfs_path
))
245 * look for this disk in the picl tree, and if it's
246 * location indicates that it's one of our internal
247 * disks, then set sbl_id to incdicate which one.
248 * otherwise, return as it is not one of our disks.
250 lookup
.path
= strdup(devfs_path
);
252 lookup
.result
= DISK_NOT_FOUND
;
254 /* first, find the disk */
255 status
= ptree_walk_tree_by_class(root_node
, "disk", (void *)&lookup
,
257 if (status
!= PICL_SUCCESS
)
260 if (lookup
.result
== DISK_FOUND
) {
261 /* now, lookup it's location in the node */
262 status
= ptree_get_propval_by_name(lookup
.disk
, "Location",
263 (void *)&hdd_location
, PICL_PROPNAMELEN_MAX
);
264 if (status
!= PICL_SUCCESS
) {
265 syslog(LOG_ERR
, "piclsbl: failed hdd discovery");
271 * Strip off the target from the NAC name.
272 * The disk NAC will always be HDD#
274 if (strncmp(hdd_location
, NAC_DISK_PREFIX
,
275 strlen(NAC_DISK_PREFIX
)) == 0) {
276 (void) sscanf(hdd_location
, "%*3s%d", &req_ptr
->sbl_id
);
277 target
= (int)req_ptr
->sbl_id
;
279 /* this is not one of the onboard disks */
284 * check the onboard RAID configuration for this disk. if it is
285 * a member of a RAID and is not the RAID itself, ignore the event
287 if (check_raid(target
))
291 * we have the information we need, init the platform channel.
292 * the platform channel driver will only allow one connection
293 * at a time on this socket. on the offchance that more than
294 * one event comes in, we'll retry to initialize this connection
297 if ((channel_fd
= (*pcp_init_ptr
)(LED_CHANNEL
)) < 0) {
298 /* failed to init; wait and retry up to 3 times */
299 int s
= PCPINIT_TIMEOUT
;
303 if ((channel_fd
= (*pcp_init_ptr
)(LED_CHANNEL
)) >= 0)
305 else if (retries
== 3) {
306 syslog(LOG_ERR
, "piclsbl: ",
307 "SC channel initialization failed");
315 * populate the message for libpcp
317 send_msg
.msg_type
= PCP_SBL_CONTROL
;
318 send_msg
.sub_type
= NULL
;
319 send_msg
.msg_len
= sizeof (pcp_sbl_req_t
);
320 send_msg
.msg_data
= (uint8_t *)req_ptr
;
323 * send the request, receive the response
325 if ((*pcp_send_recv_ptr
)(channel_fd
, &send_msg
, &recv_msg
,
326 PCPCOMM_TIMEOUT
) < 0) {
327 /* we either timed out or erred; either way try again */
328 int s
= PCPCOMM_TIMEOUT
;
330 if ((*pcp_send_recv_ptr
)(channel_fd
, &send_msg
, &recv_msg
,
331 PCPCOMM_TIMEOUT
) < 0) {
332 syslog(LOG_ERR
, "piclsbl: communication failure");
338 * validate that this data was meant for us
340 if (recv_msg
.msg_type
!= PCP_SBL_CONTROL_R
) {
341 syslog(LOG_ERR
, "piclsbl: unbound packet received");
346 * verify that the LED action has taken place
348 resp_ptr
= (pcp_sbl_resp_t
*)recv_msg
.msg_data
;
349 if (resp_ptr
->status
== PCP_SBL_ERROR
) {
350 syslog(LOG_ERR
, "piclsbl: OK2RM LED action error");
355 * ensure the LED action taken is the one requested
357 if ((req_ptr
->sbl_action
== PCP_SBL_DISABLE
) &&
358 (resp_ptr
->sbl_state
!= SBL_STATE_OFF
))
359 syslog(LOG_ERR
, "piclsbl: OK2RM LED not OFF after disk "
361 else if ((req_ptr
->sbl_action
== PCP_SBL_ENABLE
) &&
362 (resp_ptr
->sbl_state
!= SBL_STATE_ON
))
363 syslog(LOG_ERR
, "piclsbl: OK2RM LED not ON after disk "
365 else if (resp_ptr
->sbl_state
== SBL_STATE_UNKNOWN
)
366 syslog(LOG_ERR
, "piclsbl: OK2RM LED set to unknown state");
370 (*pcp_close_ptr
)(channel_fd
);
372 umem_free(req_ptr
, sizeof (pcp_sbl_req_t
));
380 char platbuf
[SYS_NMLN
];
382 /* check for Erie platform name */
383 if ((sysinfo(SI_PLATFORM
, platbuf
, SYS_NMLN
) != -1) &&
384 ((strcmp(platbuf
, ERIE_PLATFORM
) == 0) ||
385 (strcmp(platbuf
, ERIE_PLATFORM2
) == 0)))
388 /* retrieve the root node for lookups in the event handler */
389 if ((ptree_get_root(&root_node
)) != NULL
)
393 if (load_pcp_libs()) {
394 syslog(LOG_ERR
, "piclsbl: failed to load libpcp");
395 syslog(LOG_ERR
, "piclsbl: aborting");
400 * register piclsbl_handler for both "sysevent-device-added" and
401 * and for "sysevent-device-removed" PICL events
403 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED
,
404 piclsbl_handler
, NULL
);
405 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED
,
406 piclsbl_handler
, NULL
);
412 /* unregister the event handler */
413 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED
,
414 piclsbl_handler
, NULL
);
415 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED
,
416 piclsbl_handler
, NULL
);
420 piclsbl_register(void)
422 picld_plugin_register(&piclsbl_reg
);