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