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 2008 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, 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 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 sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler); 477 return (DDI_FAILURE); 478 } 479 480 lw8_env_payload_msg.msg_buf = (caddr_t)&lw8_env_payload; 481 lw8_env_payload_msg.msg_len = sizeof (lw8_env_payload); 482 err = sbbc_mbox_reg_intr(MBOX_EVENT_ENV, lw8_env_data_handler, 483 &lw8_env_payload_msg, NULL, &lw8_env_hdlr_lock); 484 if (err != 0) { 485 cmn_err(CE_WARN, "Failed to register MBOX_EVENT_ENV " 486 " handler. Err=%d", err); 487 sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler); 488 sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler); 489 return (DDI_FAILURE); 490 } 491 492 lw8_cap_payload_msg.msg_buf = (caddr_t)&lw8_cap_payload; 493 lw8_cap_payload_msg.msg_len = sizeof (lw8_cap_payload); 494 err = sbbc_mbox_reg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler, 495 &lw8_cap_payload_msg, NULL, &lw8_cap_msg_hdlr_lock); 496 if (err != 0) { 497 cmn_err(CE_WARN, "Failed to register INFO_MBOX " 498 " handler. Err=%d", err); 499 sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler); 500 sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler); 501 sbbc_mbox_unreg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler); 502 return (DDI_FAILURE); 503 } 504 505 return (DDI_SUCCESS); 506 } 507 508 static int 509 lw8_remove_intr_handlers(void) 510 { 511 int rv = DDI_SUCCESS; 512 int err; 513 514 err = sbbc_mbox_unreg_intr(MBOX_EVENT_LW8, lw8_event_data_handler); 515 if (err != 0) { 516 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_LW8 " 517 "handler. Err=%d", err); 518 rv = DDI_FAILURE; 519 } 520 err = sbbc_mbox_unreg_intr(MBOX_EVENT_GENERIC, lw8_dr_data_handler); 521 if (err != 0) { 522 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_GENERIC " 523 "handler. Err=%d", err); 524 rv = DDI_FAILURE; 525 } 526 err = sbbc_mbox_unreg_intr(MBOX_EVENT_ENV, lw8_env_data_handler); 527 if (err != 0) { 528 cmn_err(CE_WARN, "Failed to unregister MBOX_EVENT_ENV " 529 "handler. Err=%d", err); 530 rv = DDI_FAILURE; 531 } 532 err = sbbc_mbox_unreg_intr(INFO_MBOX, lw8_cap_ecc_msg_handler); 533 if (err != 0) { 534 cmn_err(CE_WARN, "Failed to unregister INFO_MBOX " 535 "handler. Err=%d", err); 536 rv = DDI_FAILURE; 537 } 538 return (rv); 539 } 540 541 static uint_t 542 lw8_dr_data_handler(char *arg) 543 { 544 sg_system_fru_descriptor_t *payload; 545 sbbc_msg_t *msg; 546 int hint; 547 sysevent_t *ev; 548 sysevent_id_t eid; 549 int rv = 0; 550 sysevent_value_t evnt_val; 551 sysevent_attr_list_t *evnt_attr_list = NULL; 552 char attach_pnt[MAXPATHLEN]; 553 554 msg = (sbbc_msg_t *)arg; 555 if (msg == NULL) { 556 return (DDI_INTR_CLAIMED); 557 } 558 payload = (sg_system_fru_descriptor_t *)msg->msg_buf; 559 if (payload == NULL) { 560 return (DDI_INTR_CLAIMED); 561 } 562 if (payload->slot < 0 || payload->slot >= sizeof (fru_locn) / 563 sizeof (char *)) { 564 return (DDI_INTR_CLAIMED); 565 } 566 567 /* 568 * if not SB send sysevent (SBs send sysevent from ssm driver) 569 */ 570 if (strncmp(fru_locn[payload->slot], "SB", 2) != 0) { 571 switch (payload->event_details) { 572 case SG_EVT_BOARD_ABSENT: 573 hint = SE_HINT_REMOVE; 574 break; 575 case SG_EVT_BOARD_PRESENT: 576 hint = SE_HINT_INSERT; 577 break; 578 default: 579 hint = SE_NO_HINT; 580 break; 581 } 582 (void) snprintf(attach_pnt, sizeof (attach_pnt), "ssm0:N0.%s", 583 fru_locn[payload->slot]); 584 ev = sysevent_alloc(EC_DR, ESC_DR_AP_STATE_CHANGE, EP_DDI, 585 KM_NOSLEEP); 586 if (ev == NULL) { 587 cmn_err(CE_WARN, "Failed to allocate %s event", EC_DR); 588 return (DDI_INTR_CLAIMED); 589 } 590 evnt_val.value_type = SE_DATA_TYPE_STRING; 591 evnt_val.value.sv_string = attach_pnt; 592 rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val, 593 KM_NOSLEEP); 594 if (rv != 0) { 595 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 596 DR_AP_ID, EC_DR); 597 sysevent_free(ev); 598 return (DDI_INTR_CLAIMED); 599 } 600 601 /* 602 * Add the hint 603 */ 604 evnt_val.value_type = SE_DATA_TYPE_STRING; 605 evnt_val.value.sv_string = SE_HINT2STR(hint); 606 rv = sysevent_add_attr(&evnt_attr_list, DR_HINT, &evnt_val, 607 KM_NOSLEEP); 608 if (rv != 0) { 609 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 610 DR_HINT, EC_DR); 611 sysevent_free_attr(evnt_attr_list); 612 sysevent_free(ev); 613 return (DDI_INTR_CLAIMED); 614 } 615 if (sysevent_attach_attributes(ev, evnt_attr_list) != 0) { 616 cmn_err(CE_WARN, "Failed to attach attr list for %s " 617 "event", EC_DR); 618 sysevent_free_attr(evnt_attr_list); 619 sysevent_free(ev); 620 return (DDI_INTR_CLAIMED); 621 } 622 rv = log_sysevent(ev, KM_NOSLEEP, &eid); 623 if (rv != 0) { 624 cmn_err(CE_WARN, 625 "lw8_dr_event_handler: failed to log event"); 626 } 627 sysevent_free(ev); 628 } 629 lw8_wakeup_sleepers(); 630 return (DDI_INTR_CLAIMED); 631 } 632 633 static uint_t 634 lw8_cap_ecc_msg_handler(char *addr) 635 { 636 sbbc_msg_t *msg = NULL; 637 plat_capability_data_t *cap = NULL; 638 639 msg = (sbbc_msg_t *)addr; 640 if (msg == NULL || msg->msg_buf == NULL) 641 return (DDI_INTR_CLAIMED); 642 643 cap = (plat_capability_data_t *)msg->msg_buf; 644 switch (cap->capd_msg_type) { 645 case PLAT_ECC_CAPABILITY_MESSAGE: 646 plat_ecc_capability_sc_set(cap->capd_capability); 647 break; 648 default: 649 break; 650 } 651 652 return (DDI_INTR_CLAIMED); 653 } 654 655 /*ARGSUSED*/ 656 static uint_t 657 lw8_env_data_handler(char *arg) 658 { 659 lw8_wakeup_sleepers(); 660 return (DDI_INTR_CLAIMED); 661 } 662 663 /* 664 * wakeup sleepers + mark led cache for this fru as invalid 665 */ 666 static void 667 lw8_wakeup_sleepers() 668 { 669 mutex_enter(&lw8_event_mutex); 670 lw8_event_pending = B_TRUE; 671 cv_broadcast(&lw8_event_cv); 672 led_state_cached = B_FALSE; 673 mutex_exit(&lw8_event_mutex); 674 } 675 676 /* 677 * This function is triggered by a soft interrupt and it's purpose is to call 678 * to kadmin() to shutdown the system. 679 */ 680 /*ARGSUSED*/ 681 static uint_t 682 lw8_fast_shutdown(char *arg) 683 { 684 (void) kadmin(A_SHUTDOWN, AD_POWEROFF, NULL, kcred); 685 686 /* 687 * If kadmin fails for some reason then we bring the system down 688 * via power_down(), or failing that using halt(). 689 */ 690 power_down("kadmin() failed, trying power_down()"); 691 692 halt("power_down() failed, trying halt()"); 693 694 /* 695 * We should never make it this far, so something must have gone 696 * horribly, horribly wrong. 697 */ 698 /*NOTREACHED*/ 699 return (DDI_INTR_UNCLAIMED); 700 } 701 702 /* 703 * This function is triggered by a soft interrupt and it's purpose is to call 704 * to do_shutdown() to shutdown the system. 705 */ 706 /*ARGSUSED*/ 707 static uint_t 708 lw8_slow_shutdown(char *arg) 709 { 710 do_shutdown(); 711 return (DDI_SUCCESS); 712 } 713 714 static uint_t 715 lw8_event_data_handler(char *arg) 716 { 717 lw8_event_t *payload; 718 sbbc_msg_t *msg; 719 720 if (arg == NULL) { 721 return (DDI_INTR_CLAIMED); 722 } 723 724 msg = (sbbc_msg_t *)arg; 725 if (msg->msg_buf == NULL) { 726 return (DDI_INTR_CLAIMED); 727 } 728 729 payload = (lw8_event_t *)msg->msg_buf; 730 switch (payload->event_type) { 731 case LW8_EVENT_REQUESTED_SHUTDOWN: 732 733 /* 734 * Let the user know why the domain is going down. 735 */ 736 cmn_err(CE_WARN, "%s", SHUTDOWN_EVENT_MSG); 737 ddi_trigger_softintr(lw8_slow_shutdown_softint_id); 738 739 /*NOTREACHED*/ 740 break; 741 742 case LW8_EVENT_VOLTAGE_SHUTDOWN: 743 744 /* 745 * Let the user know why the domain is going down. 746 */ 747 cmn_err(CE_WARN, "%s", VOLTAGE_EVENT_MSG); 748 ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 749 750 /*NOTREACHED*/ 751 break; 752 753 case LW8_EVENT_TEMPERATURE_SHUTDOWN: 754 755 /* 756 * Let the user know why the domain is going down. 757 */ 758 cmn_err(CE_WARN, "%s", TEMPERATURE_EVENT_MSG); 759 ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 760 761 /*NOTREACHED*/ 762 break; 763 764 case LW8_EVENT_FANFAIL_SHUTDOWN: 765 766 /* 767 * Let the user know why the domain is going down. 768 */ 769 cmn_err(CE_WARN, "%s", FANFAIL_EVENT_MSG); 770 ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 771 772 /*NOTREACHED*/ 773 break; 774 775 case LW8_EVENT_NO_SCC_SHUTDOWN: 776 777 /* 778 * Let the user know why the domain is going down. 779 */ 780 cmn_err(CE_WARN, "%s", NO_SCC_EVENT_MSG); 781 ddi_trigger_softintr(lw8_fast_shutdown_softint_id); 782 783 /*NOTREACHED*/ 784 break; 785 786 case LW8_EVENT_NEW_LOG_MSG: 787 788 /* 789 * Wake up the log retrieval thread. 790 */ 791 lw8_logger_wakeup(); 792 793 break; 794 795 default: 796 return (DDI_INTR_CLAIMED); 797 } 798 799 return (DDI_INTR_CLAIMED); 800 } 801 802 /*ARGSUSED*/ 803 static int 804 lw8_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 805 { 806 int error = 0; 807 int instance = getminor(*dev_p); 808 static fn_t f = "lw8_open"; 809 810 if (instance != 0) 811 return (ENXIO); 812 813 if ((error = drv_priv(cred_p)) != 0) { 814 cmn_err(CE_WARN, "lw8:%s: inst %d drv_priv failed", 815 f, instance); 816 return (error); 817 } 818 return (error); 819 } 820 821 /*ARGSUSED*/ 822 static int 823 lw8_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 824 { 825 return (DDI_SUCCESS); 826 } 827 828 static int 829 lw8_lomcmd(int cmd, intptr_t arg) 830 { 831 sbbc_msg_t request, *reqp = &request; 832 sbbc_msg_t response, *resp = &response; 833 int rv = 0; 834 lom_eventreq_t *eventreqp; 835 836 bzero((caddr_t)&request, sizeof (request)); 837 reqp->msg_type.type = LW8_MBOX; 838 reqp->msg_type.sub_type = cmd; 839 bzero((caddr_t)&response, sizeof (response)); 840 resp->msg_type.type = LW8_MBOX; 841 resp->msg_type.sub_type = cmd; 842 843 switch (cmd) { 844 case LW8_MBOX_GET_INFO: 845 reqp->msg_len = 0; 846 reqp->msg_buf = (caddr_t)NULL; 847 resp->msg_len = sizeof (lom2_info_t); 848 resp->msg_buf = (caddr_t)arg; 849 break; 850 case LW8_MBOX_SET_CTL: 851 reqp->msg_len = sizeof (lom_ctl2_t); 852 reqp->msg_buf = (caddr_t)arg; 853 resp->msg_len = 0; 854 resp->msg_buf = (caddr_t)NULL; 855 break; 856 case LW8_MBOX_UPDATE_FW: 857 reqp->msg_len = sizeof (lom_prog_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_GET_LED: 863 reqp->msg_len = sizeof (lw8_get_led_payload_t); 864 reqp->msg_buf = (caddr_t)arg; 865 resp->msg_len = sizeof (lw8_get_led_payload_t); 866 resp->msg_buf = (caddr_t)arg; 867 break; 868 case LW8_MBOX_SET_LED: 869 reqp->msg_len = sizeof (lw8_set_led_payload_t); 870 reqp->msg_buf = (caddr_t)arg; 871 resp->msg_len = 0; 872 resp->msg_buf = (caddr_t)NULL; 873 break; 874 case LW8_MBOX_GET_EVENTS: 875 /* 876 * cast as lom_eventreq_t to minimise data traffic 877 */ 878 eventreqp = (lom_eventreq_t *)arg; 879 reqp->msg_len = sizeof (lom_eventreq_t); 880 reqp->msg_buf = (caddr_t)arg; 881 resp->msg_len = sizeof (lom_eventreq_t) + 882 (eventreqp->num * MAX_EVENT_STR); 883 resp->msg_buf = (caddr_t)arg; 884 break; 885 case LW8_MBOX_GET_NEXT_MSG: 886 reqp->msg_len = 0; 887 reqp->msg_buf = (caddr_t)NULL; 888 resp->msg_len = sizeof (lw8_logmsg_t); 889 resp->msg_buf = (caddr_t)arg; 890 break; 891 default: 892 return (EINVAL); 893 } 894 895 rv = sbbc_mbox_request_response(reqp, resp, 896 LW8_DEFAULT_MAX_MBOX_WAIT_TIME); 897 898 if ((rv) || (resp->msg_status != SG_MBOX_STATUS_SUCCESS)) { 899 900 /* errors from sgsbbc */ 901 if (resp->msg_status > 0) { 902 return (resp->msg_status); 903 } 904 905 /* errors from SCAPP */ 906 switch (resp->msg_status) { 907 908 case SG_MBOX_STATUS_COMMAND_FAILURE: 909 /* internal SCAPP error */ 910 return (EINTR); 911 912 case SG_MBOX_STATUS_HARDWARE_FAILURE: 913 /* seprom read/write errors */ 914 return (EIO); 915 916 case SG_MBOX_STATUS_ILLEGAL_PARAMETER: 917 /* illegal ioctl parameter */ 918 return (EINVAL); 919 920 case SG_MBOX_STATUS_BOARD_ACCESS_DENIED: 921 /* board access denied */ 922 return (EACCES); 923 924 case SG_MBOX_STATUS_STALE_CONTENTS: 925 /* stale contents */ 926 return (ESTALE); 927 928 case SG_MBOX_STATUS_STALE_OBJECT: 929 /* stale handle */ 930 return (ENOENT); 931 932 case SG_MBOX_STATUS_NO_SEPROM_SPACE: 933 /* seprom lacks space */ 934 return (ENOSPC); 935 936 case SG_MBOX_STATUS_NO_MEMORY: 937 /* user prog. lacks space */ 938 return (ENOMEM); 939 940 case SG_MBOX_STATUS_NOT_SUPPORTED: 941 /* unsupported operation */ 942 return (ENOTSUP); 943 944 default: 945 return (EIO); 946 } 947 } 948 return (0); 949 } 950 951 /* 952 * set the requested led, and mark cache as empty 953 */ 954 static int 955 lw8_setled(lom_set_led_t *set_ledp) 956 { 957 int retval; 958 int i, j; 959 struct led_info *lip; 960 lw8_set_led_payload_t lw8_set_led; 961 962 for (i = 0; i < MAX_FRUS; i++) { 963 if (strncmp(set_ledp->location, fru_led_table[i].location, 964 MAX_LOCATION_LEN) != 0) 965 continue; 966 for (j = 0; j < MAX_LEDS_PER_FRU; j++) { 967 lip = &fru_led_table[i].led_info[j]; 968 if (lip->id == NULL) 969 continue; 970 if (strncmp(set_ledp->id, lip->id, MAX_ID_LEN) != 0) 971 continue; 972 lw8_set_led.value = set_ledp->status; 973 974 /* 975 * to minimise data transfer, the SC maintains 976 * just 3 values per fru - except for 977 * the chassis itself at the end which has 978 * MAX_LEDS_PER_FRU 979 */ 980 lw8_set_led.offset = (i * 3) + j; 981 retval = lw8_lomcmd(LW8_MBOX_SET_LED, 982 (intptr_t)&lw8_set_led); 983 if (retval != 0) 984 return (retval); 985 mutex_enter(&lw8_event_mutex); 986 led_state_cached = B_FALSE; 987 mutex_exit(&lw8_event_mutex); 988 return (0); 989 } 990 } 991 return (EINVAL); 992 } 993 994 /* 995 * read led value from cache if possible, otherwise read from sc and 996 * update the cache 997 */ 998 static int 999 lw8_getled(lom_get_led_t *get_ledp) 1000 { 1001 int retval; 1002 int i, j, k; 1003 struct led_info *lip; 1004 lw8_get_led_payload_t lw8_get_led; 1005 1006 for (i = 0; i < MAX_FRUS; i++) { 1007 if (strncmp(get_ledp->location, fru_led_table[i].location, 1008 MAX_LOCATION_LEN) != 0) 1009 continue; 1010 if (get_ledp->id[0] == '\0') { 1011 (void) strncpy(get_ledp->next_id, 1012 fru_led_table[i].led_info[0].id, MAX_ID_LEN); 1013 return (0); 1014 } 1015 for (j = 0; j < MAX_LEDS_PER_FRU; j++) { 1016 lip = &fru_led_table[i].led_info[j]; 1017 if (lip->id == NULL) 1018 continue; 1019 if (strncmp(get_ledp->id, lip->id, MAX_ID_LEN) != 0) 1020 continue; 1021 mutex_enter(&lw8_event_mutex); 1022 if (!led_state_cached) { 1023 mutex_exit(&lw8_event_mutex); 1024 retval = lw8_lomcmd(LW8_MBOX_GET_LED, 1025 (intptr_t)&lw8_get_led); 1026 if (retval != 0) 1027 return (retval); 1028 mutex_enter(&lw8_event_mutex); 1029 1030 /* 1031 * to minimise data transfer, the 1032 * lw8_get_led_payload_t structure just has 3 1033 * values per fru - except for the chassis 1034 * itself at the end which has MAX_LEDS_PER_FRU 1035 */ 1036 for (k = 0; k < (MAX_FRUS - 1) * 3; k++) { 1037 fru_led_table[k / 3].led_info[k % 3]. 1038 status = lw8_get_led.value[k]; 1039 } 1040 for (k = 0; k < MAX_LEDS_PER_FRU; k++) { 1041 fru_led_table[MAX_FRUS - 1].led_info[k]. 1042 status = lw8_get_led.value[k + 1043 ((MAX_FRUS - 1) * 3)]; 1044 } 1045 led_state_cached = B_TRUE; 1046 } 1047 get_ledp->status = lip->status; 1048 mutex_exit(&lw8_event_mutex); 1049 get_ledp->position = lip->position; 1050 (void) strncpy(get_ledp->color, lip->color, 1051 MAX_COLOR_LEN); 1052 if (j == MAX_LEDS_PER_FRU - 1) { 1053 get_ledp->next_id[0] = '\0'; 1054 return (0); 1055 } 1056 (void) strncpy(get_ledp->next_id, 1057 fru_led_table[i].led_info[j + 1].id, MAX_ID_LEN); 1058 return (0); 1059 } 1060 } 1061 if (get_ledp->id[0] == '\0') { 1062 get_ledp->next_id[0] = '\0'; 1063 return (0); 1064 } 1065 return (EINVAL); 1066 } 1067 1068 /*ARGSUSED*/ 1069 static int 1070 lw8_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 1071 int *rval_p) 1072 { 1073 int instance = getminor(dev); 1074 lom2_info_t lw8_info2; 1075 lom_ctl_t lw8_ctl; 1076 lom_ctl2_t lw8_ctl2; 1077 lom_mprog_t lw8_mprog; 1078 lom_fled_info_t lw8_fled_info; 1079 lom_info_t lw8_info; 1080 lom_aldata_t lw8_aldata; 1081 lom_get_led_t lw8_get_led; 1082 lom_set_led_t lw8_set_led; 1083 lom_prog_t *lw8_progp; 1084 lom_eventlog2_t *lw8_eventlogp; 1085 lom_eventresp_t *lw8_eventresp; 1086 int retval = 0; 1087 int i, j; 1088 1089 if (instance != 0) 1090 return (ENXIO); 1091 1092 switch (cmd) { 1093 case LOMIOCWTMON: 1094 mutex_enter(&lw8_event_mutex); 1095 if (!lw8_event_pending) { 1096 if (cv_wait_sig(&lw8_event_cv, &lw8_event_mutex) == 0) { 1097 mutex_exit(&lw8_event_mutex); 1098 retval = EINTR; 1099 break; 1100 } 1101 } 1102 lw8_event_pending = B_FALSE; 1103 mutex_exit(&lw8_event_mutex); 1104 break; 1105 case LOMIOCMREAD: 1106 bzero((caddr_t)&lw8_mprog, sizeof (lw8_mprog)); 1107 lw8_mprog.config = 4; 1108 if (ddi_copyout((caddr_t)&lw8_mprog, (caddr_t)arg, 1109 sizeof (lw8_mprog), mode) != 0) { 1110 retval = EFAULT; 1111 } 1112 break; 1113 case LOMIOCCTL2: 1114 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl2, 1115 sizeof (lw8_ctl2), mode) != 0) { 1116 retval = EFAULT; 1117 break; 1118 } 1119 retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2); 1120 break; 1121 case LOMIOCPROG: 1122 lw8_progp = kmem_alloc(sizeof (*lw8_progp), KM_SLEEP); 1123 if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_progp, 1124 sizeof (*lw8_progp), mode) != 0) { 1125 kmem_free(lw8_progp, sizeof (*lw8_progp)); 1126 retval = EFAULT; 1127 break; 1128 } 1129 retval = lw8_lomcmd(LW8_MBOX_UPDATE_FW, (intptr_t)lw8_progp); 1130 kmem_free(lw8_progp, sizeof (*lw8_progp)); 1131 break; 1132 case LOMIOCINFO2: 1133 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 1134 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 1135 if (retval != 0) 1136 break; 1137 if (ddi_copyout((caddr_t)&lw8_info2, (caddr_t)arg, 1138 sizeof (lw8_info2), mode) != 0) { 1139 retval = EFAULT; 1140 } 1141 break; 1142 case LOMIOCINFO: 1143 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 1144 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 1145 if (retval != 0) 1146 break; 1147 bzero((caddr_t)&lw8_info, sizeof (lw8_info)); 1148 lw8_info.ser_char = lw8_info2.escape_chars[0]; 1149 lw8_info.fver = lw8_info2.fver; 1150 lw8_info.fchksum = lw8_info2.fchksum; 1151 lw8_info.prod_rev = lw8_info2.prod_rev; 1152 strncpy(lw8_info.prod_id, lw8_info2.prod_id, MAX_ID_LEN); 1153 if (ddi_copyout((caddr_t)&lw8_info, (caddr_t)arg, 1154 sizeof (lw8_info), mode) != 0) { 1155 retval = EFAULT; 1156 } 1157 break; 1158 case LOMIOCFLEDSTATE: 1159 bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led)); 1160 (void) strncpy(lw8_get_led.location, "chassis", 1161 MAX_LOCATION_LEN); 1162 (void) strncpy(lw8_get_led.id, "fault", MAX_ID_LEN); 1163 retval = lw8_getled(&lw8_get_led); 1164 if (retval != 0) 1165 break; 1166 lw8_fled_info.on = lw8_get_led.status; 1167 if (ddi_copyout((caddr_t)&lw8_fled_info, (caddr_t)arg, 1168 sizeof (lw8_fled_info), mode) != 0) { 1169 retval = EFAULT; 1170 } 1171 break; 1172 case LOMIOCALSTATE: 1173 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata, 1174 sizeof (lw8_aldata), mode) != 0) { 1175 retval = EFAULT; 1176 break; 1177 } 1178 bzero((caddr_t)&lw8_get_led, sizeof (lw8_get_led)); 1179 (void) strncpy(lw8_get_led.location, "chassis", 1180 MAX_LOCATION_LEN); 1181 if (lw8_aldata.alarm_no == 3) 1182 (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "system"); 1183 else 1184 (void) snprintf(lw8_get_led.id, MAX_ID_LEN, "alarm%d", 1185 lw8_aldata.alarm_no); 1186 retval = lw8_getled(&lw8_get_led); 1187 if (retval != 0) 1188 break; 1189 lw8_aldata.state = lw8_get_led.status; 1190 if (ddi_copyout((caddr_t)&lw8_aldata, (caddr_t)arg, 1191 sizeof (lw8_aldata), mode) != 0) { 1192 retval = EFAULT; 1193 } 1194 break; 1195 case LOMIOCGETLED: 1196 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_get_led, 1197 sizeof (lw8_get_led), mode) != 0) { 1198 retval = EFAULT; 1199 break; 1200 } 1201 retval = lw8_getled(&lw8_get_led); 1202 if (retval != 0) 1203 break; 1204 if (ddi_copyout((caddr_t)&lw8_get_led, (caddr_t)arg, 1205 sizeof (lw8_get_led), mode) != 0) { 1206 retval = EFAULT; 1207 } 1208 break; 1209 case LOMIOCEVENTLOG2: 1210 lw8_eventlogp = kmem_alloc(sizeof (*lw8_eventlogp), KM_SLEEP); 1211 lw8_eventresp = kmem_zalloc(sizeof (*lw8_eventresp), KM_SLEEP); 1212 if (ddi_copyin((caddr_t)arg, (caddr_t)lw8_eventlogp, 1213 sizeof (*lw8_eventlogp), mode) != 0) { 1214 kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp)); 1215 kmem_free(lw8_eventresp, sizeof (*lw8_eventresp)); 1216 retval = EFAULT; 1217 break; 1218 } 1219 lw8_eventresp->num = lw8_eventlogp->num; 1220 lw8_eventresp->level = lw8_eventlogp->level; 1221 retval = lw8_lomcmd(LW8_MBOX_GET_EVENTS, 1222 (intptr_t)lw8_eventresp); 1223 if (retval == 0) { 1224 lw8_eventlogp->num = lw8_eventresp->num; 1225 for (i = 0; i < lw8_eventresp->num; i++) { 1226 for (j = 0; j < MAX_EVENT_STR; j++) { 1227 lw8_eventlogp->string[i][j] = 1228 lw8_eventresp->string[i][j]; 1229 } 1230 } 1231 if (ddi_copyout((caddr_t)lw8_eventlogp, (caddr_t)arg, 1232 sizeof (*lw8_eventlogp), mode) != 0) { 1233 retval = EFAULT; 1234 } 1235 } 1236 kmem_free(lw8_eventlogp, sizeof (*lw8_eventlogp)); 1237 kmem_free(lw8_eventresp, sizeof (*lw8_eventresp)); 1238 break; 1239 case LOMIOCALCTL: 1240 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_aldata, 1241 sizeof (lw8_aldata), mode) != 0) { 1242 retval = EFAULT; 1243 break; 1244 } 1245 bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led)); 1246 (void) strncpy(lw8_set_led.location, "chassis", 1247 MAX_LOCATION_LEN); 1248 if (lw8_aldata.alarm_no == 3) 1249 (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "system"); 1250 else 1251 (void) snprintf(lw8_set_led.id, MAX_ID_LEN, "alarm%d", 1252 lw8_aldata.alarm_no); 1253 lw8_set_led.status = lw8_aldata.state; 1254 retval = lw8_setled(&lw8_set_led); 1255 break; 1256 case LOMIOCSETLED: 1257 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_set_led, 1258 sizeof (lw8_set_led), mode) != 0) { 1259 retval = EFAULT; 1260 break; 1261 } 1262 retval = lw8_setled(&lw8_set_led); 1263 break; 1264 case LOMIOCCTL: 1265 /* 1266 * for this ioctl, as well as setting the fault led in the 1267 * LOMIOCCTL case in lw8_lomcmd(), we also need to set the 1268 * escape character. To do this we must use LW8_MBOX_SET_CTL, 1269 * but this also needs the serial_event value which we have 1270 * to get via LW8_MBOX_GET_INFO 1271 */ 1272 if (ddi_copyin((caddr_t)arg, (caddr_t)&lw8_ctl, 1273 sizeof (lw8_ctl), mode) != 0) { 1274 retval = EFAULT; 1275 break; 1276 } 1277 bzero((caddr_t)&lw8_info2, sizeof (lw8_info2)); 1278 retval = lw8_lomcmd(LW8_MBOX_GET_INFO, (intptr_t)&lw8_info2); 1279 if (retval != 0) 1280 break; 1281 bzero((caddr_t)&lw8_ctl2, sizeof (lw8_ctl2)); 1282 lw8_ctl2.escape_chars[0] = lw8_ctl.ser_char; 1283 lw8_ctl2.serial_events = lw8_info2.serial_events; 1284 retval = lw8_lomcmd(LW8_MBOX_SET_CTL, (intptr_t)&lw8_ctl2); 1285 if (retval != 0) 1286 break; 1287 1288 /* 1289 * if fault_led != 0, then set the led 1290 */ 1291 if (lw8_ctl.fault_led == 0) 1292 break; 1293 bzero((caddr_t)&lw8_set_led, sizeof (lw8_set_led)); 1294 (void) strncpy(lw8_set_led.location, "chassis", 1295 MAX_LOCATION_LEN); 1296 (void) strncpy(lw8_set_led.id, "fault", MAX_ID_LEN); 1297 lw8_set_led.status = lw8_ctl.fault_led - 1; 1298 retval = lw8_setled(&lw8_set_led); 1299 break; 1300 default: 1301 retval = ENOTSUP; 1302 break; 1303 } 1304 return (retval); 1305 } 1306 1307 /* ARGSUSED */ 1308 static void 1309 lw8_logger(caddr_t arg) 1310 { 1311 callb_cpr_t cprinfo; 1312 lw8_logmsg_t *lw8_logmsgp; 1313 boolean_t more_waiting; 1314 char level; 1315 int retval; 1316 1317 CALLB_CPR_INIT(&cprinfo, &lw8_logger_lock, callb_generic_cpr, 1318 "lw8_logger"); 1319 1320 lw8_logmsgp = kmem_zalloc(sizeof (*lw8_logmsgp), KM_SLEEP); 1321 mutex_enter(&lw8_logger_lock); 1322 for (;;) { 1323 1324 /* 1325 * Wait for someone to tell me to continue. 1326 */ 1327 while (lw8_logger_sig == LW8_LOGGER_WAIT) { 1328 CALLB_CPR_SAFE_BEGIN(&cprinfo); 1329 cv_wait(&lw8_logger_sig_cv, &lw8_logger_lock); 1330 CALLB_CPR_SAFE_END(&cprinfo, &lw8_logger_lock); 1331 } 1332 1333 /* LW8_LOGGER_EXITNOW implies signal by _detach(). */ 1334 if (lw8_logger_sig == LW8_LOGGER_EXITNOW) { 1335 lw8_logger_sig = LW8_LOGGER_WAIT; 1336 1337 kmem_free(lw8_logmsgp, sizeof (*lw8_logmsgp)); 1338 1339 /* lw8_logger_lock is held at this point! */ 1340 CALLB_CPR_EXIT(&cprinfo); 1341 1342 thread_exit(); 1343 /* NOTREACHED */ 1344 } 1345 1346 ASSERT(lw8_logger_sig == LW8_LOGGER_PROCESSNOW); 1347 lw8_logger_sig = LW8_LOGGER_WAIT; 1348 1349 mutex_exit(&lw8_logger_lock); 1350 1351 /* Do lw8_event logging */ 1352 1353 /* 1354 * Get one message per iteration. We do not sleep if 1355 * there are more to process. This makes exit from the 1356 * routine much more reliable. 1357 */ 1358 more_waiting = B_FALSE; 1359 1360 retval = lw8_lomcmd(LW8_MBOX_GET_NEXT_MSG, 1361 (intptr_t)lw8_logmsgp); 1362 if (retval == 0) { 1363 if (lw8_logmsgp->msg_valid) { 1364 1365 switch (lw8_logmsgp->level) { 1366 case 0: /* LOG_EMERG */ 1367 level = SL_FATAL; 1368 break; 1369 case 1: /* LOG_ALERT */ 1370 level = SL_FATAL; 1371 break; 1372 case 2: /* LOG_CRIT */ 1373 level = SL_FATAL; 1374 break; 1375 case 3: /* LOG_ERR */ 1376 level = SL_ERROR; 1377 break; 1378 case 4: /* LOG_WARNING */ 1379 level = SL_WARN; 1380 break; 1381 case 5: /* LOG_NOTICE */ 1382 level = SL_NOTE; 1383 break; 1384 case 6: /* LOG_INFO */ 1385 level = SL_NOTE; 1386 break; 1387 case 7: /* LOG_DEBUG */ 1388 level = SL_TRACE; 1389 break; 1390 default: /* unknown */ 1391 level = SL_NOTE; 1392 break; 1393 } 1394 1395 /* Ensure NUL termination */ 1396 lw8_logmsgp->msg[ 1397 sizeof (lw8_logmsgp->msg) - 1] = '\0'; 1398 strlog(0, 0, 0, SL_CONSOLE | level, 1399 lw8_logmsgp->msg); 1400 } 1401 1402 if (lw8_logmsgp->num_remaining > 0) 1403 more_waiting = B_TRUE; 1404 } 1405 1406 /* 1407 * Re-enter the lock to prepare for another iteration. 1408 * We must have the lock here to protect lw8_logger_sig. 1409 */ 1410 mutex_enter(&lw8_logger_lock); 1411 if ((lw8_logger_sig == LW8_LOGGER_WAIT) && more_waiting) 1412 /* We need to get more events */ 1413 lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 1414 } 1415 } 1416 1417 static void 1418 lw8_logger_start(void) 1419 { 1420 kthread_t *tp; 1421 1422 mutex_enter(&lw8_logger_lock); 1423 1424 if (lw8_logger_tid == 0) { 1425 /* Force retrieval of any pending messages */ 1426 lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 1427 1428 tp = thread_create(NULL, 0, lw8_logger, NULL, 0, 1429 &p0, TS_RUN, maxclsyspri); 1430 lw8_logger_tid = tp->t_did; 1431 } 1432 1433 mutex_exit(&lw8_logger_lock); 1434 } 1435 1436 static void 1437 lw8_logger_destroy(void) 1438 { 1439 kt_did_t tid; 1440 1441 mutex_enter(&lw8_logger_lock); 1442 tid = lw8_logger_tid; 1443 if (tid != 0) { 1444 lw8_logger_sig = LW8_LOGGER_EXITNOW; 1445 cv_signal(&lw8_logger_sig_cv); 1446 lw8_logger_tid = 0; 1447 } 1448 mutex_exit(&lw8_logger_lock); 1449 1450 /* 1451 * Wait for lw8_logger() to finish. 1452 */ 1453 if (tid != 0) 1454 thread_join(tid); 1455 } 1456 1457 static void 1458 lw8_logger_wakeup(void) 1459 { 1460 mutex_enter(&lw8_logger_lock); 1461 1462 if (lw8_logger_sig != LW8_LOGGER_EXITNOW) 1463 lw8_logger_sig = LW8_LOGGER_PROCESSNOW; 1464 cv_signal(&lw8_logger_sig_cv); 1465 1466 mutex_exit(&lw8_logger_lock); 1467 } 1468