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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 #include <sys/time.h>
29 #include <sys/errno.h>
30 #include <sys/kmem.h>
31 #include <sys/stat.h>
32 #include <sys/cmn_err.h>
33
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/devops.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/callb.h>
40 #include <sys/disp.h>
41 #include <sys/strlog.h>
42
43 #include <sys/sgevents.h>
44 #include <sys/serengeti.h>
45 #include <sys/sgsbbc.h>
46 #include <sys/sgsbbc_iosram.h>
47 #include <sys/sgsbbc_mailbox.h>
48 #include <sys/uadmin.h>
49 #include <sys/machsystm.h>
50 #include <sys/sysevent.h>
51 #include <sys/sysevent/dr.h>
52 #include <sys/sysevent/eventdefs.h>
53 #include <sys/file.h>
54 #include <sys/lw8.h>
55 #include <sys/lw8_impl.h>
56 #include <sys/plat_ecc_unum.h>
57
58 /*
59 * Global Variables - can be patched from Solaris
60 * ==============================================
61 */
62
63 /*
64 * Module Variables
65 * ================
66 */
67
68 /*
69 * functions local to this driver.
70 */
71 static int lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
72 static int lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
73 static int lw8_add_intr_handlers(void);
74 static int lw8_remove_intr_handlers(void);
75 static void lw8_wakeup_sleepers(void);
76 static uint_t lw8_fast_shutdown(char *arg);
77 static uint_t lw8_slow_shutdown(char *arg);
78 static uint_t lw8_event_data_handler(char *);
79 static uint_t lw8_dr_data_handler(char *);
80 static uint_t lw8_env_data_handler(char *);
81 static uint_t lw8_cap_ecc_msg_handler(char *);
82 static int lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p);
83 static int lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
84 static int lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
85 cred_t *cred_p, int *rval_p);
86 static void lw8_logger_start(void);
87 static void lw8_logger_destroy(void);
88 static void lw8_logger_wakeup(void);
89
90 /*
91 * Driver entry points
92 */
93 static struct cb_ops lw8_cb_ops = {
94 lw8_open, /* open */
95 lw8_close, /* close */
96 nodev, /* strategy() */
97 nodev, /* print() */
98 nodev, /* dump() */
99 nodev, /* read() */
100 nodev, /* write() */
101 lw8_ioctl, /* ioctl() */
102 nodev, /* devmap() */
103 nodev, /* mmap() */
104 ddi_segmap, /* segmap() */
105 nochpoll, /* poll() */
106 ddi_prop_op, /* prop_op() */
107 NULL, /* cb_str */
108 D_NEW | D_MP /* cb_flag */
109 };
110
111
112 static struct dev_ops lw8_ops = {
113 DEVO_REV,
114 0, /* ref count */
115 ddi_getinfo_1to1, /* getinfo() */
116 nulldev, /* identify() */
117 nulldev, /* probe() */
118 lw8_attach, /* attach() */
119 lw8_detach, /* detach */
120 nodev, /* reset */
121 &lw8_cb_ops, /* pointer to cb_ops structure */
122 (struct bus_ops *)NULL,
123 nulldev, /* power() */
124 ddi_quiesce_not_needed, /* quiesce() */
125 };
126
127 /*
128 * Loadable module support.
129 */
130 extern struct mod_ops mod_driverops;
131
132 static struct modldrv modldrv = {
133 &mod_driverops, /* Type of module. This is a driver */
134 "Netra-T12 control driver", /* Name of the module */
135 &lw8_ops /* pointer to the dev_ops structure */
136 };
137
138 static struct modlinkage modlinkage = {
139 MODREV_1,
140 &modldrv,
141 NULL
142 };
143
144 /*
145 * messages
146 */
147 #define SHUTDOWN_EVENT_MSG "lw8: system shutdown due to " \
148 "SC request.\n"
149 #define VOLTAGE_EVENT_MSG "lw8: system shutdown due to " \
150 "voltage out of range.\n"
151 #define TEMPERATURE_EVENT_MSG "lw8: system shutdown due to " \
152 "temperature exceeding limits.\n"
153 #define FANFAIL_EVENT_MSG "lw8: system shutdown due to " \
154 "too many fan failures.\n"
155 #define NO_SCC_EVENT_MSG "lw8: system shutdown due to " \
156 "no system configuration card.\n"
157
158 /*
159 * led table - the following provides a cache of the led state - needed
160 * to avoid the overhead of readoing from the SC each time
161 */
162
163 struct led_info {
164 char id[MAX_ID_LEN];
165 int position;
166 int status;
167 char color[MAX_COLOR_LEN];
168 };
169
170 static struct fru_led_info {
171 char location[MAX_LOCATION_LEN];
172 struct led_info led_info[MAX_LEDS_PER_FRU];
173 } fru_led_table[MAX_FRUS] = {
174 "SB0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
175 "power", LOM_LED_POSITION_FRU, 0, "green",
176 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
177 "PS0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
178 "power", LOM_LED_POSITION_FRU, 0, "green",
179 "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
180 "SB2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
181 "power", LOM_LED_POSITION_FRU, 0, "green",
182 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
183 "PS1", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
184 "power", LOM_LED_POSITION_FRU, 0, "green",
185 "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
186 "SB4", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
187 "power", LOM_LED_POSITION_FRU, 0, "green",
188 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
189 "PS2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
190 "power", LOM_LED_POSITION_FRU, 0, "green",
191 "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
192 "IB6", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
193 "power", LOM_LED_POSITION_FRU, 0, "green",
194 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
195 "PS3", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
196 "power", LOM_LED_POSITION_FRU, 0, "green",
197 "predicted_fault", LOM_LED_POSITION_FRU, 0, "amber"},
198 "FT0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
199 "power", LOM_LED_POSITION_FRU, 0, "green",
200 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
201 "FAN0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
202 "FAN1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
203 "FAN2", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
204 "FAN3", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
205 "FAN4", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
206 "FAN5", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
207 "FAN6", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
208 "FAN7", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
209 "FAN8", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
210 "FAN9", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber"},
211 "DISK0", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber",
212 "power", LOM_LED_POSITION_LOCATION, 0, "green",
213 "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"},
214 "DISK1", {"fault", LOM_LED_POSITION_LOCATION, 0, "amber",
215 "power", LOM_LED_POSITION_LOCATION, 0, "green",
216 "ok_to_remove", LOM_LED_POSITION_LOCATION, 0, "blue"},
217 "RP0", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
218 "power", LOM_LED_POSITION_FRU, 0, "green",
219 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
220 "RP2", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
221 "power", LOM_LED_POSITION_FRU, 0, "green",
222 "ok_to_remove", LOM_LED_POSITION_FRU, 0, "amber"},
223 "chassis", {"fault", LOM_LED_POSITION_FRU, 0, "amber",
224 "power", LOM_LED_POSITION_FRU, 0, "green",
225 "locator", LOM_LED_POSITION_FRU, 0, "white",
226 "top_access", LOM_LED_POSITION_FRU, 0, "amber",
227 "alarm1", LOM_LED_POSITION_FRU, 0, "amber",
228 "alarm2", LOM_LED_POSITION_FRU, 0, "amber",
229 "system", LOM_LED_POSITION_FRU, 0, "green",
230 "supplyA", LOM_LED_POSITION_FRU, 0, "green",
231 "supplyB", LOM_LED_POSITION_FRU, 0, "green"},
232 };
233
234 char *fru_locn[MAX_LOCATION_LEN] = {
235 "SB0",
236 "PS0",
237 "SB2",
238 "PS1",
239 "SB4",
240 "PS2",
241 "IB6",
242 "PS3",
243 "SCC",
244 "SSC1",
245 };
246
247 /*
248 * mutexes which protect the interrupt handlers.
249 */
250 static kmutex_t lw8_shutdown_hdlr_lock;
251 static kmutex_t lw8_dr_hdlr_lock;
252 static kmutex_t lw8_env_hdlr_lock;
253 static kmutex_t lw8_event_mutex;
254 static kmutex_t lw8_logger_lock;
255 static kmutex_t lw8_cap_msg_hdlr_lock;
256 static kcondvar_t lw8_event_cv;
257 static kcondvar_t lw8_logger_sig_cv;
258
259 /*
260 * state booleans
261 */
262 static boolean_t lw8_event_pending = B_FALSE;
263 static boolean_t led_state_cached = B_FALSE;
264
265 /*
266 * Payloads of the event handlers.
267 */
268 static lw8_event_t lw8_shutdown_payload;
269 static sbbc_msg_t lw8_shutdown_payload_msg;
270 static sg_system_fru_descriptor_t lw8_dr_payload;
271 static sbbc_msg_t lw8_dr_payload_msg;
272 static sg_event_fan_status_t lw8_env_payload;
273 static sbbc_msg_t lw8_env_payload_msg;
274 static plat_capability_data_t lw8_cap_payload;
275 static sbbc_msg_t lw8_cap_payload_msg;
276
277 /*
278 * The IDs of the soft interrupts
279 */
280 static ddi_softintr_t lw8_slow_shutdown_softint_id;
281 static ddi_softintr_t lw8_fast_shutdown_softint_id;
282
283 /*
284 * Logger commands..
285 */
286 #define LW8_LOGGER_EXITNOW -1
287 #define LW8_LOGGER_WAIT 0
288 #define LW8_LOGGER_PROCESSNOW 1
289
290 /*
291 * Logger thread state
292 */
293 static int lw8_logger_sig = LW8_LOGGER_WAIT;
294 static kt_did_t lw8_logger_tid = 0;
295
296 extern pri_t maxclsyspri;
297
298 int
_init(void)299 _init(void)
300 {
301 int error = 0;
302
303 mutex_init(&lw8_shutdown_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
304 mutex_init(&lw8_dr_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
305 mutex_init(&lw8_env_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
306 mutex_init(&lw8_cap_msg_hdlr_lock, NULL, MUTEX_DEFAULT, NULL);
307 mutex_init(&lw8_event_mutex, NULL, MUTEX_DRIVER, NULL);
308 mutex_init(&lw8_logger_lock, NULL, MUTEX_DRIVER, NULL);
309 cv_init(&lw8_event_cv, NULL, CV_DRIVER, NULL);
310 cv_init(&lw8_logger_sig_cv, NULL, CV_DRIVER, NULL);
311
312 error = mod_install(&modlinkage);
313 if (error) {
314 cv_destroy(&lw8_logger_sig_cv);
315 cv_destroy(&lw8_event_cv);
316 mutex_destroy(&lw8_logger_lock);
317 mutex_destroy(&lw8_event_mutex);
318 mutex_destroy(&lw8_env_hdlr_lock);
319 mutex_destroy(&lw8_cap_msg_hdlr_lock);
320 mutex_destroy(&lw8_dr_hdlr_lock);
321 mutex_destroy(&lw8_shutdown_hdlr_lock);
322 }
323 return (error);
324 }
325
326
327 int
_info(struct modinfo * modinfop)328 _info(struct modinfo *modinfop)
329 {
330 return (mod_info(&modlinkage, modinfop));
331 }
332
333
334 int
_fini(void)335 _fini(void)
336 {
337 int error = 0;
338
339 error = mod_remove(&modlinkage);
340 if (error)
341 return (error);
342 cv_destroy(&lw8_logger_sig_cv);
343 cv_destroy(&lw8_event_cv);
344 mutex_destroy(&lw8_logger_lock);
345 mutex_destroy(&lw8_event_mutex);
346 mutex_destroy(&lw8_env_hdlr_lock);
347 mutex_destroy(&lw8_cap_msg_hdlr_lock);
348 mutex_destroy(&lw8_dr_hdlr_lock);
349 mutex_destroy(&lw8_shutdown_hdlr_lock);
350 return (error);
351 }
352
353
354 static int
lw8_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)355 lw8_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
356 {
357 int instance;
358 int err;
359
360 switch (cmd) {
361 case DDI_ATTACH:
362 /*
363 * only allow one instance
364 */
365 instance = ddi_get_instance(dip);
366 if (instance != 0)
367 return (DDI_FAILURE);
368
369 err = ddi_create_minor_node(dip, "lw8", S_IFCHR,
370 instance, DDI_PSEUDO, NULL);
371 if (err != DDI_SUCCESS)
372 return (DDI_FAILURE);
373
374 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
375 &lw8_slow_shutdown_softint_id, NULL, NULL,
376 lw8_slow_shutdown, NULL);
377 if (err != 0) {
378 cmn_err(CE_WARN, "Failed to add polling softint"
379 "handler for lw8. Err=%d", err);
380 ddi_remove_minor_node(dip, NULL);
381 return (DDI_FAILURE);
382 }
383
384 err = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
385 &lw8_fast_shutdown_softint_id, NULL, NULL,
386 lw8_fast_shutdown, NULL);
387 if (err != 0) {
388 cmn_err(CE_WARN, "Failed to add polling softint"
389 "handler for lw8. Err=%d", err);
390 ddi_remove_softintr(lw8_slow_shutdown_softint_id);
391 ddi_remove_minor_node(dip, NULL);
392 return (DDI_FAILURE);
393 }
394
395 lw8_logger_start();
396
397 /*
398 * Add the handlers which watch for unsolicited messages
399 * and post event to Sysevent Framework.
400 */
401 err = lw8_add_intr_handlers();
402 if (err != DDI_SUCCESS) {
403 cmn_err(CE_WARN, "Failed to add event handlers");
404 lw8_logger_destroy();
405 ddi_remove_softintr(lw8_fast_shutdown_softint_id);
406 ddi_remove_softintr(lw8_slow_shutdown_softint_id);
407 ddi_remove_minor_node(dip, NULL);
408 return (DDI_FAILURE);
409 }
410
411 ddi_report_dev(dip);
412 return (DDI_SUCCESS);
413 case DDI_RESUME:
414 return (DDI_SUCCESS);
415 default:
416 return (DDI_FAILURE);
417 }
418 }
419
420
421 static int
lw8_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)422 lw8_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
423 {
424 int instance;
425 int err;
426
427 switch (cmd) {
428 case DDI_DETACH:
429 instance = ddi_get_instance(dip);
430 if (instance != 0)
431 return (DDI_FAILURE);
432
433 /*
434 * Remove the handlers which watch for unsolicited messages
435 * and post event to Sysevent Framework.
436 */
437 err = lw8_remove_intr_handlers();
438 if (err != DDI_SUCCESS) {
439 cmn_err(CE_WARN, "Failed to remove event handlers");
440 return (DDI_FAILURE);
441 }
442 lw8_logger_destroy();
443 ddi_remove_softintr(lw8_slow_shutdown_softint_id);
444 ddi_remove_softintr(lw8_fast_shutdown_softint_id);
445 ddi_remove_minor_node(dip, NULL);
446 return (DDI_SUCCESS);
447 case DDI_SUSPEND:
448 return (DDI_SUCCESS);
449 default:
450 return (DDI_FAILURE);
451 }
452 }
453
454 static int
lw8_add_intr_handlers()455 lw8_add_intr_handlers()
456 {
457 int err;
458
459 lw8_shutdown_payload_msg.msg_buf = (caddr_t)&lw8_shutdown_payload;
460 lw8_shutdown_payload_msg.msg_len = sizeof (lw8_shutdown_payload);
461 err = sbbc_mbox_reg_intr(MBOX_EVENT_LW8, lw8_event_data_handler,
462 &lw8_shutdown_payload_msg, NULL, &lw8_shutdown_hdlr_lock);
463 if (err != 0) {
464 cmn_err(CE_WARN, "Failed to register MBOX_EVENT_LW8 "
465 " handler. Err=%d", err);
466 return (DDI_FAILURE);
467 }
468
469 lw8_dr_payload_msg.msg_buf = (caddr_t)&lw8_dr_payload;
470 lw8_dr_payload_msg.msg_len = sizeof (lw8_dr_payload);
471 err = sbbc_mbox_reg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler,
472 &lw8_dr_payload_msg, NULL, &lw8_dr_hdlr_lock);
473 if (err != 0) {
474 cmn_err(CE_WARN, "Failed to register MBOX_EVENT_GENERIC "
475 " handler. Err=%d", err);
476 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
477 lw8_event_data_handler);
478 return (DDI_FAILURE);
479 }
480
481 lw8_env_payload_msg.msg_buf = (caddr_t)&lw8_env_payload;
482 lw8_env_payload_msg.msg_len = sizeof (lw8_env_payload);
483 err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, lw8_env_data_handler,
484 &lw8_env_payload_msg, NULL, &lw8_env_hdlr_lock);
485 if (err != 0) {
486 cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV "
487 " handler. Err=%d", err);
488 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC,
489 lw8_dr_data_handler);
490 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
491 lw8_event_data_handler);
492 return (DDI_FAILURE);
493 }
494
495 lw8_cap_payload_msg.msg_buf = (caddr_t)&lw8_cap_payload;
496 lw8_cap_payload_msg.msg_len = sizeof (lw8_cap_payload);
497 err = sbbc_mbox_reg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler,
498 &lw8_cap_payload_msg, NULL, &lw8_cap_msg_hdlr_lock);
499 if (err != 0) {
500 cmn_err(CE_WARN, "Failed to register INFO_MBOX "
501 " handler. Err=%d", err);
502 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC,
503 lw8_dr_data_handler);
504 (void) sbbc_mbox_unreg_intr(MBOX_EVENT_LW8,
505 lw8_event_data_handler);
506 (void) sbbc_mbox_unreg_intr(INFO_MBOX,
507 lw8_cap_ecc_msg_handler);
508 return (DDI_FAILURE);
509 }
510
511 return (DDI_SUCCESS);
512 }
513
514 static int
lw8_remove_intr_handlers(void)515 lw8_remove_intr_handlers(void)
516 {
517 int rv = DDI_SUCCESS;
518 int err;
519
520 err = sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler);
521 if (err != 0) {
522 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_LW8 "
523 "handler. Err=%d", err);
524 rv = DDI_FAILURE;
525 }
526 err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler);
527 if (err != 0) {
528 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC "
529 "handler. Err=%d", err);
530 rv = DDI_FAILURE;
531 }
532 err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, lw8_env_data_handler);
533 if (err != 0) {
534 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV "
535 "handler. Err=%d", err);
536 rv = DDI_FAILURE;
537 }
538 err = sbbc_mbox_unreg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler);
539 if (err != 0) {
540 cmn_err(CE_WARN, "Failed to unregister INFO_MBOX "
541 "handler. Err=%d", err);
542 rv = DDI_FAILURE;
543 }
544 return (rv);
545 }
546
547 static uint_t
lw8_dr_data_handler(char * arg)548 lw8_dr_data_handler(char *arg)
549 {
550 sg_system_fru_descriptor_t *payload;
551 sbbc_msg_t *msg;
552 int hint;
553 sysevent_t *ev;
554 sysevent_id_t eid;
555 int rv = 0;
556 sysevent_value_t evnt_val;
557 sysevent_attr_list_t *evnt_attr_list = NULL;
558 char attach_pnt[MAXPATHLEN];
559
560 msg = (sbbc_msg_t *)arg;
561 if (msg == NULL) {
562 return (DDI_INTR_CLAIMED);
563 }
564 payload = (sg_system_fru_descriptor_t *)msg->msg_buf;
565 if (payload == NULL) {
566 return (DDI_INTR_CLAIMED);
567 }
568 if (payload->slot < 0 || payload->slot >= sizeof (fru_locn) /
569 sizeof (char *)) {
570 return (DDI_INTR_CLAIMED);
571 }
572
573 /*
574 * if not SB send sysevent (SBs send sysevent from ssm driver)
575 */
576 if (strncmp(fru_locn[payload->slot], "SB", 2) != 0) {
577 switch (payload->event_details) {
578 case SG_EVT_BOARD_ABSENT:
579 hint = SE_HINT_REMOVE;
580 break;
581 case SG_EVT_BOARD_PRESENT:
582 hint = SE_HINT_INSERT;
583 break;
584 default:
585 hint = SE_NO_HINT;
586 break;
587 }
588 (void) snprintf(attach_pnt, sizeof (attach_pnt), "ssm0:N0.%s",
589 fru_locn[payload->slot]);
590 ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, EP_DDI,
591 KM_NOSLEEP);
592 if (ev == NULL) {
593 cmn_err(CE_WARN, "Failed to allocate %s event", EC_DR);
594 return (DDI_INTR_CLAIMED);
595 }
596 evnt_val.value_type = SE_DATA_TYPE_STRING;
597 evnt_val.value.sv_string = attach_pnt;
598 rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val,
599 KM_NOSLEEP);
600 if (rv != 0) {
601 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
602 DR_AP_ID, EC_DR);
603 sysevent_free(ev);
604 return (DDI_INTR_CLAIMED);
605 }
606
607 /*
608 * Add the hint
609 */
610 evnt_val.value_type = SE_DATA_TYPE_STRING;
611 evnt_val.value.sv_string = SE_HINT2STR(hint);
612 rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val,
613 KM_NOSLEEP);
614 if (rv != 0) {
615 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event",
616 DR_HINT, EC_DR);
617 sysevent_free_attr(evnt_attr_list);
618 sysevent_free(ev);
619 return (DDI_INTR_CLAIMED);
620 }
621 if (sysevent_attach_attributes(ev, evnt_attr_list) != 0) {
622 cmn_err(CE_WARN, "Failed to attach attr list for %s "
623 "event", EC_DR);
624 sysevent_free_attr(evnt_attr_list);
625 sysevent_free(ev);
626 return (DDI_INTR_CLAIMED);
627 }
628 rv = log_sysevent(ev, KM_NOSLEEP, &eid);
629 if (rv != 0) {
630 cmn_err(CE_WARN,
631 "lw8_dr_event_handler: failed to log event");
632 }
633 sysevent_free(ev);
634 }
635 lw8_wakeup_sleepers();
636 return (DDI_INTR_CLAIMED);
637 }
638
639 static uint_t
lw8_cap_ecc_msg_handler(char * addr)640 lw8_cap_ecc_msg_handler(char *addr)
641 {
642 sbbc_msg_t *msg = NULL;
643 plat_capability_data_t *cap = NULL;
644
645 msg = (sbbc_msg_t *)addr;
646 if (msg == NULL || msg->msg_buf == NULL)
647 return (DDI_INTR_CLAIMED);
648
649 cap = (plat_capability_data_t *)msg->msg_buf;
650 switch (cap->capd_msg_type) {
651 case PLAT_ECC_CAPABILITY_MESSAGE:
652 plat_ecc_capability_sc_set(cap->capd_capability);
653 break;
654 default:
655 break;
656 }
657
658 return (DDI_INTR_CLAIMED);
659 }
660
661 /*ARGSUSED*/
662 static uint_t
lw8_env_data_handler(char * arg)663 lw8_env_data_handler(char *arg)
664 {
665 lw8_wakeup_sleepers();
666 return (DDI_INTR_CLAIMED);
667 }
668
669 /*
670 * wakeup sleepers + mark led cache for this fru as invalid
671 */
672 static void
lw8_wakeup_sleepers()673 lw8_wakeup_sleepers()
674 {
675 mutex_enter(&lw8_event_mutex);
676 lw8_event_pending = B_TRUE;
677 cv_broadcast(&lw8_event_cv);
678 led_state_cached = B_FALSE;
679 mutex_exit(&lw8_event_mutex);
680 }
681
682 /*
683 * This function is triggered by a soft interrupt and it's purpose is to call
684 * to kadmin() to shutdown the system.
685 */
686 /*ARGSUSED*/
687 static uint_t
lw8_fast_shutdown(char * arg)688 lw8_fast_shutdown(char *arg)
689 {
690 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred);
691
692 /*
693 * If kadmin fails for some reason then we bring the system down
694 * via power_down(), or failing that using halt().
695 */
696 power_down("kadmin() failed, trying power_down()");
697
698 halt("power_down() failed, trying halt()");
699
700 /*
701 * We should never make it this far, so something must have gone
702 * horribly, horribly wrong.
703 */
704 /*NOTREACHED*/
705 return (DDI_INTR_UNCLAIMED);
706 }
707
708 /*
709 * This function is triggered by a soft interrupt and it's purpose is to call
710 * to do_shutdown() to shutdown the system.
711 */
712 /*ARGSUSED*/
713 static uint_t
lw8_slow_shutdown(char * arg)714 lw8_slow_shutdown(char *arg)
715 {
716 do_shutdown();
717 return (DDI_SUCCESS);
718 }
719
720 static uint_t
lw8_event_data_handler(char * arg)721 lw8_event_data_handler(char *arg)
722 {
723 lw8_event_t *payload;
724 sbbc_msg_t *msg;
725
726 if (arg == NULL) {
727 return (DDI_INTR_CLAIMED);
728 }
729
730 msg = (sbbc_msg_t *)arg;
731 if (msg->msg_buf == NULL) {
732 return (DDI_INTR_CLAIMED);
733 }
734
735 payload = (lw8_event_t *)msg->msg_buf;
736 switch (payload->event_type) {
737 case LW8_EVENT_REQUESTED_SHUTDOWN:
738
739 /*
740 * Let the user know why the domain is going down.
741 */
742 cmn_err(CE_WARN, "%s", SHUTDOWN_EVENT_MSG);
743 ddi_trigger_softintr(lw8_slow_shutdown_softint_id);
744
745 /*NOTREACHED*/
746 break;
747
748 case LW8_EVENT_VOLTAGE_SHUTDOWN:
749
750 /*
751 * Let the user know why the domain is going down.
752 */
753 cmn_err(CE_WARN, "%s", VOLTAGE_EVENT_MSG);
754 ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
755
756 /*NOTREACHED*/
757 break;
758
759 case LW8_EVENT_TEMPERATURE_SHUTDOWN:
760
761 /*
762 * Let the user know why the domain is going down.
763 */
764 cmn_err(CE_WARN, "%s", TEMPERATURE_EVENT_MSG);
765 ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
766
767 /*NOTREACHED*/
768 break;
769
770 case LW8_EVENT_FANFAIL_SHUTDOWN:
771
772 /*
773 * Let the user know why the domain is going down.
774 */
775 cmn_err(CE_WARN, "%s", FANFAIL_EVENT_MSG);
776 ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
777
778 /*NOTREACHED*/
779 break;
780
781 case LW8_EVENT_NO_SCC_SHUTDOWN:
782
783 /*
784 * Let the user know why the domain is going down.
785 */
786 cmn_err(CE_WARN, "%s", NO_SCC_EVENT_MSG);
787 ddi_trigger_softintr(lw8_fast_shutdown_softint_id);
788
789 /*NOTREACHED*/
790 break;
791
792 case LW8_EVENT_NEW_LOG_MSG:
793
794 /*
795 * Wake up the log retrieval thread.
796 */
797 lw8_logger_wakeup();
798
799 break;
800
801 default:
802 return (DDI_INTR_CLAIMED);
803 }
804
805 return (DDI_INTR_CLAIMED);
806 }
807
808 /*ARGSUSED*/
809 static int
lw8_open(dev_t * dev_p,int flag,int otyp,cred_t * cred_p)810 lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p)
811 {
812 int error = 0;
813 int instance = getminor(*dev_p);
814 static fn_t f = "lw8_open";
815
816 if (instance != 0)
817 return (ENXIO);
818
819 if ((error = drv_priv(cred_p)) != 0) {
820 cmn_err(CE_WARN, "lw8:%s: inst %d drv_priv failed",
821 f, instance);
822 return (error);
823 }
824 return (error);
825 }
826
827 /*ARGSUSED*/
828 static int
lw8_close(dev_t dev,int flag,int otyp,cred_t * cred_p)829 lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
830 {
831 return (DDI_SUCCESS);
832 }
833
834 static int
lw8_lomcmd(int cmd,intptr_t arg)835 lw8_lomcmd(int cmd, intptr_t arg)
836 {
837 sbbc_msg_t request, *reqp = &request;
838 sbbc_msg_t response, *resp = &response;
839 int rv = 0;
840 lom_eventreq_t *eventreqp;
841
842 bzero((caddr_t)&request, sizeof (request));
843 reqp->msg_type.type = LW8_MBOX;
844 reqp->msg_type.sub_type = cmd;
845 bzero((caddr_t)&response, sizeof (response));
846 resp->msg_type.type = LW8_MBOX;
847 resp->msg_type.sub_type = cmd;
848
849 switch (cmd) {
850 case LW8_MBOX_GET_INFO:
851 reqp->msg_len = 0;
852 reqp->msg_buf = (caddr_t)NULL;
853 resp->msg_len = sizeof (lom2_info_t);
854 resp->msg_buf = (caddr_t)arg;
855 break;
856 case LW8_MBOX_SET_CTL:
857 reqp->msg_len = sizeof (lom_ctl2_t);
858 reqp->msg_buf = (caddr_t)arg;
859 resp->msg_len = 0;
860 resp->msg_buf = (caddr_t)NULL;
861 break;
862 case LW8_MBOX_UPDATE_FW:
863 reqp->msg_len = sizeof (lom_prog_t);
864 reqp->msg_buf = (caddr_t)arg;
865 resp->msg_len = 0;
866 resp->msg_buf = (caddr_t)NULL;
867 break;
868 case LW8_MBOX_GET_LED:
869 reqp->msg_len = sizeof (lw8_get_led_payload_t);
870 reqp->msg_buf = (caddr_t)arg;
871 resp->msg_len = sizeof (lw8_get_led_payload_t);
872 resp->msg_buf = (caddr_t)arg;
873 break;
874 case LW8_MBOX_SET_LED:
875 reqp->msg_len = sizeof (lw8_set_led_payload_t);
876 reqp->msg_buf = (caddr_t)arg;
877 resp->msg_len = 0;
878 resp->msg_buf = (caddr_t)NULL;
879 break;
880 case LW8_MBOX_GET_EVENTS:
881 /*
882 * cast as lom_eventreq_t to minimise data traffic
883 */
884 eventreqp = (lom_eventreq_t *)arg;
885 reqp->msg_len = sizeof (lom_eventreq_t);
886 reqp->msg_buf = (caddr_t)arg;
887 resp->msg_len = sizeof (lom_eventreq_t) +
888 (eventreqp->num * MAX_EVENT_STR);
889 resp->msg_buf = (caddr_t)arg;
890 break;
891 case LW8_MBOX_GET_NEXT_MSG:
892 reqp->msg_len = 0;
893 reqp->msg_buf = (caddr_t)NULL;
894 resp->msg_len = sizeof (lw8_logmsg_t);
895 resp->msg_buf = (caddr_t)arg;
896 break;
897 default:
898 return (EINVAL);
899 }
900
901 rv = sbbc_mbox_request_response(reqp, resp,
902 LW8_DEFAULT_MAX_MBOX_WAIT_TIME);
903
904 if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) {
905
906 /* errors from sgsbbc */
907 if (resp->msg_status > 0) {
908 return (resp->msg_status);
909 }
910
911 /* errors from SCAPP */
912 switch (resp->msg_status) {
913
914 case SG_MBOX_STATUS_COMMAND_FAILURE:
915 /* internal SCAPP error */
916 return (EINTR);
917
918 case SG_MBOX_STATUS_HARDWARE_FAILURE:
919 /* seprom read/write errors */
920 return (EIO);
921
922 case SG_MBOX_STATUS_ILLEGAL_PARAMETER:
923 /* illegal ioctl parameter */
924 return (EINVAL);
925
926 case SG_MBOX_STATUS_BOARD_ACCESS_DENIED:
927 /* board access denied */
928 return (EACCES);
929
930 case SG_MBOX_STATUS_STALE_CONTENTS:
931 /* stale contents */
932 return (ESTALE);
933
934 case SG_MBOX_STATUS_STALE_OBJECT:
935 /* stale handle */
936 return (ENOENT);
937
938 case SG_MBOX_STATUS_NO_SEPROM_SPACE:
939 /* seprom lacks space */
940 return (ENOSPC);
941
942 case SG_MBOX_STATUS_NO_MEMORY:
943 /* user prog. lacks space */
944 return (ENOMEM);
945
946 case SG_MBOX_STATUS_NOT_SUPPORTED:
947 /* unsupported operation */
948 return (ENOTSUP);
949
950 default:
951 return (EIO);
952 }
953 }
954 return (0);
955 }
956
957 /*
958 * set the requested led, and mark cache as empty
959 */
960 static int
lw8_setled(lom_set_led_t * set_ledp)961 lw8_setled(lom_set_led_t *set_ledp)
962 {
963 int retval;
964 int i, j;
965 struct led_info *lip;
966 lw8_set_led_payload_t lw8_set_led;
967
968 for (i = 0; i < MAX_FRUS; i++) {
969 if (strncmp(set_ledp->location, fru_led_table[i].location,
970 MAX_LOCATION_LEN) != 0)
971 continue;
972 for (j = 0; j < MAX_LEDS_PER_FRU; j++) {
973 lip = &fru_led_table[i].led_info[j];
974 if (lip->id == NULL)
975 continue;
976 if (strncmp(set_ledp->id, lip->id, MAX_ID_LEN) != 0)
977 continue;
978 lw8_set_led.value = set_ledp->status;
979
980 /*
981 * to minimise data transfer, the SC maintains
982 * just 3 values per fru - except for
983 * the chassis itself at the end which has
984 * MAX_LEDS_PER_FRU
985 */
986 lw8_set_led.offset = (i * 3) + j;
987 retval = lw8_lomcmd(LW8_MBOX_SET_LED,
988 (intptr_t)&lw8_set_led);
989 if (retval != 0)
990 return (retval);
991 mutex_enter(&lw8_event_mutex);
992 led_state_cached = B_FALSE;
993 mutex_exit(&lw8_event_mutex);
994 return (0);
995 }
996 }
997 return (EINVAL);
998 }
999
1000 /*
1001 * read led value from cache if possible, otherwise read from sc and
1002 * update the cache
1003 */
1004 static int
lw8_getled(lom_get_led_t * get_ledp)1005 lw8_getled(lom_get_led_t *get_ledp)
1006 {
1007 int retval;
1008 int i, j, k;
1009 struct led_info *lip;
1010 lw8_get_led_payload_t lw8_get_led;
1011
1012 for (i = 0; i < MAX_FRUS; i++) {
1013 if (strncmp(get_ledp->location, fru_led_table[i].location,
1014 MAX_LOCATION_LEN) != 0)
1015 continue;
1016 if (get_ledp->id[0] == '\0') {
1017 (void) strncpy(get_ledp->next_id,
1018 fru_led_table[i].led_info[0].id, MAX_ID_LEN);
1019 return (0);
1020 }
1021 for (j = 0; j < MAX_LEDS_PER_FRU; j++) {
1022 lip = &fru_led_table[i].led_info[j];
1023 if (lip->id == NULL)
1024 continue;
1025 if (strncmp(get_ledp->id, lip->id, MAX_ID_LEN) != 0)
1026 continue;
1027 mutex_enter(&lw8_event_mutex);
1028 if (!led_state_cached) {
1029 mutex_exit(&lw8_event_mutex);
1030 retval = lw8_lomcmd(LW8_MBOX_GET_LED,
1031 (intptr_t)&lw8_get_led);
1032 if (retval != 0)
1033 return (retval);
1034 mutex_enter(&lw8_event_mutex);
1035
1036 /*
1037 * to minimise data transfer, the
1038 * lw8_get_led_payload_t structure just has 3
1039 * values per fru - except for the chassis
1040 * itself at the end which has MAX_LEDS_PER_FRU
1041 */
1042 for (k = 0; k < (MAX_FRUS - 1) * 3; k++) {
1043 fru_led_table[k / 3].led_info[k % 3].
1044 status = lw8_get_led.value[k];
1045 }
1046 for (k = 0; k < MAX_LEDS_PER_FRU; k++) {
1047 fru_led_table[MAX_FRUS - 1].led_info[k].
1048 status = lw8_get_led.value[k +
1049 ((MAX_FRUS - 1) * 3)];
1050 }
1051 led_state_cached = B_TRUE;
1052 }
1053 get_ledp->status = lip->status;
1054 mutex_exit(&lw8_event_mutex);
1055 get_ledp->position = lip->position;
1056 (void) strncpy(get_ledp->color, lip->color,
1057 MAX_COLOR_LEN);
1058 if (j == MAX_LEDS_PER_FRU - 1) {
1059 get_ledp->next_id[0] = '\0';
1060 return (0);
1061 }
1062 (void) strncpy(get_ledp->next_id,
1063 fru_led_table[i].led_info[j + 1].id, MAX_ID_LEN);
1064 return (0);
1065 }
1066 }
1067 if (get_ledp->id[0] == '\0') {
1068 get_ledp->next_id[0] = '\0';
1069 return (0);
1070 }
1071 return (EINVAL);
1072 }
1073
1074 /*ARGSUSED*/
1075 static int
lw8_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)1076 lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
1077 int *rval_p)
1078 {
1079 int instance = getminor(dev);
1080 lom2_info_t lw8_info2;
1081 lom_ctl_t lw8_ctl;
1082 lom_ctl2_t lw8_ctl2;
1083 lom_mprog_t lw8_mprog;
1084 lom_fled_info_t lw8_fled_info;
1085 lom_info_t lw8_info;
1086 lom_aldata_t lw8_aldata;
1087 lom_get_led_t lw8_get_led;
1088 lom_set_led_t lw8_set_led;
1089 lom_prog_t *lw8_progp;
1090 lom_eventlog2_t *lw8_eventlogp;
1091 lom_eventresp_t *lw8_eventresp;
1092 int retval = 0;
1093 int i, j;
1094
1095 if (instance != 0)
1096 return (ENXIO);
1097
1098 switch (cmd) {
1099 case LOMIOCWTMON:
1100 mutex_enter(&lw8_event_mutex);
1101 if (!lw8_event_pending) {
1102 if (cv_wait_sig(&lw8_event_cv, &lw8_event_mutex) == 0) {
1103 mutex_exit(&lw8_event_mutex);
1104 retval = EINTR;
1105 break;
1106 }
1107 }
1108 lw8_event_pending = B_FALSE;
1109 mutex_exit(&lw8_event_mutex);
1110 break;
1111 case LOMIOCMREAD:
1112 bzero((caddr_t)&lw8_mprog, sizeof (lw8_mprog));
1113 lw8_mprog.config = 4;
1114 if (ddi_copyout((caddr_t)&lw8_mprog, (caddr_t)arg,
1115 sizeof (lw8_mprog), mode) != 0) {
1116 retval = EFAULT;
1117 }
1118 break;
1119 case LOMIOCCTL2:
1120 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl2,
1121 sizeof (lw8_ctl2), mode) != 0) {
1122 retval = EFAULT;
1123 break;
1124 }
1125 retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2);
1126 break;
1127 case LOMIOCPROG:
1128 lw8_progp = kmem_alloc(sizeof (*lw8_progp), KM_SLEEP);
1129 if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_progp,
1130 sizeof (*lw8_progp), mode) != 0) {
1131 kmem_free(lw8_progp, sizeof (*lw8_progp));
1132 retval = EFAULT;
1133 break;
1134 }
1135 retval = lw8_lomcmd(LW8_MBOX_UPDATE_FW, (intptr_t)lw8_progp);
1136 kmem_free(lw8_progp, sizeof (*lw8_progp));
1137 break;
1138 case LOMIOCINFO2:
1139 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
1140 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
1141 if (retval != 0)
1142 break;
1143 if (ddi_copyout((caddr_t)&lw8_info2, (caddr_t)arg,
1144 sizeof (lw8_info2), mode) != 0) {
1145 retval = EFAULT;
1146 }
1147 break;
1148 case LOMIOCINFO:
1149 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
1150 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
1151 if (retval != 0)
1152 break;
1153 bzero((caddr_t)&lw8_info, sizeof (lw8_info));
1154 lw8_info.ser_char = lw8_info2.escape_chars[0];
1155 lw8_info.fver = lw8_info2.fver;
1156 lw8_info.fchksum = lw8_info2.fchksum;
1157 lw8_info.prod_rev = lw8_info2.prod_rev;
1158 (void) strncpy(lw8_info.prod_id, lw8_info2.prod_id, MAX_ID_LEN);
1159 if (ddi_copyout((caddr_t)&lw8_info, (caddr_t)arg,
1160 sizeof (lw8_info), mode) != 0) {
1161 retval = EFAULT;
1162 }
1163 break;
1164 case LOMIOCFLEDSTATE:
1165 bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led));
1166 (void) strncpy(lw8_get_led.location, "chassis",
1167 MAX_LOCATION_LEN);
1168 (void) strncpy(lw8_get_led.id, "fault", MAX_ID_LEN);
1169 retval = lw8_getled(&lw8_get_led);
1170 if (retval != 0)
1171 break;
1172 lw8_fled_info.on = lw8_get_led.status;
1173 if (ddi_copyout((caddr_t)&lw8_fled_info, (caddr_t)arg,
1174 sizeof (lw8_fled_info), mode) != 0) {
1175 retval = EFAULT;
1176 }
1177 break;
1178 case LOMIOCALSTATE:
1179 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata,
1180 sizeof (lw8_aldata), mode) != 0) {
1181 retval = EFAULT;
1182 break;
1183 }
1184 bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led));
1185 (void) strncpy(lw8_get_led.location, "chassis",
1186 MAX_LOCATION_LEN);
1187 if (lw8_aldata.alarm_no == 3)
1188 (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "system");
1189 else
1190 (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "alarm%d",
1191 lw8_aldata.alarm_no);
1192 retval = lw8_getled(&lw8_get_led);
1193 if (retval != 0)
1194 break;
1195 lw8_aldata.state = lw8_get_led.status;
1196 if (ddi_copyout((caddr_t)&lw8_aldata, (caddr_t)arg,
1197 sizeof (lw8_aldata), mode) != 0) {
1198 retval = EFAULT;
1199 }
1200 break;
1201 case LOMIOCGETLED:
1202 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_get_led,
1203 sizeof (lw8_get_led), mode) != 0) {
1204 retval = EFAULT;
1205 break;
1206 }
1207 retval = lw8_getled(&lw8_get_led);
1208 if (retval != 0)
1209 break;
1210 if (ddi_copyout((caddr_t)&lw8_get_led, (caddr_t)arg,
1211 sizeof (lw8_get_led), mode) != 0) {
1212 retval = EFAULT;
1213 }
1214 break;
1215 case LOMIOCEVENTLOG2:
1216 lw8_eventlogp = kmem_alloc(sizeof (*lw8_eventlogp), KM_SLEEP);
1217 lw8_eventresp = kmem_zalloc(sizeof (*lw8_eventresp), KM_SLEEP);
1218 if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_eventlogp,
1219 sizeof (*lw8_eventlogp), mode) != 0) {
1220 kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp));
1221 kmem_free(lw8_eventresp, sizeof (*lw8_eventresp));
1222 retval = EFAULT;
1223 break;
1224 }
1225 lw8_eventresp->num = lw8_eventlogp->num;
1226 lw8_eventresp->level = lw8_eventlogp->level;
1227 retval = lw8_lomcmd(LW8_MBOX_GET_EVENTS,
1228 (intptr_t)lw8_eventresp);
1229 if (retval == 0) {
1230 lw8_eventlogp->num = lw8_eventresp->num;
1231 for (i = 0; i < lw8_eventresp->num; i++) {
1232 for (j = 0; j < MAX_EVENT_STR; j++) {
1233 lw8_eventlogp->string[i][j] =
1234 lw8_eventresp->string[i][j];
1235 }
1236 }
1237 if (ddi_copyout((caddr_t)lw8_eventlogp, (caddr_t)arg,
1238 sizeof (*lw8_eventlogp), mode) != 0) {
1239 retval = EFAULT;
1240 }
1241 }
1242 kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp));
1243 kmem_free(lw8_eventresp, sizeof (*lw8_eventresp));
1244 break;
1245 case LOMIOCALCTL:
1246 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata,
1247 sizeof (lw8_aldata), mode) != 0) {
1248 retval = EFAULT;
1249 break;
1250 }
1251 bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led));
1252 (void) strncpy(lw8_set_led.location, "chassis",
1253 MAX_LOCATION_LEN);
1254 if (lw8_aldata.alarm_no == 3)
1255 (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "system");
1256 else
1257 (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "alarm%d",
1258 lw8_aldata.alarm_no);
1259 lw8_set_led.status = lw8_aldata.state;
1260 retval = lw8_setled(&lw8_set_led);
1261 break;
1262 case LOMIOCSETLED:
1263 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_set_led,
1264 sizeof (lw8_set_led), mode) != 0) {
1265 retval = EFAULT;
1266 break;
1267 }
1268 retval = lw8_setled(&lw8_set_led);
1269 break;
1270 case LOMIOCCTL:
1271 /*
1272 * for this ioctl, as well as setting the fault led in the
1273 * LOMIOCCTL case in lw8_lomcmd(), we also need to set the
1274 * escape character. To do this we must use LW8_MBOX_SET_CTL,
1275 * but this also needs the serial_event value which we have
1276 * to get via LW8_MBOX_GET_INFO
1277 */
1278 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl,
1279 sizeof (lw8_ctl), mode) != 0) {
1280 retval = EFAULT;
1281 break;
1282 }
1283 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2));
1284 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2);
1285 if (retval != 0)
1286 break;
1287 bzero((caddr_t)&lw8_ctl2, sizeof (lw8_ctl2));
1288 lw8_ctl2.escape_chars[0] = lw8_ctl.ser_char;
1289 lw8_ctl2.serial_events = lw8_info2.serial_events;
1290 retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2);
1291 if (retval != 0)
1292 break;
1293
1294 /*
1295 * if fault_led != 0, then set the led
1296 */
1297 if (lw8_ctl.fault_led == 0)
1298 break;
1299 bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led));
1300 (void) strncpy(lw8_set_led.location, "chassis",
1301 MAX_LOCATION_LEN);
1302 (void) strncpy(lw8_set_led.id, "fault", MAX_ID_LEN);
1303 lw8_set_led.status = lw8_ctl.fault_led - 1;
1304 retval = lw8_setled(&lw8_set_led);
1305 break;
1306 default:
1307 retval = ENOTSUP;
1308 break;
1309 }
1310 return (retval);
1311 }
1312
1313 /* ARGSUSED */
1314 static void
lw8_logger(caddr_t arg)1315 lw8_logger(caddr_t arg)
1316 {
1317 callb_cpr_t cprinfo;
1318 lw8_logmsg_t *lw8_logmsgp;
1319 boolean_t more_waiting;
1320 char level;
1321 int retval;
1322
1323 CALLB_CPR_INIT(&cprinfo, &lw8_logger_lock, callb_generic_cpr,
1324 "lw8_logger");
1325
1326 lw8_logmsgp = kmem_zalloc(sizeof (*lw8_logmsgp), KM_SLEEP);
1327 mutex_enter(&lw8_logger_lock);
1328 for (;;) {
1329
1330 /*
1331 * Wait for someone to tell me to continue.
1332 */
1333 while (lw8_logger_sig == LW8_LOGGER_WAIT) {
1334 CALLB_CPR_SAFE_BEGIN(&cprinfo);
1335 cv_wait(&lw8_logger_sig_cv, &lw8_logger_lock);
1336 CALLB_CPR_SAFE_END(&cprinfo, &lw8_logger_lock);
1337 }
1338
1339 /* LW8_LOGGER_EXITNOW implies signal by _detach(). */
1340 if (lw8_logger_sig == LW8_LOGGER_EXITNOW) {
1341 lw8_logger_sig = LW8_LOGGER_WAIT;
1342
1343 kmem_free(lw8_logmsgp, sizeof (*lw8_logmsgp));
1344
1345 /* lw8_logger_lock is held at this point! */
1346 CALLB_CPR_EXIT(&cprinfo);
1347
1348 thread_exit();
1349 /* NOTREACHED */
1350 }
1351
1352 ASSERT(lw8_logger_sig == LW8_LOGGER_PROCESSNOW);
1353 lw8_logger_sig = LW8_LOGGER_WAIT;
1354
1355 mutex_exit(&lw8_logger_lock);
1356
1357 /* Do lw8_event logging */
1358
1359 /*
1360 * Get one message per iteration. We do not sleep if
1361 * there are more to process. This makes exit from the
1362 * routine much more reliable.
1363 */
1364 more_waiting = B_FALSE;
1365
1366 retval = lw8_lomcmd(LW8_MBOX_GET_NEXT_MSG,
1367 (intptr_t)lw8_logmsgp);
1368 if (retval == 0) {
1369 if (lw8_logmsgp->msg_valid) {
1370
1371 switch (lw8_logmsgp->level) {
1372 case 0: /* LOG_EMERG */
1373 level = SL_FATAL;
1374 break;
1375 case 1: /* LOG_ALERT */
1376 level = SL_FATAL;
1377 break;
1378 case 2: /* LOG_CRIT */
1379 level = SL_FATAL;
1380 break;
1381 case 3: /* LOG_ERR */
1382 level = SL_ERROR;
1383 break;
1384 case 4: /* LOG_WARNING */
1385 level = SL_WARN;
1386 break;
1387 case 5: /* LOG_NOTICE */
1388 level = SL_NOTE;
1389 break;
1390 case 6: /* LOG_INFO */
1391 level = SL_NOTE;
1392 break;
1393 case 7: /* LOG_DEBUG */
1394 level = SL_TRACE;
1395 break;
1396 default: /* unknown */
1397 level = SL_NOTE;
1398 break;
1399 }
1400
1401 /* Ensure NUL termination */
1402 lw8_logmsgp->msg[
1403 sizeof (lw8_logmsgp->msg) - 1] = '\0';
1404 (void) strlog(0, 0, 0, SL_CONSOLE | level,
1405 lw8_logmsgp->msg);
1406 }
1407
1408 if (lw8_logmsgp->num_remaining > 0)
1409 more_waiting = B_TRUE;
1410 }
1411
1412 /*
1413 * Re-enter the lock to prepare for another iteration.
1414 * We must have the lock here to protect lw8_logger_sig.
1415 */
1416 mutex_enter(&lw8_logger_lock);
1417 if ((lw8_logger_sig == LW8_LOGGER_WAIT) && more_waiting)
1418 /* We need to get more events */
1419 lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
1420 }
1421 }
1422
1423 static void
lw8_logger_start(void)1424 lw8_logger_start(void)
1425 {
1426 kthread_t *tp;
1427
1428 mutex_enter(&lw8_logger_lock);
1429
1430 if (lw8_logger_tid == 0) {
1431 /* Force retrieval of any pending messages */
1432 lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
1433
1434 tp = thread_create(NULL, 0, lw8_logger, NULL, 0,
1435 &p0, TS_RUN, maxclsyspri);
1436 lw8_logger_tid = tp->t_did;
1437 }
1438
1439 mutex_exit(&lw8_logger_lock);
1440 }
1441
1442 static void
lw8_logger_destroy(void)1443 lw8_logger_destroy(void)
1444 {
1445 kt_did_t tid;
1446
1447 mutex_enter(&lw8_logger_lock);
1448 tid = lw8_logger_tid;
1449 if (tid != 0) {
1450 lw8_logger_sig = LW8_LOGGER_EXITNOW;
1451 cv_signal(&lw8_logger_sig_cv);
1452 lw8_logger_tid = 0;
1453 }
1454 mutex_exit(&lw8_logger_lock);
1455
1456 /*
1457 * Wait for lw8_logger() to finish.
1458 */
1459 if (tid != 0)
1460 thread_join(tid);
1461 }
1462
1463 static void
lw8_logger_wakeup(void)1464 lw8_logger_wakeup(void)
1465 {
1466 mutex_enter(&lw8_logger_lock);
1467
1468 if (lw8_logger_sig != LW8_LOGGER_EXITNOW)
1469 lw8_logger_sig = LW8_LOGGER_PROCESSNOW;
1470 cv_signal(&lw8_logger_sig_cv);
1471
1472 mutex_exit(&lw8_logger_lock);
1473 }
1474