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