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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains the environmental PICL plug-in module. 28 */ 29 30 /* 31 * This plugin sets up the PICLTREE for Chicago WS. 32 * It provides functionality to get/set temperatures and 33 * fan speeds. 34 * 35 * The environmental policy defaults to the auto mode 36 * as programmed by OBP at boot time. 37 */ 38 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <sys/sysmacros.h> 42 #include <limits.h> 43 #include <string.h> 44 #include <strings.h> 45 #include <stdarg.h> 46 #include <alloca.h> 47 #include <unistd.h> 48 #include <sys/processor.h> 49 #include <syslog.h> 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <picl.h> 53 #include <picltree.h> 54 #include <picldefs.h> 55 #include <pthread.h> 56 #include <signal.h> 57 #include <libdevinfo.h> 58 #include <sys/pm.h> 59 #include <sys/open.h> 60 #include <sys/time.h> 61 #include <sys/utsname.h> 62 #include <sys/systeminfo.h> 63 #include <note.h> 64 #include <sys/pic16f747.h> 65 #include "envd.h" 66 #include <sys/scsi/scsi.h> 67 #include <sys/scsi/generic/commands.h> 68 69 int debug_fd; 70 /* 71 * PICL plugin entry points 72 */ 73 static void piclenvd_register(void); 74 static void piclenvd_init(void); 75 static void piclenvd_fini(void); 76 77 /* 78 * Env setup routines 79 */ 80 extern void env_picl_setup(void); 81 extern void env_picl_destroy(void); 82 extern int env_picl_setup_tuneables(void); 83 84 static boolean_t has_fan_failed(env_fan_t *fanp); 85 86 /* 87 * PSU fan fault handling 88 */ 89 static boolean_t has_psufan_failed(void); 90 static int psufan_last_status = FAN_OK; 91 92 #pragma init(piclenvd_register) 93 94 /* 95 * Plugin registration information 96 */ 97 static picld_plugin_reg_t my_reg_info = { 98 PICLD_PLUGIN_VERSION, 99 PICLD_PLUGIN_CRITICAL, 100 "SUNW_piclenvd", 101 piclenvd_init, 102 piclenvd_fini, 103 }; 104 105 #define REGISTER_INFORMATION_STRING_LENGTH 16 106 static char fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 107 static char fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 108 109 static int scsi_log_sense(env_disk_t *diskp, uchar_t page_code, 110 void *pagebuf, uint16_t pagelen, int page_control); 111 static int scsi_mode_select(env_disk_t *diskp, uchar_t page_code, 112 uchar_t *pagebuf, uint16_t pagelen); 113 114 static int get_disk_temp(env_disk_t *); 115 116 /* 117 * ES Segment stuff 118 */ 119 static es_sensor_blk_t sensor_ctl[MAX_SENSORS]; 120 121 /* 122 * Default limits for sensors, in case ES segment is not present, or has 123 * inconsistent information 124 */ 125 static es_sensor_blk_t sensor_default_ctl[MAX_SENSORS] = { 126 { 127 CPU0_HIGH_POWER_OFF, CPU0_HIGH_SHUTDOWN, CPU0_HIGH_WARNING, 128 CPU0_LOW_WARNING, CPU0_LOW_SHUTDOWN, CPU0_LOW_POWER_OFF 129 }, 130 { 131 CPU1_HIGH_POWER_OFF, CPU1_HIGH_SHUTDOWN, CPU1_HIGH_WARNING, 132 CPU1_LOW_WARNING, CPU1_LOW_SHUTDOWN, CPU1_LOW_POWER_OFF 133 }, 134 { 135 ADT7462_HIGH_POWER_OFF, ADT7462_HIGH_SHUTDOWN, ADT7462_HIGH_WARNING, 136 ADT7462_LOW_WARNING, ADT7462_LOW_SHUTDOWN, ADT7462_LOW_POWER_OFF 137 }, 138 { 139 MB_HIGH_POWER_OFF, MB_HIGH_SHUTDOWN, MB_HIGH_WARNING, 140 MB_LOW_WARNING, MB_LOW_SHUTDOWN, MB_LOW_POWER_OFF 141 }, 142 { 143 LM95221_HIGH_POWER_OFF, LM95221_HIGH_SHUTDOWN, LM95221_HIGH_WARNING, 144 LM95221_LOW_WARNING, LM95221_LOW_SHUTDOWN, LM95221_LOW_POWER_OFF 145 }, 146 { 147 FIRE_HIGH_POWER_OFF, FIRE_HIGH_SHUTDOWN, FIRE_HIGH_WARNING, 148 FIRE_LOW_WARNING, FIRE_LOW_SHUTDOWN, FIRE_LOW_POWER_OFF 149 }, 150 { 151 LSI1064_HIGH_POWER_OFF, LSI1064_HIGH_SHUTDOWN, LSI1064_HIGH_WARNING, 152 LSI1064_LOW_WARNING, LSI1064_LOW_SHUTDOWN, LSI1064_LOW_POWER_OFF 153 }, 154 { 155 FRONT_PANEL_HIGH_POWER_OFF, FRONT_PANEL_HIGH_SHUTDOWN, 156 FRONT_PANEL_HIGH_WARNING, FRONT_PANEL_LOW_WARNING, 157 FRONT_PANEL_LOW_SHUTDOWN, FRONT_PANEL_LOW_POWER_OFF 158 }, 159 { 160 PSU_HIGH_POWER_OFF, PSU_HIGH_SHUTDOWN, PSU_HIGH_WARNING, 161 PSU_LOW_WARNING, PSU_LOW_SHUTDOWN, PSU_LOW_POWER_OFF 162 } 163 }; 164 165 /* 166 * Env thread variables 167 */ 168 static boolean_t system_shutdown_started = B_FALSE; 169 static boolean_t system_temp_thr_created = B_FALSE; 170 static pthread_t system_temp_thr_id; 171 static pthread_attr_t thr_attr; 172 static boolean_t disk_temp_thr_created = B_FALSE; 173 static pthread_t disk_temp_thr_id; 174 static boolean_t fan_thr_created = B_FALSE; 175 static pthread_t fan_thr_id; 176 177 /* 178 * PM thread related variables 179 */ 180 static pthread_t pmthr_tid; /* pmthr thread ID */ 181 static int pm_fd = -1; /* PM device file descriptor */ 182 static boolean_t pmthr_created = B_FALSE; 183 static int cur_lpstate; /* cur low power state */ 184 185 /* 186 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var 187 * Setting the verbose tuneable also enables debugging for better 188 * control 189 */ 190 int env_debug = 0; 191 192 /* 193 * These are debug variables for keeping track of the total number 194 * of Fan and Temp sensor retries over the lifetime of the plugin. 195 */ 196 static int total_fan_retries = 0; 197 static int total_temp_retries = 0; 198 199 /* 200 * Fan devices 201 */ 202 static env_fan_t envd_system_fan0 = { 203 ENV_SYSTEM_FAN0, ENV_SYSTEM_FAN0_DEVFS, SYSTEM_FAN0_ID, 204 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 205 }; 206 static env_fan_t envd_system_fan1 = { 207 ENV_SYSTEM_FAN1, ENV_SYSTEM_FAN1_DEVFS, SYSTEM_FAN1_ID, 208 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 209 }; 210 static env_fan_t envd_system_fan2 = { 211 ENV_SYSTEM_FAN2, ENV_SYSTEM_FAN2_DEVFS, SYSTEM_FAN2_ID, 212 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 213 }; 214 static env_fan_t envd_system_fan3 = { 215 ENV_SYSTEM_FAN3, ENV_SYSTEM_FAN3_DEVFS, SYSTEM_FAN3_ID, 216 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 217 }; 218 static env_fan_t envd_system_fan4 = { 219 ENV_SYSTEM_FAN4, ENV_SYSTEM_FAN4_DEVFS, SYSTEM_FAN4_ID, 220 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 221 }; 222 223 /* 224 * Disk devices 225 */ 226 static env_disk_t envd_disk0 = { 227 ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH, 228 DISK0_ID, -1, 229 }; 230 static env_disk_t envd_disk1 = { 231 ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH, 232 DISK1_ID, -1, 233 }; 234 static env_disk_t envd_disk2 = { 235 ENV_DISK2, ENV_DISK2_DEVFS, DISK2_PHYSPATH, DISK2_NODE_PATH, 236 DISK2_ID, -1, 237 }; 238 static env_disk_t envd_disk3 = { 239 ENV_DISK3, ENV_DISK3_DEVFS, DISK3_PHYSPATH, DISK3_NODE_PATH, 240 DISK3_ID, -1, 241 }; 242 243 /* 244 * Sensors 245 */ 246 static env_sensor_t envd_sensor_cpu0 = { 247 SENSOR_CPU0, SENSOR_CPU0_DEVFS, CPU0_SENSOR_ID, -1, NULL, 248 }; 249 static env_sensor_t envd_sensor_cpu1 = { 250 SENSOR_CPU1, SENSOR_CPU1_DEVFS, CPU1_SENSOR_ID, -1, NULL, 251 }; 252 static env_sensor_t envd_sensor_adt7462 = { 253 SENSOR_ADT7462, SENSOR_ADT7462_DEVFS, ADT7462_SENSOR_ID, -1, NULL, 254 }; 255 static env_sensor_t envd_sensor_mb = { 256 SENSOR_MB, SENSOR_MB_DEVFS, MB_SENSOR_ID, -1, NULL, 257 }; 258 static env_sensor_t envd_sensor_lm95221 = { 259 SENSOR_LM95221, SENSOR_LM95221_DEVFS, LM95221_SENSOR_ID, -1, NULL, 260 }; 261 static env_sensor_t envd_sensor_fire = { 262 SENSOR_FIRE, SENSOR_FIRE_DEVFS, FIRE_SENSOR_ID, -1, NULL, 263 }; 264 static env_sensor_t envd_sensor_lsi1064 = { 265 SENSOR_LSI1064, SENSOR_LSI1064_DEVFS, LSI1064_SENSOR_ID, -1, NULL, 266 }; 267 static env_sensor_t envd_sensor_front_panel = { 268 SENSOR_FRONT_PANEL, SENSOR_FRONT_PANEL_DEVFS, FRONT_PANEL_SENSOR_ID, 269 -1, NULL, 270 }; 271 static env_sensor_t envd_sensor_psu = { 272 SENSOR_PSU, SENSOR_PSU_DEVFS, PSU_SENSOR_ID, -1, NULL, 273 }; 274 275 /* 276 * The vendor-id and device-id are the properties associated with 277 * the SCSI controller. This is used to identify a particular controller 278 * like LSI1064. 279 */ 280 #define VENDOR_ID "vendor-id" 281 #define DEVICE_ID "device-id" 282 283 /* 284 * The implementation for SCSI disk drives to supply info. about 285 * temperature is not mandatory. Hence we first determine if the 286 * temperature page is supported. To do this we need to scan the list 287 * of pages supported. 288 */ 289 #define SUPPORTED_LPAGES 0 290 #define TEMPERATURE_PAGE 0x0D 291 #define LOGPAGEHDRSIZE 4 292 293 /* 294 * NULL terminated array of fans 295 */ 296 static env_fan_t *envd_fans[] = { 297 &envd_system_fan0, 298 &envd_system_fan1, 299 &envd_system_fan2, 300 &envd_system_fan3, 301 &envd_system_fan4, 302 NULL 303 }; 304 305 /* 306 * NULL terminated array of disks 307 */ 308 static env_disk_t *envd_disks[] = { 309 &envd_disk0, 310 &envd_disk1, 311 &envd_disk2, 312 &envd_disk3, 313 NULL 314 }; 315 316 /* 317 * NULL terminated array of temperature sensors 318 */ 319 #define N_ENVD_SENSORS 9 320 static env_sensor_t *envd_sensors[] = { 321 &envd_sensor_cpu0, 322 &envd_sensor_cpu1, 323 &envd_sensor_adt7462, 324 &envd_sensor_mb, 325 &envd_sensor_lm95221, 326 &envd_sensor_fire, 327 &envd_sensor_lsi1064, 328 &envd_sensor_front_panel, 329 &envd_sensor_psu, 330 NULL 331 }; 332 333 #define NOT_AVAILABLE "NA" 334 335 /* 336 * Tuneables 337 */ 338 #define ENABLE 1 339 #define DISABLE 0 340 341 static int disk_high_warn_temperature = DISK_HIGH_WARN_TEMPERATURE; 342 static int disk_low_warn_temperature = DISK_LOW_WARN_TEMPERATURE; 343 static int disk_high_shutdown_temperature = 344 DISK_HIGH_SHUTDOWN_TEMPERATURE; 345 static int disk_low_shutdown_temperature = DISK_LOW_SHUTDOWN_TEMPERATURE; 346 347 static int disk_scan_interval = DISK_SCAN_INTERVAL; 348 static int sensor_scan_interval = SENSOR_SCAN_INTERVAL; 349 static int fan_scan_interval = FAN_SCAN_INTERVAL; 350 351 static int get_int_val(ptree_rarg_t *parg, void *buf); 352 static int set_int_val(ptree_warg_t *parg, const void *buf); 353 static int get_string_val(ptree_rarg_t *parg, void *buf); 354 static int set_string_val(ptree_warg_t *parg, const void *buf); 355 356 static int shutdown_override = 0; 357 static int sensor_warning_interval = SENSOR_WARNING_INTERVAL; 358 static int sensor_warning_duration = SENSOR_WARNING_DURATION; 359 static int sensor_shutdown_interval = SENSOR_SHUTDOWN_INTERVAL; 360 static int disk_warning_interval = DISK_WARNING_INTERVAL; 361 static int disk_warning_duration = DISK_WARNING_DURATION; 362 static int disk_shutdown_interval = DISK_SHUTDOWN_INTERVAL; 363 364 static int system_temp_monitor = 1; /* enabled */ 365 static int fan_monitor = 1; /* enabled */ 366 static int pm_monitor = 1; /* enabled */ 367 368 /* Disable disk temperature monitoring until we have LSI fw support */ 369 int disk_temp_monitor = 0; 370 371 static char shutdown_cmd[] = SHUTDOWN_CMD; 372 const char *iofru_devname = I2C_DEVFS "/" IOFRU_DEV; 373 374 env_tuneable_t tuneables[] = { 375 {"system_temp-monitor", PICL_PTYPE_INT, &system_temp_monitor, 376 &get_int_val, &set_int_val, sizeof (int)}, 377 378 {"fan-monitor", PICL_PTYPE_INT, &fan_monitor, 379 &get_int_val, &set_int_val, sizeof (int)}, 380 381 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor, 382 &get_int_val, &set_int_val, sizeof (int)}, 383 384 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override, 385 &get_int_val, &set_int_val, sizeof (int)}, 386 387 {"sensor-warning-duration", PICL_PTYPE_INT, 388 &sensor_warning_duration, 389 &get_int_val, &set_int_val, 390 sizeof (int)}, 391 392 {"disk-scan-interval", PICL_PTYPE_INT, 393 &disk_scan_interval, 394 &get_int_val, &set_int_val, 395 sizeof (int)}, 396 397 {"fan-scan-interval", PICL_PTYPE_INT, 398 &fan_scan_interval, 399 &get_int_val, &set_int_val, 400 sizeof (int)}, 401 402 {"sensor-scan-interval", PICL_PTYPE_INT, 403 &sensor_scan_interval, 404 &get_int_val, &set_int_val, 405 sizeof (int)}, 406 407 {"sensor_warning-interval", PICL_PTYPE_INT, &sensor_warning_interval, 408 &get_int_val, &set_int_val, 409 sizeof (int)}, 410 411 {"sensor_shutdown-interval", PICL_PTYPE_INT, &sensor_shutdown_interval, 412 &get_int_val, &set_int_val, 413 sizeof (int)}, 414 415 {"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval, 416 &get_int_val, &set_int_val, 417 sizeof (int)}, 418 419 {"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration, 420 &get_int_val, &set_int_val, 421 sizeof (int)}, 422 423 {"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval, 424 &get_int_val, &set_int_val, 425 sizeof (int)}, 426 427 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd, 428 &get_string_val, &set_string_val, 429 sizeof (shutdown_cmd)}, 430 431 {"monitor-disk-temp", PICL_PTYPE_INT, &disk_temp_monitor, 432 &get_int_val, &set_int_val, sizeof (int)}, 433 434 {"disk-high-warn-temperature", PICL_PTYPE_INT, 435 &disk_high_warn_temperature, &get_int_val, 436 &set_int_val, sizeof (int)}, 437 438 {"disk-low-warn-temperature", PICL_PTYPE_INT, 439 &disk_low_warn_temperature, &get_int_val, 440 &set_int_val, sizeof (int)}, 441 442 {"disk-high-shutdown-temperature", PICL_PTYPE_INT, 443 &disk_high_shutdown_temperature, &get_int_val, 444 &set_int_val, sizeof (int)}, 445 446 {"disk-low-shutdown-temperature", PICL_PTYPE_INT, 447 &disk_low_shutdown_temperature, &get_int_val, 448 &set_int_val, sizeof (int)}, 449 450 {"verbose", PICL_PTYPE_INT, &env_debug, 451 &get_int_val, &set_int_val, sizeof (int)} 452 }; 453 454 /* 455 * We use this to figure out how many tuneables there are 456 * This is variable because the publishing routine needs this info 457 * in piclenvsetup.c 458 */ 459 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0])); 460 461 /* 462 * Lookup fan and return a pointer to env_fan_t data structure. 463 */ 464 env_fan_t * 465 fan_lookup(char *name) 466 { 467 int i; 468 env_fan_t *fanp; 469 470 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 471 if (strcmp(fanp->name, name) == 0) 472 return (fanp); 473 } 474 return (NULL); 475 } 476 477 /* 478 * Lookup sensor and return a pointer to env_sensor_t data structure. 479 */ 480 env_sensor_t * 481 sensor_lookup(char *name) 482 { 483 env_sensor_t *sensorp; 484 int i; 485 486 for (i = 0; i < N_ENVD_SENSORS; ++i) { 487 sensorp = envd_sensors[i]; 488 if (strcmp(sensorp->name, name) == 0) 489 return (sensorp); 490 } 491 return (NULL); 492 } 493 494 /* 495 * Lookup disk and return a pointer to env_disk_t data structure. 496 */ 497 env_disk_t * 498 disk_lookup(char *name) 499 { 500 int i; 501 env_disk_t *diskp; 502 503 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 504 if (strncmp(diskp->name, name, strlen(name)) == 0) 505 return (diskp); 506 } 507 return (NULL); 508 } 509 510 /* 511 * Get current temperature 512 * Returns -1 on error, 0 if successful 513 */ 514 int 515 get_temperature(env_sensor_t *sensorp, tempr_t *temp) 516 { 517 int fd = sensorp->fd; 518 int retval = 0; 519 520 if (fd == -1) 521 retval = -1; 522 else if (ioctl(fd, PIC_GET_TEMPERATURE, temp) != 0) { 523 524 retval = -1; 525 526 sensorp->error++; 527 528 if (sensorp->error == MAX_SENSOR_RETRIES) { 529 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, 530 sensorp->name, errno, strerror(errno)); 531 } 532 533 total_temp_retries++; 534 (void) sleep(1); 535 536 } else if (sensorp->error != 0) { 537 if (sensorp->error >= MAX_SENSOR_RETRIES) { 538 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, 539 sensorp->name); 540 } 541 542 sensorp->error = 0; 543 544 if (total_temp_retries && env_debug) { 545 envd_log(LOG_WARNING, 546 "Total retries for sensors = %d", 547 total_temp_retries); 548 } 549 } 550 551 return (retval); 552 } 553 554 /* 555 * Get current disk temperature 556 * Returns -1 on error, 0 if successful 557 */ 558 int 559 disk_temperature(env_disk_t *diskp, tempr_t *temp) 560 { 561 int retval = 0; 562 563 if (diskp == NULL) 564 retval = -1; 565 else 566 *temp = diskp->current_temp; 567 568 return (retval); 569 } 570 571 /* 572 * Get current fan speed 573 * This function returns a RPM value for fanspeed 574 * in fanspeedp. 575 * Returns -1 on error, 0 if successful 576 */ 577 int 578 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp) 579 { 580 uint8_t tach; 581 int real_tach; 582 int retries; 583 584 if (fanp->fd == -1) 585 return (-1); 586 587 if (has_fan_failed(fanp)) { 588 *fanspeedp = 0; 589 return (0); 590 } 591 592 /* try to read the fan information */ 593 for (retries = 0; retries < MAX_FAN_RETRIES; retries++) { 594 if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) == 0) 595 break; 596 (void) sleep(1); 597 } 598 599 total_fan_retries += retries; 600 if (retries >= MAX_FAN_RETRIES) 601 return (-1); 602 603 if (total_fan_retries && env_debug) { 604 envd_log(LOG_WARNING, "total retries for fan = %d", 605 total_fan_retries); 606 } 607 608 real_tach = tach << 8; 609 *fanspeedp = TACH_TO_RPM(real_tach); 610 return (0); 611 } 612 613 /* 614 * Set fan speed 615 * This function accepts a percentage of fan speed 616 * from 0-100 and programs the HW monitor fans to the corresponding 617 * fanspeed value. 618 * Returns -1 on error, -2 on invalid args passed, 0 if successful 619 */ 620 int 621 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed) 622 { 623 uint8_t speed; 624 625 if (fanp->fd == -1) 626 return (-1); 627 628 if (fanspeed < 0 || fanspeed > 100) 629 return (-2); 630 631 speed = fanspeed; 632 if (ioctl(fanp->fd, PIC_SET_FAN_SPEED, &speed) != 0) 633 return (-1); 634 635 return (0); 636 } 637 638 /* 639 * close all fan devices 640 */ 641 static void 642 envd_close_fans(void) 643 { 644 int i; 645 env_fan_t *fanp; 646 647 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 648 if (fanp->fd != -1) { 649 (void) close(fanp->fd); 650 fanp->fd = -1; 651 } 652 } 653 } 654 655 /* 656 * Close sensor devices and freeup resources 657 */ 658 static void 659 envd_close_sensors(void) 660 { 661 env_sensor_t *sensorp; 662 int i; 663 664 for (i = 0; i < N_ENVD_SENSORS; ++i) { 665 sensorp = envd_sensors[i]; 666 if (sensorp->fd != -1) { 667 (void) close(sensorp->fd); 668 sensorp->fd = -1; 669 } 670 } 671 } 672 673 /* 674 * Open fan devices and initialize per fan data structure. 675 */ 676 static int 677 envd_setup_fans(void) 678 { 679 int i, fd; 680 env_fan_t *fanp; 681 int fancnt = 0; 682 picl_nodehdl_t tnodeh; 683 684 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 685 fanp->last_status = FAN_OK; 686 687 /* Make sure cpu0/1 present for validating cpu fans */ 688 if (fanp->id == CPU0_FAN_ID) { 689 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 690 PICL_SUCCESS) { 691 if (env_debug) { 692 envd_log(LOG_ERR, 693 "get node by path failed for %s\n", 694 CPU0_PATH); 695 } 696 fanp->present = B_FALSE; 697 continue; 698 } 699 } 700 if (fanp->id == CPU1_FAN_ID) { 701 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 702 PICL_SUCCESS) { 703 if (env_debug) { 704 envd_log(LOG_ERR, 705 "get node by path failed for %s\n", CPU0_PATH); 706 } 707 fanp->present = B_FALSE; 708 continue; 709 } 710 } 711 if ((fd = open(fanp->devfs_path, O_RDWR)) == -1) { 712 envd_log(LOG_CRIT, 713 ENV_FAN_OPEN_FAIL, fanp->name, 714 fanp->devfs_path, errno, strerror(errno)); 715 fanp->present = B_FALSE; 716 continue; 717 } 718 fanp->fd = fd; 719 fanp->present = B_TRUE; 720 fancnt++; 721 } 722 723 if (fancnt == 0) 724 return (-1); 725 726 return (0); 727 } 728 729 static int 730 envd_setup_disks(void) 731 { 732 int ret, i, page_index, page_len; 733 picl_nodehdl_t tnodeh; 734 env_disk_t *diskp; 735 uint_t vendor_id; 736 uint_t device_id; 737 uchar_t log_page[256]; 738 739 if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH, 740 &tnodeh) != PICL_SUCCESS) { 741 if (env_debug) { 742 envd_log(LOG_ERR, "On-Board SCSI controller %s " 743 "not found in the system.\n", 744 SCSI_CONTROLLER_NODE_PATH); 745 } 746 return (-1); 747 } 748 749 if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID, 750 &vendor_id, sizeof (vendor_id))) != 0) { 751 if (env_debug) { 752 envd_log(LOG_ERR, "Error in getting vendor-id " 753 "for SCSI controller. ret = %d errno = 0x%d\n", 754 ret, errno); 755 } 756 return (-1); 757 } 758 if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID, 759 &device_id, sizeof (device_id))) != 0) { 760 if (env_debug) { 761 envd_log(LOG_ERR, "Error in getting device-id " 762 "for SCSI controller. ret = %d errno = 0x%d\n", 763 ret, errno); 764 } 765 return (-1); 766 } 767 768 /* 769 * We have found LSI1064 SCSi controller onboard. 770 */ 771 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 772 if (ptree_get_node_by_path(diskp->nodepath, 773 &tnodeh) != PICL_SUCCESS) { 774 diskp->present = B_FALSE; 775 if (env_debug) { 776 envd_log(LOG_ERR, 777 "DISK %d: %s not found in the system.\n", 778 diskp->id, diskp->nodepath); 779 } 780 continue; 781 } 782 if ((diskp->fd = open(diskp->devfs_path, O_RDONLY)) == -1) { 783 diskp->present = B_FALSE; 784 if (env_debug) { 785 envd_log(LOG_ERR, 786 "Error in opening %s errno = 0x%x\n", 787 diskp->devfs_path, errno); 788 } 789 continue; 790 } 791 diskp->present = B_TRUE; 792 diskp->tpage_supported = B_FALSE; 793 diskp->smart_supported = B_FALSE; 794 diskp->warning_tstamp = 0; 795 diskp->shutdown_tstamp = 0; 796 diskp->high_warning = disk_high_warn_temperature; 797 diskp->low_warning = disk_low_warn_temperature; 798 diskp->high_shutdown = disk_high_shutdown_temperature; 799 diskp->low_shutdown = disk_low_shutdown_temperature; 800 /* 801 * Find out if the Temperature page is supported by the disk. 802 */ 803 if (scsi_log_sense(diskp, SUPPORTED_LPAGES, log_page, 804 sizeof (log_page), 1) == 0) { 805 806 page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3]; 807 808 for (page_index = LOGPAGEHDRSIZE; 809 page_index < page_len + LOGPAGEHDRSIZE; 810 page_index++) { 811 if (log_page[page_index] != TEMPERATURE_PAGE) 812 continue; 813 814 diskp->tpage_supported = B_TRUE; 815 if (env_debug) { 816 envd_log(LOG_ERR, 817 "tpage supported for %s\n", 818 diskp->nodepath); 819 } 820 } 821 } 822 /* 823 * If the temp log page failed, we can check if this is 824 * a SATA drive and attempt to read the temperature 825 * using the SMART interface. 826 */ 827 if (diskp->tpage_supported != B_TRUE) { 828 uchar_t iec_page[IEC_PAGE_SIZE]; 829 830 if (env_debug) 831 envd_log(LOG_ERR, "Turning on SMART\n"); 832 833 (void) memset(iec_page, 0, sizeof (iec_page)); 834 iec_page[0] = IEC_PAGE; /* SMART PAGE */ 835 iec_page[1] = 0xa; /* length */ 836 /* Notification, only when requested */ 837 iec_page[3] = REPORT_ON_REQUEST; 838 839 ret = scsi_mode_select(diskp, IEC_PAGE, 840 iec_page, sizeof (iec_page)); 841 842 /* 843 * Since we know this is a SMART capable 844 * drive, we will try to set the page and 845 * determine if the drive is not capable 846 * of reading the TEMP page when we 847 * try to read the temperature and disable 848 * it then. We do not fail when reading 849 * or writing this page because we will 850 * determine the SMART capabilities 851 * when reading the temperature. 852 */ 853 if ((ret != 0) && (env_debug)) { 854 envd_log(LOG_ERR, 855 "Failed to set mode page"); 856 } 857 858 diskp->smart_supported = B_TRUE; 859 diskp->tpage_supported = B_TRUE; 860 } 861 862 if (get_disk_temp(diskp) < 0) { 863 envd_log(LOG_ERR, " error reading temperature of:%s\n", 864 diskp->name); 865 } else if (env_debug) { 866 envd_log(LOG_ERR, "%s: temperature = %d\n", 867 diskp->name, diskp->current_temp); 868 } 869 870 } 871 872 return (0); 873 } 874 875 static int 876 envd_es_setup(void) 877 { 878 seeprom_scn_t scn_hdr; 879 seeprom_seg_t seg_hdr; 880 es_data_t *envseg; 881 es_sensor_t *sensorp; 882 int i, fd, id; 883 int envseg_len, esd_len; 884 char *envsegp; 885 886 /* 887 * Open the front io fru 888 */ 889 if ((fd = open(iofru_devname, O_RDONLY)) == -1) { 890 envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, iofru_devname, errno); 891 return (-1); 892 } 893 894 /* 895 * Read section header from the fru SEEPROM 896 */ 897 if (lseek(fd, SSCN_OFFSET, SEEK_SET) == (off_t)-1 || 898 read(fd, &scn_hdr, sizeof (scn_hdr)) != sizeof (scn_hdr)) { 899 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 900 (void) close(fd); 901 return (-1); 902 } 903 if ((scn_hdr.sscn_tag != SSCN_TAG) || 904 (GET_UNALIGN16(&scn_hdr.sscn_ver) != SSCN_VER)) { 905 envd_log(LOG_ERR, ENV_FRU_BAD_SCNHDR, scn_hdr.sscn_tag, 906 GET_UNALIGN16(&scn_hdr.sscn_ver)); 907 (void) close(fd); 908 return (-1); 909 } 910 911 /* 912 * Locate environmental segment 913 */ 914 for (i = 0; i < scn_hdr.sscn_nsegs; i++) { 915 if (read(fd, &seg_hdr, sizeof (seg_hdr)) != sizeof (seg_hdr)) { 916 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 917 (void) close(fd); 918 return (-1); 919 } 920 921 if (env_debug) { 922 envd_log(LOG_INFO, 923 "Seg name: %x off:%x len:%x\n", 924 GET_UNALIGN16(&seg_hdr.sseg_name), 925 GET_UNALIGN16(&seg_hdr.sseg_off), 926 GET_UNALIGN16(&seg_hdr.sseg_len)); 927 } 928 929 if (GET_UNALIGN16(&seg_hdr.sseg_name) == ENVSEG_NAME) 930 break; 931 } 932 if (i == scn_hdr.sscn_nsegs) { 933 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 934 (void) close(fd); 935 return (-1); 936 } 937 938 /* 939 * Read environmental segment 940 */ 941 envseg_len = GET_UNALIGN16(&seg_hdr.sseg_len); 942 if ((envseg = malloc(envseg_len)) == NULL) { 943 envd_log(LOG_ERR, ENV_FRU_NOMEM_FOR_SEG, envseg_len); 944 (void) close(fd); 945 return (-1); 946 } 947 948 if (lseek(fd, (off_t)GET_UNALIGN16(&seg_hdr.sseg_off), 949 SEEK_SET) == (off_t)-1 || 950 read(fd, envseg, envseg_len) != envseg_len) { 951 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 952 free(envseg); 953 (void) close(fd); 954 return (-1); 955 } 956 957 /* 958 * Check environmental segment data for consistency 959 */ 960 esd_len = sizeof (*envseg) + 961 (envseg->esd_nsensors - 1) * sizeof (envseg->esd_sensors[0]); 962 if (envseg->esd_ver != ENVSEG_VERSION || envseg_len < esd_len) { 963 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 964 free(envseg); 965 (void) close(fd); 966 return (-1); 967 } 968 969 /* 970 * Process environmental segment data 971 */ 972 if (envseg->esd_nsensors > MAX_SENSORS) { 973 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 974 free(envseg); 975 (void) close(fd); 976 return (-1); 977 } 978 979 sensorp = &(envseg->esd_sensors[0]); 980 envsegp = (char *)envseg; 981 for (i = 0; i < envseg->esd_nsensors; i++) { 982 uint32_t ess_id; 983 984 (void) memcpy(&ess_id, 985 sensorp->ess_id, sizeof (sensorp->ess_id)); 986 987 if (env_debug) { 988 envd_log(LOG_INFO, "\n Sensor Id %x offset %x", 989 ess_id, sensorp->ess_off); 990 } 991 if (ess_id >= MAX_SENSORS) { 992 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname); 993 free(envseg); 994 (void) close(fd); 995 return (-1); 996 } 997 (void) memcpy(&sensor_ctl[ess_id], &envsegp[sensorp->ess_off], 998 sizeof (es_sensor_blk_t)); 999 1000 sensorp++; 1001 } 1002 1003 /* 1004 * Match sensor/ES id and point to correct data based on IDs 1005 */ 1006 for (i = 0; i < N_ENVD_SENSORS; i++) { 1007 id = envd_sensors[i]->id; 1008 envd_sensors[i]->es = &sensor_ctl[id]; 1009 } 1010 1011 /* 1012 * Cleanup and return 1013 */ 1014 free(envseg); 1015 (void) close(fd); 1016 1017 return (0); 1018 } 1019 1020 static void 1021 envd_es_default_setup(void) 1022 { 1023 int i, id; 1024 1025 for (i = 0; i < N_ENVD_SENSORS; i++) { 1026 id = envd_sensors[i]->id; 1027 envd_sensors[i]->es = &sensor_default_ctl[id]; 1028 } 1029 } 1030 1031 /* 1032 * Open temperature sensor devices and initialize per sensor data structure. 1033 */ 1034 static int 1035 envd_setup_sensors(void) 1036 { 1037 env_sensor_t *sensorp; 1038 int sensorcnt = 0; 1039 int i; 1040 picl_nodehdl_t tnodeh; 1041 1042 for (i = 0; i < N_ENVD_SENSORS; i++) { 1043 if (env_debug) 1044 envd_log(LOG_ERR, "scanning sensor %d\n", i); 1045 1046 sensorp = envd_sensors[i]; 1047 1048 /* Initialize sensor's initial state */ 1049 sensorp->shutdown_initiated = B_FALSE; 1050 sensorp->warning_tstamp = 0; 1051 sensorp->shutdown_tstamp = 0; 1052 sensorp->error = 0; 1053 1054 /* Make sure cpu0/1 sensors are present */ 1055 if (sensorp->id == CPU0_SENSOR_ID) { 1056 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 1057 PICL_SUCCESS) { 1058 if (env_debug) { 1059 envd_log(LOG_ERR, 1060 "get node by path failed for %s\n", 1061 CPU0_PATH); 1062 } 1063 sensorp->present = B_FALSE; 1064 continue; 1065 } 1066 } 1067 if (sensorp->id == CPU1_SENSOR_ID) { 1068 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 1069 PICL_SUCCESS) { 1070 if (env_debug) { 1071 envd_log(LOG_ERR, 1072 "get node by path failed for %s\n", 1073 CPU1_PATH); 1074 } 1075 sensorp->present = B_FALSE; 1076 continue; 1077 } 1078 } 1079 1080 sensorp->fd = open(sensorp->devfs_path, O_RDWR); 1081 if (sensorp->fd == -1) { 1082 if (env_debug) { 1083 envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL, 1084 sensorp->name, sensorp->devfs_path, 1085 errno, strerror(errno)); 1086 } 1087 sensorp->present = B_FALSE; 1088 continue; 1089 } 1090 1091 /* 1092 * Determine if the front panel is attached, we want the 1093 * information if it exists, but should not shut down 1094 * the system if it is removed. 1095 */ 1096 if (sensorp->id == FRONT_PANEL_SENSOR_ID) { 1097 tempr_t temp; 1098 int tries; 1099 1100 for (tries = 0; tries < MAX_SENSOR_RETRIES; tries++) { 1101 if (ioctl(sensorp->fd, PIC_GET_TEMPERATURE, 1102 &temp) == 0) { 1103 break; 1104 } 1105 (void) sleep(1); 1106 } 1107 if (tries == MAX_SENSOR_RETRIES) 1108 sensorp->present = B_FALSE; 1109 } 1110 1111 sensorp->present = B_TRUE; 1112 sensorcnt++; 1113 } 1114 1115 if (sensorcnt == 0) 1116 return (-1); 1117 1118 return (0); 1119 } 1120 1121 /* ARGSUSED */ 1122 static void * 1123 pmthr(void *args) 1124 { 1125 pm_state_change_t pmstate; 1126 char physpath[PATH_MAX]; 1127 int pre_lpstate; 1128 uint8_t estar_state; 1129 int env_monitor_fd; 1130 1131 pmstate.physpath = physpath; 1132 pmstate.size = sizeof (physpath); 1133 cur_lpstate = 0; 1134 pre_lpstate = 1; 1135 1136 pm_fd = open(PM_DEVICE, O_RDWR); 1137 if (pm_fd == -1) { 1138 envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno)); 1139 return (NULL); 1140 } 1141 for (;;) { 1142 /* 1143 * Get PM state change events to check if the system 1144 * is in lowest power state and inform PIC which controls 1145 * fan speeds. 1146 * 1147 * To minimize polling, we use the blocking interface 1148 * to get the power state change event here. 1149 */ 1150 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) { 1151 if (errno != EINTR) 1152 break; 1153 continue; 1154 } 1155 1156 do { 1157 if (env_debug) { 1158 envd_log(LOG_INFO, 1159 "pmstate event:0x%x flags:%x" 1160 "comp:%d oldval:%d newval:%d path:%s\n", 1161 pmstate.event, pmstate.flags, 1162 pmstate.component, 1163 pmstate.old_level, 1164 pmstate.new_level, 1165 pmstate.physpath); 1166 } 1167 cur_lpstate = 1168 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0; 1169 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0); 1170 1171 if (pre_lpstate != cur_lpstate) { 1172 pre_lpstate = cur_lpstate; 1173 estar_state = (cur_lpstate & 0x1); 1174 if (env_debug) 1175 envd_log(LOG_ERR, 1176 "setting PIC ESTAR SATE to %x\n", 1177 estar_state); 1178 1179 env_monitor_fd = open(ENV_MONITOR_DEVFS, O_RDWR); 1180 if (env_monitor_fd != -1) { 1181 if (ioctl(env_monitor_fd, PIC_SET_ESTAR_MODE, 1182 &estar_state) < 0) { 1183 if (env_debug) 1184 envd_log(LOG_ERR, 1185 "unable to set ESTAR_MODE in PIC\n"); 1186 } 1187 (void) close(env_monitor_fd); 1188 } else { 1189 if (env_debug) 1190 envd_log(LOG_ERR, 1191 "Failed to open %s\n", 1192 ENV_MONITOR_DEVFS); 1193 } 1194 } 1195 } 1196 1197 /*NOTREACHED*/ 1198 return (NULL); 1199 } 1200 1201 /* 1202 * This is env thread which monitors the current temperature when 1203 * warning threshold is exceeded. The job is to make sure it does 1204 * not execced/decrease shutdown threshold. If it does it will start 1205 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt. 1206 */ 1207 /*ARGSUSED*/ 1208 static void * 1209 system_temp_thr(void *args) 1210 { 1211 char syscmd[BUFSIZ]; 1212 char msgbuf[BUFSIZ]; 1213 timespec_t to; 1214 int ret, i; 1215 env_sensor_t *sensorp; 1216 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1217 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1218 time_t ct; 1219 tempr_t temp; 1220 1221 for (;;) { 1222 /* 1223 * Sleep for specified seconds before issuing IOCTL 1224 * again. 1225 */ 1226 (void) pthread_mutex_lock(&env_monitor_mutex); 1227 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1228 &env_monitor_mutex, &to); 1229 to.tv_sec = sensor_scan_interval; 1230 to.tv_nsec = 0; 1231 if (ret != ETIMEDOUT) { 1232 (void) pthread_mutex_unlock(&env_monitor_mutex); 1233 continue; 1234 } 1235 1236 (void) pthread_mutex_unlock(&env_monitor_mutex); 1237 for (i = 0; i < N_ENVD_SENSORS; i++) { 1238 sensorp = envd_sensors[i]; 1239 if (sensorp->present == B_FALSE) 1240 continue; 1241 if (get_temperature(sensorp, &temp) == -1) 1242 continue; 1243 1244 sensorp->cur_temp = temp; 1245 if (env_debug) { 1246 envd_log(LOG_ERR, 1247 "%s temp = %d", 1248 sensorp->name, sensorp->cur_temp); 1249 } 1250 1251 /* 1252 * If this sensor already triggered system shutdown, 1253 * don't log any more shutdown/warning messages for it. 1254 */ 1255 if (sensorp->shutdown_initiated) 1256 continue; 1257 1258 /* 1259 * Check for the temperature in warning and shutdown 1260 * range and take appropriate action. 1261 */ 1262 if (SENSOR_TEMP_IN_WARNING_RANGE(sensorp->cur_temp, 1263 sensorp)) { 1264 /* 1265 * Check if the temperature has been in 1266 * warning range during last 1267 * sensor_warning_duration interval. If so, 1268 * the temperature is truly in warning range 1269 * and we need to log a warning message, but 1270 * no more than once every 1271 * sensor_warning_interval seconds. 1272 */ 1273 time_t wtstamp = sensorp->warning_tstamp; 1274 1275 ct = (time_t)(gethrtime() / NANOSEC); 1276 if (sensorp->warning_start == 0) 1277 sensorp->warning_start = ct; 1278 if (((ct - sensorp->warning_start) >= 1279 sensor_warning_duration) && 1280 (wtstamp == 0 || (ct - wtstamp) >= 1281 sensor_warning_interval)) { 1282 envd_log(LOG_CRIT, ENV_WARNING_MSG, 1283 sensorp->name, sensorp->cur_temp, 1284 (int8_t) 1285 sensorp->es->esb_low_warning, 1286 (int8_t) 1287 sensorp->es->esb_high_warning); 1288 1289 sensorp->warning_tstamp = ct; 1290 } 1291 } else if (sensorp->warning_start != 0) 1292 sensorp->warning_start = 0; 1293 1294 if (!shutdown_override && 1295 SENSOR_TEMP_IN_SHUTDOWN_RANGE(sensorp->cur_temp, 1296 sensorp)) { 1297 ct = (time_t)(gethrtime() / NANOSEC); 1298 if (sensorp->shutdown_tstamp == 0) 1299 sensorp->shutdown_tstamp = ct; 1300 1301 /* 1302 * Shutdown the system if the temperature 1303 * remains in the shutdown range for over 1304 * sensor_shutdown_interval seconds. 1305 */ 1306 if ((ct - sensorp->shutdown_tstamp) >= 1307 sensor_shutdown_interval) { 1308 /* 1309 * Log error 1310 */ 1311 sensorp->shutdown_initiated = B_TRUE; 1312 1313 (void) snprintf(msgbuf, sizeof (msgbuf), 1314 ENV_SHUTDOWN_MSG, sensorp->name, 1315 sensorp->cur_temp, 1316 (int8_t) 1317 sensorp->es->esb_low_shutdown, 1318 (int8_t) 1319 sensorp->es->esb_high_shutdown); 1320 1321 envd_log(LOG_ALERT, msgbuf); 1322 1323 /* 1324 * Shutdown the system (only once) 1325 */ 1326 if (system_shutdown_started == 1327 B_FALSE) { 1328 (void) snprintf(syscmd, 1329 sizeof (syscmd), 1330 "%s \"%s\"", shutdown_cmd, 1331 msgbuf); 1332 1333 envd_log(LOG_ALERT, syscmd); 1334 system_shutdown_started = 1335 B_TRUE; 1336 1337 (void) system(syscmd); 1338 } 1339 } 1340 } else if (sensorp->shutdown_tstamp != 0) 1341 sensorp->shutdown_tstamp = 0; 1342 } 1343 } /* end of forever loop */ 1344 1345 /*NOTREACHED*/ 1346 return (NULL); 1347 } 1348 1349 static int 1350 scsi_log_sense(env_disk_t *diskp, uchar_t page_code, void *pagebuf, 1351 uint16_t pagelen, int page_control) 1352 { 1353 struct uscsi_cmd ucmd_buf; 1354 uchar_t cdb_buf[CDB_GROUP1]; 1355 struct scsi_extended_sense sense_buf; 1356 int ret_val; 1357 1358 bzero(&cdb_buf, sizeof (cdb_buf)); 1359 bzero(&ucmd_buf, sizeof (ucmd_buf)); 1360 bzero(&sense_buf, sizeof (sense_buf)); 1361 1362 cdb_buf[0] = SCMD_LOG_SENSE_G1; 1363 1364 /* 1365 * For SATA we need to have the current threshold value set. 1366 * For SAS drives we can use the current cumulative value. 1367 * This is set for non-SMART drives, by passing a non-zero 1368 * page_control. 1369 */ 1370 if (page_control) 1371 cdb_buf[2] = (0x01 << 6) | page_code; 1372 else 1373 cdb_buf[2] = page_code; 1374 1375 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8); 1376 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF); 1377 1378 ucmd_buf.uscsi_cdb = (char *)cdb_buf; 1379 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf); 1380 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf; 1381 ucmd_buf.uscsi_buflen = pagelen; 1382 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; 1383 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); 1384 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT; 1385 ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT; 1386 1387 ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf); 1388 if ((ret_val == 0) && (ucmd_buf.uscsi_status == 0)) { 1389 if (env_debug) 1390 envd_log(LOG_ERR, 1391 "log sense command for page_code 0x%x succeeded\n", page_code); 1392 return (ret_val); 1393 } 1394 if (env_debug) 1395 envd_log(LOG_ERR, "log sense command for %s failed. " 1396 "page_code 0x%x ret_val = 0x%x " 1397 "status = 0x%x errno = 0x%x\n", diskp->name, page_code, 1398 ret_val, ucmd_buf.uscsi_status, errno); 1399 1400 return (1); 1401 } 1402 1403 1404 static int 1405 get_disk_temp(env_disk_t *diskp) 1406 { 1407 int ret; 1408 uchar_t tpage[256]; 1409 1410 if (diskp->smart_supported == B_TRUE) { 1411 smart_structure smartpage; 1412 smart_attribute *temp_attrib = NULL; 1413 uint8_t checksum; 1414 uint8_t *index; 1415 int i; 1416 1417 bzero(&smartpage, sizeof (smartpage)); 1418 1419 ret = scsi_log_sense(diskp, GET_SMART_INFO, 1420 &smartpage, sizeof (smartpage), 0); 1421 1422 if (ret != 0) { 1423 diskp->current_temp = DISK_INVALID_TEMP; 1424 diskp->ref_temp = DISK_INVALID_TEMP; 1425 return (-1); 1426 } 1427 1428 /* 1429 * verify the checksum of the data. A 2's compliment 1430 * of the result addition of the is stored in the 1431 * last byte. The sum of all the checksum should be 1432 * 0. If the checksum is bad, return an error for 1433 * this iteration. 1434 */ 1435 index = (uint8_t *)&smartpage; 1436 1437 for (i = checksum = 0; i < 512; i++) 1438 checksum += index[i]; 1439 1440 if ((checksum != 0) && env_debug) { 1441 envd_log(LOG_ERR, 1442 "SMART checksum error! 0x%x\n", checksum); 1443 1444 /* 1445 * We got bad data back from the drive, fail this 1446 * time around and picl will retry again. If this 1447 * continues to fail picl will give this drive a 1448 * failed status. 1449 */ 1450 diskp->current_temp = DISK_INVALID_TEMP; 1451 diskp->ref_temp = DISK_INVALID_TEMP; 1452 1453 return (-1); 1454 } 1455 1456 /* 1457 * Scan through the various SMART data and look for 1458 * the complete drive temp. 1459 */ 1460 1461 for (i = 0; (i < SMART_FIELDS) && 1462 (smartpage.attribute[i].id != 0) && 1463 (temp_attrib == NULL); i++) { 1464 1465 if (smartpage.attribute[i].id == HDA_TEMP) { 1466 temp_attrib = &smartpage.attribute[i]; 1467 } 1468 } 1469 1470 /* 1471 * If we dont find any temp SMART attributes, this drive 1472 * does not support this page, disable temp checking 1473 * for this drive. 1474 */ 1475 if (temp_attrib == NULL) { 1476 1477 /* 1478 * If the checksum is valid, the temp. attributes are 1479 * not supported, disable this drive from temp. 1480 * checking. 1481 */ 1482 if (env_debug) 1483 envd_log(LOG_ERR, 1484 "Temp ATTRIBUTE not supported\n"); 1485 diskp->smart_supported = B_FALSE; 1486 diskp->tpage_supported = B_FALSE; 1487 diskp->current_temp = DISK_INVALID_TEMP; 1488 diskp->ref_temp = DISK_INVALID_TEMP; 1489 1490 return (-1); 1491 } 1492 1493 if (env_debug) { 1494 envd_log(LOG_ERR, "flags = 0x%x%x,curr = 0x%x," 1495 "data = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 1496 temp_attrib->flags[0], temp_attrib->flags[1], 1497 temp_attrib->raw_data[0], temp_attrib->raw_data[1], 1498 temp_attrib->raw_data[2], temp_attrib->raw_data[3], 1499 temp_attrib->raw_data[4], temp_attrib->raw_data[5], 1500 temp_attrib->raw_data[6], temp_attrib->raw_data[7]); 1501 } 1502 if (temp_attrib->raw_data[1] != 0xFF) { 1503 diskp->current_temp = temp_attrib->raw_data[2]; 1504 diskp->ref_temp = temp_attrib->raw_data[2]; 1505 } else { 1506 diskp->ref_temp = DISK_INVALID_TEMP; 1507 diskp->current_temp = DISK_INVALID_TEMP; 1508 1509 return (-1); 1510 } 1511 1512 } else { 1513 ret = scsi_log_sense(diskp, TEMPERATURE_PAGE, tpage, 1514 sizeof (tpage), 1); 1515 1516 if (ret != 0) { 1517 diskp->current_temp = DISK_INVALID_TEMP; 1518 diskp->ref_temp = DISK_INVALID_TEMP; 1519 return (-1); 1520 } 1521 /* 1522 * For the current temperature verify that the parameter 1523 * length is 0x02 and the parameter code is 0x00 1524 * Temperature value of 255(0xFF) is considered INVALID. 1525 */ 1526 if ((tpage[7] == 0x02) && (tpage[4] == 0x00) && 1527 (tpage[5] == 0x00)) { 1528 if (tpage[9] == 0xFF) { 1529 diskp->current_temp = DISK_INVALID_TEMP; 1530 return (-1); 1531 } else { 1532 diskp->current_temp = tpage[9]; 1533 } 1534 } 1535 1536 /* 1537 * For the reference temperature verify that the parameter 1538 * length is 0x02 and the parameter code is 0x01 1539 * Temperature value of 255(0xFF) is considered INVALID. 1540 */ 1541 if ((tpage[13] == 0x02) && (tpage[10] == 0x00) && 1542 (tpage[11] == 0x01)) { 1543 if (tpage[15] == 0xFF) { 1544 diskp->ref_temp = DISK_INVALID_TEMP; 1545 } else { 1546 diskp->ref_temp = tpage[15]; 1547 } 1548 } 1549 } 1550 return (0); 1551 } 1552 1553 /* ARGSUSED */ 1554 static void * 1555 disk_temp_thr(void *args) 1556 { 1557 char syscmd[BUFSIZ]; 1558 char msgbuf[BUFSIZ]; 1559 timespec_t to; 1560 int ret, i; 1561 env_disk_t *diskp; 1562 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1563 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1564 pm_state_change_t pmstate; 1565 int idle_time; 1566 int disk_pm_fd; 1567 time_t ct; 1568 1569 if ((disk_pm_fd = open(PM_DEVICE, O_RDWR)) == -1) { 1570 envd_log(LOG_ERR, DISK_TEMP_THREAD_EXITING, 1571 errno, strerror(errno)); 1572 return (NULL); 1573 } 1574 1575 for (;;) { 1576 /* 1577 * Sleep for specified seconds before issuing IOCTL 1578 * again. 1579 */ 1580 (void) pthread_mutex_lock(&env_monitor_mutex); 1581 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1582 &env_monitor_mutex, &to); 1583 1584 to.tv_sec = disk_scan_interval; 1585 to.tv_nsec = 0; 1586 1587 if (ret != ETIMEDOUT) { 1588 (void) pthread_mutex_unlock( 1589 &env_monitor_mutex); 1590 continue; 1591 } 1592 (void) pthread_mutex_unlock(&env_monitor_mutex); 1593 1594 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 1595 if (diskp->present == B_FALSE) 1596 continue; 1597 if (diskp->tpage_supported == B_FALSE) 1598 continue; 1599 /* 1600 * If the disk temperature is above the warning threshold 1601 * continue monitoring until the temperature drops below 1602 * warning threshold. 1603 * if the temperature is in the NORMAL range monitor only 1604 * when the disk is BUSY. 1605 * We do not want to read the disk temperature if the disk is 1606 * is idling. The reason for this is disk will never get into 1607 * lowest power mode if we scan the disk temperature 1608 * peridoically. To avoid this situation we first determine 1609 * the idle_time of the disk. If the disk has been IDLE since 1610 * we scanned the temperature last time we will not read the 1611 * temperature. 1612 */ 1613 if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 1614 pmstate.physpath = diskp->physpath; 1615 pmstate.size = strlen(diskp->physpath); 1616 pmstate.component = 0; 1617 if ((idle_time = 1618 ioctl(disk_pm_fd, PM_GET_TIME_IDLE, 1619 &pmstate)) == -1) { 1620 1621 if (errno != EINTR) { 1622 if (env_debug) 1623 envd_log(LOG_ERR, 1624 "ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n", 1625 errno); 1626 continue; 1627 } 1628 continue; 1629 } 1630 if (idle_time >= (disk_scan_interval/2)) { 1631 if (env_debug) { 1632 envd_log(LOG_ERR, "%s idle time = %d\n", 1633 diskp->name, idle_time); 1634 } 1635 continue; 1636 } 1637 } 1638 ret = get_disk_temp(diskp); 1639 if (ret != 0) 1640 continue; 1641 if (env_debug) { 1642 envd_log(LOG_ERR, "%s temp = %d ref. temp = %d\n", 1643 diskp->name, diskp->current_temp, diskp->ref_temp); 1644 } 1645 /* 1646 * If this disk already triggered system shutdown, don't 1647 * log any more shutdown/warning messages for it. 1648 */ 1649 if (diskp->shutdown_initiated) 1650 continue; 1651 1652 /* 1653 * Check for the temperature in warning and shutdown range 1654 * and take appropriate action. 1655 */ 1656 if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 1657 /* 1658 * Check if the temperature has been in warning 1659 * range during last disk_warning_duration interval. 1660 * If so, the temperature is truly in warning 1661 * range and we need to log a warning message, 1662 * but no more than once every disk_warning_interval 1663 * seconds. 1664 */ 1665 time_t wtstamp = diskp->warning_tstamp; 1666 1667 ct = (time_t)(gethrtime() / NANOSEC); 1668 if (diskp->warning_start == 0) 1669 diskp->warning_start = ct; 1670 if (((ct - diskp->warning_start) >= 1671 disk_warning_duration) && (wtstamp == 0 || 1672 (ct - wtstamp) >= disk_warning_interval)) { 1673 envd_log(LOG_CRIT, ENV_WARNING_MSG, 1674 diskp->name, diskp->current_temp, 1675 diskp->low_warning, 1676 diskp->high_warning); 1677 diskp->warning_tstamp = ct; 1678 } 1679 } else if (diskp->warning_start != 0) 1680 diskp->warning_start = 0; 1681 1682 if (!shutdown_override && 1683 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) { 1684 ct = (time_t)(gethrtime() / NANOSEC); 1685 if (diskp->shutdown_tstamp == 0) 1686 diskp->shutdown_tstamp = ct; 1687 1688 /* 1689 * Shutdown the system if the temperature remains 1690 * in the shutdown range for over disk_shutdown_interval 1691 * seconds. 1692 */ 1693 if ((ct - diskp->shutdown_tstamp) >= 1694 disk_shutdown_interval) { 1695 /* log error */ 1696 diskp->shutdown_initiated = B_TRUE; 1697 (void) snprintf(msgbuf, sizeof (msgbuf), 1698 ENV_SHUTDOWN_MSG, diskp->name, 1699 diskp->current_temp, diskp->low_shutdown, 1700 diskp->high_shutdown); 1701 envd_log(LOG_ALERT, msgbuf); 1702 1703 /* shutdown the system (only once) */ 1704 if (system_shutdown_started == B_FALSE) { 1705 (void) snprintf(syscmd, sizeof (syscmd), 1706 "%s \"%s\"", shutdown_cmd, msgbuf); 1707 envd_log(LOG_ALERT, syscmd); 1708 system_shutdown_started = B_TRUE; 1709 (void) system(syscmd); 1710 } 1711 } 1712 } else if (diskp->shutdown_tstamp != 0) 1713 diskp->shutdown_tstamp = 0; 1714 } 1715 } /* end of forever loop */ 1716 } 1717 1718 static void * 1719 fan_thr(void *args) 1720 { 1721 char msgbuf[BUFSIZ]; 1722 timespec_t to; 1723 int ret, i; 1724 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1725 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1726 env_fan_t *fanp; 1727 1728 #ifdef __lint 1729 args = args; 1730 #endif 1731 1732 for (;;) { 1733 /* 1734 * Sleep for specified seconds before issuing IOCTL 1735 * again. 1736 */ 1737 (void) pthread_mutex_lock(&env_monitor_mutex); 1738 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1739 &env_monitor_mutex, &to); 1740 to.tv_sec = fan_scan_interval; 1741 to.tv_nsec = 0; 1742 if (ret != ETIMEDOUT) { 1743 (void) pthread_mutex_unlock(&env_monitor_mutex); 1744 continue; 1745 } 1746 (void) pthread_mutex_unlock(&env_monitor_mutex); 1747 1748 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 1749 if (fanp->present == B_FALSE) 1750 continue; 1751 1752 if (has_fan_failed(fanp) == B_TRUE) { 1753 if (fanp->last_status == FAN_FAILED) 1754 continue; 1755 fanp->last_status = FAN_FAILED; 1756 (void) snprintf(msgbuf, sizeof (msgbuf), 1757 ENV_FAN_FAILURE_WARNING_MSG, fanp->name, 1758 fan_rpm_string, fan_status_string); 1759 envd_log(LOG_ALERT, msgbuf); 1760 } else { 1761 if (fanp->last_status == FAN_OK) 1762 continue; 1763 fanp->last_status = FAN_OK; 1764 (void) snprintf(msgbuf, sizeof (msgbuf), 1765 ENV_FAN_OK_MSG, fanp->name); 1766 envd_log(LOG_ALERT, msgbuf); 1767 } 1768 } 1769 1770 if (has_psufan_failed() == B_TRUE) { 1771 if (psufan_last_status == FAN_FAILED) 1772 continue; 1773 psufan_last_status = FAN_FAILED; 1774 (void) snprintf(msgbuf, sizeof (msgbuf), 1775 ENV_FAN_FAILURE_WARNING_MSG, SENSOR_PSU, 1776 fan_rpm_string, fan_status_string); 1777 envd_log(LOG_ALERT, msgbuf); 1778 } else { 1779 if (psufan_last_status == FAN_OK) 1780 continue; 1781 psufan_last_status = FAN_OK; 1782 (void) snprintf(msgbuf, sizeof (msgbuf), 1783 ENV_FAN_OK_MSG, SENSOR_PSU); 1784 envd_log(LOG_ALERT, msgbuf); 1785 } 1786 } 1787 1788 /*NOTREACHED*/ 1789 return (NULL); 1790 } 1791 1792 /* 1793 * Setup envrionmental monitor state and start threads to monitor 1794 * temperature, fan, disk and power management state. 1795 * Returns -1 on error, 0 if successful. 1796 */ 1797 static int 1798 envd_setup(void) 1799 { 1800 1801 if (getenv("SUNW_piclenvd_debug") != NULL) 1802 env_debug = 1; 1803 1804 if (pthread_attr_init(&thr_attr) != 0 || 1805 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) { 1806 return (-1); 1807 } 1808 1809 /* 1810 * If ES segment is not present or has inconsistent information, we 1811 * use default values for sensor limits. For the sake of simplicity, 1812 * we still store these limits internally in the 'es' member in the 1813 * structure. 1814 */ 1815 if (envd_es_setup() < 0) { 1816 envd_log(LOG_WARNING, ENV_DEFAULT_LIMITS); 1817 envd_es_default_setup(); 1818 } 1819 1820 if (envd_setup_sensors() < 0) { 1821 if (env_debug) 1822 envd_log(LOG_ERR, "Failed to setup sensors\n"); 1823 system_temp_monitor = 0; 1824 } 1825 1826 if (envd_setup_fans() < 0) { 1827 if (env_debug) 1828 envd_log(LOG_ERR, "Failed to setup fans\n"); 1829 fan_monitor = 0; 1830 pm_monitor = 0; 1831 } 1832 1833 /* 1834 * Disable disk temperature monitoring until we have 1835 * LSI fw support to read SATA disk temperature 1836 */ 1837 if (disk_temp_monitor) { 1838 if (envd_setup_disks() < 0) { 1839 if (env_debug) 1840 envd_log(LOG_ERR, "Failed to setup disks\n"); 1841 disk_temp_monitor = 0; 1842 } 1843 } 1844 1845 /* 1846 * Create a thread to monitor system temperatures 1847 */ 1848 if ((system_temp_monitor) && (system_temp_thr_created == B_FALSE)) { 1849 if (pthread_create(&system_temp_thr_id, &thr_attr, 1850 system_temp_thr, NULL) != 0) { 1851 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1852 } else { 1853 system_temp_thr_created = B_TRUE; 1854 if (env_debug) 1855 envd_log(LOG_ERR, 1856 "Created thread to monitor system temperatures\n"); 1857 } 1858 } 1859 1860 /* 1861 * Create a thread to monitor fans 1862 */ 1863 if ((fan_monitor) && (fan_thr_created == B_FALSE)) { 1864 if (pthread_create(&fan_thr_id, &thr_attr, fan_thr, NULL) != 0) 1865 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1866 else { 1867 fan_thr_created = B_TRUE; 1868 if (env_debug) { 1869 envd_log(LOG_ERR, 1870 "Created thread to monitor system fans\n"); 1871 } 1872 } 1873 } 1874 1875 /* 1876 * Create a thread to monitor PM state 1877 */ 1878 if ((pm_monitor) && (pmthr_created == B_FALSE)) { 1879 if (pthread_create(&pmthr_tid, &thr_attr, pmthr, NULL) != 0) 1880 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); 1881 else { 1882 pmthr_created = B_TRUE; 1883 if (env_debug) 1884 envd_log(LOG_ERR, 1885 "Created thread to monitor system power state\n"); 1886 } 1887 } 1888 1889 /* 1890 * Create a thread to monitor disk temperature 1891 */ 1892 if ((disk_temp_monitor) && (disk_temp_thr_created == B_FALSE)) { 1893 if (pthread_create(&disk_temp_thr_id, &thr_attr, 1894 disk_temp_thr, NULL) != 0) { 1895 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1896 } else { 1897 disk_temp_thr_created = B_TRUE; 1898 if (env_debug) 1899 envd_log(LOG_ERR, 1900 "Created thread for disk temperatures\n"); 1901 } 1902 } 1903 1904 return (0); 1905 } 1906 1907 static void 1908 piclenvd_register(void) 1909 { 1910 picld_plugin_register(&my_reg_info); 1911 } 1912 1913 static void 1914 piclenvd_init(void) 1915 { 1916 1917 (void) env_picl_setup_tuneables(); 1918 1919 /* 1920 * Do not allow disk temperature monitoring to be enabled 1921 * via tuneables. Disk temperature monitoring is disabled 1922 * until we have LSI fw support to read the temperature of 1923 * SATA disks 1924 */ 1925 disk_temp_monitor = 0; 1926 1927 /* 1928 * Setup the environmental data structures 1929 */ 1930 if (envd_setup() != 0) { 1931 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); 1932 return; 1933 } 1934 1935 /* 1936 * Now setup/populate PICL tree 1937 */ 1938 env_picl_setup(); 1939 } 1940 1941 static void 1942 piclenvd_fini(void) 1943 { 1944 1945 /* 1946 * Invoke env_picl_destroy() to remove any PICL nodes/properties 1947 * (including volatile properties) we created. Once this call 1948 * returns, there can't be any more calls from the PICL framework 1949 * to get current temperature or fan speed. 1950 */ 1951 env_picl_destroy(); 1952 envd_close_sensors(); 1953 envd_close_fans(); 1954 } 1955 1956 /*VARARGS2*/ 1957 void 1958 envd_log(int pri, const char *fmt, ...) 1959 { 1960 va_list ap; 1961 1962 va_start(ap, fmt); 1963 vsyslog(pri, fmt, ap); 1964 va_end(ap); 1965 } 1966 1967 /* 1968 * Tunables support functions 1969 */ 1970 static env_tuneable_t * 1971 tuneable_lookup(picl_prophdl_t proph) 1972 { 1973 int i; 1974 env_tuneable_t *tuneablep = NULL; 1975 1976 for (i = 0; i < ntuneables; i++) { 1977 tuneablep = &tuneables[i]; 1978 if (tuneablep->proph == proph) 1979 return (tuneablep); 1980 } 1981 1982 return (NULL); 1983 } 1984 1985 static int 1986 get_string_val(ptree_rarg_t *parg, void *buf) 1987 { 1988 picl_prophdl_t proph; 1989 env_tuneable_t *tuneablep; 1990 1991 proph = parg->proph; 1992 1993 tuneablep = tuneable_lookup(proph); 1994 1995 if (tuneablep == NULL) 1996 return (PICL_FAILURE); 1997 1998 (void) memcpy(buf, tuneablep->value, tuneablep->nbytes); 1999 2000 return (PICL_SUCCESS); 2001 } 2002 2003 static int 2004 set_string_val(ptree_warg_t *parg, const void *buf) 2005 { 2006 picl_prophdl_t proph; 2007 env_tuneable_t *tuneablep; 2008 2009 if (parg->cred.dc_euid != 0) 2010 return (PICL_PERMDENIED); 2011 2012 proph = parg->proph; 2013 2014 tuneablep = tuneable_lookup(proph); 2015 2016 if (tuneablep == NULL) 2017 return (PICL_FAILURE); 2018 2019 (void) memcpy(tuneables->value, buf, tuneables->nbytes); 2020 2021 2022 return (PICL_SUCCESS); 2023 } 2024 2025 static int 2026 get_int_val(ptree_rarg_t *parg, void *buf) 2027 { 2028 picl_prophdl_t proph; 2029 env_tuneable_t *tuneablep; 2030 2031 proph = parg->proph; 2032 2033 tuneablep = tuneable_lookup(proph); 2034 2035 if (tuneablep == NULL) 2036 return (PICL_FAILURE); 2037 2038 (void) memcpy(buf, tuneablep->value, tuneablep->nbytes); 2039 2040 return (PICL_SUCCESS); 2041 } 2042 2043 static int 2044 set_int_val(ptree_warg_t *parg, const void *buf) 2045 { 2046 picl_prophdl_t proph; 2047 env_tuneable_t *tuneablep; 2048 2049 if (parg->cred.dc_euid != 0) 2050 return (PICL_PERMDENIED); 2051 2052 proph = parg->proph; 2053 2054 tuneablep = tuneable_lookup(proph); 2055 2056 if (tuneablep == NULL) 2057 return (PICL_FAILURE); 2058 2059 (void) memcpy(tuneablep->value, buf, tuneablep->nbytes); 2060 2061 return (PICL_SUCCESS); 2062 } 2063 2064 boolean_t 2065 has_fan_failed(env_fan_t *fanp) 2066 { 2067 fanspeed_t fan_speed; 2068 uchar_t status; 2069 uint8_t tach; 2070 int real_tach; 2071 int ret, ntries; 2072 2073 if (fanp->fd == -1) 2074 return (B_TRUE); 2075 2076 /* 2077 * Read RF_FAN_STATUS bit of the fan fault register, retry if 2078 * the PIC is busy, with a 1 second delay to allow it to update. 2079 */ 2080 for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) { 2081 ret = ioctl(fanp->fd, PIC_GET_FAN_STATUS, &status); 2082 if ((ret == 0) && ((status & 0x1) == 0)) 2083 break; 2084 (void) sleep(1); 2085 } 2086 2087 if (ntries > 0) { 2088 if (env_debug) { 2089 envd_log(LOG_ERR, 2090 "%d retries attempted in reading fan status.\n", 2091 ntries); 2092 } 2093 } 2094 2095 if (ntries == MAX_RETRIES_FOR_FAN_FAULT) { 2096 (void) strncpy(fan_status_string, NOT_AVAILABLE, 2097 sizeof (fan_status_string)); 2098 (void) strncpy(fan_rpm_string, NOT_AVAILABLE, 2099 sizeof (fan_rpm_string)); 2100 return (B_TRUE); 2101 } 2102 2103 if (env_debug) 2104 envd_log(LOG_ERR, "fan status = 0x%x\n", status); 2105 2106 /* 2107 * ST_FFAULT bit isn't implemented yet and we're reading only 2108 * individual fan status 2109 */ 2110 if (status & 0x1) { 2111 (void) snprintf(fan_status_string, sizeof (fan_status_string), 2112 "0x%x", status); 2113 if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) != 0) { 2114 (void) strncpy(fan_rpm_string, NOT_AVAILABLE, 2115 sizeof (fan_rpm_string)); 2116 } else { 2117 real_tach = tach << 8; 2118 fan_speed = TACH_TO_RPM(real_tach); 2119 (void) snprintf(fan_rpm_string, sizeof (fan_rpm_string), 2120 "%d", fan_speed); 2121 } 2122 return (B_TRUE); 2123 } 2124 2125 return (B_FALSE); 2126 } 2127 2128 boolean_t 2129 has_psufan_failed(void) 2130 { 2131 uchar_t status; 2132 int ret, ntries; 2133 2134 if (envd_sensor_psu.fd == -1) 2135 return (B_FALSE); 2136 2137 /* 2138 * For psu, only fan fault is visible, no fan speed 2139 */ 2140 (void) strncpy(fan_rpm_string, NOT_AVAILABLE, sizeof (fan_rpm_string)); 2141 2142 /* 2143 * Read RF_FAN_STATUS bit of the fan fault register, retry if 2144 * the PIC is busy, with a 1 second delay to allow it to update. 2145 */ 2146 for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) { 2147 ret = ioctl(envd_sensor_psu.fd, PIC_GET_FAN_STATUS, &status); 2148 if ((ret == 0) && ((status & 0x1) == 0)) 2149 break; 2150 (void) sleep(1); 2151 } 2152 2153 if (ntries > 0) { 2154 if (env_debug) { 2155 envd_log(LOG_ERR, 2156 "%d retries attempted in reading fan status.\n", 2157 ntries); 2158 } 2159 } 2160 2161 if (ntries == MAX_RETRIES_FOR_FAN_FAULT) { 2162 (void) strncpy(fan_status_string, NOT_AVAILABLE, 2163 sizeof (fan_status_string)); 2164 return (B_TRUE); 2165 } 2166 2167 if (env_debug) 2168 envd_log(LOG_ERR, "fan status = 0x%x\n", status); 2169 2170 if (status & 0x1) { 2171 (void) snprintf(fan_status_string, sizeof (fan_status_string), 2172 "0x%x", status); 2173 return (B_TRUE); 2174 } 2175 2176 return (B_FALSE); 2177 } 2178 2179 static int 2180 scsi_mode_select(env_disk_t *diskp, uchar_t page_code, uchar_t *pagebuf, 2181 uint16_t pagelen) 2182 { 2183 struct uscsi_cmd ucmd_buf; 2184 uchar_t cdb_buf[CDB_GROUP1]; 2185 struct scsi_extended_sense sense_buf; 2186 int ret_val; 2187 2188 bzero(&cdb_buf, sizeof (cdb_buf)); 2189 bzero(&ucmd_buf, sizeof (ucmd_buf)); 2190 bzero(&sense_buf, sizeof (sense_buf)); 2191 2192 cdb_buf[0] = SCMD_MODE_SELECT_G1; 2193 cdb_buf[1] = 1<<PAGE_FMT; 2194 2195 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8); 2196 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF); 2197 2198 ucmd_buf.uscsi_cdb = (char *)cdb_buf; 2199 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf); 2200 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf; 2201 ucmd_buf.uscsi_buflen = pagelen; 2202 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; 2203 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); 2204 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_WRITE | USCSI_SILENT; 2205 ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT; 2206 2207 ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf); 2208 2209 if (ret_val == 0 && ucmd_buf.uscsi_status == 0) { 2210 return (ret_val); 2211 } 2212 if (env_debug) 2213 envd_log(LOG_ERR, "mode select command for %s failed. " 2214 "page_code 0x%x ret_val = 0x%x " 2215 "status = 0x%x errno = 0x%x\n", diskp->name, page_code, 2216 ret_val, ucmd_buf.uscsi_status, errno); 2217 2218 return (1); 2219 2220 } 2221