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