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