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