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