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/types.h> 29 #include <sys/stat.h> 30 #include <sys/conf.h> 31 #include <sys/modctl.h> 32 #include <sys/callb.h> 33 #include <sys/strlog.h> 34 #include <sys/cyclic.h> 35 #include <sys/rmc_comm_dp.h> 36 #include <sys/rmc_comm_dp_boot.h> 37 #include <sys/rmc_comm_drvintf.h> 38 #include <sys/rmc_comm.h> 39 #include <sys/machsystm.h> 40 #include <sys/sysevent.h> 41 #include <sys/sysevent/dr.h> 42 #include <sys/sysevent/env.h> 43 #include <sys/sysevent/eventdefs.h> 44 #include <sys/file.h> 45 #include <sys/disp.h> 46 #include <sys/reboot.h> 47 #include <sys/envmon.h> 48 #include <sys/rmclomv_impl.h> 49 #include <sys/cpu_sgnblk_defs.h> 50 #include <sys/utsname.h> 51 #include <sys/systeminfo.h> 52 #include <sys/ddi.h> 53 #include <sys/time.h> 54 #include <sys/promif.h> 55 56 #define offsetof(s, m) (size_t)(&(((s *)0)->m)) 57 #define RMCRESBUFLEN 1024 58 #define DATE_TIME_MSG_SIZE 78 59 #define RMCLOMV_WATCHDOG_MODE "rmclomv-watchdog-mode" 60 #define DELAY_TIME 5000000 /* 5 seconds, in microseconds */ 61 #define CPU_SIGNATURE_DELAY_TIME 5000000 /* 5 secs, in microsecs */ 62 63 extern void pmugpio_watchdog_pat(); 64 static clock_t timesync_interval; 65 66 extern int watchdog_activated; 67 static int last_watchdog_msg = 1; 68 extern int watchdog_enable; 69 extern int boothowto; 70 71 int rmclomv_watchdog_mode; 72 73 /* 74 * functions local to this driver. 75 */ 76 static int rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 77 void **resultp); 78 static int rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 79 static int rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 80 static uint_t rmclomv_break_intr(caddr_t arg); 81 static int rmclomv_add_intr_handlers(void); 82 static int rmclomv_remove_intr_handlers(void); 83 static uint_t rmclomv_event_data_handler(char *); 84 static void rmclomv_dr_data_handler(const char *, int); 85 static int rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p); 86 static int rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 87 static int rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 88 cred_t *cred_p, int *rval_p); 89 static void rmclomv_checkrmc_start(void); 90 static void rmclomv_checkrmc_destroy(void); 91 static void rmclomv_checkrmc_wakeup(void *); 92 static void rmclomv_refresh_start(void); 93 static void rmclomv_refresh_destroy(void); 94 static void rmclomv_refresh_wakeup(void); 95 static void rmclomv_reset_cache(rmclomv_cache_section_t *new_chain, 96 rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo); 97 static rmclomv_cache_section_t *rmclomv_find_section( 98 rmclomv_cache_section_t *start, uint16_t sensor); 99 static rmclomv_cache_section_t *create_cache_section(int sensor_type, int num); 100 static int get_sensor_by_name(const rmclomv_cache_section_t *section, 101 const char *name, int *index); 102 static int validate_section_entry(rmclomv_cache_section_t *section, 103 int index); 104 static int add_names_to_section(rmclomv_cache_section_t *section); 105 static void free_section(rmclomv_cache_section_t *section); 106 static void add_section(rmclomv_cache_section_t **head, 107 rmclomv_cache_section_t *section); 108 static int rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, 109 intptr_t arg_req, intptr_t arg_res); 110 static void refresh_name_cache(int force_fail); 111 static void set_val_unav(envmon_sensor_t *sensor); 112 static void set_fan_unav(envmon_fan_t *fan); 113 static int do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind, 114 dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r, 115 int detector_type); 116 static uint_t rmc_set_watchdog_timer(uint_t timeoutval); 117 static uint_t rmc_clear_watchdog_timer(void); 118 static void send_watchdog_msg(int msg); 119 static void plat_timesync(void *arg); 120 121 /* 122 * Driver entry points 123 */ 124 static struct cb_ops rmclomv_cb_ops = { 125 rmclomv_open, /* open */ 126 rmclomv_close, /* close */ 127 nodev, /* strategy() */ 128 nodev, /* print() */ 129 nodev, /* dump() */ 130 nodev, /* read() */ 131 nodev, /* write() */ 132 rmclomv_ioctl, /* ioctl() */ 133 nodev, /* devmap() */ 134 nodev, /* mmap() */ 135 ddi_segmap, /* segmap() */ 136 nochpoll, /* poll() */ 137 ddi_prop_op, /* prop_op() */ 138 NULL, /* cb_str */ 139 D_NEW | D_MP /* cb_flag */ 140 }; 141 142 143 static struct dev_ops rmclomv_ops = { 144 DEVO_REV, 145 0, /* ref count */ 146 rmclomv_getinfo, /* getinfo() */ 147 nulldev, /* identify() */ 148 nulldev, /* probe() */ 149 rmclomv_attach, /* attach() */ 150 rmclomv_detach, /* detach */ 151 nodev, /* reset */ 152 &rmclomv_cb_ops, /* pointer to cb_ops structure */ 153 (struct bus_ops *)NULL, 154 nulldev, /* power() */ 155 ddi_quiesce_not_supported, /* devo_quiesce */ 156 }; 157 158 /* 159 * Loadable module support. 160 */ 161 extern struct mod_ops mod_driverops; 162 163 static struct modldrv modldrv = { 164 &mod_driverops, /* Type of module. This is a driver */ 165 "rmclomv control driver", /* Name of the module */ 166 &rmclomv_ops /* pointer to the dev_ops structure */ 167 }; 168 169 static struct modlinkage modlinkage = { 170 MODREV_1, 171 &modldrv, 172 NULL 173 }; 174 175 /* 176 * Device info 177 */ 178 static dev_info_t *rmclomv_dip = NULL; 179 static int rmclomv_break_requested = B_FALSE; 180 static ddi_softintr_t rmclomv_softintr_id; 181 static ddi_iblock_cookie_t rmclomv_soft_iblock_cookie; 182 183 extern void (*abort_seq_handler)(); 184 /* key_position is effective key-position. Set to locked if unknown */ 185 static rsci8 key_position = RMC_KEYSWITCH_POS_LOCKED; 186 /* real_key_position starts off as unknown and records value actually seen */ 187 static rsci8 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN; 188 static void rmclomv_abort_seq_handler(char *msg); 189 190 /* 191 * mutexes which protect the interrupt handlers. 192 */ 193 static kmutex_t rmclomv_event_hdlr_lock; 194 static kmutex_t rmclomv_refresh_lock; 195 static kcondvar_t rmclomv_refresh_sig_cv; 196 static kmutex_t rmclomv_checkrmc_lock; 197 static kcondvar_t rmclomv_checkrmc_sig_cv; 198 199 /* 200 * mutex to protect the handle_name cache 201 */ 202 static kmutex_t rmclomv_cache_lock; 203 204 /* 205 * mutex to protect the RMC state 206 */ 207 static kmutex_t rmclomv_state_lock; 208 209 /* 210 * Payloads of the event handlers. 211 */ 212 static dp_event_notification_t rmclomv_event_payload; 213 static rmc_comm_msg_t rmclomv_event_payload_msg; 214 215 /* 216 * Checkrmc commands.. 217 */ 218 #define RMCLOMV_CHECKRMC_EXITNOW (-1) 219 #define RMCLOMV_CHECKRMC_WAIT 0 220 #define RMCLOMV_CHECKRMC_PROCESSNOW 1 221 222 /* 223 * Checkrmc thread state 224 */ 225 static int rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 226 static kt_did_t rmclomv_checkrmc_tid = 0; 227 228 /* 229 * RMC state data 230 */ 231 #define RMCLOMV_RMCSTATE_UNKNOWN 0 232 #define RMCLOMV_RMCSTATE_OK 1 233 #define RMCLOMV_RMCSTATE_FAILED 2 234 #define RMCLOMV_RMCSTATE_DOWNLOAD 3 235 236 /* 237 * RMC error indicator values (status from last RMC command) 238 */ 239 #define RMCLOMV_RMCERROR_NONE 0 240 241 /* fail RMC after 5 minutes without a good response */ 242 #define RMCLOMV_RMCFAILTHRESHOLD 5 243 244 /* 245 * rmclomv_rmc_state is the state reported in OperationalStatus. 246 * rmclomv_rmc_error reflects the result of the last RMC interaction. 247 * rmclomv_rmcfailcount is used by the rmclomv_checkrmc thread to count 248 * failures in its regular status polls. Once RMCLOMV_RMCFAILTHRESHOLD 249 * is reached, rmclomv_rmc_state is marked as RMCLOMV_RMCSTATE_FAILED. 250 */ 251 static int rmclomv_rmc_state = RMCLOMV_RMCSTATE_UNKNOWN; 252 static int rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE; 253 static int rmclomv_rmcfailcount; 254 255 /* 256 * Refresh commands.. 257 */ 258 #define RMCLOMV_REFRESH_EXITNOW (-1) 259 #define RMCLOMV_REFRESH_WAIT 0 260 #define RMCLOMV_REFRESH_PROCESSNOW 1 261 262 /* 263 * Refresh thread state 264 */ 265 static int rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 266 static kt_did_t rmclomv_refresh_tid = 0; 267 268 /* 269 * timeout id 270 */ 271 static timeout_id_t timer_id; 272 273 /* 274 * Handle-name cache 275 */ 276 #define LOCK_CACHE mutex_enter(&rmclomv_cache_lock); 277 #define RELEASE_CACHE mutex_exit(&rmclomv_cache_lock); 278 static rmclomv_cache_section_t *rmclomv_cache; /* main handle-names */ 279 static rmclomv_cache_section_t *rmclomv_subcache; /* derived names */ 280 static dp_get_sysinfo_r_t rmclomv_sysinfo_data; 281 static boolean_t rmclomv_sysinfo_valid; 282 static int rmclomv_cache_valid; 283 284 extern pri_t maxclsyspri; 285 286 /* 287 * static strings 288 */ 289 static const char str_percent[] = "%"; 290 static const char str_rpm[] = " rpm"; 291 static const char str_ip_volts_ind[] = "P_PWR"; 292 static const char str_ip2_volts_ind[] = "P_PWR2"; 293 static const char str_ff_pok_ind[] = "FF_POK"; 294 static const char str_vlo_volts_ind[] = "FF_UV"; 295 static const char str_vhi_volts_ind[] = "FF_OV"; 296 static const char str_chi_amps_ind[] = "FF_OC"; 297 static const char str_chi_nr_ind[] = "FF_NR"; 298 static const char str_ot_tmpr_ind[] = "FF_OT"; 299 static const char str_fan_ind[] = "FF_FAN"; 300 static const char str_pdct_fan_ind[] = "FF_PDCT_FAN"; 301 static const char str_sc[] = "SC"; 302 303 int 304 _init(void) 305 { 306 int error = 0; 307 308 mutex_init(&rmclomv_event_hdlr_lock, NULL, MUTEX_DEFAULT, NULL); 309 mutex_init(&rmclomv_checkrmc_lock, NULL, MUTEX_DRIVER, NULL); 310 mutex_init(&rmclomv_refresh_lock, NULL, MUTEX_DRIVER, NULL); 311 mutex_init(&rmclomv_cache_lock, NULL, MUTEX_DRIVER, NULL); 312 mutex_init(&rmclomv_state_lock, NULL, MUTEX_DRIVER, NULL); 313 cv_init(&rmclomv_checkrmc_sig_cv, NULL, CV_DRIVER, NULL); 314 cv_init(&rmclomv_refresh_sig_cv, NULL, CV_DRIVER, NULL); 315 316 error = mod_install(&modlinkage); 317 if (error) { 318 cv_destroy(&rmclomv_refresh_sig_cv); 319 cv_destroy(&rmclomv_checkrmc_sig_cv); 320 mutex_destroy(&rmclomv_state_lock); 321 mutex_destroy(&rmclomv_cache_lock); 322 mutex_destroy(&rmclomv_refresh_lock); 323 mutex_destroy(&rmclomv_checkrmc_lock); 324 mutex_destroy(&rmclomv_event_hdlr_lock); 325 } 326 return (error); 327 } 328 329 330 int 331 _info(struct modinfo *modinfop) 332 { 333 return (mod_info(&modlinkage, modinfop)); 334 } 335 336 337 int 338 _fini(void) 339 { 340 int error = 0; 341 342 error = mod_remove(&modlinkage); 343 if (error) 344 return (error); 345 cv_destroy(&rmclomv_refresh_sig_cv); 346 cv_destroy(&rmclomv_checkrmc_sig_cv); 347 mutex_destroy(&rmclomv_state_lock); 348 mutex_destroy(&rmclomv_cache_lock); 349 mutex_destroy(&rmclomv_refresh_lock); 350 mutex_destroy(&rmclomv_checkrmc_lock); 351 mutex_destroy(&rmclomv_event_hdlr_lock); 352 return (error); 353 } 354 355 356 /* ARGSUSED */ 357 static int 358 rmclomv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 359 { 360 minor_t m = getminor((dev_t)arg); 361 362 switch (cmd) { 363 case DDI_INFO_DEVT2DEVINFO: 364 if ((m != 0) || (rmclomv_dip == NULL)) { 365 *resultp = NULL; 366 return (DDI_FAILURE); 367 } 368 *resultp = rmclomv_dip; 369 return (DDI_SUCCESS); 370 case DDI_INFO_DEVT2INSTANCE: 371 *resultp = (void *)(uintptr_t)m; 372 return (DDI_SUCCESS); 373 default: 374 return (DDI_FAILURE); 375 } 376 } 377 378 379 static int 380 rmclomv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 381 { 382 int instance; 383 int err; 384 char *wdog_state; 385 int attaching = 1; 386 387 switch (cmd) { 388 case DDI_ATTACH: 389 /* 390 * only allow one instance 391 */ 392 instance = ddi_get_instance(dip); 393 if (instance != 0) 394 return (DDI_FAILURE); 395 396 err = ddi_create_minor_node(dip, "rmclomv", S_IFCHR, 397 instance, DDI_PSEUDO, NULL); 398 if (err != DDI_SUCCESS) 399 return (DDI_FAILURE); 400 401 /* 402 * Register with rmc_comm to prevent it being detached 403 * (in the unlikely event that its attach succeeded on a 404 * platform whose platmod doesn't lock it down). 405 */ 406 err = rmc_comm_register(); 407 if (err != DDI_SUCCESS) { 408 ddi_remove_minor_node(dip, NULL); 409 return (DDI_FAILURE); 410 } 411 412 /* Remember the dev info */ 413 rmclomv_dip = dip; 414 415 /* 416 * Add the handlers which watch for unsolicited messages 417 * and post event to Sysevent Framework. 418 */ 419 err = rmclomv_add_intr_handlers(); 420 if (err != DDI_SUCCESS) { 421 rmc_comm_unregister(); 422 ddi_remove_minor_node(dip, NULL); 423 rmclomv_dip = NULL; 424 return (DDI_FAILURE); 425 } 426 427 rmclomv_checkrmc_start(); 428 rmclomv_refresh_start(); 429 430 abort_seq_handler = rmclomv_abort_seq_handler; 431 ddi_report_dev(dip); 432 433 /* 434 * Check whether we have an application watchdog 435 */ 436 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 437 DDI_PROP_DONTPASS, RMCLOMV_WATCHDOG_MODE, 438 &wdog_state) == DDI_PROP_SUCCESS) { 439 if (strcmp(wdog_state, "app") == 0) { 440 rmclomv_watchdog_mode = 1; 441 watchdog_enable = 0; 442 } 443 else 444 rmclomv_watchdog_mode = 0; 445 ddi_prop_free(wdog_state); 446 } 447 448 tod_ops.tod_set_watchdog_timer = rmc_set_watchdog_timer; 449 tod_ops.tod_clear_watchdog_timer = rmc_clear_watchdog_timer; 450 451 /* 452 * Now is a good time to activate hardware watchdog 453 * (if one exists). 454 */ 455 mutex_enter(&tod_lock); 456 if (watchdog_enable && tod_ops.tod_set_watchdog_timer != NULL) 457 err = tod_ops.tod_set_watchdog_timer(0); 458 mutex_exit(&tod_lock); 459 if (err != 0) 460 printf("Hardware watchdog enabled\n"); 461 462 /* 463 * Set time interval and start timesync routine. 464 * Also just this once set the Solaris clock 465 * to the RMC clock. 466 */ 467 timesync_interval = drv_usectohz(5*60 * MICROSEC); 468 plat_timesync((void *) &attaching); 469 470 return (DDI_SUCCESS); 471 case DDI_RESUME: 472 return (DDI_SUCCESS); 473 default: 474 return (DDI_FAILURE); 475 } 476 } 477 478 479 static int 480 rmclomv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 481 { 482 int instance; 483 int err; 484 485 switch (cmd) { 486 case DDI_DETACH: 487 instance = ddi_get_instance(dip); 488 if (instance != 0) 489 return (DDI_FAILURE); 490 491 /* 492 * Remove the handlers which watch for unsolicited messages 493 * and post event to Sysevent Framework. 494 */ 495 err = rmclomv_remove_intr_handlers(); 496 if (err != DDI_SUCCESS) { 497 cmn_err(CE_WARN, "Failed to remove event handlers"); 498 return (DDI_FAILURE); 499 } 500 rmclomv_checkrmc_destroy(); 501 rmclomv_refresh_destroy(); 502 rmclomv_reset_cache(NULL, NULL, NULL); 503 ddi_remove_minor_node(dip, NULL); 504 505 /* Forget the dev info */ 506 rmclomv_dip = NULL; 507 rmc_comm_unregister(); 508 return (DDI_SUCCESS); 509 case DDI_SUSPEND: 510 return (DDI_SUCCESS); 511 default: 512 return (DDI_FAILURE); 513 } 514 } 515 516 static int 517 rmclomv_add_intr_handlers() 518 { 519 int err; 520 521 if (ddi_get_soft_iblock_cookie(rmclomv_dip, DDI_SOFTINT_HIGH, 522 &rmclomv_soft_iblock_cookie) != DDI_SUCCESS) { 523 return (DDI_FAILURE); 524 } 525 err = ddi_add_softintr(rmclomv_dip, DDI_SOFTINT_HIGH, 526 &rmclomv_softintr_id, &rmclomv_soft_iblock_cookie, NULL, 527 rmclomv_break_intr, NULL); 528 if (err != DDI_SUCCESS) 529 return (DDI_FAILURE); 530 rmclomv_event_payload_msg.msg_buf = (caddr_t)&rmclomv_event_payload; 531 rmclomv_event_payload_msg.msg_len = sizeof (rmclomv_event_payload); 532 err = rmc_comm_reg_intr(DP_RMC_EVENTS, rmclomv_event_data_handler, 533 &rmclomv_event_payload_msg, NULL, &rmclomv_event_hdlr_lock); 534 if (err != 0) { 535 ddi_remove_softintr(rmclomv_softintr_id); 536 return (DDI_FAILURE); 537 } 538 return (DDI_SUCCESS); 539 } 540 541 static int 542 rmclomv_remove_intr_handlers(void) 543 { 544 int err = rmc_comm_unreg_intr(DP_RMC_EVENTS, 545 rmclomv_event_data_handler); 546 if (err != 0) { 547 cmn_err(CE_WARN, "Failed to unregister DP_RMC_EVENTS " 548 "handler. Err=%d", err); 549 return (DDI_FAILURE); 550 } 551 ddi_remove_softintr(rmclomv_softintr_id); 552 return (DDI_SUCCESS); 553 } 554 555 static void 556 rmclomv_abort_seq_handler(char *msg) 557 { 558 if (key_position == RMC_KEYSWITCH_POS_LOCKED) 559 cmn_err(CE_CONT, "KEY in LOCKED position, " 560 "ignoring debug enter sequence"); 561 else { 562 rmclomv_break_requested = B_TRUE; 563 if (msg != NULL) 564 prom_printf("%s\n", msg); 565 566 ddi_trigger_softintr(rmclomv_softintr_id); 567 } 568 } 569 570 /* ARGSUSED */ 571 static uint_t 572 rmclomv_break_intr(caddr_t arg) 573 { 574 if (rmclomv_break_requested) { 575 rmclomv_break_requested = B_FALSE; 576 debug_enter(NULL); 577 return (DDI_INTR_CLAIMED); 578 } 579 580 return (DDI_INTR_UNCLAIMED); 581 } 582 583 /* 584 * Create a cache section structure 585 */ 586 static rmclomv_cache_section_t * 587 create_cache_section(int sensor_type, int num) 588 { 589 size_t len = offsetof(rmclomv_cache_section_t, entry[0]) + 590 num * sizeof (rmclomv_cache_entry_t); 591 rmclomv_cache_section_t *ptr = kmem_zalloc(len, KM_SLEEP); 592 ptr->next_section = NULL; 593 ptr->sensor_type = sensor_type; 594 ptr->num_entries = num; 595 ptr->section_len = len; 596 return (ptr); 597 } 598 599 /* 600 * Free a cache_section. 601 */ 602 static void 603 free_section(rmclomv_cache_section_t *section) 604 { 605 size_t len = section->section_len; 606 kmem_free(section, len); 607 } 608 609 /* 610 * adds supplied section to end of cache chain 611 * must be called with cache locked 612 */ 613 static void 614 add_section(rmclomv_cache_section_t **head, rmclomv_cache_section_t *section) 615 { 616 section->next_section = *head; 617 *head = section; 618 } 619 620 /* 621 * This function releases all cache sections and exchanges the two 622 * chain heads for new values. 623 */ 624 static void 625 rmclomv_reset_cache(rmclomv_cache_section_t *new_chain, 626 rmclomv_cache_section_t *new_subchain, dp_get_sysinfo_r_t *sysinfo) 627 { 628 rmclomv_cache_section_t *first; 629 rmclomv_cache_section_t *sub_first; 630 rmclomv_cache_section_t *next; 631 632 LOCK_CACHE 633 634 rmclomv_cache_valid = (new_chain != NULL); 635 first = rmclomv_cache; 636 rmclomv_cache = new_chain; 637 sub_first = rmclomv_subcache; 638 rmclomv_subcache = new_subchain; 639 640 if (sysinfo == NULL) 641 bzero(&rmclomv_sysinfo_data, sizeof (rmclomv_sysinfo_data)); 642 else 643 bcopy(sysinfo, &rmclomv_sysinfo_data, 644 sizeof (rmclomv_sysinfo_data)); 645 646 rmclomv_sysinfo_valid = (sysinfo != NULL); 647 648 RELEASE_CACHE 649 650 while (first != NULL) { 651 next = first->next_section; 652 free_section(first); 653 first = next; 654 } 655 656 while (sub_first != NULL) { 657 next = sub_first->next_section; 658 free_section(sub_first); 659 sub_first = next; 660 } 661 } 662 663 /* 664 * cache must be locked before calling rmclomv_find_section 665 */ 666 static rmclomv_cache_section_t * 667 rmclomv_find_section(rmclomv_cache_section_t *start, uint16_t sensor) 668 { 669 rmclomv_cache_section_t *next = start; 670 671 while ((next != NULL) && (next->sensor_type != sensor)) 672 next = next->next_section; 673 674 return (next); 675 } 676 677 /* 678 * Return a string presenting the keyswitch position 679 * For unknown values returns "Unknown" 680 */ 681 static char * 682 rmclomv_key_position(enum rmc_keyswitch_pos pos) 683 { 684 switch (pos) { 685 686 case RMC_KEYSWITCH_POS_NORMAL: 687 return ("NORMAL"); 688 case RMC_KEYSWITCH_POS_DIAG: 689 return ("DIAG"); 690 case RMC_KEYSWITCH_POS_LOCKED: 691 return ("LOCKED"); 692 case RMC_KEYSWITCH_POS_OFF: 693 return ("STBY"); 694 default: 695 return ("UNKNOWN"); 696 } 697 } 698 699 /* 700 * The sensor id name is sought in the supplied section and if found 701 * its index within the section is written to *index. 702 * Return value is zero for success, otherwise -1. 703 * The cache must be locked before calling get_sensor_by_name 704 */ 705 static int 706 get_sensor_by_name(const rmclomv_cache_section_t *section, 707 const char *name, int *index) 708 { 709 int i; 710 711 for (i = 0; i < section->num_entries; i++) { 712 if (strcmp(name, section->entry[i].handle_name.name) == 0) { 713 *index = i; 714 return (0); 715 } 716 } 717 718 *index = 0; 719 return (-1); 720 } 721 722 /* 723 * fills in the envmon_handle name 724 * if it is unknown (not cached), the dp_handle_t is returned as a hex-digit 725 * string 726 */ 727 static void 728 rmclomv_hdl_to_envhdl(dp_handle_t hdl, envmon_handle_t *envhdl) 729 { 730 rmclomv_cache_section_t *next; 731 int i; 732 733 LOCK_CACHE 734 735 for (next = rmclomv_cache; next != NULL; next = next->next_section) { 736 for (i = 0; i < next->num_entries; i++) { 737 if (next->entry[i].handle == hdl) { 738 *envhdl = next->entry[i].handle_name; 739 RELEASE_CACHE 740 return; 741 } 742 } 743 } 744 745 /* 746 * Sought handle not currently cached. 747 */ 748 RELEASE_CACHE 749 750 (void) snprintf(envhdl->name, sizeof (envhdl->name), 751 "Unknown SC node 0x%x", hdl); 752 } 753 754 static void 755 rmclomv_dr_data_handler(const char *fru_name, int hint) 756 { 757 int err = 0; 758 nvlist_t *attr_list; 759 char attach_pnt[MAXPATHLEN]; 760 761 (void) snprintf(attach_pnt, sizeof (attach_pnt), "%s", fru_name); 762 763 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 764 if (err != 0) { 765 cmn_err(CE_WARN, 766 "Failed to allocate name-value list for %s event", EC_DR); 767 return; 768 } 769 770 err = nvlist_add_string(attr_list, DR_AP_ID, attach_pnt); 771 if (err != 0) { 772 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 773 DR_AP_ID, EC_DR); 774 nvlist_free(attr_list); 775 return; 776 } 777 778 /* 779 * Add the hint 780 */ 781 err = nvlist_add_string(attr_list, DR_HINT, SE_HINT2STR(hint)); 782 if (err != 0) { 783 cmn_err(CE_WARN, "Failed to add attr [%s] for %s event", 784 DR_HINT, EC_DR); 785 nvlist_free(attr_list); 786 return; 787 } 788 789 err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_DR, 790 ESC_DR_AP_STATE_CHANGE, attr_list, NULL, DDI_NOSLEEP); 791 if (err != 0) { 792 cmn_err(CE_WARN, "Failed to log %s/%s event", 793 DR_AP_ID, EC_DR); 794 } 795 796 nvlist_free(attr_list); 797 } 798 799 static void 800 fan_sysevent(char *fru_name, char *sensor_name, int sub_event) 801 { 802 nvlist_t *attr_list; 803 char fan_str[MAXNAMELEN]; 804 int err; 805 806 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 807 if (err != 0) { 808 cmn_err(CE_WARN, 809 "Failed to allocate name-value list for %s/%s event", 810 EC_ENV, ESC_ENV_FAN); 811 return; 812 } 813 814 err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name); 815 if (err != 0) { 816 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 817 ENV_FRU_ID, EC_ENV, ESC_ENV_FAN); 818 nvlist_free(attr_list); 819 return; 820 } 821 822 err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name); 823 if (err != 0) { 824 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 825 ENV_FRU_RESOURCE_ID, EC_ENV, ESC_ENV_FAN); 826 nvlist_free(attr_list); 827 return; 828 } 829 830 err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR); 831 if (err != 0) { 832 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 833 ENV_FRU_DEVICE, EC_ENV, ESC_ENV_FAN); 834 nvlist_free(attr_list); 835 return; 836 } 837 838 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, 839 (sub_event == RMC_ENV_FAULT_EVENT) ? ENV_FAILED : ENV_OK); 840 if (err != 0) { 841 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 842 ENV_FRU_STATE, EC_ENV, ESC_ENV_FAN); 843 nvlist_free(attr_list); 844 return; 845 } 846 847 if (sub_event == RMC_ENV_FAULT_EVENT) { 848 (void) snprintf(fan_str, sizeof (fan_str), 849 "fan %s/%s is now failed", fru_name, sensor_name); 850 } else { 851 (void) snprintf(fan_str, sizeof (fan_str), 852 "fan %s/%s is now ok", fru_name, sensor_name); 853 } 854 err = nvlist_add_string(attr_list, ENV_MSG, fan_str); 855 if (err != 0) { 856 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 857 ENV_MSG, EC_ENV, ESC_ENV_FAN); 858 nvlist_free(attr_list); 859 return; 860 } 861 862 err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV, 863 ESC_ENV_FAN, attr_list, NULL, DDI_NOSLEEP); 864 if (err != 0) { 865 cmn_err(CE_WARN, "Failed to log %s/%s event", 866 EC_ENV, ESC_ENV_FAN); 867 } 868 869 cmn_err(CE_NOTE, "%s", fan_str); 870 nvlist_free(attr_list); 871 } 872 873 static void 874 threshold_sysevent(char *fru_name, char *sensor_name, int sub_event, 875 char event_type) 876 { 877 nvlist_t *attr_list; 878 int err; 879 char *subclass; 880 char sensor_str[MAXNAMELEN]; 881 882 subclass = (event_type == 'T') ? ESC_ENV_TEMP : ESC_ENV_POWER; 883 884 err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, KM_NOSLEEP); 885 if (err != 0) { 886 cmn_err(CE_WARN, 887 "Failed to allocate name-value list for %s/%s event", 888 EC_ENV, subclass); 889 return; 890 } 891 892 err = nvlist_add_string(attr_list, ENV_FRU_ID, fru_name); 893 if (err != 0) { 894 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 895 ENV_FRU_ID, EC_ENV, subclass); 896 nvlist_free(attr_list); 897 return; 898 } 899 900 err = nvlist_add_string(attr_list, ENV_FRU_RESOURCE_ID, sensor_name); 901 if (err != 0) { 902 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 903 ENV_FRU_RESOURCE_ID, EC_ENV, subclass); 904 nvlist_free(attr_list); 905 return; 906 } 907 908 err = nvlist_add_string(attr_list, ENV_FRU_DEVICE, ENV_RESERVED_ATTR); 909 if (err != 0) { 910 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 911 ENV_FRU_DEVICE, EC_ENV, subclass); 912 nvlist_free(attr_list); 913 return; 914 } 915 916 switch (sub_event) { 917 case RMC_ENV_OK_EVENT: 918 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_OK); 919 break; 920 case RMC_ENV_WARNING_THRESHOLD_EVENT: 921 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_WARNING); 922 break; 923 case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 924 err = nvlist_add_int32(attr_list, ENV_FRU_STATE, ENV_FAILED); 925 break; 926 } 927 if (err != 0) { 928 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 929 ENV_FRU_STATE, EC_ENV, subclass); 930 nvlist_free(attr_list); 931 return; 932 } 933 934 switch (sub_event) { 935 case RMC_ENV_OK_EVENT: 936 (void) snprintf(sensor_str, sizeof (sensor_str), 937 "sensor %s/%s is now ok", fru_name, 938 sensor_name); 939 break; 940 case RMC_ENV_WARNING_THRESHOLD_EVENT: 941 (void) snprintf(sensor_str, sizeof (sensor_str), 942 "sensor %s/%s is now outside warning thresholds", fru_name, 943 sensor_name); 944 break; 945 case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 946 (void) snprintf(sensor_str, sizeof (sensor_str), 947 "sensor %s/%s is now outside shutdown thresholds", fru_name, 948 sensor_name); 949 break; 950 } 951 err = nvlist_add_string(attr_list, ENV_MSG, sensor_str); 952 if (err != 0) { 953 cmn_err(CE_WARN, "Failed to add attr [%s] for %s/%s event", 954 ENV_MSG, EC_ENV, subclass); 955 nvlist_free(attr_list); 956 return; 957 } 958 959 err = ddi_log_sysevent(rmclomv_dip, DDI_VENDOR_SUNW, EC_ENV, 960 subclass, attr_list, NULL, DDI_NOSLEEP); 961 if (err != 0) { 962 cmn_err(CE_WARN, "Failed to log %s/%s event", 963 EC_ENV, subclass); 964 } 965 966 cmn_err(CE_NOTE, "%s", sensor_str); 967 nvlist_free(attr_list); 968 } 969 970 static uint_t 971 rmclomv_event_data_handler(char *arg) 972 { 973 dp_event_notification_t *payload; 974 rmc_comm_msg_t *msg; 975 envmon_handle_t envhdl; 976 int hint; 977 char *ptr, *save_ptr; 978 979 if (arg == NULL) { 980 return (DDI_INTR_CLAIMED); 981 } 982 983 msg = (rmc_comm_msg_t *)arg; 984 if (msg->msg_buf == NULL) { 985 return (DDI_INTR_CLAIMED); 986 } 987 988 payload = (dp_event_notification_t *)msg->msg_buf; 989 switch (payload->event) { 990 991 case RMC_KEYSWITCH_EVENT: 992 real_key_position = payload->event_info.ev_keysw.key_position; 993 cmn_err(CE_NOTE, "keyswitch change event - state = %s", 994 rmclomv_key_position(real_key_position)); 995 if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) && 996 (real_key_position <= RMC_KEYSWITCH_POS_OFF)) { 997 key_position = real_key_position; 998 } else { 999 /* treat unknown key position as locked */ 1000 key_position = RMC_KEYSWITCH_POS_LOCKED; 1001 } 1002 break; 1003 1004 case RMC_HPU_EVENT: 1005 /* 1006 * send appropriate sysevent 1007 */ 1008 switch (payload->event_info.ev_hpunot.sub_event) { 1009 case RMC_HPU_REMOVE_EVENT: 1010 hint = SE_HINT_REMOVE; 1011 break; 1012 case RMC_HPU_INSERT_EVENT: 1013 hint = SE_HINT_INSERT; 1014 break; 1015 default: 1016 hint = SE_NO_HINT; 1017 break; 1018 } 1019 rmclomv_hdl_to_envhdl(payload->event_info.ev_hpunot.hpu_hdl, 1020 &envhdl); 1021 rmclomv_dr_data_handler(envhdl.name, hint); 1022 break; 1023 1024 case RMC_INIT_EVENT: 1025 /* 1026 * Wake up the refresh thread. 1027 */ 1028 rmclomv_refresh_wakeup(); 1029 1030 /* 1031 * Wake up the checkrmc thread for an early indication to PICL 1032 */ 1033 rmclomv_checkrmc_wakeup(NULL); 1034 break; 1035 1036 case RMC_ENV_EVENT: 1037 rmclomv_hdl_to_envhdl(payload->event_info.ev_envnot.env_hdl, 1038 &envhdl); 1039 1040 /* split name into fru name and sensor name */ 1041 ptr = strchr(envhdl.name, '.'); 1042 1043 /* must have at least one '.' */ 1044 if (ptr == NULL) 1045 break; 1046 1047 /* find last '.' - convert the others to '/' */ 1048 for (;;) { 1049 save_ptr = ptr; 1050 ptr = strchr(ptr, '.'); 1051 if (ptr == NULL) { 1052 ptr = save_ptr; 1053 break; 1054 } 1055 *save_ptr = '/'; 1056 } 1057 *ptr = '\0'; 1058 ptr++; 1059 /* is it a voltage or temperature sensor? */ 1060 if ((*ptr == 'V' || *ptr == 'T') && *(ptr + 1) == '_') { 1061 switch (payload->event_info.ev_envnot.sub_event) { 1062 case RMC_ENV_WARNING_THRESHOLD_EVENT: 1063 case RMC_ENV_SHUTDOWN_THRESHOLD_EVENT: 1064 case RMC_ENV_OK_EVENT: 1065 threshold_sysevent(envhdl.name, ptr, 1066 payload->event_info.ev_envnot.sub_event, 1067 *ptr); 1068 break; 1069 default: 1070 break; 1071 } 1072 } 1073 1074 /* 1075 * is it a fan sensor? 1076 * Fan sensor names end either in RS, F0 or F1 1077 */ 1078 if ((*ptr == 'R' && *(ptr + 1) == 'S' && *(ptr + 2) == '\0') || 1079 (*ptr == 'F' && *(ptr + 1) == '0' && *(ptr + 2) == '\0') || 1080 (*ptr == 'F' && *(ptr + 1) == '1' && *(ptr + 2) == '\0')) { 1081 switch (payload->event_info.ev_envnot.sub_event) { 1082 case RMC_ENV_FAULT_EVENT: 1083 case RMC_ENV_OK_EVENT: 1084 fan_sysevent(envhdl.name, ptr, 1085 payload->event_info.ev_envnot.sub_event); 1086 break; 1087 default: 1088 break; 1089 } 1090 } 1091 break; 1092 1093 case RMC_LOG_EVENT: 1094 { 1095 int level = 10; 1096 int flags = SL_NOTE | SL_CONSOLE; 1097 char *message = 1098 (char *)payload->event_info.ev_rmclog.log_record; 1099 1100 message[ payload->event_info.ev_rmclog.log_record_size] = '\0'; 1101 1102 /* 1103 * Logs have a 10 character prefix - specifying the severity of 1104 * the event being logged. Thus all the magic number 10s down 1105 * here 1106 */ 1107 if (0 == strncmp("CRITICAL: ", message, 10)) { 1108 message += 10; 1109 level = 0; 1110 flags = SL_FATAL | SL_ERROR | SL_CONSOLE; 1111 } else if (0 == strncmp("MAJOR: ", message, 10)) { 1112 message += 10; 1113 level = 5; 1114 flags = SL_WARN | SL_ERROR | SL_CONSOLE; 1115 } else if (0 == strncmp("MINOR: ", message, 10)) { 1116 message += 10; 1117 level = 10; 1118 flags = SL_NOTE | SL_CONSOLE; 1119 } 1120 1121 (void) strlog(0, 0, level, flags, message); 1122 break; 1123 } 1124 1125 default: 1126 return (DDI_INTR_CLAIMED); 1127 } 1128 1129 return (DDI_INTR_CLAIMED); 1130 } 1131 1132 /*ARGSUSED*/ 1133 static int 1134 rmclomv_open(dev_t *dev_p, int flag, int otyp, cred_t *cred_p) 1135 { 1136 int error = 0; 1137 int instance = getminor(*dev_p); 1138 1139 if (instance != 0) 1140 return (ENXIO); 1141 1142 if ((flag & FWRITE) != 0 && (error = drv_priv(cred_p)) != 0) 1143 return (error); 1144 1145 return (0); 1146 } 1147 1148 /*ARGSUSED*/ 1149 static int 1150 rmclomv_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 1151 { 1152 return (DDI_SUCCESS); 1153 } 1154 1155 static int 1156 rmclomv_do_cmd(int req_cmd, int resp_cmd, int resp_len, intptr_t arg_req, 1157 intptr_t arg_res) 1158 { 1159 rmc_comm_msg_t request, *reqp = &request; 1160 rmc_comm_msg_t response, *resp = &response; 1161 int rv = 0; 1162 1163 bzero((caddr_t)&request, sizeof (request)); 1164 reqp->msg_type = req_cmd; 1165 reqp->msg_buf = (caddr_t)arg_req; 1166 bzero((caddr_t)&response, sizeof (response)); 1167 resp->msg_type = resp_cmd; 1168 resp->msg_buf = (caddr_t)arg_res; 1169 resp->msg_len = resp_len; 1170 1171 switch (req_cmd) { 1172 case DP_GET_SYSINFO: 1173 resp->msg_len = sizeof (dp_get_sysinfo_r_t); 1174 break; 1175 case DP_GET_EVENT_LOG: 1176 resp->msg_len = sizeof (dp_get_event_log_r_t); 1177 break; 1178 case DP_GET_VOLTS: 1179 reqp->msg_len = sizeof (dp_get_volts_t); 1180 break; 1181 case DP_GET_TEMPERATURES: 1182 reqp->msg_len = sizeof (dp_get_temperatures_t); 1183 break; 1184 case DP_GET_CIRCUIT_BRKS: 1185 reqp->msg_len = sizeof (dp_get_circuit_brks_t); 1186 break; 1187 case DP_GET_FAN_STATUS: 1188 reqp->msg_len = sizeof (dp_get_fan_status_t); 1189 break; 1190 case DP_GET_PSU_STATUS: 1191 reqp->msg_len = sizeof (dp_get_psu_status_t); 1192 break; 1193 case DP_GET_LED_STATE: 1194 reqp->msg_len = sizeof (dp_get_led_state_t); 1195 break; 1196 case DP_SET_LED_STATE: 1197 reqp->msg_len = sizeof (dp_set_led_state_t); 1198 break; 1199 case DP_GET_FRU_STATUS: 1200 reqp->msg_len = sizeof (dp_get_fru_status_t); 1201 break; 1202 case DP_GET_HANDLE_NAME: 1203 reqp->msg_len = sizeof (dp_get_handle_name_t); 1204 break; 1205 case DP_GET_ALARM_STATE: 1206 reqp->msg_len = sizeof (dp_get_alarm_state_t); 1207 break; 1208 case DP_SET_ALARM_STATE: 1209 reqp->msg_len = sizeof (dp_set_alarm_state_t); 1210 break; 1211 case DP_GET_SDP_VERSION: 1212 resp->msg_len = sizeof (dp_get_sdp_version_r_t); 1213 break; 1214 case DP_GET_CHASSIS_SERIALNUM: 1215 reqp->msg_len = 0; 1216 break; 1217 case DP_GET_DATE_TIME: 1218 reqp->msg_len = 0; 1219 break; 1220 default: 1221 return (EINVAL); 1222 } 1223 1224 rv = rmc_comm_request_response(reqp, resp, 1225 RMCLOMV_DEFAULT_MAX_MBOX_WAIT_TIME); 1226 1227 if (rv != RCNOERR) { 1228 /* 1229 * RMC returned an error or failed to respond. 1230 * Where the RMC itself is implicated, rmclomv_rmc_error 1231 * is set non-zero. It is cleared after an error free exchange. 1232 * Two failure cases are distinguished: 1233 * RMCLOMV_RMCSTATE_FAILED and RMCLOMV_RMCSTATE_DOWNLOAD. 1234 */ 1235 switch (rv) { 1236 case RCENOSOFTSTATE: 1237 /* invalid/NULL soft state structure */ 1238 return (EIO); 1239 case RCENODATALINK: 1240 /* 1241 * firmware download in progress, 1242 * can you come back later? 1243 */ 1244 rmclomv_rmc_error = RMCLOMV_RMCSTATE_DOWNLOAD; 1245 rmclomv_rmc_state = RMCLOMV_RMCSTATE_DOWNLOAD; 1246 return (EAGAIN); 1247 case RCENOMEM: 1248 /* memory problems */ 1249 return (ENOMEM); 1250 case RCECANTRESEND: 1251 /* resend failed */ 1252 rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 1253 return (EIO); 1254 case RCEMAXRETRIES: 1255 /* reply not received - retries exceeded */ 1256 rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 1257 return (EINTR); 1258 case RCETIMEOUT: 1259 /* reply not received - command has timed out */ 1260 rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 1261 return (EINTR); 1262 case RCEINVCMD: 1263 /* data protocol cmd not supported */ 1264 return (ENOTSUP); 1265 case RCEINVARG: 1266 /* invalid argument(s) */ 1267 return (ENOTSUP); 1268 case RCEGENERIC: 1269 /* generic error */ 1270 rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 1271 return (EIO); 1272 default: 1273 rmclomv_rmc_error = RMCLOMV_RMCSTATE_FAILED; 1274 return (EIO); 1275 } 1276 } 1277 1278 rmclomv_rmc_error = RMCLOMV_RMCERROR_NONE; 1279 return (0); 1280 } 1281 1282 /* 1283 * validate_section_entry checks that the entry at the specified index 1284 * is valid and not duplicated by an entry above. If these tests fail 1285 * the entry is removed and B_FALSE returned. Otherwise returns B_TRUE. 1286 */ 1287 static int 1288 validate_section_entry(rmclomv_cache_section_t *section, int index) 1289 { 1290 int i; 1291 rmclomv_cache_entry_t *entry; 1292 1293 for (i = index; i < section->num_entries; i++) { 1294 entry = §ion->entry[i]; 1295 if (entry->handle_name.name[0] == '\0') { 1296 cmn_err(CE_WARN, 1297 "rmclomv: empty handle_name, handle 0x%x type %x", 1298 entry->handle, section->sensor_type); 1299 } else if (entry->ind_mask != 0) { 1300 continue; /* skip special entries */ 1301 } else if (entry->handle == DP_NULL_HANDLE) { 1302 cmn_err(CE_WARN, 1303 "rmclomv: null handle id for \"%s\" type %x", 1304 entry->handle_name.name, section->sensor_type); 1305 } else if (i == index) { 1306 continue; 1307 } else if (section->entry[index].handle == entry->handle) { 1308 cmn_err(CE_WARN, 1309 "rmclomv: duplicate handle 0x%x type %x", 1310 entry->handle, section->sensor_type); 1311 } else if (strcmp(entry->handle_name.name, 1312 section->entry[index].handle_name.name) == 0) { 1313 cmn_err(CE_WARN, 1314 "rmclomv: duplicate handle_name \"%s\", " 1315 "handle 0x%x type %x", entry->handle_name.name, 1316 entry->handle, section->sensor_type); 1317 } else 1318 continue; 1319 1320 /* 1321 * need to remove the entry at index 1322 */ 1323 section->num_entries--; 1324 1325 for (i = index; i < section->num_entries; i++) { 1326 section->entry[i] = section->entry[i + 1]; 1327 } 1328 1329 return (B_FALSE); 1330 } 1331 1332 return (B_TRUE); 1333 } 1334 1335 /* 1336 * Populate a section containing handles with corresponding names 1337 * The supplied section structure must not be publically visible and the 1338 * name cache must not be locked either (because RMC i/o is required). 1339 * 1340 * This is the place where a sanity check is applied. Entries containing 1341 * duplicate handles, duplicate names or empty names are removed and the 1342 * structure is compacted. As a result num_entries may be reduced. 1343 */ 1344 static int 1345 add_names_to_section(rmclomv_cache_section_t *section) 1346 { 1347 int retval = 0; 1348 int ditched = B_FALSE; 1349 int index; 1350 dp_get_handle_name_r_t handle_name_r; 1351 rmclomv_cache_entry_t *entry; 1352 1353 for (index = 0; index < section->num_entries; index++) { 1354 entry = §ion->entry[index]; 1355 if (entry->ind_mask != 0) 1356 continue; /* skip special entries */ 1357 handle_name_r.handle = entry->handle; 1358 retval = rmclomv_do_cmd(DP_GET_HANDLE_NAME, 1359 DP_GET_HANDLE_NAME_R, sizeof (handle_name_r), 1360 (intptr_t)&handle_name_r, (intptr_t)&handle_name_r); 1361 if (retval == 0) 1362 bcopy(handle_name_r.name, 1363 entry->handle_name.name, DP_MAX_HANDLE_NAME); 1364 } 1365 1366 /* 1367 * now ditch invalid and duplicate entries 1368 */ 1369 for (index = 0; index < section->num_entries; index++) { 1370 while (validate_section_entry(section, index) == B_FALSE) 1371 ditched = B_TRUE; 1372 } 1373 1374 if (ditched) 1375 cmn_err(CE_WARN, "Retaining %d nodes of type %d", 1376 section->num_entries, section->sensor_type); 1377 1378 return (retval); 1379 } 1380 1381 /* 1382 * The supplied (PSU) cache section is traversed and entries are created 1383 * for the individual indicators belonging to a PSU. These entries are 1384 * placed in a private chain. The caller, subsequently acquires the 1385 * cache lock and copies the chain head to make it public. 1386 * The handle-names for PSU indicators are derived from the parent PSU 1387 * handle-name. 1388 * NOTE: add_names_to_section() may have reduced psu_section->num_entries 1389 * so DON'T USE psu_resp->num_psus 1390 */ 1391 static void 1392 make_psu_subsections(rmclomv_cache_section_t *psu_section, 1393 rmclomv_cache_section_t **chain_head, dp_get_psu_status_r_t *psu_resp) 1394 { 1395 int index; 1396 int subindex = 0; 1397 rmclomv_cache_section_t *subsection; 1398 rmclomv_cache_entry_t *src_entry; 1399 rmclomv_cache_entry_t *dst_entry; 1400 1401 subsection = create_cache_section(RMCLOMV_VOLT_IND, 1402 RMCLOMV_MAX_VI_PER_PSU * psu_section->num_entries); 1403 for (index = 0; index < psu_section->num_entries; index++) { 1404 src_entry = &psu_section->entry[index]; 1405 if ((psu_resp->psu_status[index].mask & 1406 DP_PSU_INPUT_STATUS) != 0) { 1407 dst_entry = &subsection->entry[subindex++]; 1408 dst_entry->handle = src_entry->handle; 1409 dst_entry->ind_mask = DP_PSU_INPUT_STATUS; 1410 (void) snprintf(dst_entry->handle_name.name, 1411 ENVMON_MAXNAMELEN, "%s.%s", 1412 src_entry->handle_name.name, 1413 str_ip_volts_ind); 1414 } 1415 1416 if ((psu_resp->psu_status[index].mask & 1417 DP_PSU_SEC_INPUT_STATUS) != 0) { 1418 dst_entry = &subsection->entry[subindex++]; 1419 dst_entry->handle = src_entry->handle; 1420 dst_entry->ind_mask = DP_PSU_SEC_INPUT_STATUS; 1421 (void) snprintf(dst_entry->handle_name.name, 1422 ENVMON_MAXNAMELEN, "%s.%s", 1423 src_entry->handle_name.name, 1424 str_ip2_volts_ind); 1425 } 1426 1427 if ((psu_resp->psu_status[index].mask & 1428 DP_PSU_OUTPUT_STATUS) != 0) { 1429 dst_entry = &subsection->entry[subindex++]; 1430 dst_entry->handle = src_entry->handle; 1431 dst_entry->ind_mask = DP_PSU_OUTPUT_STATUS; 1432 (void) snprintf(dst_entry->handle_name.name, 1433 ENVMON_MAXNAMELEN, "%s.%s", 1434 src_entry->handle_name.name, 1435 str_ff_pok_ind); 1436 } 1437 1438 if ((psu_resp->psu_status[index].mask & 1439 DP_PSU_OUTPUT_VLO_STATUS) != 0) { 1440 dst_entry = &subsection->entry[subindex++]; 1441 dst_entry->handle = src_entry->handle; 1442 dst_entry->ind_mask = DP_PSU_OUTPUT_VLO_STATUS; 1443 (void) snprintf(dst_entry->handle_name.name, 1444 ENVMON_MAXNAMELEN, "%s.%s", 1445 src_entry->handle_name.name, 1446 str_vlo_volts_ind); 1447 } 1448 1449 if ((psu_resp->psu_status[index].mask & 1450 DP_PSU_OUTPUT_VHI_STATUS) != 0) { 1451 dst_entry = &subsection->entry[subindex++]; 1452 dst_entry->handle = src_entry->handle; 1453 dst_entry->ind_mask = DP_PSU_OUTPUT_VHI_STATUS; 1454 (void) snprintf(dst_entry->handle_name.name, 1455 ENVMON_MAXNAMELEN, "%s.%s", 1456 src_entry->handle_name.name, 1457 str_vhi_volts_ind); 1458 } 1459 } 1460 /* 1461 * Adjust number of entries value in cache section 1462 * to match the facts. 1463 */ 1464 subsection->num_entries = subindex; 1465 add_section(chain_head, subsection); 1466 1467 subsection = create_cache_section(RMCLOMV_AMP_IND, 1468 RMCLOMV_MAX_CI_PER_PSU * psu_section->num_entries); 1469 subindex = 0; 1470 for (index = 0; index < psu_section->num_entries; index++) { 1471 int mask = psu_resp->psu_status[index].mask; 1472 src_entry = &psu_section->entry[index]; 1473 if ((mask & DP_PSU_OUTPUT_AHI_STATUS) != 0) { 1474 dst_entry = &subsection->entry[subindex++]; 1475 dst_entry->handle = src_entry->handle; 1476 dst_entry->ind_mask = DP_PSU_OUTPUT_AHI_STATUS; 1477 (void) snprintf(dst_entry->handle_name.name, 1478 ENVMON_MAXNAMELEN, "%s.%s", 1479 src_entry->handle_name.name, 1480 str_chi_amps_ind); 1481 } 1482 if ((mask & DP_PSU_NR_WARNING) != 0) { 1483 dst_entry = &subsection->entry[subindex++]; 1484 dst_entry->handle = src_entry->handle; 1485 dst_entry->ind_mask = DP_PSU_NR_WARNING; 1486 (void) snprintf(dst_entry->handle_name.name, 1487 ENVMON_MAXNAMELEN, "%s.%s", 1488 src_entry->handle_name.name, 1489 str_chi_nr_ind); 1490 } 1491 } 1492 subsection->num_entries = subindex; 1493 add_section(chain_head, subsection); 1494 1495 subsection = create_cache_section(RMCLOMV_TEMP_IND, 1496 psu_section->num_entries); 1497 subindex = 0; 1498 for (index = 0; index < psu_section->num_entries; index++) { 1499 if ((psu_resp->psu_status[index].mask & 1500 DP_PSU_OVERTEMP_FAULT) != 0) { 1501 src_entry = &psu_section->entry[index]; 1502 dst_entry = &subsection->entry[subindex++]; 1503 dst_entry->handle = src_entry->handle; 1504 dst_entry->ind_mask = DP_PSU_OVERTEMP_FAULT; 1505 (void) snprintf(dst_entry->handle_name.name, 1506 ENVMON_MAXNAMELEN, "%s.%s", 1507 src_entry->handle_name.name, 1508 str_ot_tmpr_ind); 1509 } 1510 } 1511 subsection->num_entries = subindex; 1512 add_section(chain_head, subsection); 1513 1514 subsection = create_cache_section(RMCLOMV_FAN_IND, 1515 RMCLOMV_MAX_FI_PER_PSU * psu_section->num_entries); 1516 subindex = 0; 1517 for (index = 0; index < psu_section->num_entries; index++) { 1518 int mask = psu_resp->psu_status[index].mask; 1519 src_entry = &psu_section->entry[index]; 1520 if ((mask & DP_PSU_FAN_FAULT) != 0) { 1521 dst_entry = &subsection->entry[subindex++]; 1522 dst_entry->handle = src_entry->handle; 1523 dst_entry->ind_mask = DP_PSU_FAN_FAULT; 1524 (void) snprintf(dst_entry->handle_name.name, 1525 ENVMON_MAXNAMELEN, "%s.%s", 1526 src_entry->handle_name.name, str_fan_ind); 1527 } 1528 if ((mask & DP_PSU_PDCT_FAN) != 0) { 1529 dst_entry = &subsection->entry[subindex++]; 1530 dst_entry->handle = src_entry->handle; 1531 dst_entry->ind_mask = DP_PSU_PDCT_FAN; 1532 (void) snprintf(dst_entry->handle_name.name, 1533 ENVMON_MAXNAMELEN, "%s.%s", 1534 src_entry->handle_name.name, str_pdct_fan_ind); 1535 } 1536 } 1537 subsection->num_entries = subindex; 1538 add_section(chain_head, subsection); 1539 } 1540 1541 static void 1542 refresh_name_cache(int force_fail) 1543 { 1544 union { 1545 dp_get_volts_t u_volts_cmd; 1546 dp_get_temperatures_t u_temp_cmd; 1547 dp_get_circuit_brks_t u_ampi_cmd; 1548 dp_get_fan_status_t u_fan_cmd; 1549 dp_get_psu_status_t u_psu_cmd; 1550 dp_get_fru_status_t u_fru_cmd; 1551 dp_get_led_state_t u_led_cmd; 1552 dp_set_led_state_t u_setled_cmd; 1553 dp_get_alarm_state_t u_alarm_cmd; 1554 dp_set_alarm_state_t u_setalarm_cmd; 1555 } rmc_cmdbuf; 1556 1557 /* defines for accessing union fields */ 1558 #define volts_cmd rmc_cmdbuf.u_volts_cmd 1559 #define temp_cmd rmc_cmdbuf.u_temp_cmd 1560 #define ampi_cmd rmc_cmdbuf.u_ampi_cmd 1561 #define fan_cmd rmc_cmdbuf.u_fan_cmd 1562 #define psu_cmd rmc_cmdbuf.u_psu_cmd 1563 #define fru_cmd rmc_cmdbuf.u_fru_cmd 1564 #define led_cmd rmc_cmdbuf.u_led_cmd 1565 #define setled_cmd rmc_cmdbuf.u_setled_cmd 1566 #define alarm_cmd rmc_cmdbuf.u_alarm_cmd 1567 #define setalarm_cmd rmc_cmdbuf.u_setalarm_cmd 1568 1569 /* 1570 * Data area to read sensor data into 1571 */ 1572 static union { 1573 char reservation[RMCRESBUFLEN]; 1574 dp_get_volts_r_t u_volts_r; 1575 dp_get_temperatures_r_t u_temp_r; 1576 dp_get_circuit_brks_r_t u_ampi_r; 1577 dp_get_fan_status_r_t u_fan_r; 1578 dp_get_psu_status_r_t u_psu_r; 1579 dp_get_fru_status_r_t u_fru_r; 1580 dp_get_led_state_r_t u_led_r; 1581 dp_set_led_state_r_t u_setled_r; 1582 dp_get_alarm_state_r_t u_alarm_r; 1583 dp_set_alarm_state_r_t u_setalarm_r; 1584 } rmc_sensbuf; 1585 1586 /* defines for accessing union fields */ 1587 #define volts_r rmc_sensbuf.u_volts_r 1588 #define temp_r rmc_sensbuf.u_temp_r 1589 #define ampi_r rmc_sensbuf.u_ampi_r 1590 #define fan_r rmc_sensbuf.u_fan_r 1591 #define psu_r rmc_sensbuf.u_psu_r 1592 #define fru_r rmc_sensbuf.u_fru_r 1593 #define led_r rmc_sensbuf.u_led_r 1594 #define setled_r rmc_sensbuf.u_setled_r 1595 #define alarm_r rmc_sensbuf.u_alarm_r 1596 #define setalarm_r rmc_sensbuf.u_setalarm_r 1597 1598 int retval = force_fail; 1599 int retval1 = retval; 1600 int index; 1601 rmclomv_cache_section_t *my_chain = NULL; 1602 rmclomv_cache_section_t *derived_chain = NULL; 1603 rmclomv_cache_section_t *section; 1604 rmclomv_cache_section_t *psu_section; 1605 rmclomv_cache_section_t *fru_section; 1606 dp_get_sysinfo_r_t sysinfo; 1607 rmclomv_cache_entry_t *entry; 1608 1609 if (retval == 0) { 1610 retval = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R, 1611 sizeof (sysinfo), NULL, (intptr_t)&sysinfo); 1612 } 1613 if (retval == 0) { 1614 fru_cmd.handle = DP_NULL_HANDLE; 1615 retval = rmclomv_do_cmd(DP_GET_FRU_STATUS, DP_GET_FRU_STATUS_R, 1616 RMCRESBUFLEN, (intptr_t)&fru_cmd, (intptr_t)&fru_r); 1617 } 1618 if (retval != 0) 1619 fru_r.num_frus = 0; 1620 1621 /* 1622 * Reserve space for special additional entries in the FRU section 1623 */ 1624 fru_section = create_cache_section(RMCLOMV_HPU_IND, 1625 RMCLOMV_NUM_SPECIAL_FRUS + fru_r.num_frus); 1626 1627 /* 1628 * add special entry for RMC itself 1629 */ 1630 entry = &fru_section->entry[0]; 1631 (void) snprintf(entry->handle_name.name, sizeof (envmon_handle_t), 1632 "SC"); 1633 entry->handle = 0; 1634 entry->ind_mask = 1; /* flag as a special entry */ 1635 1636 /* 1637 * populate any other FRU entries 1638 */ 1639 for (index = 0; index < fru_r.num_frus; index++) { 1640 fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].handle = 1641 fru_r.fru_status[index].handle; 1642 fru_section->entry[RMCLOMV_NUM_SPECIAL_FRUS + index].ind_mask = 1643 0; 1644 } 1645 1646 my_chain = fru_section; 1647 1648 if (retval == 0) { 1649 volts_cmd.handle = DP_NULL_HANDLE; 1650 retval = rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R, 1651 RMCRESBUFLEN, (intptr_t)&volts_cmd, (intptr_t)&volts_r); 1652 } 1653 if (retval == 0) { 1654 section = create_cache_section(RMCLOMV_VOLT_SENS, 1655 volts_r.num_volts); 1656 for (index = 0; index < volts_r.num_volts; index++) { 1657 section->entry[index].handle = 1658 volts_r.volt_status[index].handle; 1659 } 1660 add_section(&my_chain, section); 1661 } 1662 if (retval == 0) { 1663 temp_cmd.handle = DP_NULL_HANDLE; 1664 retval = rmclomv_do_cmd(DP_GET_TEMPERATURES, 1665 DP_GET_TEMPERATURES_R, RMCRESBUFLEN, 1666 (intptr_t)&temp_cmd, (intptr_t)&temp_r); 1667 } 1668 if (retval == 0) { 1669 section = create_cache_section(RMCLOMV_TEMP_SENS, 1670 temp_r.num_temps); 1671 for (index = 0; index < temp_r.num_temps; index++) { 1672 section->entry[index].handle = 1673 temp_r.temp_status[index].handle; 1674 } 1675 add_section(&my_chain, section); 1676 } 1677 if (retval == 0) { 1678 fan_cmd.handle = DP_NULL_HANDLE; 1679 retval = rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R, 1680 RMCRESBUFLEN, (intptr_t)&fan_cmd, (intptr_t)&fan_r); 1681 } 1682 if (retval == 0) { 1683 section = create_cache_section(RMCLOMV_FAN_SENS, 1684 fan_r.num_fans); 1685 for (index = 0; index < fan_r.num_fans; index++) { 1686 section->entry[index].handle = 1687 fan_r.fan_status[index].handle; 1688 } 1689 add_section(&my_chain, section); 1690 } 1691 if (retval == 0) { 1692 ampi_cmd.handle = DP_NULL_HANDLE; 1693 retval = rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, 1694 DP_GET_CIRCUIT_BRKS_R, RMCRESBUFLEN, 1695 (intptr_t)&i_cmd, (intptr_t)&i_r); 1696 } 1697 if (retval == 0) { 1698 section = create_cache_section(RMCLOMV_AMP_IND, 1699 ampi_r.num_circuit_brks); 1700 for (index = 0; index < ampi_r.num_circuit_brks; index++) { 1701 section->entry[index].handle = 1702 ampi_r.circuit_brk_status[index].handle; 1703 } 1704 add_section(&my_chain, section); 1705 } 1706 if (retval == 0) { 1707 led_cmd.handle = DP_NULL_HANDLE; 1708 retval = rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R, 1709 RMCRESBUFLEN, (intptr_t)&led_cmd, (intptr_t)&led_r); 1710 } 1711 if (retval == 0) { 1712 section = create_cache_section(RMCLOMV_LED_IND, 1713 led_r.num_leds); 1714 for (index = 0; index < led_r.num_leds; index++) { 1715 section->entry[index].handle = 1716 led_r.led_state[index].handle; 1717 } 1718 add_section(&my_chain, section); 1719 } 1720 /* 1721 * The command DP_GET_ALARM_STATE may not be valid on 1722 * some RMC versions, so we ignore the return value 1723 * and proceed 1724 */ 1725 if (retval == 0) { 1726 alarm_cmd.handle = DP_NULL_HANDLE; 1727 retval1 = rmclomv_do_cmd(DP_GET_ALARM_STATE, 1728 DP_GET_ALARM_STATE_R, RMCRESBUFLEN, 1729 (intptr_t)&alarm_cmd, (intptr_t)&alarm_r); 1730 if ((retval1 == 0) && alarm_r.num_alarms) { 1731 section = create_cache_section(RMCLOMV_ALARM_IND, 1732 alarm_r.num_alarms); 1733 for (index = 0; index < alarm_r.num_alarms; index++) { 1734 section->entry[index].handle = 1735 alarm_r.alarm_state[index].handle; 1736 } 1737 add_section(&my_chain, section); 1738 } 1739 } 1740 if (retval == 0) { 1741 psu_cmd.handle = DP_NULL_HANDLE; 1742 retval = rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R, 1743 RMCRESBUFLEN, (intptr_t)&psu_cmd, (intptr_t)&psu_r); 1744 } 1745 if (retval == 0) { 1746 /* 1747 * WARNING: 1748 * ======= 1749 * The PSUs must be probed last so that the response data 1750 * (psu_r) is available for make_psu_subsections() below. 1751 * Note that all the responses share the same data area 1752 * which is declared as a union. 1753 */ 1754 psu_section = create_cache_section(RMCLOMV_PSU_IND, 1755 psu_r.num_psus); 1756 for (index = 0; index < psu_r.num_psus; index++) { 1757 psu_section->entry[index].handle = 1758 psu_r.psu_status[index].handle; 1759 } 1760 add_section(&my_chain, psu_section); 1761 } 1762 if (retval == 0) { 1763 for (section = my_chain; 1764 section != NULL; 1765 section = section->next_section) { 1766 retval = add_names_to_section(section); 1767 if (retval != 0) { 1768 break; 1769 } 1770 } 1771 } 1772 1773 /* 1774 * now add nodes derived from PSUs 1775 */ 1776 if (retval == 0) { 1777 make_psu_subsections(psu_section, &derived_chain, &psu_r); 1778 /* 1779 * name cache sections all set, exchange new for old 1780 */ 1781 rmclomv_reset_cache(my_chain, derived_chain, &sysinfo); 1782 } else { 1783 /* 1784 * RMC is not responding, ditch any existing cache 1785 * and just leave the special SC FRU node 1786 */ 1787 rmclomv_reset_cache(my_chain, NULL, NULL); 1788 } 1789 } 1790 1791 static void 1792 set_val_unav(envmon_sensor_t *sensor) 1793 { 1794 sensor->value = ENVMON_VAL_UNAVAILABLE; 1795 sensor->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE; 1796 sensor->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 1797 sensor->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 1798 sensor->highthresholds.warning = ENVMON_VAL_UNAVAILABLE; 1799 sensor->highthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 1800 sensor->highthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 1801 } 1802 1803 static void 1804 set_fan_unav(envmon_fan_t *fan) 1805 { 1806 fan->speed = ENVMON_VAL_UNAVAILABLE; 1807 fan->units[0] = '\0'; 1808 fan->lowthresholds.warning = ENVMON_VAL_UNAVAILABLE; 1809 fan->lowthresholds.shutdown = ENVMON_VAL_UNAVAILABLE; 1810 fan->lowthresholds.poweroff = ENVMON_VAL_UNAVAILABLE; 1811 } 1812 1813 static int 1814 do_psu_cmd(intptr_t arg, int mode, envmon_indicator_t *env_ind, 1815 dp_get_psu_status_t *rmc_psu, dp_get_psu_status_r_t *rmc_psu_r, 1816 int detector_type) 1817 { 1818 int index; 1819 uint16_t sensor_status; 1820 rmclomv_cache_section_t *section; 1821 uint16_t indicator_mask; 1822 1823 if (ddi_copyin((caddr_t)arg, (caddr_t)env_ind, 1824 sizeof (envmon_indicator_t), mode) != 0) 1825 return (EFAULT); 1826 1827 /* ensure we've got PSU handles cached */ 1828 LOCK_CACHE 1829 1830 sensor_status = ENVMON_SENSOR_OK; 1831 section = rmclomv_find_section(rmclomv_subcache, detector_type); 1832 if (env_ind->id.name[0] == '\0') { 1833 /* request for first handle */ 1834 if ((section == NULL) || (section->num_entries == 0)) 1835 env_ind->next_id.name[0] = '\0'; 1836 else 1837 env_ind->next_id = section->entry[0].handle_name; 1838 sensor_status = ENVMON_NOT_PRESENT; 1839 } else { 1840 /* ensure name is properly terminated */ 1841 env_ind->id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 1842 if ((section == NULL) || (get_sensor_by_name(section, 1843 env_ind->id.name, &index)) != 0) { 1844 env_ind->next_id.name[0] = '\0'; 1845 sensor_status = ENVMON_NOT_PRESENT; 1846 } else if (index + 1 < section->num_entries) 1847 env_ind->next_id = 1848 section->entry[index + 1].handle_name; 1849 else 1850 env_ind->next_id.name[0] = '\0'; 1851 } 1852 if (sensor_status == ENVMON_SENSOR_OK) { 1853 /* 1854 * user correctly identified a sensor, note its 1855 * handle value and request the indicator status 1856 */ 1857 rmc_psu->handle = section->entry[index].handle; 1858 indicator_mask = section->entry[index].ind_mask; 1859 } 1860 1861 RELEASE_CACHE 1862 1863 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 1864 rmclomv_do_cmd(DP_GET_PSU_STATUS, DP_GET_PSU_STATUS_R, 1865 sizeof (dp_get_psu_status_r_t), (intptr_t)rmc_psu, 1866 (intptr_t)rmc_psu_r) != 0)) { 1867 sensor_status = ENVMON_INACCESSIBLE; 1868 } 1869 if ((env_ind->sensor_status = sensor_status) == ENVMON_SENSOR_OK) { 1870 /* 1871 * copy results into buffer for user 1872 */ 1873 if ((rmc_psu_r->psu_status[0].flag & DP_PSU_PRESENCE) == 0) 1874 env_ind->sensor_status |= ENVMON_NOT_PRESENT; 1875 if (rmc_psu_r->psu_status[0].sensor_status != 1876 DP_SENSOR_DATA_AVAILABLE) 1877 env_ind->sensor_status |= ENVMON_INACCESSIBLE; 1878 env_ind->condition = 1879 (rmc_psu_r->psu_status[0].flag & indicator_mask) == 0 ? 1880 0 : 1; 1881 } 1882 1883 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 1884 env_ind->sensor_status = ENVMON_INACCESSIBLE; 1885 1886 if (ddi_copyout((caddr_t)env_ind, (caddr_t)arg, 1887 sizeof (envmon_indicator_t), mode) != 0) 1888 return (EFAULT); 1889 1890 return (0); 1891 } 1892 1893 /*ARGSUSED*/ 1894 static int 1895 rmclomv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p, 1896 int *rval_p) 1897 { 1898 int instance = getminor(dev); 1899 envmon_sysinfo_t lomv_sysinfo; 1900 union { 1901 envmon_sensor_t u_env_sensor; 1902 envmon_indicator_t u_env_ind; 1903 envmon_fan_t u_env_fan; 1904 envmon_led_info_t u_env_ledinfo; 1905 envmon_led_ctl_t u_env_ledctl; 1906 envmon_hpu_t u_env_hpu; 1907 envmon_alarm_info_t u_env_alarminfo; 1908 envmon_alarm_ctl_t u_env_alarmctl; 1909 } env_buf; 1910 #define env_sensor env_buf.u_env_sensor 1911 #define env_ind env_buf.u_env_ind 1912 #define env_fan env_buf.u_env_fan 1913 #define env_ledinfo env_buf.u_env_ledinfo 1914 #define env_ledctl env_buf.u_env_ledctl 1915 #define env_hpu env_buf.u_env_hpu 1916 #define env_alarminfo env_buf.u_env_alarminfo 1917 #define env_alarmctl env_buf.u_env_alarmctl 1918 1919 union { 1920 dp_get_volts_t u_rmc_volts; 1921 dp_get_temperatures_t u_rmc_temp; 1922 dp_get_circuit_brks_t u_rmc_ampi; 1923 dp_get_fan_status_t u_rmc_fan; 1924 dp_get_psu_status_t u_rmc_psu; 1925 dp_get_fru_status_t u_rmc_fru; 1926 dp_get_led_state_t u_rmc_led; 1927 dp_set_led_state_t u_rmc_setled; 1928 dp_get_alarm_state_t u_rmc_alarm; 1929 dp_set_alarm_state_t u_rmc_setalarm; 1930 } rmc_reqbuf; 1931 #define rmc_volts rmc_reqbuf.u_rmc_volts 1932 #define rmc_temp rmc_reqbuf.u_rmc_temp 1933 #define rmc_ampi rmc_reqbuf.u_rmc_ampi 1934 #define rmc_fan rmc_reqbuf.u_rmc_fan 1935 #define rmc_psu rmc_reqbuf.u_rmc_psu 1936 #define rmc_fru rmc_reqbuf.u_rmc_fru 1937 #define rmc_led rmc_reqbuf.u_rmc_led 1938 #define rmc_setled rmc_reqbuf.u_rmc_setled 1939 #define rmc_alarm rmc_reqbuf.u_rmc_alarm 1940 #define rmc_setalarm rmc_reqbuf.u_rmc_setalarm 1941 1942 union { 1943 dp_get_volts_r_t u_rmc_volts_r; 1944 dp_get_temperatures_r_t u_rmc_temp_r; 1945 dp_get_circuit_brks_r_t u_rmc_ampi_r; 1946 dp_get_fan_status_r_t u_rmc_fan_r; 1947 dp_get_psu_status_r_t u_rmc_psu_r; 1948 dp_get_fru_status_r_t u_rmc_fru_r; 1949 dp_get_led_state_r_t u_rmc_led_r; 1950 dp_set_led_state_r_t u_rmc_setled_r; 1951 dp_get_alarm_state_r_t u_rmc_alarm_r; 1952 dp_set_alarm_state_r_t u_rmc_setalarm_r; 1953 dp_get_sdp_version_r_t u_rmc_sdpversion_r; 1954 dp_get_serialnum_r_t u_rmc_serialnum_r; 1955 } rmc_resbuf; 1956 #define rmc_volts_r rmc_resbuf.u_rmc_volts_r 1957 #define rmc_temp_r rmc_resbuf.u_rmc_temp_r 1958 #define rmc_ampi_r rmc_resbuf.u_rmc_ampi_r 1959 #define rmc_fan_r rmc_resbuf.u_rmc_fan_r 1960 #define rmc_psu_r rmc_resbuf.u_rmc_psu_r 1961 #define rmc_fru_r rmc_resbuf.u_rmc_fru_r 1962 #define rmc_led_r rmc_resbuf.u_rmc_led_r 1963 #define rmc_setled_r rmc_resbuf.u_rmc_setled_r 1964 #define rmc_alarm_r rmc_resbuf.u_rmc_alarm_r 1965 #define rmc_setalarm_r rmc_resbuf.u_rmc_setalarm_r 1966 #define rmc_sdpver_r rmc_resbuf.u_rmc_sdpversion_r 1967 #define rmc_serialnum_r rmc_resbuf.u_rmc_serialnum_r 1968 1969 int retval = 0; 1970 int special = 0; 1971 int index; 1972 uint16_t sensor_status; 1973 rmclomv_cache_section_t *section; 1974 envmon_chassis_t chassis; 1975 1976 if (instance != 0) 1977 return (ENXIO); 1978 1979 switch (cmd) { 1980 case ENVMONIOCSYSINFO: 1981 1982 LOCK_CACHE 1983 1984 /* 1985 * A number of OK/not_OK indicators are supported by PSUs 1986 * (voltage, current, fan, temperature). So the maximum 1987 * number of such indicators relates to the maximum number 1988 * of power-supplies. 1989 */ 1990 if (rmclomv_sysinfo_valid) { 1991 lomv_sysinfo.maxVoltSens = rmclomv_sysinfo_data.maxVolt; 1992 lomv_sysinfo.maxVoltInd = 1993 RMCLOMV_MAX_VI_PER_PSU * 1994 rmclomv_sysinfo_data.maxPSU; 1995 /* 1996 * the ALOM-Solaris interface does not include 1997 * amp sensors, so we can hard code this value 1998 */ 1999 lomv_sysinfo.maxAmpSens = 0; 2000 lomv_sysinfo.maxAmpInd = 2001 rmclomv_sysinfo_data.maxCircuitBrks + 2002 (RMCLOMV_MAX_CI_PER_PSU * 2003 rmclomv_sysinfo_data.maxPSU); 2004 lomv_sysinfo.maxTempSens = rmclomv_sysinfo_data.maxTemp; 2005 lomv_sysinfo.maxTempInd = 2006 (RMCLOMV_MAX_TI_PER_PSU * 2007 rmclomv_sysinfo_data.maxPSU); 2008 lomv_sysinfo.maxFanSens = rmclomv_sysinfo_data.maxFan; 2009 lomv_sysinfo.maxFanInd = 2010 RMCLOMV_MAX_FI_PER_PSU * 2011 rmclomv_sysinfo_data.maxPSU; 2012 lomv_sysinfo.maxLED = rmclomv_sysinfo_data.maxLED; 2013 lomv_sysinfo.maxHPU = RMCLOMV_NUM_SPECIAL_FRUS + 2014 rmclomv_sysinfo_data.maxFRU; 2015 } else { 2016 bzero(&lomv_sysinfo, sizeof (lomv_sysinfo)); 2017 lomv_sysinfo.maxHPU = 1; /* just the SC node */ 2018 } 2019 2020 RELEASE_CACHE 2021 2022 if (ddi_copyout((caddr_t)&lomv_sysinfo, (caddr_t)arg, 2023 sizeof (lomv_sysinfo), mode) != 0) 2024 return (EFAULT); 2025 break; 2026 2027 case ENVMONIOCVOLTSENSOR: 2028 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 2029 sizeof (envmon_sensor_t), mode) != 0) 2030 return (EFAULT); 2031 2032 /* see if we've got volts handles cached */ 2033 LOCK_CACHE 2034 sensor_status = ENVMON_SENSOR_OK; 2035 2036 if ((rmclomv_cache_valid == B_FALSE) || 2037 ((section = rmclomv_find_section(rmclomv_cache, 2038 RMCLOMV_VOLT_SENS)) == NULL)) { 2039 env_sensor.next_id.name[0] = '\0'; 2040 sensor_status = ENVMON_NOT_PRESENT; 2041 } else if (env_sensor.id.name[0] == '\0') { 2042 /* request for first handle */ 2043 if (section->num_entries == 0) 2044 env_sensor.next_id.name[0] = '\0'; 2045 else 2046 env_sensor.next_id = 2047 section->entry[0].handle_name; 2048 sensor_status = ENVMON_NOT_PRESENT; 2049 } else { 2050 /* ensure name is properly terminated */ 2051 env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2052 if (get_sensor_by_name(section, env_sensor.id.name, 2053 &index) != 0) { 2054 env_sensor.next_id.name[0] = '\0'; 2055 sensor_status = ENVMON_NOT_PRESENT; 2056 } else if (index + 1 < section->num_entries) 2057 env_sensor.next_id = 2058 section->entry[index + 1].handle_name; 2059 else 2060 env_sensor.next_id.name[0] = '\0'; 2061 } 2062 if (sensor_status == ENVMON_SENSOR_OK) { 2063 /* 2064 * user correctly identified a sensor, note its 2065 * handle value and request the sensor value 2066 */ 2067 rmc_volts.handle = section->entry[index].handle; 2068 } 2069 RELEASE_CACHE 2070 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 2071 rmclomv_do_cmd(DP_GET_VOLTS, DP_GET_VOLTS_R, 2072 sizeof (rmc_volts_r), (intptr_t)&rmc_volts, 2073 (intptr_t)&rmc_volts_r) != 0)) { 2074 sensor_status = ENVMON_INACCESSIBLE; 2075 } 2076 if ((sensor_status == ENVMON_SENSOR_OK) && 2077 (rmc_volts_r.volt_status[0].sensor_status == 2078 DP_SENSOR_NOT_PRESENT)) { 2079 sensor_status = ENVMON_NOT_PRESENT; 2080 } 2081 if ((env_sensor.sensor_status = sensor_status) == 2082 ENVMON_SENSOR_OK) { 2083 /* 2084 * copy results into buffer for user 2085 */ 2086 if (rmc_volts_r.volt_status[0].sensor_status != 2087 DP_SENSOR_DATA_AVAILABLE) 2088 env_sensor.sensor_status = ENVMON_INACCESSIBLE; 2089 env_sensor.value = 2090 rmc_volts_r.volt_status[0].reading; 2091 env_sensor.lowthresholds.warning = 2092 rmc_volts_r.volt_status[0].low_warning; 2093 env_sensor.lowthresholds.shutdown = 2094 rmc_volts_r.volt_status[0].low_soft_shutdown; 2095 env_sensor.lowthresholds.poweroff = 2096 rmc_volts_r.volt_status[0].low_hard_shutdown; 2097 env_sensor.highthresholds.warning = 2098 rmc_volts_r.volt_status[0].high_warning; 2099 env_sensor.highthresholds.shutdown = 2100 rmc_volts_r.volt_status[0].high_soft_shutdown; 2101 env_sensor.highthresholds.poweroff = 2102 rmc_volts_r.volt_status[0].high_hard_shutdown; 2103 } 2104 if (env_sensor.sensor_status != ENVMON_SENSOR_OK || 2105 rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 2106 set_val_unav(&env_sensor); 2107 2108 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 2109 sizeof (envmon_sensor_t), mode) != 0) 2110 return (EFAULT); 2111 break; 2112 2113 case ENVMONIOCVOLTIND: 2114 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 2115 RMCLOMV_VOLT_IND)); 2116 2117 case ENVMONIOCTEMPIND: 2118 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 2119 RMCLOMV_TEMP_IND)); 2120 2121 case ENVMONIOCFANIND: 2122 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, &rmc_psu_r, 2123 RMCLOMV_FAN_IND)); 2124 2125 case ENVMONIOCAMPSENSOR: 2126 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 2127 sizeof (envmon_sensor_t), mode) != 0) 2128 return (EFAULT); 2129 2130 env_sensor.sensor_status = ENVMON_NOT_PRESENT; 2131 env_sensor.next_id.name[0] = '\0'; 2132 2133 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 2134 sizeof (envmon_sensor_t), mode) != 0) 2135 return (EFAULT); 2136 break; 2137 2138 case ENVMONIOCTEMPSENSOR: 2139 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_sensor, 2140 sizeof (envmon_sensor_t), mode) != 0) 2141 return (EFAULT); 2142 2143 /* see if we've got temperature handles cached */ 2144 LOCK_CACHE 2145 sensor_status = ENVMON_SENSOR_OK; 2146 2147 if ((rmclomv_cache_valid == B_FALSE) || 2148 ((section = rmclomv_find_section(rmclomv_cache, 2149 RMCLOMV_TEMP_SENS)) == NULL)) { 2150 env_sensor.next_id.name[0] = '\0'; 2151 sensor_status = ENVMON_NOT_PRESENT; 2152 } else if (env_sensor.id.name[0] == '\0') { 2153 /* request for first handle */ 2154 if (section->num_entries == 0) 2155 env_sensor.next_id.name[0] = '\0'; 2156 else 2157 env_sensor.next_id = 2158 section->entry[0].handle_name; 2159 sensor_status = ENVMON_NOT_PRESENT; 2160 } else { 2161 /* ensure name is properly terminated */ 2162 env_sensor.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2163 if (get_sensor_by_name(section, env_sensor.id.name, 2164 &index) != 0) { 2165 env_sensor.next_id.name[0] = '\0'; 2166 sensor_status = ENVMON_NOT_PRESENT; 2167 } else if (index + 1 < section->num_entries) 2168 env_sensor.next_id = 2169 section->entry[index + 1].handle_name; 2170 else 2171 env_sensor.next_id.name[0] = '\0'; 2172 } 2173 if (sensor_status == ENVMON_SENSOR_OK) { 2174 /* 2175 * user correctly identified a sensor, note its 2176 * handle value and request the sensor value 2177 */ 2178 rmc_temp.handle = section->entry[index].handle; 2179 } 2180 RELEASE_CACHE 2181 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 2182 rmclomv_do_cmd(DP_GET_TEMPERATURES, DP_GET_TEMPERATURES_R, 2183 sizeof (rmc_temp_r), (intptr_t)&rmc_temp, 2184 (intptr_t)&rmc_temp_r) != 0)) { 2185 sensor_status = ENVMON_INACCESSIBLE; 2186 } 2187 if ((sensor_status == ENVMON_SENSOR_OK) && 2188 (rmc_temp_r.temp_status[0].sensor_status == 2189 DP_SENSOR_NOT_PRESENT)) { 2190 sensor_status = ENVMON_NOT_PRESENT; 2191 } 2192 if ((env_sensor.sensor_status = sensor_status) == 2193 ENVMON_SENSOR_OK) { 2194 /* 2195 * copy results into buffer for user 2196 */ 2197 if (rmc_temp_r.temp_status[0].sensor_status != 2198 DP_SENSOR_DATA_AVAILABLE) 2199 env_sensor.sensor_status = ENVMON_INACCESSIBLE; 2200 env_sensor.value = 2201 rmc_temp_r.temp_status[0].value; 2202 env_sensor.lowthresholds.warning = 2203 rmc_temp_r.temp_status[0].low_warning; 2204 env_sensor.lowthresholds.shutdown = 2205 rmc_temp_r.temp_status[0].low_soft_shutdown; 2206 env_sensor.lowthresholds.poweroff = 2207 rmc_temp_r.temp_status[0].low_hard_shutdown; 2208 env_sensor.highthresholds.warning = 2209 rmc_temp_r.temp_status[0].high_warning; 2210 env_sensor.highthresholds.shutdown = 2211 rmc_temp_r.temp_status[0].high_soft_shutdown; 2212 env_sensor.highthresholds.poweroff = 2213 rmc_temp_r.temp_status[0].high_hard_shutdown; 2214 } 2215 if (env_sensor.sensor_status != ENVMON_SENSOR_OK || 2216 rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 2217 set_val_unav(&env_sensor); 2218 2219 if (ddi_copyout((caddr_t)&env_sensor, (caddr_t)arg, 2220 sizeof (envmon_sensor_t), mode) != 0) 2221 return (EFAULT); 2222 break; 2223 2224 2225 case ENVMONIOCFAN: 2226 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_fan, 2227 sizeof (envmon_fan_t), mode) != 0) 2228 return (EFAULT); 2229 2230 /* see if we've got fan handles cached */ 2231 LOCK_CACHE 2232 sensor_status = ENVMON_SENSOR_OK; 2233 2234 if ((rmclomv_cache_valid == B_FALSE) || 2235 ((section = rmclomv_find_section(rmclomv_cache, 2236 RMCLOMV_FAN_SENS)) == NULL)) { 2237 env_fan.next_id.name[0] = '\0'; 2238 sensor_status = ENVMON_NOT_PRESENT; 2239 } else if (env_fan.id.name[0] == '\0') { 2240 /* request for first handle */ 2241 if (section->num_entries == 0) 2242 env_fan.next_id.name[0] = '\0'; 2243 else 2244 env_fan.next_id = 2245 section->entry[0].handle_name; 2246 sensor_status = ENVMON_NOT_PRESENT; 2247 } else { 2248 /* ensure name is properly terminated */ 2249 env_fan.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2250 if (get_sensor_by_name(section, env_fan.id.name, 2251 &index) != 0) { 2252 env_fan.next_id.name[0] = '\0'; 2253 sensor_status = ENVMON_NOT_PRESENT; 2254 } else if (index + 1 < section->num_entries) 2255 env_fan.next_id = 2256 section->entry[index + 1].handle_name; 2257 else 2258 env_fan.next_id.name[0] = '\0'; 2259 } 2260 if (sensor_status == ENVMON_SENSOR_OK) { 2261 /* 2262 * user correctly identified a sensor, note its 2263 * handle value and request the sensor value 2264 */ 2265 rmc_fan.handle = section->entry[index].handle; 2266 } 2267 RELEASE_CACHE 2268 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 2269 rmclomv_do_cmd(DP_GET_FAN_STATUS, DP_GET_FAN_STATUS_R, 2270 sizeof (rmc_fan_r), (intptr_t)&rmc_fan, 2271 (intptr_t)&rmc_fan_r) != 0)) { 2272 sensor_status = ENVMON_INACCESSIBLE; 2273 } 2274 if ((sensor_status == ENVMON_SENSOR_OK) && 2275 (rmc_fan_r.fan_status[0].sensor_status == 2276 DP_SENSOR_NOT_PRESENT)) { 2277 sensor_status = ENVMON_NOT_PRESENT; 2278 } 2279 if ((env_fan.sensor_status = sensor_status) == 2280 ENVMON_SENSOR_OK) { 2281 if ((rmc_fan_r.fan_status[0].flag & 2282 DP_FAN_PRESENCE) == 0) 2283 env_fan.sensor_status = ENVMON_NOT_PRESENT; 2284 if (rmc_fan_r.fan_status[0].sensor_status != 2285 DP_SENSOR_DATA_AVAILABLE) 2286 env_fan.sensor_status |= ENVMON_INACCESSIBLE; 2287 if (env_fan.sensor_status == ENVMON_SENSOR_OK) { 2288 /* 2289 * copy results into buffer for user 2290 */ 2291 env_fan.speed = 2292 rmc_fan_r.fan_status[0].speed; 2293 env_fan.lowthresholds.warning = 2294 rmc_fan_r.fan_status[0].minspeed; 2295 env_fan.lowthresholds.shutdown = 2296 ENVMON_VAL_UNAVAILABLE; 2297 env_fan.lowthresholds.poweroff = 2298 ENVMON_VAL_UNAVAILABLE; 2299 if ((rmc_fan_r.fan_status[0].flag & 2300 DP_FAN_SPEED_VAL_UNIT) == 0) 2301 bcopy(str_rpm, env_fan.units, 2302 sizeof (str_rpm)); 2303 else 2304 bcopy(str_percent, env_fan.units, 2305 sizeof (str_percent)); 2306 } 2307 } 2308 if (env_fan.sensor_status != ENVMON_SENSOR_OK || 2309 rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) 2310 set_fan_unav(&env_fan); 2311 2312 if (ddi_copyout((caddr_t)&env_fan, (caddr_t)arg, 2313 sizeof (envmon_fan_t), mode) != 0) 2314 return (EFAULT); 2315 break; 2316 2317 case ENVMONIOCAMPIND: 2318 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ind, 2319 sizeof (envmon_indicator_t), mode) != 0) 2320 return (EFAULT); 2321 2322 /* see if we've got amp indicator handles cached */ 2323 LOCK_CACHE 2324 sensor_status = ENVMON_SENSOR_OK; 2325 2326 if ((rmclomv_cache_valid == B_FALSE) || 2327 ((section = rmclomv_find_section(rmclomv_cache, 2328 RMCLOMV_AMP_IND)) == NULL)) { 2329 RELEASE_CACHE 2330 return (do_psu_cmd(arg, mode, &env_ind, &rmc_psu, 2331 &rmc_psu_r, RMCLOMV_AMP_IND)); 2332 } else if (env_ind.id.name[0] == '\0') { 2333 /* request for first handle */ 2334 if (section->num_entries == 0) { 2335 RELEASE_CACHE 2336 return (do_psu_cmd(arg, mode, &env_ind, 2337 &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND)); 2338 } 2339 env_ind.next_id = section->entry[0].handle_name; 2340 sensor_status = ENVMON_NOT_PRESENT; 2341 } else { 2342 /* ensure name is properly terminated */ 2343 env_ind.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2344 if (get_sensor_by_name(section, env_ind.id.name, 2345 &index) != 0) { 2346 RELEASE_CACHE 2347 return (do_psu_cmd(arg, mode, &env_ind, 2348 &rmc_psu, &rmc_psu_r, RMCLOMV_AMP_IND)); 2349 } 2350 if (index + 1 < section->num_entries) { 2351 env_ind.next_id = 2352 section->entry[index + 1].handle_name; 2353 } else { 2354 rmclomv_cache_section_t *sub_section = 2355 rmclomv_find_section(rmclomv_subcache, 2356 RMCLOMV_AMP_IND); 2357 if ((sub_section == NULL) || 2358 (sub_section->num_entries == 0)) 2359 env_ind.next_id.name[0] = '\0'; 2360 else 2361 env_ind.next_id = 2362 sub_section->entry[0].handle_name; 2363 } 2364 } 2365 if (sensor_status == ENVMON_SENSOR_OK) { 2366 /* 2367 * user correctly identified an indicator, note its 2368 * handle value and request the indicator status 2369 */ 2370 rmc_ampi.handle = section->entry[index].handle; 2371 } 2372 RELEASE_CACHE 2373 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 2374 rmclomv_do_cmd(DP_GET_CIRCUIT_BRKS, DP_GET_CIRCUIT_BRKS_R, 2375 sizeof (rmc_ampi_r), (intptr_t)&rmc_ampi, 2376 (intptr_t)&rmc_ampi_r) != 0)) { 2377 sensor_status = ENVMON_INACCESSIBLE; 2378 } 2379 if ((sensor_status == ENVMON_SENSOR_OK) && 2380 (rmc_ampi_r.circuit_brk_status[0].sensor_status == 2381 DP_SENSOR_NOT_PRESENT)) { 2382 sensor_status = ENVMON_NOT_PRESENT; 2383 } 2384 if ((env_ind.sensor_status = sensor_status) == 2385 ENVMON_SENSOR_OK) { 2386 /* 2387 * copy results into buffer for user 2388 */ 2389 if (rmc_ampi_r.circuit_brk_status[0].sensor_status != 2390 DP_SENSOR_DATA_AVAILABLE) 2391 env_ind.sensor_status = ENVMON_INACCESSIBLE; 2392 env_ind.condition = 2393 rmc_ampi_r.circuit_brk_status[0].status; 2394 } 2395 2396 /* 2397 * If rmclomv_rmc_error is set there is no way 2398 * that we read information from RSC. Just copy 2399 * out an inaccessible evironmental. 2400 */ 2401 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 2402 env_ind.sensor_status = ENVMON_INACCESSIBLE; 2403 env_ind.condition = ENVMON_INACCESSIBLE; 2404 } 2405 2406 if (ddi_copyout((caddr_t)&env_ind, (caddr_t)arg, 2407 sizeof (envmon_indicator_t), mode) != 0) 2408 return (EFAULT); 2409 break; 2410 2411 case ENVMONIOCHPU: 2412 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_hpu, 2413 sizeof (envmon_hpu_t), mode) != 0) 2414 return (EFAULT); 2415 2416 /* see if we've got hpu handles cached */ 2417 LOCK_CACHE 2418 2419 if ((rmclomv_cache_valid == B_FALSE) || 2420 ((section = rmclomv_find_section(rmclomv_cache, 2421 RMCLOMV_HPU_IND)) == NULL)) { 2422 RELEASE_CACHE 2423 return (EAGAIN); 2424 } 2425 2426 /* 2427 * At this point the cache is locked and section points to 2428 * the section relating to hpus. 2429 */ 2430 sensor_status = ENVMON_SENSOR_OK; 2431 if (env_hpu.id.name[0] == '\0') { 2432 /* request for first handle */ 2433 if (section->num_entries == 0) 2434 env_hpu.next_id.name[0] = '\0'; 2435 else 2436 env_hpu.next_id = 2437 section->entry[0].handle_name; 2438 sensor_status = ENVMON_NOT_PRESENT; 2439 } else { 2440 /* ensure name is properly terminated */ 2441 env_hpu.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2442 if (get_sensor_by_name(section, env_hpu.id.name, 2443 &index) != 0) { 2444 env_hpu.next_id.name[0] = '\0'; 2445 sensor_status = ENVMON_NOT_PRESENT; 2446 } else if (index + 1 < section->num_entries) 2447 env_hpu.next_id = 2448 section->entry[index + 1].handle_name; 2449 else 2450 env_hpu.next_id.name[0] = '\0'; 2451 } 2452 if (sensor_status == ENVMON_SENSOR_OK) { 2453 /* 2454 * user correctly identified an hpu, note its 2455 * handle value and request the hpu status 2456 */ 2457 rmc_fru.handle = section->entry[index].handle; 2458 special = section->entry[index].ind_mask; 2459 } 2460 RELEASE_CACHE 2461 if ((env_hpu.sensor_status = sensor_status) == 2462 ENVMON_SENSOR_OK) { 2463 env_hpu.fru_status = ENVMON_FRU_PRESENT; 2464 2465 if (special != 0) { 2466 /* this is the pseudo SC node */ 2467 mutex_enter(&rmclomv_state_lock); 2468 switch (rmclomv_rmc_state) { 2469 case RMCLOMV_RMCSTATE_OK: 2470 break; 2471 case RMCLOMV_RMCSTATE_FAILED: 2472 env_hpu.fru_status = ENVMON_FRU_FAULT; 2473 break; 2474 case RMCLOMV_RMCSTATE_DOWNLOAD: 2475 env_hpu.fru_status = 2476 ENVMON_FRU_DOWNLOAD; 2477 break; 2478 default: 2479 env_hpu.sensor_status = 2480 ENVMON_INACCESSIBLE; 2481 break; 2482 } 2483 mutex_exit(&rmclomv_state_lock); 2484 } else if (rmclomv_rmc_error || 2485 rmclomv_do_cmd(DP_GET_FRU_STATUS, 2486 DP_GET_FRU_STATUS_R, sizeof (rmc_fru_r), 2487 (intptr_t)&rmc_fru, (intptr_t)&rmc_fru_r) != 0) { 2488 env_hpu.sensor_status = ENVMON_INACCESSIBLE; 2489 } else { 2490 /* 2491 * copy results into buffer for user 2492 */ 2493 if (rmc_fru_r.fru_status[0].presence == 0) { 2494 env_hpu.sensor_status = 2495 ENVMON_NOT_PRESENT; 2496 env_hpu.fru_status = 2497 ENVMON_FRU_NOT_PRESENT; 2498 } else if (rmc_fru_r.fru_status[0].sensor_status 2499 != DP_SENSOR_DATA_AVAILABLE) { 2500 env_hpu.sensor_status = 2501 ENVMON_INACCESSIBLE; 2502 } else { 2503 uint8_t status = 2504 rmc_fru_r.fru_status[0].status; 2505 if (status == DP_FRU_STATUS_UNKNOWN) { 2506 env_hpu.sensor_status = 2507 ENVMON_INACCESSIBLE; 2508 } else if (status != DP_FRU_STATUS_OK) { 2509 env_hpu.fru_status = 2510 ENVMON_FRU_FAULT; 2511 } 2512 } 2513 } 2514 } 2515 2516 /* 2517 * If rmclomv_rmc_error is set there is no way 2518 * that we read information from RSC. Just copy 2519 * out an inaccessible environmental. 2520 */ 2521 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 2522 env_hpu.sensor_status = ENVMON_INACCESSIBLE; 2523 env_hpu.fru_status = ENVMON_INACCESSIBLE; 2524 } 2525 2526 if (ddi_copyout((caddr_t)&env_hpu, (caddr_t)arg, 2527 sizeof (envmon_hpu_t), mode) != 0) 2528 return (EFAULT); 2529 break; 2530 2531 case ENVMONIOCGETLED: 2532 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledinfo, 2533 sizeof (envmon_led_info_t), mode) != 0) 2534 return (EFAULT); 2535 2536 /* see if we've got LED handles cached */ 2537 LOCK_CACHE 2538 sensor_status = ENVMON_SENSOR_OK; 2539 2540 if ((rmclomv_cache_valid == B_FALSE) || 2541 ((section = rmclomv_find_section(rmclomv_cache, 2542 RMCLOMV_LED_IND)) == NULL)) { 2543 env_ledinfo.next_id.name[0] = '\0'; 2544 sensor_status = ENVMON_NOT_PRESENT; 2545 } else if (env_ledinfo.id.name[0] == '\0') { 2546 /* request for first handle */ 2547 if (section->num_entries == 0) 2548 env_ledinfo.next_id.name[0] = '\0'; 2549 else 2550 env_ledinfo.next_id = 2551 section->entry[0].handle_name; 2552 sensor_status = ENVMON_NOT_PRESENT; 2553 } else { 2554 /* ensure name is properly terminated */ 2555 env_ledinfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2556 if (get_sensor_by_name(section, env_ledinfo.id.name, 2557 &index) != 0) { 2558 env_ledinfo.next_id.name[0] = '\0'; 2559 sensor_status = ENVMON_NOT_PRESENT; 2560 } else if (index + 1 < section->num_entries) 2561 env_ledinfo.next_id = 2562 section->entry[index + 1].handle_name; 2563 else 2564 env_ledinfo.next_id.name[0] = '\0'; 2565 } 2566 if (sensor_status == ENVMON_SENSOR_OK) { 2567 /* 2568 * user correctly identified a LED, note its 2569 * handle value and request the LED status 2570 */ 2571 rmc_led.handle = section->entry[index].handle; 2572 } 2573 RELEASE_CACHE 2574 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 2575 rmclomv_do_cmd(DP_GET_LED_STATE, DP_GET_LED_STATE_R, 2576 sizeof (rmc_led_r), (intptr_t)&rmc_led, 2577 (intptr_t)&rmc_led_r) != 0)) { 2578 sensor_status = ENVMON_INACCESSIBLE; 2579 } 2580 if ((sensor_status == ENVMON_SENSOR_OK) && 2581 (rmc_led_r.led_state[0].sensor_status == 2582 DP_SENSOR_NOT_PRESENT)) { 2583 sensor_status = ENVMON_NOT_PRESENT; 2584 } 2585 if ((env_ledinfo.sensor_status = sensor_status) == 2586 ENVMON_SENSOR_OK) { 2587 /* 2588 * copy results into buffer for user 2589 * start with some defaults then override 2590 */ 2591 env_ledinfo.sensor_status = ENVMON_SENSOR_OK; 2592 env_ledinfo.led_state = ENVMON_LED_OFF; 2593 env_ledinfo.led_color = ENVMON_LED_CLR_NONE; 2594 2595 if (rmc_led_r.led_state[0].sensor_status != 2596 DP_SENSOR_DATA_AVAILABLE) 2597 env_ledinfo.sensor_status = ENVMON_INACCESSIBLE; 2598 else { 2599 dp_led_state_t ledState; 2600 ledState = rmc_led_r.led_state[0]; 2601 env_ledinfo.led_color = (int8_t)ledState.colour; 2602 2603 switch (ledState.state) { 2604 case (rsci8)DP_LED_OFF: 2605 break; 2606 case (rsci8)DP_LED_ON: 2607 env_ledinfo.led_state = ENVMON_LED_ON; 2608 break; 2609 case (rsci8)DP_LED_BLINKING: 2610 env_ledinfo.led_state = 2611 ENVMON_LED_BLINKING; 2612 break; 2613 case (rsci8)DP_LED_FLASHING: 2614 env_ledinfo.led_state = 2615 ENVMON_LED_FLASHING; 2616 break; 2617 default: 2618 break; 2619 } 2620 } 2621 } 2622 2623 /* 2624 * If rmclomv_rmc_error is set there is no way 2625 * that we read information from RSC. Just copy 2626 * out an inaccessible environmental. 2627 */ 2628 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 2629 env_ledinfo.sensor_status = ENVMON_INACCESSIBLE; 2630 env_ledinfo.led_state = ENVMON_INACCESSIBLE; 2631 } 2632 2633 if (ddi_copyout((caddr_t)&env_ledinfo, (caddr_t)arg, 2634 sizeof (envmon_led_info_t), mode) != 0) 2635 return (EFAULT); 2636 break; 2637 2638 case ENVMONIOCSETLED: 2639 if ((mode & FWRITE) == 0) 2640 return (EACCES); 2641 if (drv_priv(cred_p) != 0) 2642 return (EPERM); 2643 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_ledctl, 2644 sizeof (envmon_led_ctl_t), mode) != 0) 2645 return (EFAULT); 2646 if (env_ledctl.led_state < RMCLOMV_MIN_LED_STATE || 2647 env_ledctl.led_state > RMCLOMV_MAX_LED_STATE) 2648 return (EINVAL); 2649 /* 2650 * Ensure name is properly terminated. 2651 */ 2652 env_ledctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2653 2654 /* see if we've got LED handles cached */ 2655 LOCK_CACHE 2656 2657 if ((rmclomv_cache_valid == B_FALSE) || 2658 ((section = rmclomv_find_section(rmclomv_cache, 2659 RMCLOMV_LED_IND)) == NULL) || 2660 (get_sensor_by_name(section, env_ledctl.id.name, 2661 &index) != 0)) { 2662 RELEASE_CACHE 2663 return (EINVAL); /* no such LED */ 2664 } 2665 /* 2666 * user correctly identified a LED, note its handle value 2667 */ 2668 rmc_setled.handle = section->entry[index].handle; 2669 RELEASE_CACHE 2670 switch (env_ledctl.led_state) { 2671 case ENVMON_LED_ON: 2672 rmc_setled.state = DP_LED_ON; 2673 break; 2674 case ENVMON_LED_BLINKING: 2675 rmc_setled.state = DP_LED_BLINKING; 2676 break; 2677 case ENVMON_LED_FLASHING: 2678 rmc_setled.state = DP_LED_FLASHING; 2679 break; 2680 default: 2681 rmc_setled.state = DP_LED_OFF; 2682 break; 2683 } 2684 retval = rmclomv_do_cmd(DP_SET_LED_STATE, DP_SET_LED_STATE_R, 2685 sizeof (rmc_setled_r), (intptr_t)&rmc_setled, 2686 (intptr_t)&rmc_setled_r); 2687 2688 if (retval != 0) { 2689 break; 2690 } 2691 2692 if (rmc_setled_r.status != 0) { 2693 cmn_err(CE_WARN, "ENVMONIOCSETLED: \"%s\" status: 0x%x", 2694 env_ledctl.id.name, rmc_setled_r.status); 2695 return (EIO); 2696 } 2697 break; 2698 2699 case ENVMONIOCGETKEYSW: 2700 { 2701 enum rmc_keyswitch_pos rmc_pos = real_key_position; 2702 envmon_keysw_pos_t envmon_pos; 2703 2704 /* 2705 * Yes, I know this is ugly, but the V210 has no keyswitch, 2706 * even though the ALOM returns a value for it 2707 */ 2708 if (strcmp(platform, "SUNW,Sun-Fire-V210") == 0) { 2709 return (ENOTSUP); 2710 } 2711 2712 switch (rmc_pos) { 2713 2714 case RMC_KEYSWITCH_POS_NORMAL: 2715 envmon_pos = ENVMON_KEYSW_POS_NORMAL; 2716 break; 2717 case RMC_KEYSWITCH_POS_DIAG: 2718 envmon_pos = ENVMON_KEYSW_POS_DIAG; 2719 break; 2720 case RMC_KEYSWITCH_POS_LOCKED: 2721 envmon_pos = ENVMON_KEYSW_POS_LOCKED; 2722 break; 2723 case RMC_KEYSWITCH_POS_OFF: 2724 envmon_pos = ENVMON_KEYSW_POS_OFF; 2725 break; 2726 default: 2727 envmon_pos = ENVMON_KEYSW_POS_UNKNOWN; 2728 break; 2729 } 2730 2731 if (ddi_copyout((caddr_t)&envmon_pos, (caddr_t)arg, 2732 sizeof (envmon_pos), mode) != 0) 2733 return (EFAULT); 2734 break; 2735 } 2736 2737 case ENVMONIOCGETALARM: 2738 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarminfo, 2739 sizeof (envmon_alarm_info_t), mode) != 0) 2740 return (EFAULT); 2741 2742 /* see if we've got ALARM handles cached */ 2743 LOCK_CACHE 2744 sensor_status = ENVMON_SENSOR_OK; 2745 2746 if ((rmclomv_cache_valid == B_FALSE) || 2747 ((section = rmclomv_find_section(rmclomv_cache, 2748 RMCLOMV_ALARM_IND)) == NULL)) { 2749 env_alarminfo.next_id.name[0] = '\0'; 2750 sensor_status = ENVMON_NOT_PRESENT; 2751 } else if (env_alarminfo.id.name[0] == '\0') { 2752 /* request for first handle */ 2753 if (section->num_entries == 0) 2754 env_alarminfo.next_id.name[0] = '\0'; 2755 else 2756 env_alarminfo.next_id = 2757 section->entry[0].handle_name; 2758 sensor_status = ENVMON_NOT_PRESENT; 2759 } else { 2760 /* ensure name is properly terminated */ 2761 env_alarminfo.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2762 if (get_sensor_by_name(section, env_alarminfo.id.name, 2763 &index) != 0) { 2764 env_alarminfo.next_id.name[0] = '\0'; 2765 sensor_status = ENVMON_NOT_PRESENT; 2766 } else if (index + 1 < section->num_entries) 2767 env_alarminfo.next_id = 2768 section->entry[index + 1].handle_name; 2769 else 2770 env_alarminfo.next_id.name[0] = '\0'; 2771 } 2772 if (sensor_status == ENVMON_SENSOR_OK) { 2773 /* 2774 * user correctly identified a ALARM, note its 2775 * handle value and request the ALARM status 2776 */ 2777 rmc_alarm.handle = section->entry[index].handle; 2778 } 2779 RELEASE_CACHE 2780 if ((sensor_status == ENVMON_SENSOR_OK) && 2781 (rmclomv_rmc_error || 2782 rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R, 2783 sizeof (rmc_alarm_r), (intptr_t)&rmc_alarm, 2784 (intptr_t)&rmc_alarm_r) != 0)) { 2785 sensor_status = ENVMON_INACCESSIBLE; 2786 } 2787 if ((env_alarminfo.sensor_status = sensor_status) == 2788 ENVMON_SENSOR_OK) { 2789 /* 2790 * copy results into buffer for user 2791 * start with some defaults then override 2792 */ 2793 env_alarminfo.sensor_status = ENVMON_SENSOR_OK; 2794 env_alarminfo.alarm_state = ENVMON_ALARM_OFF; 2795 2796 if (rmc_alarm_r.alarm_state[0].sensor_status != 2797 DP_SENSOR_DATA_AVAILABLE) 2798 env_alarminfo.sensor_status = 2799 ENVMON_INACCESSIBLE; 2800 else { 2801 dp_alarm_state_t alarmState; 2802 alarmState = rmc_alarm_r.alarm_state[0]; 2803 2804 switch (alarmState.state) { 2805 case DP_ALARM_OFF: 2806 break; 2807 case DP_ALARM_ON: 2808 env_alarminfo.alarm_state = 2809 ENVMON_ALARM_ON; 2810 break; 2811 default: 2812 break; 2813 } 2814 } 2815 } 2816 2817 /* 2818 * If rmclomv_rmc_error is set there is no way 2819 * that we read information from RSC. Just copy 2820 * out an inaccessible environmental. 2821 */ 2822 if (rmclomv_rmc_error != RMCLOMV_RMCERROR_NONE) { 2823 env_alarminfo.sensor_status = ENVMON_INACCESSIBLE; 2824 env_alarminfo.alarm_state = ENVMON_INACCESSIBLE; 2825 } 2826 2827 if (ddi_copyout((caddr_t)&env_alarminfo, (caddr_t)arg, 2828 sizeof (envmon_alarm_info_t), mode) != 0) 2829 return (EFAULT); 2830 break; 2831 2832 case ENVMONIOCSETALARM: 2833 if ((mode & FWRITE) == 0) 2834 return (EACCES); 2835 if (drv_priv(cred_p) != 0) 2836 return (EPERM); 2837 if (ddi_copyin((caddr_t)arg, (caddr_t)&env_alarmctl, 2838 sizeof (envmon_alarm_ctl_t), mode) != 0) 2839 return (EFAULT); 2840 if (env_alarmctl.alarm_state < RMCLOMV_MIN_ALARM_STATE || 2841 env_alarmctl.alarm_state > RMCLOMV_MAX_ALARM_STATE) 2842 return (EINVAL); 2843 /* 2844 * Ensure name is properly terminated. 2845 */ 2846 env_alarmctl.id.name[ENVMON_MAXNAMELEN - 1] = '\0'; 2847 2848 /* see if we've got ALARM handles cached */ 2849 LOCK_CACHE 2850 2851 if ((rmclomv_cache_valid == B_FALSE) || 2852 ((section = rmclomv_find_section(rmclomv_cache, 2853 RMCLOMV_ALARM_IND)) == NULL) || 2854 (get_sensor_by_name(section, env_alarmctl.id.name, 2855 &index) != 0)) { 2856 RELEASE_CACHE 2857 return (EINVAL); /* no such ALARM */ 2858 } 2859 /* 2860 * user correctly identified a ALARM, note its handle value 2861 */ 2862 rmc_setalarm.handle = section->entry[index].handle; 2863 RELEASE_CACHE 2864 rmc_setalarm.state = (rsci8)env_alarmctl.alarm_state; 2865 retval = rmclomv_do_cmd(DP_SET_ALARM_STATE, 2866 DP_SET_ALARM_STATE_R, 2867 sizeof (rmc_setalarm_r), 2868 (intptr_t)&rmc_setalarm, 2869 (intptr_t)&rmc_setalarm_r); 2870 2871 if (retval != 0) { 2872 break; 2873 } 2874 2875 if (rmc_setalarm_r.status != 0) { 2876 cmn_err(CE_WARN, "ENVMONIOCSETALARM: \"%s\" status: " 2877 "0x%x", env_alarmctl.id.name, 2878 rmc_setalarm_r.status); 2879 return (EIO); 2880 } 2881 break; 2882 2883 case ENVMONIOCCHASSISSERIALNUM: 2884 retval = rmclomv_do_cmd(DP_GET_SDP_VERSION, 2885 DP_GET_SDP_VERSION_R, sizeof (rmc_sdpver_r), 2886 NULL, (intptr_t)&rmc_sdpver_r); 2887 2888 if (retval != 0) { 2889 cmn_err(CE_WARN, "DP_GET_SDP_VERSION failed, ret=%d\n", 2890 retval); 2891 break; 2892 } else if (rmc_sdpver_r.version < SDP_RESPONDS_TO_ALL_CMDS) { 2893 retval = ENOTSUP; 2894 break; 2895 } 2896 retval = rmclomv_do_cmd(DP_GET_CHASSIS_SERIALNUM, 2897 DP_GET_CHASSIS_SERIALNUM_R, sizeof (rmc_serialnum_r), 2898 NULL, (intptr_t)&rmc_serialnum_r); 2899 2900 if (retval != 0) { 2901 break; 2902 } 2903 bcopy(rmc_serialnum_r.chassis_serial_number, 2904 chassis.serial_number, 2905 sizeof (rmc_serialnum_r.chassis_serial_number)); 2906 2907 if (ddi_copyout((caddr_t)&chassis, (caddr_t)arg, 2908 sizeof (chassis), mode) != 0) { 2909 return (EFAULT); 2910 } 2911 sensor_status = ENVMON_SENSOR_OK; 2912 break; 2913 2914 default: 2915 retval = ENOTSUP; 2916 break; 2917 } 2918 2919 return (retval); 2920 } 2921 2922 /* ARGSUSED */ 2923 static void 2924 rmclomv_checkrmc(caddr_t arg) 2925 { 2926 callb_cpr_t cprinfo; 2927 int err; 2928 int retries; 2929 int state; 2930 dp_get_sysinfo_r_t sysinfo; 2931 2932 CALLB_CPR_INIT(&cprinfo, &rmclomv_checkrmc_lock, callb_generic_cpr, 2933 "rmclomv_checkrmc"); 2934 2935 mutex_enter(&rmclomv_checkrmc_lock); 2936 for (;;) { 2937 /* 2938 * Initial entry to this for loop is made with 2939 * rmclomv_checkrmc_sig set to RMCLOMV_PROCESS_NOW. So the 2940 * following while loop drops through the first time. A 2941 * timeout call is made just before polling the RMC. Its 2942 * interrupt routine sustains this loop by injecting additional 2943 * state changes and cv events. 2944 */ 2945 /* 2946 * Wait for someone to tell me to continue. 2947 */ 2948 while (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_WAIT) { 2949 CALLB_CPR_SAFE_BEGIN(&cprinfo); 2950 cv_wait(&rmclomv_checkrmc_sig_cv, 2951 &rmclomv_checkrmc_lock); 2952 CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_checkrmc_lock); 2953 } 2954 2955 mutex_exit(&rmclomv_checkrmc_lock); 2956 /* 2957 * mustn't hold same lock as timeout called with 2958 * when cancelling timer 2959 */ 2960 if (timer_id != 0) { 2961 (void) untimeout(timer_id); 2962 timer_id = 0; 2963 } 2964 mutex_enter(&rmclomv_checkrmc_lock); 2965 2966 /* RMCLOMV_CHECKRMC_EXITNOW implies signal by _detach(). */ 2967 if (rmclomv_checkrmc_sig == RMCLOMV_CHECKRMC_EXITNOW) { 2968 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 2969 2970 /* rmclomv_checkrmc_lock is held at this point! */ 2971 CALLB_CPR_EXIT(&cprinfo); 2972 2973 thread_exit(); 2974 /* NOTREACHED */ 2975 } 2976 2977 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_WAIT; 2978 2979 /* 2980 * If the RMC is not responding, rmclomv_do_cmd() takes a 2981 * long time and eventually times out. We conclude that the 2982 * RMC is broken if it doesn't respond to a number of polls 2983 * made 60 secs apart. So that the rmclomv_do_cmd() time-out 2984 * period isn't added to our 60 second timer, make the 2985 * timeout() call before calling rmclomv_do_cmd(). 2986 */ 2987 if (timer_id == 0) { 2988 timer_id = timeout(rmclomv_checkrmc_wakeup, NULL, 2989 60 * drv_usectohz(1000000)); 2990 } 2991 2992 mutex_exit(&rmclomv_checkrmc_lock); 2993 2994 err = rmclomv_do_cmd(DP_GET_SYSINFO, DP_GET_SYSINFO_R, 2995 sizeof (sysinfo), NULL, (intptr_t)&sysinfo); 2996 if (err == 0) { 2997 mutex_enter(&rmclomv_state_lock); 2998 state = rmclomv_rmc_state; 2999 /* successful poll, reset fail count */ 3000 rmclomv_rmcfailcount = 0; 3001 mutex_exit(&rmclomv_state_lock); 3002 3003 if (state != RMCLOMV_RMCSTATE_OK) { 3004 rmclomv_refresh_wakeup(); 3005 } 3006 } 3007 if ((err != 0) && 3008 (rmclomv_rmc_error != RMCLOMV_RMCSTATE_DOWNLOAD)) { 3009 /* 3010 * Failed response or no response from RMC. 3011 * Count the failure. 3012 * If threshold exceeded, send a DR event. 3013 */ 3014 mutex_enter(&rmclomv_state_lock); 3015 retries = rmclomv_rmcfailcount; 3016 state = rmclomv_rmc_state; 3017 if (retries == RMCLOMV_RMCFAILTHRESHOLD) 3018 rmclomv_rmc_state = RMCLOMV_RMCSTATE_FAILED; 3019 if (rmclomv_rmcfailcount <= RMCLOMV_RMCFAILTHRESHOLD) 3020 rmclomv_rmcfailcount++; 3021 mutex_exit(&rmclomv_state_lock); 3022 3023 if (retries == RMCLOMV_RMCFAILTHRESHOLD) { 3024 cmn_err(CE_WARN, "SC %s responding", 3025 state == RMCLOMV_RMCSTATE_OK ? 3026 "has stopped" : "is not"); 3027 refresh_name_cache(B_TRUE); 3028 rmclomv_dr_data_handler(str_sc, SE_NO_HINT); 3029 } 3030 } 3031 3032 /* 3033 * Re-enter the lock to prepare for another iteration. 3034 * We must have the lock here to protect rmclomv_checkrmc_sig. 3035 */ 3036 mutex_enter(&rmclomv_checkrmc_lock); 3037 } 3038 } 3039 3040 static void 3041 rmclomv_checkrmc_start(void) 3042 { 3043 kthread_t *tp; 3044 3045 mutex_enter(&rmclomv_checkrmc_lock); 3046 3047 if (rmclomv_checkrmc_tid == 0) { 3048 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW; 3049 3050 tp = thread_create(NULL, 0, rmclomv_checkrmc, NULL, 0, 3051 &p0, TS_RUN, maxclsyspri); 3052 rmclomv_checkrmc_tid = tp->t_did; 3053 } 3054 3055 mutex_exit(&rmclomv_checkrmc_lock); 3056 } 3057 3058 static void 3059 rmclomv_checkrmc_destroy(void) 3060 { 3061 kt_did_t tid; 3062 3063 mutex_enter(&rmclomv_checkrmc_lock); 3064 tid = rmclomv_checkrmc_tid; 3065 if (tid != 0) { 3066 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_EXITNOW; 3067 cv_signal(&rmclomv_checkrmc_sig_cv); 3068 rmclomv_checkrmc_tid = 0; 3069 } 3070 mutex_exit(&rmclomv_checkrmc_lock); 3071 3072 /* 3073 * Wait for rmclomv_checkrmc() to finish 3074 */ 3075 if (tid != 0) 3076 thread_join(tid); 3077 } 3078 3079 /*ARGSUSED*/ 3080 static void 3081 rmclomv_checkrmc_wakeup(void *arg) 3082 { 3083 mutex_enter(&rmclomv_checkrmc_lock); 3084 3085 if (rmclomv_checkrmc_sig != RMCLOMV_CHECKRMC_EXITNOW) 3086 rmclomv_checkrmc_sig = RMCLOMV_CHECKRMC_PROCESSNOW; 3087 cv_signal(&rmclomv_checkrmc_sig_cv); 3088 3089 mutex_exit(&rmclomv_checkrmc_lock); 3090 } 3091 3092 /* ARGSUSED */ 3093 static void 3094 rmclomv_refresh(caddr_t arg) 3095 { 3096 void (*plat_nodename_set_fun)(void); 3097 sig_state_t *current_sgn_p; 3098 callb_cpr_t cprinfo; 3099 int state; 3100 int tmp_checkrmc_sig; 3101 3102 CALLB_CPR_INIT(&cprinfo, &rmclomv_refresh_lock, callb_generic_cpr, 3103 "rmclomv_refresh"); 3104 3105 /* 3106 * Wait until the rmclomv_checkrmc() thread has had a chance to 3107 * run its main loop. This is done so that rmclomv_refresh will 3108 * only run its main loop once at start of day; otherwise, it may 3109 * run twice and generate warning messages when redundantly populating 3110 * its internal cache. 3111 */ 3112 do { 3113 delay(drv_usectohz(DELAY_TIME)); 3114 mutex_enter(&rmclomv_checkrmc_lock); 3115 tmp_checkrmc_sig = rmclomv_checkrmc_sig; 3116 mutex_exit(&rmclomv_checkrmc_lock); 3117 } while (tmp_checkrmc_sig != RMCLOMV_CHECKRMC_WAIT); 3118 3119 mutex_enter(&rmclomv_refresh_lock); 3120 for (;;) { 3121 3122 /* 3123 * Wait for someone to tell me to continue. 3124 */ 3125 while (rmclomv_refresh_sig == RMCLOMV_REFRESH_WAIT) { 3126 CALLB_CPR_SAFE_BEGIN(&cprinfo); 3127 cv_wait(&rmclomv_refresh_sig_cv, &rmclomv_refresh_lock); 3128 CALLB_CPR_SAFE_END(&cprinfo, &rmclomv_refresh_lock); 3129 } 3130 3131 /* RMCLOMV_REFRESH_EXITNOW implies signal by _detach(). */ 3132 if (rmclomv_refresh_sig == RMCLOMV_REFRESH_EXITNOW) { 3133 rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 3134 3135 /* rmclomv_refresh_lock is held at this point! */ 3136 CALLB_CPR_EXIT(&cprinfo); 3137 3138 thread_exit(); 3139 /* NOTREACHED */ 3140 } 3141 3142 ASSERT(rmclomv_refresh_sig == RMCLOMV_REFRESH_PROCESSNOW); 3143 rmclomv_refresh_sig = RMCLOMV_REFRESH_WAIT; 3144 3145 mutex_exit(&rmclomv_refresh_lock); 3146 3147 refresh_name_cache(B_FALSE); 3148 3149 /* 3150 * We're not going to access rmclomv_sysinfo_data here, 3151 * so there's no point in locking it before reading 3152 * rmclomv_sysinfo_valid. Also this avoids holding two 3153 * locks at once and the concommitant worry about deadlocks. 3154 */ 3155 if (rmclomv_sysinfo_valid) { 3156 /* 3157 * We've just successfully read the RMC sysinfo 3158 * so the RMC must be operational. Update its 3159 * state and if it was previously not OK, refresh 3160 * nodename, CPU signatures and watchdog settings. 3161 */ 3162 mutex_enter(&rmclomv_state_lock); 3163 rmclomv_rmcfailcount = 0; 3164 state = rmclomv_rmc_state; 3165 rmclomv_rmc_state = RMCLOMV_RMCSTATE_OK; 3166 mutex_exit(&rmclomv_state_lock); 3167 3168 if (state != RMCLOMV_RMCSTATE_OK) { 3169 rmclomv_dr_data_handler(str_sc, SE_NO_HINT); 3170 if (state == RMCLOMV_RMCSTATE_FAILED) { 3171 cmn_err(CE_NOTE, "SC recovered"); 3172 } 3173 } 3174 3175 if (utsname.nodename[0] != 0) { 3176 plat_nodename_set_fun = 3177 (void (*)(void))modgetsymvalue( 3178 "plat_nodename_set", 0); 3179 if (plat_nodename_set_fun != NULL) 3180 plat_nodename_set_fun(); 3181 } 3182 3183 current_sgn_p = (sig_state_t *)modgetsymvalue( 3184 "current_sgn", 0); 3185 3186 /* 3187 * Delay before calling CPU_SIGNATURE, to allow 3188 * any pending asynchronous communications (i.e. 3189 * plat_timesync()) to complete. This helps to 3190 * prevent the situation where the message associated 3191 * with the CPU_SIGNATURE state cannot be sent to the 3192 * system controller. 3193 */ 3194 if ((current_sgn_p != NULL) && 3195 (current_sgn_p->state_t.sig != 0)) { 3196 delay(drv_usectohz(CPU_SIGNATURE_DELAY_TIME)); 3197 CPU_SIGNATURE(current_sgn_p->state_t.sig, 3198 current_sgn_p->state_t.state, 3199 current_sgn_p->state_t.sub_state, -1); 3200 3201 if (!(boothowto & RB_DEBUG)) { 3202 /* 3203 * Delay before calling 3204 * send_watchdog_msg, to allow 3205 * CPU_SIGNATURE() time to 3206 * complete; this increases the 3207 * chances of successfully sending 3208 * the watchdog message to the 3209 * system controller. 3210 */ 3211 delay(drv_usectohz( 3212 CPU_SIGNATURE_DELAY_TIME)); 3213 send_watchdog_msg(last_watchdog_msg); 3214 } 3215 } 3216 } 3217 3218 /* 3219 * update keyswitch value in case it changed while the 3220 * RMC was out of action 3221 */ 3222 LOCK_CACHE 3223 if (rmclomv_sysinfo_valid) { 3224 real_key_position = rmclomv_sysinfo_data.keyswitch; 3225 if ((real_key_position != RMC_KEYSWITCH_POS_UNKNOWN) && 3226 (real_key_position <= RMC_KEYSWITCH_POS_OFF)) { 3227 key_position = real_key_position; 3228 } else { 3229 /* treat unknown key position as locked */ 3230 key_position = RMC_KEYSWITCH_POS_LOCKED; 3231 } 3232 } else { 3233 /* treat unreadable key position as locked */ 3234 key_position = RMC_KEYSWITCH_POS_LOCKED; 3235 real_key_position = RMC_KEYSWITCH_POS_UNKNOWN; 3236 } 3237 RELEASE_CACHE 3238 3239 /* 3240 * Re-enter the lock to prepare for another iteration. 3241 * We must have the lock here to protect rmclomv_refresh_sig. 3242 */ 3243 mutex_enter(&rmclomv_refresh_lock); 3244 } 3245 } 3246 3247 static void 3248 rmclomv_refresh_start(void) 3249 { 3250 kthread_t *tp; 3251 3252 mutex_enter(&rmclomv_refresh_lock); 3253 3254 if (rmclomv_refresh_tid == 0) { 3255 rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW; 3256 3257 tp = thread_create(NULL, 0, rmclomv_refresh, NULL, 0, 3258 &p0, TS_RUN, maxclsyspri); 3259 rmclomv_refresh_tid = tp->t_did; 3260 } 3261 3262 mutex_exit(&rmclomv_refresh_lock); 3263 } 3264 3265 static void 3266 rmclomv_refresh_destroy(void) 3267 { 3268 kt_did_t tid; 3269 3270 mutex_enter(&rmclomv_refresh_lock); 3271 tid = rmclomv_refresh_tid; 3272 if (tid != 0) { 3273 rmclomv_refresh_sig = RMCLOMV_REFRESH_EXITNOW; 3274 cv_signal(&rmclomv_refresh_sig_cv); 3275 rmclomv_refresh_tid = 0; 3276 } 3277 mutex_exit(&rmclomv_refresh_lock); 3278 3279 /* 3280 * Wait for rmclomv_refresh() to finish 3281 */ 3282 if (tid != 0) 3283 thread_join(tid); 3284 } 3285 3286 static void 3287 rmclomv_refresh_wakeup(void) 3288 { 3289 mutex_enter(&rmclomv_refresh_lock); 3290 3291 if (rmclomv_refresh_sig != RMCLOMV_REFRESH_EXITNOW) 3292 rmclomv_refresh_sig = RMCLOMV_REFRESH_PROCESSNOW; 3293 cv_signal(&rmclomv_refresh_sig_cv); 3294 3295 mutex_exit(&rmclomv_refresh_lock); 3296 } 3297 3298 static void 3299 send_watchdog_msg(int msg) 3300 { 3301 rmc_comm_msg_t request; 3302 dp_set_host_watchdog_t watchdog_msg; 3303 3304 if (rmclomv_watchdog_mode) 3305 return; 3306 3307 watchdog_msg.enable = msg; 3308 request.msg_type = DP_SET_HOST_WATCHDOG; 3309 request.msg_len = sizeof (watchdog_msg); 3310 request.msg_buf = (caddr_t)&watchdog_msg; 3311 (void) rmc_comm_request_nowait(&request, (msg == 1) ? 3312 RMC_COMM_DREQ_URGENT : 0); 3313 } 3314 3315 /*ARGSUSED*/ 3316 static uint_t 3317 rmc_set_watchdog_timer(uint_t timeoutval) 3318 { 3319 ASSERT(MUTEX_HELD(&tod_lock)); 3320 3321 if ((watchdog_enable == 0) || (watchdog_available == 0)) { 3322 return (0); 3323 } 3324 3325 /* 3326 * If boothowto has RB_DEBUG set we never want to set the watchdog 3327 * support on. 3328 */ 3329 if (boothowto & RB_DEBUG) { 3330 return (0); 3331 } 3332 3333 /* 3334 * When the watchdog is shut off last_watchdog_msg goes from a 3335 * 0 to a 1. So we must test to see that last_watchdog_msg is 3336 * set to 1 indicating that watchdog was shut off and 3337 * After which we set last_watchdog_msg back to 0 so that we do not 3338 * run this code 3339 * again. 3340 */ 3341 if (last_watchdog_msg == 1) { 3342 send_watchdog_msg(0); 3343 last_watchdog_msg = 0; 3344 } 3345 3346 pmugpio_watchdog_pat(); 3347 3348 watchdog_activated = 1; 3349 3350 return (1); 3351 } 3352 3353 static uint_t 3354 rmc_clear_watchdog_timer(void) 3355 { 3356 ASSERT(MUTEX_HELD(&tod_lock)); 3357 if ((watchdog_activated == 0) || (boothowto & RB_DEBUG)) 3358 return (0); 3359 3360 send_watchdog_msg(1); 3361 last_watchdog_msg = 1; 3362 watchdog_activated = 0; 3363 3364 return (0); 3365 } 3366 3367 static void 3368 plat_timesync(void *arg) 3369 { 3370 timestruc_t now; 3371 todinfo_t tod; 3372 rmc_comm_msg_t request; 3373 dp_set_date_time_t set_time_msg; 3374 int retval; 3375 timestruc_t ts; 3376 dp_get_date_time_r_t *date_and_time_info; 3377 int buffer[DATE_TIME_MSG_SIZE]; 3378 3379 /* Is the system coming up? */ 3380 if (arg != NULL) { 3381 /* Request the time from the RMC clock. */ 3382 retval = rmclomv_do_cmd(DP_GET_DATE_TIME, DP_GET_DATE_TIME_R, 3383 DATE_TIME_MSG_SIZE, NULL, (intptr_t)&buffer); 3384 3385 /* 3386 * If we were able to get the time lets set the local clock. 3387 * The time returned from RMC is in Unix time format. 3388 * 3389 * If we couldn't get the time we'll accept the drift so as not 3390 * to cause congestion on the I2C bus or cause boot 3391 * performance regressions. 3392 */ 3393 if (retval == RCNOERR) { 3394 date_and_time_info = (dp_get_date_time_r_t *)buffer; 3395 ts.tv_sec = date_and_time_info->current_datetime; 3396 ts.tv_nsec = 0; 3397 mutex_enter(&tod_lock); 3398 tod_set(ts); 3399 set_hrestime(&ts); 3400 mutex_exit(&tod_lock); 3401 } 3402 } 3403 3404 gethrestime(&now); 3405 mutex_enter(&tod_lock); 3406 tod = utc_to_tod(now.tv_sec); 3407 mutex_exit(&tod_lock); 3408 3409 set_time_msg.year = tod.tod_year; 3410 set_time_msg.month = tod.tod_month - 1; 3411 set_time_msg.day = tod.tod_day; 3412 set_time_msg.hour = tod.tod_hour; 3413 set_time_msg.minute = tod.tod_min; 3414 set_time_msg.second = tod.tod_sec; 3415 3416 request.msg_type = DP_SET_DATE_TIME; 3417 request.msg_len = sizeof (set_time_msg); 3418 request.msg_buf = (caddr_t)&set_time_msg; 3419 3420 (void) rmc_comm_request_nowait(&request, 0); 3421 3422 (void) timeout(plat_timesync, NULL, timesync_interval); 3423 } 3424 3425 /* 3426 * Interfaces to get/set alarm relays from outside 3427 */ 3428 int 3429 rmclomv_alarm_get(int alarm_type, int *alarm_state) 3430 { 3431 rmclomv_cache_section_t *section; 3432 int index; 3433 uint16_t sensor_status; 3434 dp_get_alarm_state_t u_rmc_alarm; 3435 dp_get_alarm_state_r_t u_rmc_alarm_r; 3436 3437 /* see if we've got ALARM handles cached */ 3438 LOCK_CACHE 3439 sensor_status = ENVMON_SENSOR_OK; 3440 3441 if ((rmclomv_cache_valid == B_FALSE) || 3442 ((section = rmclomv_find_section(rmclomv_cache, 3443 RMCLOMV_ALARM_IND)) == NULL)) { 3444 sensor_status = ENVMON_NOT_PRESENT; 3445 } 3446 if (sensor_status == ENVMON_SENSOR_OK) { 3447 /* 3448 * user correctly identified a ALARM, note its 3449 * handle value and request the ALARM status 3450 */ 3451 index = alarm_type; 3452 if (index >= section->num_entries) 3453 sensor_status = ENVMON_INACCESSIBLE; 3454 else 3455 u_rmc_alarm.handle = section->entry[index].handle; 3456 } 3457 RELEASE_CACHE 3458 if ((sensor_status == ENVMON_SENSOR_OK) && (rmclomv_rmc_error || 3459 rmclomv_do_cmd(DP_GET_ALARM_STATE, DP_GET_ALARM_STATE_R, 3460 sizeof (u_rmc_alarm_r), (intptr_t)&u_rmc_alarm, 3461 (intptr_t)&u_rmc_alarm_r) != 0)) { 3462 sensor_status = ENVMON_INACCESSIBLE; 3463 } 3464 if (sensor_status == ENVMON_SENSOR_OK) { 3465 /* 3466 * copy results into buffer for user 3467 * start with some defaults then override 3468 */ 3469 *alarm_state = 0; 3470 3471 if (u_rmc_alarm_r.alarm_state[0].sensor_status != 3472 DP_SENSOR_DATA_AVAILABLE) 3473 return (ENXIO); 3474 else { 3475 dp_alarm_state_t alarmState; 3476 alarmState = u_rmc_alarm_r.alarm_state[0]; 3477 3478 switch (alarmState.state) { 3479 case DP_ALARM_OFF: 3480 break; 3481 case DP_ALARM_ON: 3482 *alarm_state = 1; 3483 break; 3484 default: 3485 break; 3486 } 3487 } 3488 } else 3489 return (ENXIO); 3490 3491 return (0); 3492 } 3493 3494 int 3495 rmclomv_alarm_set(int alarm_type, int new_state) 3496 { 3497 rmclomv_cache_section_t *section; 3498 int index; 3499 uint16_t sensor_status; 3500 dp_set_alarm_state_t u_rmc_setalarm; 3501 dp_set_alarm_state_r_t u_rmc_setalarm_r; 3502 3503 /* see if we've got ALARM handles cached */ 3504 LOCK_CACHE 3505 sensor_status = ENVMON_SENSOR_OK; 3506 3507 if ((rmclomv_cache_valid == B_FALSE) || 3508 ((section = rmclomv_find_section(rmclomv_cache, 3509 RMCLOMV_ALARM_IND)) == NULL)) { 3510 sensor_status = ENVMON_NOT_PRESENT; 3511 } 3512 if (sensor_status == ENVMON_SENSOR_OK) { 3513 /* 3514 * user correctly identified a ALARM, note its 3515 * handle value and request the ALARM status 3516 */ 3517 index = alarm_type; 3518 if (index >= section->num_entries) 3519 sensor_status = ENVMON_INACCESSIBLE; 3520 else { 3521 u_rmc_setalarm.handle = section->entry[index].handle; 3522 u_rmc_setalarm.state = new_state; 3523 } 3524 } 3525 RELEASE_CACHE 3526 if ((sensor_status == ENVMON_SENSOR_OK) && 3527 (rmclomv_rmc_error || 3528 rmclomv_do_cmd(DP_SET_ALARM_STATE, DP_SET_ALARM_STATE_R, 3529 sizeof (u_rmc_setalarm_r), (intptr_t)&u_rmc_setalarm, 3530 (intptr_t)&u_rmc_setalarm_r) != 0)) { 3531 sensor_status = ENVMON_INACCESSIBLE; 3532 } 3533 3534 if (u_rmc_setalarm_r.status != DP_SET_ALARM_OK) { 3535 return (EIO); 3536 } 3537 3538 if (sensor_status != ENVMON_SENSOR_OK) { 3539 return (ENXIO); 3540 } 3541 3542 return (0); 3543 } 3544