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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the environmental PICL plug-in module. 31 */ 32 33 /* 34 * This plugin sets up the PICLTREE for Chicago WS. 35 * It provides functionality to get/set temperatures and 36 * fan speeds. 37 * 38 * The environmental policy defaults to the auto mode 39 * as programmed by OBP at boot time. 40 */ 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <sys/sysmacros.h> 45 #include <limits.h> 46 #include <string.h> 47 #include <strings.h> 48 #include <stdarg.h> 49 #include <alloca.h> 50 #include <unistd.h> 51 #include <sys/processor.h> 52 #include <syslog.h> 53 #include <errno.h> 54 #include <fcntl.h> 55 #include <picl.h> 56 #include <picltree.h> 57 #include <picldefs.h> 58 #include <pthread.h> 59 #include <signal.h> 60 #include <libdevinfo.h> 61 #include <sys/pm.h> 62 #include <sys/open.h> 63 #include <sys/time.h> 64 #include <sys/utsname.h> 65 #include <sys/systeminfo.h> 66 #include <note.h> 67 #include <sys/pic16f747.h> 68 #include "envd.h" 69 #include <sys/scsi/scsi.h> 70 #include <sys/scsi/generic/commands.h> 71 72 int debug_fd; 73 /* 74 * PICL plugin entry points 75 */ 76 static void piclenvd_register(void); 77 static void piclenvd_init(void); 78 static void piclenvd_fini(void); 79 80 /* 81 * Env setup routines 82 */ 83 extern void env_picl_setup(void); 84 extern void env_picl_destroy(void); 85 extern int env_picl_setup_tuneables(void); 86 87 static boolean_t has_fan_failed(env_fan_t *fanp); 88 89 #pragma init(piclenvd_register) 90 91 /* 92 * Plugin registration information 93 */ 94 static picld_plugin_reg_t my_reg_info = { 95 PICLD_PLUGIN_VERSION, 96 PICLD_PLUGIN_CRITICAL, 97 "SUNW_piclenvd", 98 piclenvd_init, 99 piclenvd_fini, 100 }; 101 102 #define REGISTER_INFORMATION_STRING_LENGTH 16 103 static char fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 104 static char fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 105 106 static int scsi_log_sense(env_disk_t *diskp, uchar_t page_code, 107 uchar_t *pagebuf, uint16_t pagelen); 108 static int get_disk_temp(env_disk_t *); 109 110 /* 111 * Env thread variables 112 */ 113 static boolean_t system_shutdown_started = B_FALSE; 114 static boolean_t system_temp_thr_created = B_FALSE; 115 static pthread_t system_temp_thr_id; 116 static pthread_attr_t thr_attr; 117 static boolean_t disk_temp_thr_created = B_FALSE; 118 static pthread_t disk_temp_thr_id; 119 static boolean_t fan_thr_created = B_FALSE; 120 static pthread_t fan_thr_id; 121 122 /* 123 * PM thread related variables 124 */ 125 static pthread_t pmthr_tid; /* pmthr thread ID */ 126 static int pm_fd = -1; /* PM device file descriptor */ 127 static boolean_t pmthr_created = B_FALSE; 128 static int cur_lpstate; /* cur low power state */ 129 130 /* 131 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var 132 * Setting the verbose tuneable also enables debugging for better 133 * control 134 */ 135 int env_debug = 0; 136 137 /* 138 * These are debug variables for keeping track of the total number 139 * of Fan and Temp sensor retries over the lifetime of the plugin. 140 */ 141 static int total_fan_retries = 0; 142 static int total_temp_retries = 0; 143 144 /* 145 * Fan devices 146 */ 147 static env_fan_t envd_system_fan0 = { 148 ENV_SYSTEM_FAN0, ENV_SYSTEM_FAN0_DEVFS, SYSTEM_FAN0_ID, 149 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 150 }; 151 static env_fan_t envd_system_fan1 = { 152 ENV_SYSTEM_FAN1, ENV_SYSTEM_FAN1_DEVFS, SYSTEM_FAN1_ID, 153 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 154 }; 155 static env_fan_t envd_system_fan2 = { 156 ENV_SYSTEM_FAN2, ENV_SYSTEM_FAN2_DEVFS, SYSTEM_FAN2_ID, 157 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 158 }; 159 static env_fan_t envd_system_fan3 = { 160 ENV_SYSTEM_FAN3, ENV_SYSTEM_FAN3_DEVFS, SYSTEM_FAN3_ID, 161 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 162 }; 163 static env_fan_t envd_system_fan4 = { 164 ENV_SYSTEM_FAN4, ENV_SYSTEM_FAN4_DEVFS, SYSTEM_FAN4_ID, 165 SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1, 166 }; 167 168 /* 169 * Disk devices 170 */ 171 static env_disk_t envd_disk0 = { 172 ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH, 173 DISK0_ID, -1, 174 }; 175 static env_disk_t envd_disk1 = { 176 ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH, 177 DISK1_ID, -1, 178 }; 179 static env_disk_t envd_disk2 = { 180 ENV_DISK2, ENV_DISK2_DEVFS, DISK2_PHYSPATH, DISK2_NODE_PATH, 181 DISK2_ID, -1, 182 }; 183 static env_disk_t envd_disk3 = { 184 ENV_DISK3, ENV_DISK3_DEVFS, DISK3_PHYSPATH, DISK3_NODE_PATH, 185 DISK3_ID, -1, 186 }; 187 188 /* 189 * Sensors 190 */ 191 static env_sensor_t envd_sensor_cpu0 = { 192 SENSOR_CPU0, SENSOR_CPU0_DEVFS, CPU0_SENSOR_ID, -1, 193 CPU0_HIGH_SHUTDOWN, CPU0_HIGH_WARNING, CPU0_LOW_WARNING, 194 CPU0_LOW_SHUTDOWN, CPU0_LOW_POWER_OFF, CPU0_HIGH_POWER_OFF, 195 }; 196 static env_sensor_t envd_sensor_cpu1 = { 197 SENSOR_CPU1, SENSOR_CPU1_DEVFS, CPU1_SENSOR_ID, -1, 198 CPU1_HIGH_SHUTDOWN, CPU1_HIGH_WARNING, CPU1_LOW_WARNING, 199 CPU1_LOW_SHUTDOWN, CPU1_LOW_POWER_OFF, CPU1_HIGH_POWER_OFF, 200 }; 201 static env_sensor_t envd_sensor_adt7462 = { 202 SENSOR_ADT7462, SENSOR_ADT7462_DEVFS, ADT7462_SENSOR_ID, -1, 203 ADT7462_HIGH_SHUTDOWN, ADT7462_HIGH_WARNING, ADT7462_LOW_WARNING, 204 ADT7462_LOW_SHUTDOWN, ADT7462_LOW_POWER_OFF, ADT7462_HIGH_POWER_OFF, 205 }; 206 static env_sensor_t envd_sensor_mb = { 207 SENSOR_MB, SENSOR_MB_DEVFS, MB_SENSOR_ID, -1, 208 MB_HIGH_SHUTDOWN, MB_HIGH_WARNING, MB_LOW_WARNING, 209 MB_LOW_SHUTDOWN, MB_LOW_POWER_OFF, MB_HIGH_POWER_OFF, 210 }; 211 static env_sensor_t envd_sensor_lm95221 = { 212 SENSOR_LM95221, SENSOR_LM95221_DEVFS, LM95221_SENSOR_ID, -1, 213 LM95221_HIGH_SHUTDOWN, LM95221_HIGH_WARNING, LM95221_LOW_WARNING, 214 LM95221_LOW_SHUTDOWN, LM95221_LOW_POWER_OFF, LM95221_HIGH_POWER_OFF, 215 }; 216 static env_sensor_t envd_sensor_fire = { 217 SENSOR_FIRE, SENSOR_FIRE_DEVFS, FIRE_SENSOR_ID, -1, 218 FIRE_HIGH_SHUTDOWN, FIRE_HIGH_WARNING, FIRE_LOW_WARNING, 219 FIRE_LOW_SHUTDOWN, FIRE_LOW_POWER_OFF, FIRE_HIGH_POWER_OFF, 220 }; 221 static env_sensor_t envd_sensor_lsi1064 = { 222 SENSOR_LSI1064, SENSOR_LSI1064_DEVFS, LSI1064_SENSOR_ID, -1, 223 LSI1064_HIGH_SHUTDOWN, LSI1064_HIGH_WARNING, LSI1064_LOW_WARNING, 224 LSI1064_LOW_SHUTDOWN, LSI1064_LOW_POWER_OFF, LSI1064_HIGH_POWER_OFF, 225 }; 226 static env_sensor_t envd_sensor_front_panel = { 227 SENSOR_FRONT_PANEL, SENSOR_FRONT_PANEL_DEVFS, FRONT_PANEL_SENSOR_ID, -1, 228 FRONT_PANEL_HIGH_SHUTDOWN, FRONT_PANEL_HIGH_WARNING, 229 FRONT_PANEL_LOW_WARNING, FRONT_PANEL_LOW_SHUTDOWN, 230 FRONT_PANEL_LOW_POWER_OFF, FRONT_PANEL_HIGH_POWER_OFF, 231 }; 232 233 /* 234 * The vendor-id and device-id are the properties associated with 235 * the SCSI controller. This is used to identify a particular controller 236 * like LSI1064. 237 */ 238 #define VENDOR_ID "vendor-id" 239 #define DEVICE_ID "device-id" 240 241 /* 242 * The implementation for SCSI disk drives to supply info. about 243 * temperature is not mandatory. Hence we first determine if the 244 * temperature page is supported. To do this we need to scan the list 245 * of pages supported. 246 */ 247 #define SUPPORTED_LPAGES 0 248 #define TEMPERATURE_PAGE 0x0D 249 #define LOGPAGEHDRSIZE 4 250 251 /* 252 * NULL terminated array of fans 253 */ 254 static env_fan_t *envd_fans[] = { 255 &envd_system_fan0, 256 &envd_system_fan1, 257 &envd_system_fan2, 258 &envd_system_fan3, 259 &envd_system_fan4, 260 NULL 261 }; 262 263 /* 264 * NULL terminated array of disks 265 */ 266 static env_disk_t *envd_disks[] = { 267 &envd_disk0, 268 &envd_disk1, 269 &envd_disk2, 270 &envd_disk3, 271 NULL 272 }; 273 274 /* 275 * NULL terminated array of temperature sensors 276 */ 277 #define N_ENVD_SENSORS 8 278 static env_sensor_t *envd_sensors[] = { 279 &envd_sensor_cpu0, 280 &envd_sensor_cpu1, 281 &envd_sensor_adt7462, 282 &envd_sensor_mb, 283 &envd_sensor_lm95221, 284 &envd_sensor_fire, 285 &envd_sensor_lsi1064, 286 &envd_sensor_front_panel, 287 NULL 288 }; 289 290 #define NOT_AVAILABLE "NA" 291 292 /* 293 * Tuneables 294 */ 295 #define ENABLE 1 296 #define DISABLE 0 297 298 static int disk_high_warn_temperature = DISK_HIGH_WARN_TEMPERATURE; 299 static int disk_low_warn_temperature = DISK_LOW_WARN_TEMPERATURE; 300 static int disk_high_shutdown_temperature = 301 DISK_HIGH_SHUTDOWN_TEMPERATURE; 302 static int disk_low_shutdown_temperature = DISK_LOW_SHUTDOWN_TEMPERATURE; 303 304 static int disk_scan_interval = DISK_SCAN_INTERVAL; 305 static int sensor_scan_interval = SENSOR_SCAN_INTERVAL; 306 static int fan_scan_interval = FAN_SCAN_INTERVAL; 307 308 static int get_int_val(ptree_rarg_t *parg, void *buf); 309 static int set_int_val(ptree_warg_t *parg, const void *buf); 310 static int get_string_val(ptree_rarg_t *parg, void *buf); 311 static int set_string_val(ptree_warg_t *parg, const void *buf); 312 313 static int shutdown_override = 0; 314 static int sensor_warning_interval = SENSOR_WARNING_INTERVAL; 315 static int sensor_warning_duration = SENSOR_WARNING_DURATION; 316 static int sensor_shutdown_interval = SENSOR_SHUTDOWN_INTERVAL; 317 static int disk_warning_interval = DISK_WARNING_INTERVAL; 318 static int disk_warning_duration = DISK_WARNING_DURATION; 319 static int disk_shutdown_interval = DISK_SHUTDOWN_INTERVAL; 320 static int system_temp_monitor = 1; /* enabled */ 321 static int fan_monitor = 1; /* enabled */ 322 static int pm_monitor = 1; /* enabled */ 323 int disk_temp_monitor = 1; /* enabled */ 324 325 static char shutdown_cmd[] = SHUTDOWN_CMD; 326 327 env_tuneable_t tuneables[] = { 328 {"system_temp-monitor", PICL_PTYPE_INT, &system_temp_monitor, 329 &get_int_val, &set_int_val, sizeof (int)}, 330 331 {"fan-monitor", PICL_PTYPE_INT, &fan_monitor, 332 &get_int_val, &set_int_val, sizeof (int)}, 333 334 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor, 335 &get_int_val, &set_int_val, sizeof (int)}, 336 337 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override, 338 &get_int_val, &set_int_val, sizeof (int)}, 339 340 {"sensor-warning-duration", PICL_PTYPE_INT, 341 &sensor_warning_duration, 342 &get_int_val, &set_int_val, 343 sizeof (int)}, 344 345 {"disk-scan-interval", PICL_PTYPE_INT, 346 &disk_scan_interval, 347 &get_int_val, &set_int_val, 348 sizeof (int)}, 349 350 {"fan-scan-interval", PICL_PTYPE_INT, 351 &fan_scan_interval, 352 &get_int_val, &set_int_val, 353 sizeof (int)}, 354 355 {"sensor-scan-interval", PICL_PTYPE_INT, 356 &sensor_scan_interval, 357 &get_int_val, &set_int_val, 358 sizeof (int)}, 359 360 {"sensor_warning-interval", PICL_PTYPE_INT, &sensor_warning_interval, 361 &get_int_val, &set_int_val, 362 sizeof (int)}, 363 364 {"sensor_shutdown-interval", PICL_PTYPE_INT, &sensor_shutdown_interval, 365 &get_int_val, &set_int_val, 366 sizeof (int)}, 367 368 {"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval, 369 &get_int_val, &set_int_val, 370 sizeof (int)}, 371 372 {"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration, 373 &get_int_val, &set_int_val, 374 sizeof (int)}, 375 376 {"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval, 377 &get_int_val, &set_int_val, 378 sizeof (int)}, 379 380 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd, 381 &get_string_val, &set_string_val, 382 sizeof (shutdown_cmd)}, 383 384 {"monitor-disk-temp", PICL_PTYPE_INT, &disk_temp_monitor, 385 &get_int_val, &set_int_val, sizeof (int)}, 386 387 {"disk-high-warn-temperature", PICL_PTYPE_INT, 388 &disk_high_warn_temperature, &get_int_val, 389 &set_int_val, sizeof (int)}, 390 391 {"disk-low-warn-temperature", PICL_PTYPE_INT, 392 &disk_low_warn_temperature, &get_int_val, 393 &set_int_val, sizeof (int)}, 394 395 {"disk-high-shutdown-temperature", PICL_PTYPE_INT, 396 &disk_high_shutdown_temperature, &get_int_val, 397 &set_int_val, sizeof (int)}, 398 399 {"disk-low-shutdown-temperature", PICL_PTYPE_INT, 400 &disk_low_shutdown_temperature, &get_int_val, 401 &set_int_val, sizeof (int)}, 402 403 {"verbose", PICL_PTYPE_INT, &env_debug, 404 &get_int_val, &set_int_val, sizeof (int)} 405 }; 406 407 /* 408 * We use this to figure out how many tuneables there are 409 * This is variable because the publishing routine needs this info 410 * in piclenvsetup.c 411 */ 412 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0])); 413 414 /* 415 * Lookup fan and return a pointer to env_fan_t data structure. 416 */ 417 env_fan_t * 418 fan_lookup(char *name) 419 { 420 int i; 421 env_fan_t *fanp; 422 423 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 424 if (strcmp(fanp->name, name) == 0) 425 return (fanp); 426 } 427 return (NULL); 428 } 429 430 /* 431 * Lookup sensor and return a pointer to env_sensor_t data structure. 432 */ 433 env_sensor_t * 434 sensor_lookup(char *name) 435 { 436 env_sensor_t *sensorp; 437 int i; 438 439 for (i = 0; i < N_ENVD_SENSORS; ++i) { 440 sensorp = envd_sensors[i]; 441 if (strcmp(sensorp->name, name) == 0) 442 return (sensorp); 443 } 444 return (NULL); 445 } 446 447 /* 448 * Lookup disk and return a pointer to env_disk_t data structure. 449 */ 450 env_disk_t * 451 disk_lookup(char *name) 452 { 453 int i; 454 env_disk_t *diskp; 455 456 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 457 if (strncmp(diskp->name, name, strlen(name)) == 0) 458 return (diskp); 459 } 460 return (NULL); 461 } 462 463 /* 464 * Get current temperature 465 * Returns -1 on error, 0 if successful 466 */ 467 int 468 get_temperature(env_sensor_t *sensorp, tempr_t *temp) 469 { 470 int fd = sensorp->fd; 471 int retval = 0; 472 473 if (fd == -1) 474 retval = -1; 475 else if (ioctl(fd, PIC_GET_TEMPERATURE, temp) != 0) { 476 477 retval = -1; 478 479 sensorp->error++; 480 481 if (sensorp->error == MAX_SENSOR_RETRIES) { 482 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, 483 sensorp->name, errno, strerror(errno)); 484 } 485 486 total_temp_retries++; 487 (void) sleep(1); 488 489 } else if (sensorp->error != 0) { 490 if (sensorp->error >= MAX_SENSOR_RETRIES) { 491 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, 492 sensorp->name); 493 } 494 495 sensorp->error = 0; 496 497 if (total_temp_retries && env_debug) { 498 envd_log(LOG_WARNING, 499 "Total retries for sensors = %d", 500 total_temp_retries); 501 } 502 } 503 504 return (retval); 505 } 506 507 /* 508 * Get current disk temperature 509 * Returns -1 on error, 0 if successful 510 */ 511 int 512 disk_temperature(env_disk_t *diskp, tempr_t *temp) 513 { 514 int retval = 0; 515 516 if (diskp == NULL) 517 retval = -1; 518 else 519 *temp = diskp->current_temp; 520 521 return (retval); 522 } 523 524 /* 525 * Get current fan speed 526 * This function returns a RPM value for fanspeed 527 * in fanspeedp. 528 * Returns -1 on error, 0 if successful 529 */ 530 int 531 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp) 532 { 533 uint8_t tach; 534 int real_tach; 535 int retries; 536 537 if (fanp->fd == -1) 538 return (-1); 539 540 if (has_fan_failed(fanp)) { 541 *fanspeedp = 0; 542 return (0); 543 } 544 545 /* try to read the fan information */ 546 for (retries = 0; retries <= MAX_FAN_RETRIES; retries++) { 547 if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) == 0) 548 break; 549 (void) sleep(1); 550 } 551 552 total_fan_retries += retries; 553 if (retries == MAX_FAN_RETRIES) 554 return (-1); 555 556 if (total_fan_retries && env_debug) { 557 envd_log(LOG_WARNING, "total retries for fan = %d", 558 total_fan_retries); 559 } 560 561 real_tach = tach << 8; 562 *fanspeedp = TACH_TO_RPM(real_tach); 563 return (0); 564 } 565 566 /* 567 * Set fan speed 568 * This function accepts a percentage of fan speed 569 * from 0-100 and programs the HW monitor fans to the corresponding 570 * fanspeed value. 571 * Returns -1 on error, -2 on invalid args passed, 0 if successful 572 */ 573 int 574 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed) 575 { 576 uint8_t speed; 577 578 if (fanp->fd == -1) 579 return (-1); 580 581 if (fanspeed < 0 || fanspeed > 100) 582 return (-2); 583 584 speed = fanspeed; 585 if (ioctl(fanp->fd, PIC_SET_FAN_SPEED, &speed) != 0) 586 return (-1); 587 588 return (0); 589 } 590 591 /* 592 * close all fan devices 593 */ 594 static void 595 envd_close_fans(void) 596 { 597 int i; 598 env_fan_t *fanp; 599 600 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 601 if (fanp->fd != -1) { 602 (void) close(fanp->fd); 603 fanp->fd = -1; 604 } 605 } 606 } 607 608 /* 609 * Close sensor devices and freeup resources 610 */ 611 static void 612 envd_close_sensors(void) 613 { 614 env_sensor_t *sensorp; 615 int i; 616 617 for (i = 0; i < N_ENVD_SENSORS; ++i) { 618 sensorp = envd_sensors[i]; 619 if (sensorp->fd != -1) { 620 (void) close(sensorp->fd); 621 sensorp->fd = -1; 622 } 623 } 624 } 625 626 /* 627 * Open fan devices and initialize per fan data structure. 628 */ 629 static int 630 envd_setup_fans(void) 631 { 632 int i, fd; 633 env_fan_t *fanp; 634 int fancnt = 0; 635 picl_nodehdl_t tnodeh; 636 637 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 638 fanp->last_status = FAN_OK; 639 640 /* Make sure cpu0/1 present for validating cpu fans */ 641 if (fanp->id == CPU0_FAN_ID) { 642 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 643 PICL_SUCCESS) { 644 if (env_debug) { 645 envd_log(LOG_ERR, 646 "get node by path failed for %s\n", 647 CPU0_PATH); 648 } 649 fanp->present = B_FALSE; 650 continue; 651 } 652 } 653 if (fanp->id == CPU1_FAN_ID) { 654 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 655 PICL_SUCCESS) { 656 if (env_debug) { 657 envd_log(LOG_ERR, 658 "get node by path failed for %s\n", CPU0_PATH); 659 } 660 fanp->present = B_FALSE; 661 continue; 662 } 663 } 664 if ((fd = open(fanp->devfs_path, O_RDWR)) == -1) { 665 envd_log(LOG_CRIT, 666 ENV_FAN_OPEN_FAIL, fanp->name, 667 fanp->devfs_path, errno, strerror(errno)); 668 fanp->present = B_FALSE; 669 continue; 670 } 671 fanp->fd = fd; 672 fanp->present = B_TRUE; 673 fancnt++; 674 } 675 676 if (fancnt == 0) 677 return (-1); 678 679 return (0); 680 } 681 682 static int 683 envd_setup_disks(void) 684 { 685 int ret, i, page_index, page_len; 686 picl_nodehdl_t tnodeh; 687 env_disk_t *diskp; 688 uint_t vendor_id; 689 uint_t device_id; 690 uchar_t log_page[256]; 691 692 if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH, 693 &tnodeh) != PICL_SUCCESS) { 694 if (env_debug) { 695 envd_log(LOG_ERR, 696 "On-Board SCSI controller %s not found in the system.\n", 697 SCSI_CONTROLLER_NODE_PATH); 698 } 699 return (-1); 700 } 701 702 if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID, 703 &vendor_id, sizeof (vendor_id))) != 0) { 704 if (env_debug) { 705 envd_log(LOG_ERR, 706 "Error in getting vendor-id for SCSI controller. ret = %d errno = 0x%d\n", 707 ret, errno); 708 } 709 return (-1); 710 } 711 if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID, 712 &device_id, sizeof (device_id))) != 0) { 713 if (env_debug) { 714 envd_log(LOG_ERR, 715 "Error in getting device-id for SCSI controller. ret = %d errno = 0x%d\n", 716 ret, errno); 717 } 718 return (-1); 719 } 720 721 /* 722 * We have found LSI1064 SCSi controller onboard. 723 */ 724 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 725 if (ptree_get_node_by_path(diskp->nodepath, 726 &tnodeh) != PICL_SUCCESS) { 727 diskp->present = B_FALSE; 728 if (env_debug) { 729 envd_log(LOG_ERR, 730 "DISK %d: %s not found in the system.\n", 731 diskp->id, diskp->nodepath); 732 } 733 continue; 734 } 735 if ((diskp->fd = open(diskp->devfs_path, O_RDONLY)) == -1) { 736 diskp->present = B_FALSE; 737 if (env_debug) { 738 envd_log(LOG_ERR, 739 "Error in opening %s errno = 0x%x\n", 740 diskp->devfs_path, errno); 741 } 742 continue; 743 } 744 diskp->present = B_TRUE; 745 diskp->tpage_supported = B_FALSE; 746 diskp->warning_tstamp = 0; 747 diskp->shutdown_tstamp = 0; 748 diskp->high_warning = disk_high_warn_temperature; 749 diskp->low_warning = disk_low_warn_temperature; 750 diskp->high_shutdown = disk_high_shutdown_temperature; 751 diskp->low_shutdown = disk_low_shutdown_temperature; 752 /* 753 * Find out if the Temperature page is supported by the disk. 754 */ 755 if (scsi_log_sense(diskp, SUPPORTED_LPAGES, log_page, 756 sizeof (log_page)) != 0) { 757 continue; 758 } 759 760 page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3]; 761 762 for (page_index = LOGPAGEHDRSIZE; 763 page_index < page_len + LOGPAGEHDRSIZE; page_index++) { 764 if (log_page[page_index] != TEMPERATURE_PAGE) 765 continue; 766 767 diskp->tpage_supported = B_TRUE; 768 if (env_debug) { 769 envd_log(LOG_ERR, "tpage supported for %s\n", 770 diskp->nodepath); 771 } 772 } 773 774 if (get_disk_temp(diskp) < 0) { 775 envd_log(LOG_ERR, " error reading temperature of:%s\n", 776 diskp->name); 777 } else if (env_debug) { 778 envd_log(LOG_ERR, "%s: temperature = %d\n", 779 diskp->name, diskp->current_temp); 780 } 781 } 782 783 return (0); 784 } 785 786 /* 787 * Open temperature sensor devices and initialize per sensor data structure. 788 */ 789 static int 790 envd_setup_sensors(void) 791 { 792 env_sensor_t *sensorp; 793 int sensorcnt = 0; 794 int i; 795 picl_nodehdl_t tnodeh; 796 797 for (i = 0; i < N_ENVD_SENSORS; i++) { 798 if (env_debug) 799 envd_log(LOG_ERR, "scanning sensor %d\n", i); 800 801 sensorp = envd_sensors[i]; 802 803 /* Initialize sensor's initial state */ 804 sensorp->shutdown_initiated = B_FALSE; 805 sensorp->warning_tstamp = 0; 806 sensorp->shutdown_tstamp = 0; 807 sensorp->error = 0; 808 809 /* Make sure cpu0/1 sensors are present */ 810 if (sensorp->id == CPU0_SENSOR_ID) { 811 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 812 PICL_SUCCESS) { 813 if (env_debug) { 814 envd_log(LOG_ERR, 815 "get node by path failed for %s\n", 816 CPU0_PATH); 817 } 818 sensorp->present = B_FALSE; 819 continue; 820 } 821 } 822 if (sensorp->id == CPU1_SENSOR_ID) { 823 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 824 PICL_SUCCESS) { 825 if (env_debug) { 826 envd_log(LOG_ERR, 827 "get node by path failed for %s\n", 828 CPU1_PATH); 829 } 830 sensorp->present = B_FALSE; 831 continue; 832 } 833 } 834 835 sensorp->fd = open(sensorp->devfs_path, O_RDWR); 836 if (sensorp->fd == -1) { 837 if (env_debug) { 838 envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL, 839 sensorp->name, sensorp->devfs_path, 840 errno, strerror(errno)); 841 } 842 sensorp->present = B_FALSE; 843 continue; 844 } 845 846 /* 847 * Determine if the front panel is attached, we want the 848 * information if it exists, but should not shut down 849 * the system if it is removed. 850 */ 851 if (sensorp->id == FRONT_PANEL_SENSOR_ID) { 852 tempr_t temp; 853 int tries; 854 855 for (tries = 0; tries < MAX_SENSOR_RETRIES; tries++) { 856 if (ioctl(sensorp->fd, PIC_GET_TEMPERATURE, 857 &temp) == 0) { 858 break; 859 } 860 (void) sleep(1); 861 } 862 if (tries == MAX_SENSOR_RETRIES) 863 sensorp->present = B_FALSE; 864 } 865 866 sensorp->present = B_TRUE; 867 sensorcnt++; 868 } 869 870 if (sensorcnt == 0) 871 return (-1); 872 873 return (0); 874 } 875 876 /* ARGSUSED */ 877 static void * 878 pmthr(void *args) 879 { 880 pm_state_change_t pmstate; 881 char physpath[PATH_MAX]; 882 int pre_lpstate; 883 uint8_t estar_state; 884 int env_monitor_fd; 885 886 pmstate.physpath = physpath; 887 pmstate.size = sizeof (physpath); 888 cur_lpstate = 0; 889 pre_lpstate = 1; 890 891 pm_fd = open(PM_DEVICE, O_RDWR); 892 if (pm_fd == -1) { 893 envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno)); 894 return (NULL); 895 } 896 for (;;) { 897 /* 898 * Get PM state change events to check if the system 899 * is in lowest power state and inform PIC which controls 900 * fan speeds. 901 * 902 * To minimize polling, we use the blocking interface 903 * to get the power state change event here. 904 */ 905 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) { 906 if (errno != EINTR) 907 break; 908 continue; 909 } 910 911 do { 912 if (env_debug) { 913 envd_log(LOG_INFO, 914 "pmstate event:0x%x flags:%x" 915 "comp:%d oldval:%d newval:%d path:%s\n", 916 pmstate.event, pmstate.flags, 917 pmstate.component, 918 pmstate.old_level, 919 pmstate.new_level, 920 pmstate.physpath); 921 } 922 cur_lpstate = 923 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0; 924 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0); 925 926 if (pre_lpstate != cur_lpstate) { 927 pre_lpstate = cur_lpstate; 928 estar_state = (cur_lpstate & 0x1); 929 if (env_debug) 930 envd_log(LOG_ERR, 931 "setting PIC ESTAR SATE to %x\n", 932 estar_state); 933 934 env_monitor_fd = open(ENV_MONITOR_DEVFS, O_RDWR); 935 if (env_monitor_fd != -1) { 936 if (ioctl(env_monitor_fd, PIC_SET_ESTAR_MODE, 937 &estar_state) < 0) { 938 if (env_debug) 939 envd_log(LOG_ERR, 940 "unable to set ESTAR_MODE in PIC\n"); 941 } 942 (void) close(env_monitor_fd); 943 } else { 944 if (env_debug) 945 envd_log(LOG_ERR, 946 "Failed to open %s\n", 947 ENV_MONITOR_DEVFS); 948 } 949 } 950 } 951 952 /*NOTREACHED*/ 953 return (NULL); 954 } 955 956 /* 957 * This is env thread which monitors the current temperature when 958 * warning threshold is exceeded. The job is to make sure it does 959 * not execced/decrease shutdown threshold. If it does it will start 960 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt. 961 */ 962 /*ARGSUSED*/ 963 static void * 964 system_temp_thr(void *args) 965 { 966 char syscmd[BUFSIZ]; 967 char msgbuf[BUFSIZ]; 968 timespec_t to; 969 int ret, i; 970 env_sensor_t *sensorp; 971 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 972 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 973 time_t ct; 974 tempr_t temp; 975 976 for (;;) { 977 /* 978 * Sleep for specified seconds before issuing IOCTL 979 * again. 980 */ 981 (void) pthread_mutex_lock(&env_monitor_mutex); 982 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 983 &env_monitor_mutex, &to); 984 to.tv_sec = sensor_scan_interval; 985 to.tv_nsec = 0; 986 if (ret != ETIMEDOUT) { 987 (void) pthread_mutex_unlock(&env_monitor_mutex); 988 continue; 989 } 990 991 (void) pthread_mutex_unlock(&env_monitor_mutex); 992 for (i = 0; i < N_ENVD_SENSORS; i++) { 993 sensorp = envd_sensors[i]; 994 if (sensorp->present == B_FALSE) 995 continue; 996 if (get_temperature(sensorp, &temp) == -1) 997 continue; 998 999 sensorp->cur_temp = temp; 1000 if (env_debug) { 1001 envd_log(LOG_ERR, 1002 "%s temp = %d", 1003 sensorp->name, sensorp->cur_temp); 1004 } 1005 1006 /* 1007 * If this sensor already triggered system shutdown, 1008 * don't log any more shutdown/warning messages for it. 1009 */ 1010 if (sensorp->shutdown_initiated) 1011 continue; 1012 1013 /* 1014 * Check for the temperature in warning and shutdown 1015 * range and take appropriate action. 1016 */ 1017 if (SENSOR_TEMP_IN_WARNING_RANGE(sensorp->cur_temp, 1018 sensorp)) { 1019 /* 1020 * Check if the temperature has been in 1021 * warning range during last 1022 * sensor_warning_duration interval. If so, 1023 * the temperature is truly in warning range 1024 * and we need to log a warning message, but 1025 * no more than once every 1026 * sensor_warning_interval seconds. 1027 */ 1028 time_t wtstamp = sensorp->warning_tstamp; 1029 1030 ct = (time_t)(gethrtime() / NANOSEC); 1031 if (sensorp->warning_start == 0) 1032 sensorp->warning_start = ct; 1033 if (((ct - sensorp->warning_start) >= 1034 sensor_warning_duration) && 1035 (wtstamp == 0 || (ct - wtstamp) >= 1036 sensor_warning_interval)) { 1037 envd_log(LOG_CRIT, ENV_WARNING_MSG, 1038 sensorp->name, sensorp->cur_temp, 1039 sensorp->low_warning, 1040 sensorp->high_warning); 1041 sensorp->warning_tstamp = ct; 1042 } 1043 } else if (sensorp->warning_start != 0) 1044 sensorp->warning_start = 0; 1045 1046 if (!shutdown_override && 1047 SENSOR_TEMP_IN_SHUTDOWN_RANGE(sensorp->cur_temp, 1048 sensorp)) { 1049 ct = (time_t)(gethrtime() / NANOSEC); 1050 if (sensorp->shutdown_tstamp == 0) 1051 sensorp->shutdown_tstamp = ct; 1052 1053 /* 1054 * Shutdown the system if the temperature 1055 * remains in the shutdown range for over 1056 * sensor_shutdown_interval seconds. 1057 */ 1058 if ((ct - sensorp->shutdown_tstamp) >= 1059 sensor_shutdown_interval) { 1060 /* 1061 * Log error 1062 */ 1063 sensorp->shutdown_initiated = B_TRUE; 1064 (void) snprintf(msgbuf, sizeof (msgbuf), 1065 ENV_SHUTDOWN_MSG, sensorp->name, 1066 sensorp->cur_temp, 1067 sensorp->low_shutdown, 1068 sensorp->high_shutdown); 1069 envd_log(LOG_ALERT, msgbuf); 1070 1071 /* 1072 * Shutdown the system (only once) 1073 */ 1074 if (system_shutdown_started == 1075 B_FALSE) { 1076 (void) snprintf(syscmd, 1077 sizeof (syscmd), 1078 "%s \"%s\"", shutdown_cmd, 1079 msgbuf); 1080 1081 envd_log(LOG_ALERT, syscmd); 1082 system_shutdown_started = 1083 B_TRUE; 1084 1085 (void) system(syscmd); 1086 } 1087 } 1088 } else if (sensorp->shutdown_tstamp != 0) 1089 sensorp->shutdown_tstamp = 0; 1090 1091 } 1092 } /* end of forever loop */ 1093 1094 /*NOTREACHED*/ 1095 return (NULL); 1096 } 1097 1098 static int 1099 scsi_log_sense(env_disk_t *diskp, uchar_t page_code, uchar_t *pagebuf, 1100 uint16_t pagelen) 1101 { 1102 struct uscsi_cmd ucmd_buf; 1103 uchar_t cdb_buf[CDB_GROUP1]; 1104 struct scsi_extended_sense sense_buf; 1105 int ret_val; 1106 1107 bzero((void *)&cdb_buf, sizeof (cdb_buf)); 1108 bzero((void *)&ucmd_buf, sizeof (ucmd_buf)); 1109 bzero((void *)&sense_buf, sizeof (sense_buf)); 1110 1111 cdb_buf[0] = SCMD_LOG_SENSE_G1; 1112 cdb_buf[2] = (0x01 << 6) | page_code; 1113 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8); 1114 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF); 1115 1116 ucmd_buf.uscsi_cdb = (char *)cdb_buf; 1117 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf); 1118 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf; 1119 ucmd_buf.uscsi_buflen = pagelen; 1120 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; 1121 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); 1122 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT; 1123 ucmd_buf.uscsi_timeout = 60; 1124 1125 ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf); 1126 if ((ret_val == 0) && (ucmd_buf.uscsi_status == 0)) { 1127 if (env_debug) 1128 envd_log(LOG_ERR, 1129 "log sense command for page_code 0x%x succeeded\n", page_code); 1130 return (ret_val); 1131 } 1132 if (env_debug) { 1133 envd_log(LOG_ERR, "log sense command for %s failed. " 1134 "page_code 0x%x ret_val = 0x%x " 1135 "status = 0x%x errno = 0x%x\n", diskp->name, page_code, 1136 ret_val, ucmd_buf.uscsi_status, errno); 1137 } 1138 1139 return (1); 1140 } 1141 1142 static int 1143 get_disk_temp(env_disk_t *diskp) 1144 { 1145 int ret; 1146 uchar_t tpage[256]; 1147 1148 ret = scsi_log_sense(diskp, TEMPERATURE_PAGE, tpage, sizeof (tpage)); 1149 if (ret != 0) { 1150 diskp->current_temp = DISK_INVALID_TEMP; 1151 diskp->ref_temp = DISK_INVALID_TEMP; 1152 return (-1); 1153 } 1154 /* 1155 * For the current temperature verify that the parameter 1156 * length is 0x02 and the parameter code is 0x00 1157 * Temperature value of 255(0xFF) is considered INVALID. 1158 */ 1159 if ((tpage[7] == 0x02) && (tpage[4] == 0x00) && 1160 (tpage[5] == 0x00)) { 1161 if (tpage[9] == 0xFF) { 1162 diskp->current_temp = DISK_INVALID_TEMP; 1163 return (-1); 1164 } else { 1165 diskp->current_temp = tpage[9]; 1166 } 1167 } 1168 1169 /* 1170 * For the reference temperature verify that the parameter 1171 * length is 0x02 and the parameter code is 0x01 1172 * Temperature value of 255(0xFF) is considered INVALID. 1173 */ 1174 if ((tpage[13] == 0x02) && (tpage[10] == 0x00) && 1175 (tpage[11] == 0x01)) { 1176 if (tpage[15] == 0xFF) { 1177 diskp->ref_temp = DISK_INVALID_TEMP; 1178 } else { 1179 diskp->ref_temp = tpage[15]; 1180 } 1181 } 1182 return (0); 1183 } 1184 1185 /* ARGSUSED */ 1186 static void * 1187 disk_temp_thr(void *args) 1188 { 1189 char syscmd[BUFSIZ]; 1190 char msgbuf[BUFSIZ]; 1191 timespec_t to; 1192 int ret, i; 1193 env_disk_t *diskp; 1194 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1195 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1196 pm_state_change_t pmstate; 1197 int idle_time; 1198 int disk_pm_fd; 1199 time_t ct; 1200 1201 if ((disk_pm_fd = open(PM_DEVICE, O_RDWR)) == -1) { 1202 envd_log(LOG_ERR, DISK_TEMP_THREAD_EXITING, 1203 errno, strerror(errno)); 1204 return (NULL); 1205 } 1206 1207 for (;;) { 1208 /* 1209 * Sleep for specified seconds before issuing IOCTL 1210 * again. 1211 */ 1212 (void) pthread_mutex_lock(&env_monitor_mutex); 1213 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1214 &env_monitor_mutex, &to); 1215 1216 to.tv_sec = disk_scan_interval; 1217 to.tv_nsec = 0; 1218 1219 if (ret != ETIMEDOUT) { 1220 (void) pthread_mutex_unlock( 1221 &env_monitor_mutex); 1222 continue; 1223 } 1224 (void) pthread_mutex_unlock(&env_monitor_mutex); 1225 1226 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 1227 if (diskp->present == B_FALSE) 1228 continue; 1229 if (diskp->tpage_supported == B_FALSE) 1230 continue; 1231 /* 1232 * If the disk temperature is above the warning threshold 1233 * continue monitoring until the temperature drops below 1234 * warning threshold. 1235 * if the temperature is in the NORMAL range monitor only 1236 * when the disk is BUSY. 1237 * We do not want to read the disk temperature if the disk is 1238 * is idling. The reason for this is disk will never get into 1239 * lowest power mode if we scan the disk temperature 1240 * peridoically. To avoid this situation we first determine 1241 * the idle_time of the disk. If the disk has been IDLE since 1242 * we scanned the temperature last time we will not read the 1243 * temperature. 1244 */ 1245 if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 1246 pmstate.physpath = diskp->physpath; 1247 pmstate.size = strlen(diskp->physpath); 1248 pmstate.component = 0; 1249 if ((idle_time = 1250 ioctl(disk_pm_fd, PM_GET_TIME_IDLE, 1251 &pmstate)) == -1) { 1252 1253 if (errno != EINTR) { 1254 if (env_debug) 1255 envd_log(LOG_ERR, 1256 "ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n", 1257 errno); 1258 continue; 1259 } 1260 continue; 1261 } 1262 if (idle_time >= (disk_scan_interval/2)) { 1263 if (env_debug) { 1264 envd_log(LOG_ERR, "%s idle time = %d\n", 1265 diskp->name, idle_time); 1266 } 1267 continue; 1268 } 1269 } 1270 ret = get_disk_temp(diskp); 1271 if (ret != 0) 1272 continue; 1273 if (env_debug) { 1274 envd_log(LOG_ERR, "%s temp = %d ref. temp = %d\n", 1275 diskp->name, diskp->current_temp, diskp->ref_temp); 1276 } 1277 /* 1278 * If this disk already triggered system shutdown, don't 1279 * log any more shutdown/warning messages for it. 1280 */ 1281 if (diskp->shutdown_initiated) 1282 continue; 1283 1284 /* 1285 * Check for the temperature in warning and shutdown range 1286 * and take appropriate action. 1287 */ 1288 if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 1289 /* 1290 * Check if the temperature has been in warning 1291 * range during last disk_warning_duration interval. 1292 * If so, the temperature is truly in warning 1293 * range and we need to log a warning message, 1294 * but no more than once every disk_warning_interval 1295 * seconds. 1296 */ 1297 time_t wtstamp = diskp->warning_tstamp; 1298 1299 ct = (time_t)(gethrtime() / NANOSEC); 1300 if (diskp->warning_start == 0) 1301 diskp->warning_start = ct; 1302 if (((ct - diskp->warning_start) >= 1303 disk_warning_duration) && (wtstamp == 0 || 1304 (ct - wtstamp) >= disk_warning_interval)) { 1305 envd_log(LOG_CRIT, ENV_WARNING_MSG, 1306 diskp->name, diskp->current_temp, 1307 diskp->low_warning, 1308 diskp->high_warning); 1309 diskp->warning_tstamp = ct; 1310 } 1311 } else if (diskp->warning_start != 0) 1312 diskp->warning_start = 0; 1313 1314 if (!shutdown_override && 1315 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) { 1316 ct = (time_t)(gethrtime() / NANOSEC); 1317 if (diskp->shutdown_tstamp == 0) 1318 diskp->shutdown_tstamp = ct; 1319 1320 /* 1321 * Shutdown the system if the temperature remains 1322 * in the shutdown range for over disk_shutdown_interval 1323 * seconds. 1324 */ 1325 if ((ct - diskp->shutdown_tstamp) >= 1326 disk_shutdown_interval) { 1327 /* log error */ 1328 diskp->shutdown_initiated = B_TRUE; 1329 (void) snprintf(msgbuf, sizeof (msgbuf), 1330 ENV_SHUTDOWN_MSG, diskp->name, 1331 diskp->current_temp, diskp->low_shutdown, 1332 diskp->high_shutdown); 1333 envd_log(LOG_ALERT, msgbuf); 1334 1335 /* shutdown the system (only once) */ 1336 if (system_shutdown_started == B_FALSE) { 1337 (void) snprintf(syscmd, sizeof (syscmd), 1338 "%s \"%s\"", shutdown_cmd, msgbuf); 1339 envd_log(LOG_ALERT, syscmd); 1340 system_shutdown_started = B_TRUE; 1341 (void) system(syscmd); 1342 } 1343 } 1344 } else if (diskp->shutdown_tstamp != 0) 1345 diskp->shutdown_tstamp = 0; 1346 } 1347 } /* end of forever loop */ 1348 } 1349 1350 static void * 1351 fan_thr(void *args) 1352 { 1353 char msgbuf[BUFSIZ]; 1354 timespec_t to; 1355 int ret, i; 1356 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1357 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1358 env_fan_t *fanp; 1359 1360 #ifdef __lint 1361 args = args; 1362 #endif 1363 1364 for (;;) { 1365 /* 1366 * Sleep for specified seconds before issuing IOCTL 1367 * again. 1368 */ 1369 (void) pthread_mutex_lock(&env_monitor_mutex); 1370 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1371 &env_monitor_mutex, &to); 1372 to.tv_sec = fan_scan_interval; 1373 to.tv_nsec = 0; 1374 if (ret != ETIMEDOUT) { 1375 (void) pthread_mutex_unlock(&env_monitor_mutex); 1376 continue; 1377 } 1378 (void) pthread_mutex_unlock(&env_monitor_mutex); 1379 1380 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 1381 if (fanp->present == B_FALSE) 1382 continue; 1383 /* 1384 * We initiate shutdown if fan status indicates 1385 * failure. Also, don't warn repeatedly. 1386 */ 1387 if (has_fan_failed(fanp) == B_TRUE) { 1388 if (fanp->last_status == FAN_FAILED) 1389 continue; 1390 fanp->last_status = FAN_FAILED; 1391 (void) snprintf(msgbuf, sizeof (msgbuf), 1392 ENV_FAN_FAILURE_WARNING_MSG, fanp->name, 1393 fan_rpm_string, fan_status_string); 1394 envd_log(LOG_ALERT, msgbuf); 1395 } else { 1396 if (fanp->last_status == FAN_OK) 1397 continue; 1398 fanp->last_status = FAN_OK; 1399 (void) snprintf(msgbuf, sizeof (msgbuf), 1400 ENV_FAN_OK_MSG, fanp->name); 1401 envd_log(LOG_ALERT, msgbuf); 1402 } 1403 } 1404 } 1405 1406 /*NOTREACHED*/ 1407 return (NULL); 1408 } 1409 1410 /* 1411 * Setup envrionmental monitor state and start threads to monitor 1412 * temperature, fan, disk and power management state. 1413 * Returns -1 on error, 0 if successful. 1414 */ 1415 static int 1416 envd_setup(void) 1417 { 1418 1419 if (getenv("SUNW_piclenvd_debug") != NULL) 1420 env_debug = 1; 1421 1422 if (pthread_attr_init(&thr_attr) != 0 || 1423 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) { 1424 return (-1); 1425 } 1426 1427 if (envd_setup_sensors() < 0) { 1428 if (env_debug) 1429 envd_log(LOG_ERR, "Failed to setup sensors\n"); 1430 system_temp_monitor = 0; 1431 } 1432 1433 if (envd_setup_fans() < 0) { 1434 if (env_debug) 1435 envd_log(LOG_ERR, "Failed to setup fans\n"); 1436 fan_monitor = 0; 1437 pm_monitor = 0; 1438 } 1439 1440 if (envd_setup_disks() < 0) { 1441 if (env_debug) 1442 envd_log(LOG_ERR, "Failed to setup disks\n"); 1443 disk_temp_monitor = 0; 1444 } 1445 1446 if ((system_temp_monitor) && (system_temp_thr_created == B_FALSE)) { 1447 if (pthread_create(&system_temp_thr_id, &thr_attr, 1448 system_temp_thr, NULL) != 0) { 1449 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1450 } else { 1451 system_temp_thr_created = B_TRUE; 1452 if (env_debug) 1453 envd_log(LOG_ERR, 1454 "Created thread to monitor system temperatures\n"); 1455 } 1456 } 1457 1458 if ((fan_monitor) && (fan_thr_created == B_FALSE)) { 1459 if (pthread_create(&fan_thr_id, &thr_attr, fan_thr, NULL) != 0) 1460 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1461 else { 1462 fan_thr_created = B_TRUE; 1463 if (env_debug) { 1464 envd_log(LOG_ERR, 1465 "Created thread to monitor system fans\n"); 1466 } 1467 } 1468 } 1469 1470 if ((pm_monitor) && (pmthr_created == B_FALSE)) { 1471 if (pthread_create(&pmthr_tid, &thr_attr, pmthr, NULL) != 0) 1472 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); 1473 else { 1474 pmthr_created = B_TRUE; 1475 if (env_debug) 1476 envd_log(LOG_ERR, 1477 "Created thread to monitor system power state\n"); 1478 } 1479 } 1480 1481 if ((disk_temp_monitor) && (disk_temp_thr_created == B_FALSE)) { 1482 if (pthread_create(&disk_temp_thr_id, &thr_attr, 1483 disk_temp_thr, NULL) != 0) { 1484 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1485 } else { 1486 disk_temp_thr_created = B_TRUE; 1487 if (env_debug) 1488 envd_log(LOG_ERR, 1489 "Created thread for disk temperatures\n"); 1490 } 1491 } 1492 1493 return (0); 1494 } 1495 1496 static void 1497 piclenvd_register(void) 1498 { 1499 picld_plugin_register(&my_reg_info); 1500 } 1501 1502 static void 1503 piclenvd_init(void) 1504 { 1505 1506 (void) env_picl_setup_tuneables(); 1507 1508 /* 1509 * Setup the environmental data structures 1510 */ 1511 if (envd_setup() != 0) { 1512 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); 1513 return; 1514 } 1515 1516 /* 1517 * Now setup/populate PICL tree 1518 */ 1519 env_picl_setup(); 1520 } 1521 1522 static void 1523 piclenvd_fini(void) 1524 { 1525 1526 /* 1527 * Invoke env_picl_destroy() to remove any PICL nodes/properties 1528 * (including volatile properties) we created. Once this call 1529 * returns, there can't be any more calls from the PICL framework 1530 * to get current temperature or fan speed. 1531 */ 1532 env_picl_destroy(); 1533 envd_close_sensors(); 1534 envd_close_fans(); 1535 } 1536 1537 /*VARARGS2*/ 1538 void 1539 envd_log(int pri, const char *fmt, ...) 1540 { 1541 va_list ap; 1542 1543 va_start(ap, fmt); 1544 vsyslog(pri, fmt, ap); 1545 va_end(ap); 1546 } 1547 1548 /* 1549 * Tunables support functions 1550 */ 1551 static env_tuneable_t * 1552 tuneable_lookup(picl_prophdl_t proph) 1553 { 1554 int i; 1555 env_tuneable_t *tuneablep = NULL; 1556 1557 for (i = 0; i < ntuneables; i++) { 1558 tuneablep = &tuneables[i]; 1559 if (tuneablep->proph == proph) 1560 return (tuneablep); 1561 } 1562 1563 return (NULL); 1564 } 1565 1566 static int 1567 get_string_val(ptree_rarg_t *parg, void *buf) 1568 { 1569 picl_prophdl_t proph; 1570 env_tuneable_t *tuneablep; 1571 1572 proph = parg->proph; 1573 1574 tuneablep = tuneable_lookup(proph); 1575 1576 if (tuneablep == NULL) 1577 return (PICL_FAILURE); 1578 1579 (void) memcpy(buf, (caddr_t)tuneablep->value, 1580 tuneablep->nbytes); 1581 1582 return (PICL_SUCCESS); 1583 } 1584 1585 static int 1586 set_string_val(ptree_warg_t *parg, const void *buf) 1587 { 1588 picl_prophdl_t proph; 1589 env_tuneable_t *tuneablep; 1590 1591 if (parg->cred.dc_euid != 0) 1592 return (PICL_PERMDENIED); 1593 1594 proph = parg->proph; 1595 1596 tuneablep = tuneable_lookup(proph); 1597 1598 if (tuneablep == NULL) 1599 return (PICL_FAILURE); 1600 1601 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf, 1602 tuneables->nbytes); 1603 1604 1605 return (PICL_SUCCESS); 1606 } 1607 1608 static int 1609 get_int_val(ptree_rarg_t *parg, void *buf) 1610 { 1611 picl_prophdl_t proph; 1612 env_tuneable_t *tuneablep; 1613 1614 proph = parg->proph; 1615 1616 tuneablep = tuneable_lookup(proph); 1617 1618 if (tuneablep == NULL) 1619 return (PICL_FAILURE); 1620 1621 (void) memcpy((int *)buf, (int *)tuneablep->value, 1622 tuneablep->nbytes); 1623 1624 return (PICL_SUCCESS); 1625 } 1626 1627 static int 1628 set_int_val(ptree_warg_t *parg, const void *buf) 1629 { 1630 picl_prophdl_t proph; 1631 env_tuneable_t *tuneablep; 1632 1633 if (parg->cred.dc_euid != 0) 1634 return (PICL_PERMDENIED); 1635 1636 proph = parg->proph; 1637 1638 tuneablep = tuneable_lookup(proph); 1639 1640 if (tuneablep == NULL) 1641 return (PICL_FAILURE); 1642 1643 (void) memcpy((int *)tuneablep->value, (int *)buf, 1644 tuneablep->nbytes); 1645 1646 return (PICL_SUCCESS); 1647 } 1648 1649 boolean_t 1650 has_fan_failed(env_fan_t *fanp) 1651 { 1652 fanspeed_t fan_speed; 1653 uchar_t status; 1654 uint8_t tach; 1655 int real_tach; 1656 int ret, ntries; 1657 1658 if (fanp->fd == -1) 1659 return (B_TRUE); 1660 1661 /* 1662 * Read RF_FAN_STATUS bit of the fan fault register, retry if 1663 * the PIC is busy, with a 1 second delay to allow it to update. 1664 */ 1665 for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) { 1666 ret = ioctl(fanp->fd, PIC_GET_FAN_STATUS, &status); 1667 if ((ret == 0) && ((status & 0x1) == 0)) 1668 break; 1669 (void) sleep(1); 1670 } 1671 1672 if (ntries > 0) { 1673 if (env_debug) { 1674 envd_log(LOG_ERR, 1675 "%d retries attempted in reading fan status.\n", 1676 ntries); 1677 } 1678 } 1679 1680 if (ntries == MAX_RETRIES_FOR_FAN_FAULT) { 1681 (void) strncpy(fan_status_string, NOT_AVAILABLE, 1682 sizeof (fan_status_string)); 1683 (void) strncpy(fan_rpm_string, NOT_AVAILABLE, 1684 sizeof (fan_rpm_string)); 1685 return (B_TRUE); 1686 } 1687 1688 if (env_debug) 1689 envd_log(LOG_ERR, "fan status = 0x%x\n", status); 1690 1691 /* 1692 * ST_FFAULT bit isn't implemented yet and we're reading only 1693 * individual fan status 1694 */ 1695 if (status & 0x1) { 1696 (void) snprintf(fan_status_string, sizeof (fan_status_string), 1697 "0x%x", status); 1698 if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) != 0) { 1699 (void) strncpy(fan_rpm_string, NOT_AVAILABLE, 1700 sizeof (fan_rpm_string)); 1701 } else { 1702 real_tach = tach << 8; 1703 fan_speed = TACH_TO_RPM(real_tach); 1704 (void) snprintf(fan_rpm_string, sizeof (fan_rpm_string), 1705 "%d", fan_speed); 1706 } 1707 return (B_TRUE); 1708 } 1709 1710 return (B_FALSE); 1711 } 1712