Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/picl/plugins/sun4v/piclsbl/piclsbl.c
+++ new/usr/src/cmd/picl/plugins/sun4v/piclsbl/piclsbl.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * PICL Ontario platform plug-in to message the SC to light
28 28 * or extinguish the hdd 'OK2RM' ready-to-service light in
29 29 * the event of a soft unconfigure or configure, respectively.
30 30 *
31 31 * Erie platforms (T1000) do not have ok-to-remove LEDs
32 32 * so they do not need handlers for the SBL events.
33 33 */
34 34
35 35 #include <picl.h>
36 36 #include <picltree.h>
37 37 #include <picldefs.h>
38 38 #include <stdio.h>
39 39 #include <umem.h>
40 40 #include <unistd.h>
41 41 #include <libnvpair.h>
42 42 #include <strings.h>
43 43 #include <syslog.h>
44 44 #include <dlfcn.h>
45 45 #include <link.h>
46 46 #include <signal.h>
47 47 #include <sys/types.h>
48 48 #include <sys/stat.h>
49 49 #include <fcntl.h>
50 50 #include <sys/param.h>
51 51 #include <sys/raidioctl.h>
52 52 #include <sys/utsname.h>
53 53 #include <sys/systeminfo.h>
54 54 #include <libpcp.h>
55 55 #include "piclsbl.h"
56 56
57 57 #include "errno.h"
58 58
59 59 #pragma init(piclsbl_register)
60 60
61 61 static void *pcp_handle;
62 62
63 63 static char hba_devctl[MAXPATHLEN];
64 64
65 65 static int (* pcp_init_ptr)();
66 66 static int (* pcp_send_recv_ptr)();
67 67 static int (* pcp_close_ptr)();
68 68
69 69 static int load_pcp_libs(void);
70 70 static void piclsbl_init(void);
71 71 static void piclsbl_fini(void);
72 72 static void piclsbl_register(void);
73 73 static void piclsbl_handler(const char *ename, const void *earg,
74 74 size_t size, void *cookie);
75 75
76 76 static picld_plugin_reg_t piclsbl_reg = {
77 77 PICLD_PLUGIN_VERSION_1,
78 78 PICLD_PLUGIN_CRITICAL,
79 79 "piclsbl",
80 80 piclsbl_init,
81 81 piclsbl_fini
82 82 };
83 83
84 84 /*
85 85 * called from init to load the pcp library
86 86 */
87 87 static int
88 88 load_pcp_libs()
89 89 {
90 90 char pcp_dl_lib[80];
91 91
92 92 (void) snprintf(pcp_dl_lib, sizeof (pcp_dl_lib), "%s%s",
93 93 LIB_PCP_PATH, PCPLIB);
94 94
95 95 /* load the library and set up function pointers */
96 96 if ((pcp_handle = dlopen(pcp_dl_lib, RTLD_NOW)) == (void *) NULL)
97 97 return (1);
98 98
99 99 pcp_init_ptr = (int(*)())dlsym(pcp_handle, "pcp_init");
100 100 pcp_close_ptr = (int(*)())dlsym(pcp_handle, "pcp_close");
101 101 pcp_send_recv_ptr = (int(*)())dlsym(pcp_handle, "pcp_send_recv");
102 102
103 103 if (pcp_init_ptr == NULL || pcp_send_recv_ptr == NULL ||
104 104 pcp_close_ptr == NULL)
105 105 return (1);
106 106
107 107 return (0);
108 108 }
109 109
110 110 /*
111 111 * callback routine for ptree_walk_tree_by_class()
112 112 */
113 113 static int
114 114 cb_find_disk(picl_nodehdl_t node, void *args)
115 115 {
116 116 disk_lookup_t *lookup = (disk_lookup_t *)args;
117 117 int status = -1;
118 118 char *n;
119 119 char path[PICL_PROPNAMELEN_MAX];
120 120
121 121 status = ptree_get_propval_by_name(node, "Path", (void *)&path,
122 122 PICL_PROPNAMELEN_MAX);
123 123 if (status != PICL_SUCCESS) {
124 124 return (PICL_WALK_CONTINUE);
125 125 }
126 126
127 127 if (strcmp(path, lookup->path) == 0) {
128 128 lookup->disk = node;
129 129 lookup->result = DISK_FOUND;
130 130
131 131 /* store the HBA's device path for use in check_raid() */
132 132 n = strstr(path, "/sd");
133 133 strncpy(n, "\0", 1);
134 134 (void) snprintf(hba_devctl, MAXPATHLEN, "/devices%s:devctl",
135 135 path);
136 136
137 137 return (PICL_WALK_TERMINATE);
138 138 }
139 139
140 140 return (PICL_WALK_CONTINUE);
141 141 }
142 142
143 143 /*
144 144 * check a target for RAID membership
145 145 */
146 146 static int
147 147 check_raid(int target)
148 148 {
149 149 raid_config_t config;
150 150 int fd;
151 151 int numvols;
152 152 int i;
153 153 int j;
154 154
155 155 /*
156 156 * hba_devctl is set to the onboard hba, so it will
157 157 * always house any onboard RAID volumes
158 158 */
159 159 if ((fd = open(hba_devctl, O_RDONLY)) < 0) {
160 160 syslog(LOG_ERR, "%s", strerror(errno));
161 161 return (0);
162 162 }
163 163
164 164 /*
165 165 * look up the RAID configurations for the onboard
166 166 * HBA and check target against all member targets
167 167 */
168 168 if (ioctl(fd, RAID_NUMVOLUMES, &numvols)) {
169 169 syslog(LOG_ERR, "%s", strerror(errno));
170 170 (void) close(fd);
171 171 return (0);
172 172 }
173 173
174 174 for (i = 0; i < numvols; i++) {
175 175 config.unitid = i;
176 176 if (ioctl(fd, RAID_GETCONFIG, &config)) {
177 177 syslog(LOG_ERR, "%s", strerror(errno));
178 178 (void) close(fd);
179 179 return (0);
180 180 }
181 181
182 182 for (j = 0; j < config.ndisks; j++) {
183 183 if (config.disk[j] == target) {
184 184 (void) close(fd);
185 185 return (1);
186 186 }
187 187 }
188 188 }
189 189 (void) close(fd);
190 190 return (0);
191 191 }
192 192
193 193 /*
194 194 * Ontario SBL event handler, subscribed to:
195 195 * PICLEVENT_SYSEVENT_DEVICE_ADDED
196 196 * PICLEVENT_SYSEVENT_DEVICE_REMOVED
197 197 */
198 198 static void
199 199 piclsbl_handler(const char *ename, const void *earg, size_t size,
200 200 void *cookie)
201 201 {
202 202 char *devfs_path;
203 203 char hdd_location[PICL_PROPNAMELEN_MAX];
204 204 nvlist_t *nvlp = NULL;
205 205 pcp_msg_t send_msg;
206 206 pcp_msg_t recv_msg;
207 207 pcp_sbl_req_t *req_ptr = NULL;
208 208 pcp_sbl_resp_t *resp_ptr = NULL;
209 209 int status = -1;
210 210 int target;
211 211 disk_lookup_t lookup;
212 212 int channel_fd;
213 213
214 214 /*
215 215 * setup the request data to attach to the libpcp msg
216 216 */
217 217 if ((req_ptr = (pcp_sbl_req_t *)umem_zalloc(sizeof (pcp_sbl_req_t),
218 218 UMEM_DEFAULT)) == NULL)
219 219 goto sbl_return;
220 220
221 221 /*
222 222 * This plugin serves to enable or disable the blue RAS
223 223 * 'ok-to-remove' LED that is on each of the 4 disks on the
224 224 * Ontario. We catch the event via the picl handler, and
225 225 * if the event is DEVICE_ADDED for one of our onboard disks,
226 226 * then we'll be turning off the LED. Otherwise, if the event
227 227 * is DEVICE_REMOVED, then we turn it on.
228 228 */
229 229 if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0)
230 230 req_ptr->sbl_action = PCP_SBL_DISABLE;
231 231 else if (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0)
232 232 req_ptr->sbl_action = PCP_SBL_ENABLE;
233 233 else
234 234 goto sbl_return;
235 235
236 236 /*
237 237 * retrieve the device's physical path from the event payload
238 238 */
239 239 if (nvlist_unpack((char *)earg, size, &nvlp, NULL))
240 240 goto sbl_return;
241 241 if (nvlist_lookup_string(nvlp, "devfs-path", &devfs_path))
242 242 goto sbl_return;
243 243
244 244 /*
245 245 * look for this disk in the picl tree, and if it's
246 246 * location indicates that it's one of our internal
247 247 * disks, then set sbl_id to incdicate which one.
248 248 * otherwise, return as it is not one of our disks.
249 249 */
250 250 lookup.path = strdup(devfs_path);
251 251 lookup.disk = NULL;
252 252 lookup.result = DISK_NOT_FOUND;
253 253
254 254 /* first, find the disk */
255 255 status = ptree_walk_tree_by_class(root_node, "disk", (void *)&lookup,
256 256 cb_find_disk);
257 257 if (status != PICL_SUCCESS)
258 258 goto sbl_return;
259 259
260 260 if (lookup.result == DISK_FOUND) {
261 261 /* now, lookup it's location in the node */
262 262 status = ptree_get_propval_by_name(lookup.disk, "Location",
263 263 (void *)&hdd_location, PICL_PROPNAMELEN_MAX);
264 264 if (status != PICL_SUCCESS) {
265 265 syslog(LOG_ERR, "piclsbl: failed hdd discovery");
266 266 goto sbl_return;
267 267 }
268 268 }
269 269
270 270 /*
271 271 * Strip off the target from the NAC name.
272 272 * The disk NAC will always be HDD#
273 273 */
274 274 if (strncmp(hdd_location, NAC_DISK_PREFIX,
275 275 strlen(NAC_DISK_PREFIX)) == 0) {
276 276 (void) sscanf(hdd_location, "%*3s%d", &req_ptr->sbl_id);
277 277 target = (int)req_ptr->sbl_id;
278 278 } else {
279 279 /* this is not one of the onboard disks */
280 280 goto sbl_return;
281 281 }
282 282
283 283 /*
284 284 * check the onboard RAID configuration for this disk. if it is
285 285 * a member of a RAID and is not the RAID itself, ignore the event
286 286 */
287 287 if (check_raid(target))
288 288 goto sbl_return;
289 289
290 290 /*
291 291 * we have the information we need, init the platform channel.
292 292 * the platform channel driver will only allow one connection
293 293 * at a time on this socket. on the offchance that more than
294 294 * one event comes in, we'll retry to initialize this connection
295 295 * up to 3 times
296 296 */
297 297 if ((channel_fd = (*pcp_init_ptr)(LED_CHANNEL)) < 0) {
298 298 /* failed to init; wait and retry up to 3 times */
299 299 int s = PCPINIT_TIMEOUT;
300 300 int retries = 0;
301 301 while (++retries) {
302 302 (void) sleep(s);
303 303 if ((channel_fd = (*pcp_init_ptr)(LED_CHANNEL)) >= 0)
304 304 break;
305 305 else if (retries == 3) {
306 306 syslog(LOG_ERR, "piclsbl: ",
307 307 "SC channel initialization failed");
308 308 goto sbl_return;
309 309 }
310 310 /* continue */
311 311 }
312 312 }
313 313
314 314 /*
315 315 * populate the message for libpcp
316 316 */
317 317 send_msg.msg_type = PCP_SBL_CONTROL;
318 318 send_msg.sub_type = NULL;
319 319 send_msg.msg_len = sizeof (pcp_sbl_req_t);
320 320 send_msg.msg_data = (uint8_t *)req_ptr;
321 321
322 322 /*
323 323 * send the request, receive the response
324 324 */
325 325 if ((*pcp_send_recv_ptr)(channel_fd, &send_msg, &recv_msg,
326 326 PCPCOMM_TIMEOUT) < 0) {
327 327 /* we either timed out or erred; either way try again */
328 328 int s = PCPCOMM_TIMEOUT;
329 329 (void) sleep(s);
330 330 if ((*pcp_send_recv_ptr)(channel_fd, &send_msg, &recv_msg,
331 331 PCPCOMM_TIMEOUT) < 0) {
332 332 syslog(LOG_ERR, "piclsbl: communication failure");
333 333 goto sbl_return;
334 334 }
335 335 }
336 336
337 337 /*
338 338 * validate that this data was meant for us
339 339 */
340 340 if (recv_msg.msg_type != PCP_SBL_CONTROL_R) {
341 341 syslog(LOG_ERR, "piclsbl: unbound packet received");
342 342 goto sbl_return;
343 343 }
344 344
345 345 /*
346 346 * verify that the LED action has taken place
347 347 */
348 348 resp_ptr = (pcp_sbl_resp_t *)recv_msg.msg_data;
349 349 if (resp_ptr->status == PCP_SBL_ERROR) {
350 350 syslog(LOG_ERR, "piclsbl: OK2RM LED action error");
351 351 goto sbl_return;
352 352 }
353 353
354 354 /*
355 355 * ensure the LED action taken is the one requested
356 356 */
357 357 if ((req_ptr->sbl_action == PCP_SBL_DISABLE) &&
358 358 (resp_ptr->sbl_state != SBL_STATE_OFF))
359 359 syslog(LOG_ERR, "piclsbl: OK2RM LED not OFF after disk "
360 360 "configuration");
361 361 else if ((req_ptr->sbl_action == PCP_SBL_ENABLE) &&
362 362 (resp_ptr->sbl_state != SBL_STATE_ON))
363 363 syslog(LOG_ERR, "piclsbl: OK2RM LED not ON after disk "
364 364 "unconfiguration");
↓ open down ↓ |
364 lines elided |
↑ open up ↑ |
365 365 else if (resp_ptr->sbl_state == SBL_STATE_UNKNOWN)
366 366 syslog(LOG_ERR, "piclsbl: OK2RM LED set to unknown state");
367 367
368 368 sbl_return:
369 369
370 370 (*pcp_close_ptr)(channel_fd);
371 371 if (req_ptr != NULL)
372 372 umem_free(req_ptr, sizeof (pcp_sbl_req_t));
373 373 if (resp_ptr != NULL)
374 374 free(resp_ptr);
375 - if (nvlp != NULL)
376 - nvlist_free(nvlp);
375 + nvlist_free(nvlp);
377 376 }
378 377
379 378 static void
380 379 piclsbl_init(void)
381 380 {
382 381 char platbuf[SYS_NMLN];
383 382
384 383 /* check for Erie platform name */
385 384 if ((sysinfo(SI_PLATFORM, platbuf, SYS_NMLN) != -1) &&
386 385 ((strcmp(platbuf, ERIE_PLATFORM) == 0) ||
387 386 (strcmp(platbuf, ERIE_PLATFORM2) == 0)))
388 387 return;
389 388
390 389 /* retrieve the root node for lookups in the event handler */
391 390 if ((ptree_get_root(&root_node)) != NULL)
392 391 return;
393 392
394 393 /* load libpcp */
395 394 if (load_pcp_libs()) {
396 395 syslog(LOG_ERR, "piclsbl: failed to load libpcp");
397 396 syslog(LOG_ERR, "piclsbl: aborting");
398 397 return;
399 398 }
400 399
401 400 /*
402 401 * register piclsbl_handler for both "sysevent-device-added" and
403 402 * and for "sysevent-device-removed" PICL events
404 403 */
405 404 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
406 405 piclsbl_handler, NULL);
407 406 (void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
408 407 piclsbl_handler, NULL);
409 408 }
410 409
411 410 static void
412 411 piclsbl_fini(void)
413 412 {
414 413 /* unregister the event handler */
415 414 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
416 415 piclsbl_handler, NULL);
417 416 (void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
418 417 piclsbl_handler, NULL);
419 418 }
420 419
421 420 static void
422 421 piclsbl_register(void)
423 422 {
424 423 picld_plugin_register(&piclsbl_reg);
425 424 }
↓ open down ↓ |
39 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX