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 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 328 _info(struct modinfo *modinfop) 329 { 330 return (mod_info(&modlinkage, modinfop)); 331 } 332 333 334 int 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 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, 0); 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 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 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 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 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 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 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 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 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 714 lw8_slow_shutdown(char *arg) 715 { 716 do_shutdown(); 717 return (DDI_SUCCESS); 718 } 719 720 static uint_t 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 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 829 lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 830 { 831 return (DDI_SUCCESS); 832 } 833 834 static int 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 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 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 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 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 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 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 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