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 2004 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 Enchilada 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/i2c/clients/i2c_client.h> 68 #include <sys/i2c/clients/adm1031.h> 69 #include <sys/i2c/clients/pic16f819_reg.h> 70 #include "envd.h" 71 #include <sys/scsi/scsi.h> 72 #include <sys/scsi/generic/commands.h> 73 74 75 /* 76 * PICL plugin entry points 77 */ 78 static void piclenvd_register(void); 79 static void piclenvd_init(void); 80 static void piclenvd_fini(void); 81 82 /* 83 * Env setup routines 84 */ 85 extern void env_picl_setup(void); 86 extern void env_picl_destroy(void); 87 extern int env_picl_setup_tuneables(void); 88 89 /* 90 * Sleep routine used for polling 91 */ 92 static int get_dimm_fan_speed(int, fanspeed_t *); 93 static int is_dimm_fan_failed(void); 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 dimm_fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 110 static char dimm_fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 111 static char dimm_fan_command_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 112 static char dimm_fan_debug_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 113 114 static int scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, 115 uint16_t pagelen); 116 static int get_disk_temp(env_disk_t *); 117 /* 118 * ES Segment data structures 119 */ 120 static sensor_ctrl_blk_t sensor_ctrl[MAX_SENSORS]; 121 static fan_ctrl_blk_t fan_ctrl[MAX_FANS]; 122 static fruenvseg_t *envfru = NULL; 123 124 /* 125 * Env thread variables 126 */ 127 static boolean_t system_shutdown_started = B_FALSE; 128 static boolean_t ovtemp_thr1_created = B_FALSE; 129 static pthread_t ovtemp_thr1_id; 130 static pthread_attr_t thr_attr; 131 static boolean_t ovtemp_thr2_created = B_FALSE; 132 static pthread_t ovtemp_thr2_id; 133 static boolean_t dimm_fan_thr_created = B_FALSE; 134 static pthread_t dimm_fan_thr_id; 135 static boolean_t disk_temp_thr_created = B_FALSE; 136 static pthread_t disk_temp_thr_id; 137 138 /* 139 * PM thread related variables 140 */ 141 static pthread_t pmthr_tid; /* pmthr thread ID */ 142 static int pm_fd = -1; /* PM device file descriptor */ 143 static boolean_t pmthr_created = B_FALSE; 144 static int cur_lpstate; /* cur low power state */ 145 146 /* 147 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var 148 * Setting the verbose tuneable also enables debugging for better 149 * control 150 */ 151 int env_debug = 0; 152 153 /* 154 * Fan devices 155 */ 156 static env_fan_t envd_sys_out_fan = { 157 ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_OUT_FAN_DEVFS, NULL, 158 SYSTEM_OUT_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN, SYSTEM_OUT_FAN_SPEED_MAX, 159 -1, -1, 160 }; 161 162 static env_fan_t envd_sys_in_fan = { 163 ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_INTAKE_FAN_DEVFS, NULL, 164 SYSTEM_INTAKE_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN, 165 SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1, 166 }; 167 168 static env_fan_t envd_cpu0_fan = { 169 ENV_CPU0_FAN, ENV_CPU0_FAN_DEVFS, NULL, 170 CPU0_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1, 171 }; 172 173 static env_fan_t envd_cpu1_fan = { 174 ENV_CPU1_FAN, ENV_CPU1_FAN_DEVFS, NULL, 175 CPU1_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1, 176 }; 177 178 static env_fan_t envd_dimm_fan = { 179 ENV_DIMM_FAN, ENV_DIMM_FAN_DEVFS, NULL, 180 DIMM_FAN_ID, 100, 100, -1, -1, 181 }; 182 183 static env_disk_t envd_disk0 = { 184 ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH, 185 DISK0_ID, -1, -1, 186 }; 187 188 static env_disk_t envd_disk1 = { 189 ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH, 190 DISK1_ID, -1, -1, 191 }; 192 193 /* 194 * The vendor-id and device-id are the properties associated with 195 * the SCSI controller. This is used to identify a particular controller 196 * like LSI1030. 197 */ 198 #define VENDOR_ID "vendor-id" 199 #define DEVICE_ID "device-id" 200 201 /* 202 * The implementation for SCSI disk drives to supply info. about 203 * temperature is not mandatory. Hence we first determine if the 204 * temperature page is supported. To do this we need to scan the list 205 * of pages supported. 206 */ 207 #define SUPPORTED_LPAGES 0 208 #define TEMPERATURE_PAGE 0x0D 209 #define LOGPAGEHDRSIZE 4 210 211 /* 212 * NULL terminated array of fans 213 */ 214 static env_fan_t *envd_fans[] = { 215 &envd_cpu0_fan, 216 &envd_cpu1_fan, 217 &envd_sys_out_fan, 218 &envd_sys_in_fan, 219 &envd_dimm_fan, 220 NULL 221 }; 222 223 static env_disk_t *envd_disks[] = { 224 &envd_disk0, 225 &envd_disk1, 226 NULL 227 }; 228 229 /* 230 * ADM1031 speedrange map is indexed by a 2-bit value 231 */ 232 static int adm_speedrange_map[] = {1, 2, 4, 8}; 233 234 /* 235 * ADM1031 devices 236 */ 237 static char *hwm_devs[] = { 238 CPU_HWM_DEVFS, /* CPU_HWM_ID */ 239 SYS_HWM_DEVFS /* SYS_HWM_ID */ 240 }; 241 242 /* 243 * Fan names associated with each ADM1031 hwms - used to 244 * print fault messages. 245 */ 246 static char *hwm_fans[MAX_HWMS][2] = { 247 {ENV_CPU0_FAN, ENV_CPU1_FAN}, 248 {ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_OUT_FAN} 249 }; 250 251 /* 252 * Temperature sensors 253 */ 254 static env_sensor_t envd_sensors[] = { 255 { SENSOR_CPU0_DIE, SENSOR_CPU0_DIE_DEVFS, NULL, 256 CPU0_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu0_fan, -1}, 257 { SENSOR_CPU1_DIE, SENSOR_CPU1_DIE_DEVFS, NULL, 258 CPU1_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu1_fan, -1}, 259 { SENSOR_INT_AMB_0, SENSOR_INT_AMB_0_DEVFS, NULL, 260 INT_AMB0_SENSOR_ID, CPU_HWM_ID, NULL, -1}, 261 { SENSOR_SYS_OUT, SENSOR_SYS_OUT_DEVFS, NULL, 262 SYS_OUT_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_out_fan, -1}, 263 { SENSOR_INT_AMB_1, SENSOR_INT_AMB_1_DEVFS, NULL, 264 INT_AMB1_SENSOR_ID, SYS_HWM_ID, NULL, -1}, 265 { SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL, 266 SYS_IN_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_in_fan, -1}, 267 }; 268 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0])) 269 270 #define NOT_AVAILABLE "NA" 271 272 /* 273 * ADM1031 macros 274 */ 275 #define TACH_UNKNOWN 255 276 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN) 277 #define ADM_HYSTERISIS 5 278 #define N_SEQ_TACH 15 279 280 #define TMIN_MASK (0xF8) 281 #define TMIN_SHIFT (3) 282 #define TMIN_UNITS (4) /* increments of 4 degrees celsius */ 283 #define TRANGE_MASK (0x7) 284 285 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS) 286 #define TRANGE(regval) (regval & TRANGE_MASK) 287 288 #define GET_TMIN_RANGE(tmin, trange) \ 289 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \ 290 (trange & TRANGE_MASK)) 291 292 #define TACH_ENABLE_MASK (0x0C) 293 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100) 294 295 /* 296 * Tuneables 297 */ 298 #define ENABLE 1 299 #define DISABLE 0 300 301 int monitor_disk_temp = 1; /* enabled */ 302 static int disk_high_warn_temperature = DISK_HIGH_WARN_TEMPERATURE; 303 static int disk_low_warn_temperature = DISK_LOW_WARN_TEMPERATURE; 304 static int disk_high_shutdown_temperature = 305 DISK_HIGH_SHUTDOWN_TEMPERATURE; 306 static int disk_low_shutdown_temperature = DISK_LOW_SHUTDOWN_TEMPERATURE; 307 static int disk_scan_interval = DISK_SCAN_INTERVAL; 308 309 static int get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf); 310 static int set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf); 311 static int get_monitor_sys_mode(ptree_rarg_t *parg, void *buf); 312 static int set_monitor_sys_mode(ptree_warg_t *parg, const void *buf); 313 static int get_int_val(ptree_rarg_t *parg, void *buf); 314 static int set_int_val(ptree_warg_t *parg, const void *buf); 315 static int get_string_val(ptree_rarg_t *parg, void *buf); 316 static int set_string_val(ptree_warg_t *parg, const void *buf); 317 static int get_cpu_tach(ptree_rarg_t *parg, void *buf); 318 static int set_cpu_tach(ptree_warg_t *parg, const void *buf); 319 static int get_sys_tach(ptree_rarg_t *parg, void *buf); 320 static int set_sys_tach(ptree_warg_t *parg, const void *buf); 321 322 static int shutdown_override = 0; 323 static int sensor_poll_interval = SENSORPOLL_INTERVAL; 324 static int warning_interval = WARNING_INTERVAL; 325 static int disk_warning_interval = DISK_WARNING_INTERVAL; 326 static int disk_warning_duration = DISK_WARNING_DURATION; 327 static int shutdown_interval = SHUTDOWN_INTERVAL; 328 static int disk_shutdown_interval = DISK_SHUTDOWN_INTERVAL; 329 static int ovtemp_monitor = 1; /* enabled */ 330 static int pm_monitor = 1; /* enabled */ 331 static int mon_fanstat = 1; /* enabled */ 332 333 static int cpu_mode; 334 static int sys_mode; 335 static int cpu_tach; 336 static int sys_tach; 337 static char shutdown_cmd[] = SHUTDOWN_CMD; 338 339 env_tuneable_t tuneables[] = { 340 {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor, 341 &get_int_val, &set_int_val, sizeof (int)}, 342 343 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor, 344 &get_int_val, &set_int_val, sizeof (int)}, 345 346 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override, 347 &get_int_val, &set_int_val, sizeof (int)}, 348 349 {"cpu-hm-automode-enable", PICL_PTYPE_INT, &cpu_mode, 350 &get_monitor_cpu_mode, &set_monitor_cpu_mode, 351 sizeof (int)}, 352 353 {"sys-hm-automode-enable", PICL_PTYPE_INT, &sys_mode, 354 &get_monitor_sys_mode, &set_monitor_sys_mode, 355 sizeof (int)}, 356 357 {"sensor-poll-interval", PICL_PTYPE_INT, 358 &sensor_poll_interval, 359 &get_int_val, &set_int_val, 360 sizeof (int)}, 361 362 {"disk-scan-interval", PICL_PTYPE_INT, 363 &disk_scan_interval, 364 &get_int_val, &set_int_val, 365 sizeof (int)}, 366 367 {"warning-interval", PICL_PTYPE_INT, &warning_interval, 368 &get_int_val, &set_int_val, 369 sizeof (int)}, 370 371 {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval, 372 &get_int_val, &set_int_val, 373 sizeof (int)}, 374 375 {"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval, 376 &get_int_val, &set_int_val, 377 sizeof (int)}, 378 379 {"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration, 380 &get_int_val, &set_int_val, 381 sizeof (int)}, 382 383 {"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval, 384 &get_int_val, &set_int_val, 385 sizeof (int)}, 386 387 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd, 388 &get_string_val, &set_string_val, 389 sizeof (shutdown_cmd)}, 390 391 {"cpu-tach-enable", PICL_PTYPE_INT, &cpu_tach, 392 &get_cpu_tach, &set_cpu_tach, 393 sizeof (int)}, 394 395 {"sys-tach-enable", PICL_PTYPE_INT, &sys_tach, 396 &get_sys_tach, &set_sys_tach, 397 sizeof (int)}, 398 399 {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat, 400 &get_int_val, &set_int_val, sizeof (int)}, 401 402 {"monitor-disk-temp", PICL_PTYPE_INT, &monitor_disk_temp, 403 &get_int_val, &set_int_val, sizeof (int)}, 404 405 {"disk-high-warn-temperature", PICL_PTYPE_INT, 406 &disk_high_warn_temperature, &get_int_val, 407 &set_int_val, sizeof (int)}, 408 409 {"disk-low-warn-temperature", PICL_PTYPE_INT, 410 &disk_low_warn_temperature, &get_int_val, 411 &set_int_val, sizeof (int)}, 412 413 {"disk-high-shutdown-temperature", PICL_PTYPE_INT, 414 &disk_high_shutdown_temperature, &get_int_val, 415 &set_int_val, sizeof (int)}, 416 417 {"disk-low-shutdown-temperature", PICL_PTYPE_INT, 418 &disk_low_shutdown_temperature, &get_int_val, 419 &set_int_val, sizeof (int)}, 420 421 {"verbose", PICL_PTYPE_INT, &env_debug, 422 &get_int_val, &set_int_val, sizeof (int)}, 423 424 425 }; 426 427 /* 428 * We use this to figure out how many tuneables there are 429 * This is variable because the publishing routine needs this info 430 * in piclenvsetup.c 431 */ 432 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0])); 433 434 /* 435 * Table Handling Code 436 */ 437 static void 438 fini_table(table_t *tblp) 439 { 440 if (tblp == NULL) 441 return; 442 free(tblp->xymap); 443 free(tblp); 444 } 445 446 static table_t * 447 init_table(int npoints) 448 { 449 table_t *tblp; 450 point_t *xy; 451 452 if (npoints == 0) 453 return (NULL); 454 455 if ((tblp = malloc(sizeof (*tblp))) == NULL) 456 return (NULL); 457 458 if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) { 459 free(tblp); 460 return (NULL); 461 } 462 463 tblp->nentries = npoints; 464 tblp->xymap = xy; 465 466 return (tblp); 467 } 468 469 /* 470 * function: calculates y for a given x based on a table of points 471 * for monotonically increasing x values. 472 * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y' 473 */ 474 static int 475 y_of_x(table_t *tbl, int xval) 476 { 477 int i; 478 int entries; 479 point_t *xymap; 480 float newval; 481 float dy, dx, slope; 482 483 entries = tbl->nentries; 484 xymap = tbl->xymap; 485 /* 486 * If the temperature is outside the correction table 487 * then simply return the original value. 488 */ 489 if ((xval < xymap[0].x) || (xval > xymap[entries - 1].x)) 490 return (xval); 491 if (xval == xymap[0].x) 492 return (xymap[0].y); 493 if (xval == xymap[entries - 1].x) 494 return (xymap[entries - 1].y); 495 496 for (i = 1; i < entries - 1; i++) { 497 if (xval == xymap[i].x) 498 return (xymap[i].y); 499 if (xval < xymap[i].x) 500 break; 501 } 502 503 /* 504 * Use linear interpolation 505 */ 506 dy = (float)(xymap[i].y - xymap[i-1].y); 507 dx = (float)(xymap[i].x - xymap[i-1].x); 508 slope = dy/dx; 509 newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x); 510 return ((int)(newval + (newval >= 0 ? 0.5 : -0.5))); 511 } 512 513 /* 514 * Get environmental segment from the specified FRU SEEPROM 515 */ 516 static int 517 get_envseg(int fd, void **envsegp, int *envseglenp) 518 { 519 int i, segcnt, envseglen; 520 section_layout_t section; 521 segment_layout_t segment; 522 uint8_t *envseg; 523 524 if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L || 525 read(fd, §ion, sizeof (section)) != sizeof (section)) { 526 return (EINVAL); 527 } 528 529 /* 530 * Verify we have the correct section and contents are valid 531 * For now, we don't verify the CRC. 532 */ 533 if (section.header_tag != SECTION_HDR_TAG || 534 GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) { 535 if (env_debug) 536 envd_log(LOG_INFO, 537 "Invalid section header tag:%x version:%x\n", 538 section.header_tag, 539 GET_UNALIGN16(§ion.header_version)); 540 return (EINVAL); 541 } 542 543 /* 544 * Locate our environmental segment 545 */ 546 segcnt = section.segment_count; 547 for (i = 0; i < segcnt; i++) { 548 if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) { 549 return (EINVAL); 550 } 551 if (env_debug) 552 envd_log(LOG_INFO, 553 "Seg name: %x desc:%x off:%x len:%x\n", 554 GET_UNALIGN16(&segment.name), 555 GET_UNALIGN32(&segment.descriptor[0]), 556 GET_UNALIGN16(&segment.offset), 557 GET_UNALIGN16(&segment.length)); 558 if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME) 559 break; 560 } 561 562 if (i >= segcnt) { 563 return (ENOENT); 564 } 565 566 /* 567 * Allocate memory to hold the environmental segment data. 568 */ 569 envseglen = GET_UNALIGN16(&segment.length); 570 if ((envseg = malloc(envseglen)) == NULL) { 571 return (ENOMEM); 572 } 573 574 if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L || 575 read(fd, envseg, envseglen) != envseglen) { 576 (void) free(envseg); 577 return (EIO); 578 } 579 *envsegp = envseg; 580 *envseglenp = envseglen; 581 return (0); 582 } 583 584 /* 585 * Get all environmental segments 586 * Return NULL on error 587 */ 588 static fruenvseg_t * 589 get_fru_envsegs(void) 590 { 591 fruenvseg_t *fruenvsegs; 592 envseg_layout_t *envsegp; 593 void *envsegbufp; 594 int fd, envseglen, hdrlen; 595 char path[PATH_MAX]; 596 597 fruenvsegs = NULL; 598 fruenvsegs = malloc(sizeof (*fruenvsegs)); 599 if (fruenvsegs == NULL) { 600 return (NULL); 601 } 602 603 /* 604 * Now get the environmental segment from this FRU 605 */ 606 (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV); 607 fd = open(path, O_RDONLY); 608 if (fd == -1) { 609 envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path); 610 free(fruenvsegs); 611 return (NULL); 612 } 613 614 /* 615 * Read environmental segment from this FRU SEEPROM 616 */ 617 if (get_envseg(fd, &envsegbufp, &envseglen) != 0) { 618 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path); 619 free(fruenvsegs); 620 (void) close(fd); 621 return (NULL); 622 } 623 624 /* 625 * Validate envseg version number and header length 626 */ 627 envsegp = (envseg_layout_t *)envsegbufp; 628 hdrlen = sizeof (envseg_layout_t) - 629 sizeof (envseg_sensor_t) + 630 (envsegp->sensor_count) * sizeof (envseg_sensor_t); 631 632 if (envsegp->version != ENVSEG_VERSION || 633 envseglen < hdrlen) { 634 /* 635 * version mismatch or header not big enough 636 */ 637 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 638 if (envsegbufp != NULL) 639 (void) free(envsegbufp); 640 free(fruenvsegs); 641 (void) close(fd); 642 return (NULL); 643 } 644 645 fruenvsegs->envseglen = envseglen; 646 fruenvsegs->envsegbufp = envsegbufp; 647 (void) close(fd); 648 return (fruenvsegs); 649 } 650 651 static int 652 process_fru_seeprom(unsigned char *buff) 653 { 654 id_off_t id; 655 int i; 656 int id_offset = 0; 657 int nsensors; 658 int nfans; 659 env_fan_t *fnodep; 660 env_sensor_t *snodep; 661 662 #define NSENSOR_OFFSET 1 663 #define ID_OFF_SIZE 6 664 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2) 665 666 nsensors = (int)buff[NSENSOR_OFFSET]; 667 if (nsensors != MAX_SENSORS) { 668 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 669 return (-1); 670 } 671 672 nfans = (int)buff[NFANS_OFFSET(nsensors)]; 673 if (nfans != MAX_FANS) { 674 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 675 return (-1); 676 } 677 678 while (nsensors > 0) { 679 (void) memcpy((char *)&id, 680 (char *)&buff[id_offset + 2], 681 ID_OFF_SIZE); 682 683 if (env_debug) 684 envd_log(LOG_ERR, "\n Sensor Id %x offset %x", 685 id.id, id.offset); 686 687 if (id.id > MAX_SENSOR_ID) { 688 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 689 FRU_SEEPROM_NAME); 690 return (-1); 691 } 692 693 /* 694 * Copy into the sensor control block array according to the 695 * sensor ID 696 */ 697 (void) memcpy((char *)&sensor_ctrl[id.id], 698 (char *)&buff[id.offset], 699 sizeof (sensor_ctrl_blk_t)); 700 nsensors--; 701 id_offset += ID_OFF_SIZE; 702 } 703 704 /* 705 * Skip past no of Fan entry(single byte) 706 */ 707 id_offset++; 708 while (nfans > 0) { 709 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], 710 ID_OFF_SIZE); 711 712 if (env_debug) 713 envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id, 714 id.offset); 715 716 if (id.id > 3) { 717 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 718 FRU_SEEPROM_NAME); 719 return (-1); 720 } 721 722 (void) memcpy((char *)&fan_ctrl[id.id], 723 (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t)); 724 725 nfans--; 726 id_offset += ID_OFF_SIZE; 727 } 728 729 /* 730 * Match Sensor/ES ID and point correct data 731 * based on IDs 732 */ 733 for (i = 0; i < N_ENVD_SENSORS; i++) { 734 snodep = &envd_sensors[i]; 735 snodep->es_ptr = &sensor_ctrl[snodep->id]; 736 } 737 738 /* 739 * Match Fan/ES ID and point to correct ES Data 740 * based on IDs 741 */ 742 for (i = 0; (fnodep = envd_fans[i]) != NULL; i++) 743 fnodep->es_ptr = &fan_ctrl[fnodep->id]; 744 745 return (0); 746 } 747 748 static int 749 envd_es_setup(void) 750 { 751 envfru = get_fru_envsegs(); 752 if (envfru == NULL) { 753 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 754 return (-1); 755 } 756 return (process_fru_seeprom((uchar_t *)envfru->envsegbufp)); 757 } 758 759 static void 760 envd_es_destroy(void) 761 { 762 if (envfru != NULL) 763 free(envfru->envsegbufp); 764 } 765 766 /* 767 * Lookup fan and return a pointer to env_fan_t data structure. 768 */ 769 env_fan_t * 770 fan_lookup(char *name) 771 { 772 int i; 773 env_fan_t *fanp; 774 775 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 776 if (strcmp(fanp->name, name) == 0) 777 return (fanp); 778 } 779 return (NULL); 780 } 781 782 /* 783 * Lookup sensor and return a pointer to env_sensor_t data structure. 784 */ 785 env_sensor_t * 786 sensor_lookup(char *name) 787 { 788 env_sensor_t *sensorp; 789 int i; 790 791 for (i = 0; i < N_ENVD_SENSORS; ++i) { 792 sensorp = &envd_sensors[i]; 793 if (strcmp(sensorp->name, name) == 0) 794 return (sensorp); 795 } 796 return (NULL); 797 } 798 799 /* 800 * Lookup disk and return a pointer to env_disk_t data structure. 801 */ 802 env_disk_t * 803 disk_lookup(char *name) 804 { 805 int i; 806 env_disk_t *diskp; 807 808 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 809 if (strncmp(diskp->name, name, strlen(name)) == 0) 810 return (diskp); 811 } 812 return (NULL); 813 } 814 815 /* 816 * Get current temperature 817 * Returns -1 on error, 0 if successful 818 */ 819 int 820 get_temperature(env_sensor_t *sensorp, tempr_t *temp) 821 { 822 int fd = sensorp->fd; 823 int retval = 0; 824 825 if (fd == -1) 826 retval = -1; 827 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 828 829 retval = -1; 830 831 if (sensorp->error == 0) { 832 sensorp->error = 1; 833 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, 834 sensorp->name, errno, strerror(errno)); 835 } 836 } else if (sensorp->error != 0) { 837 sensorp->error = 0; 838 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name); 839 } 840 if (sensorp->crtbl != NULL) { 841 *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp); 842 } 843 844 return (retval); 845 } 846 847 /* 848 * Get current disk temperature 849 * Returns -1 on error, 0 if successful 850 */ 851 int 852 disk_temperature(env_disk_t *diskp, tempr_t *temp) 853 { 854 int retval = 0; 855 856 if (diskp == NULL) 857 retval = -1; 858 else { 859 *temp = diskp->current_temp; 860 } 861 return (retval); 862 } 863 864 /* 865 * Get uncorrected current temperature 866 * Returns -1 on error, 0 if successful 867 */ 868 static int 869 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp) 870 { 871 int fd = sensorp->fd; 872 int retval = 0; 873 874 if (fd == -1) 875 retval = -1; 876 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 877 retval = -1; 878 } 879 880 return (retval); 881 } 882 883 /* 884 * Return Fan RPM given N & tach 885 * count and N are retrived from the 886 * ADM1031 chip. 887 */ 888 static int 889 tach_to_rpm(int n, uint8_t tach) 890 { 891 if (n * tach == 0) 892 return (0); 893 return ((ADCSAMPLE * 60) / (n * tach)); 894 } 895 896 static int 897 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp) 898 { 899 int fan_fd; 900 int retval = 0; 901 902 fan_fd = fanp->fd; 903 904 if (fan_fd == -1) 905 retval = -1; 906 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) { 907 retval = -1; 908 } 909 910 911 return (retval); 912 } 913 914 /* 915 * Get current fan speed 916 * This function returns a RPM value for fanspeed 917 * in fanspeedp. 918 * Returns -1 on error, 0 if successful 919 */ 920 int 921 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp) 922 { 923 int fan_fd; 924 uint8_t tach; 925 926 fan_fd = fanp->fd; 927 928 if (fan_fd == -1) 929 return (-1); 930 if (fanp->id == DIMM_FAN_ID) { 931 return (get_dimm_fan_speed(fan_fd, fanspeedp)); 932 } 933 if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) { 934 return (-1); 935 } 936 937 /* 938 * Fanspeeds are reported as 0 939 * if the tach is out of range or fan status is off 940 * and if monitoring fan status is enabled. 941 */ 942 if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) { 943 *fanspeedp = 0; 944 } else { 945 *fanspeedp = 946 tach_to_rpm(fanp->speedrange, tach); 947 } 948 949 return (0); 950 } 951 952 /* 953 * Set fan speed 954 * This function accepts a percentage of fan speed 955 * from 0-100 and programs the HW monitor fans to the corresponding 956 * fanspeed value. 957 * Returns -1 on error, -2 on invalid args passed, 0 if successful 958 */ 959 int 960 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed) 961 { 962 int fan_fd; 963 int retval = 0; 964 uint8_t speed; 965 966 fan_fd = fanp->fd; 967 if (fan_fd == -1) 968 return (-1); 969 970 if (fanspeed < 0 || fanspeed > 100) 971 return (-2); 972 973 speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed); 974 975 if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) { 976 retval = -1; 977 } 978 return (retval); 979 } 980 981 /* 982 * close all fan devices 983 */ 984 static void 985 envd_close_fans(void) 986 { 987 int i; 988 env_fan_t *fanp; 989 990 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 991 if (fanp->fd != -1) { 992 (void) close(fanp->fd); 993 fanp->fd = -1; 994 } 995 } 996 } 997 998 /* 999 * Close sensor devices and freeup resources 1000 */ 1001 static void 1002 envd_close_sensors(void) 1003 { 1004 env_sensor_t *sensorp; 1005 int i; 1006 1007 for (i = 0; i < N_ENVD_SENSORS; ++i) { 1008 sensorp = &envd_sensors[i]; 1009 if (sensorp->fd != -1) { 1010 (void) close(sensorp->fd); 1011 sensorp->fd = -1; 1012 } 1013 if (sensorp->crtbl != NULL) 1014 fini_table(sensorp->crtbl); 1015 } 1016 } 1017 1018 /* 1019 * Open fan devices and initialize per fan data structure. 1020 * Returns #fans found. 1021 */ 1022 static int 1023 envd_setup_fans(void) 1024 { 1025 int i, fd; 1026 env_fan_t *fanp; 1027 char path[PATH_MAX]; 1028 int fancnt = 0; 1029 uint8_t n = 0; 1030 picl_nodehdl_t tnodeh; 1031 i2c_reg_t i2c_reg; 1032 1033 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 1034 /* make sure cpu0/1 present for validating cpu fans */ 1035 if (fanp->id == CPU0_FAN_ID) { 1036 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 1037 PICL_SUCCESS) { 1038 fanp->present = B_FALSE; 1039 continue; 1040 } 1041 } 1042 if (fanp->id == CPU1_FAN_ID) { 1043 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 1044 PICL_SUCCESS) { 1045 fanp->present = B_FALSE; 1046 continue; 1047 } 1048 } 1049 if (fanp->id == DIMM_FAN_ID) { 1050 if (ptree_get_node_by_path(DIMM_FAN_CONTROLLER_PATH, 1051 &tnodeh) != PICL_SUCCESS) { 1052 if (env_debug) 1053 envd_log(LOG_ERR, 1054 "dimm Fan not found in the system.\n"); 1055 fanp->present = B_FALSE; 1056 continue; 1057 } 1058 } 1059 (void) strcpy(path, "/devices"); 1060 (void) strlcat(path, fanp->devfs_path, sizeof (path)); 1061 fd = open(path, O_RDWR); 1062 if (fd == -1) { 1063 envd_log(LOG_CRIT, 1064 ENV_FAN_OPEN_FAIL, fanp->name, 1065 fanp->devfs_path, errno, strerror(errno)); 1066 fanp->present = B_FALSE; 1067 continue; 1068 } 1069 fanp->fd = fd; 1070 if (fanp->id == DIMM_FAN_ID) { 1071 /* 1072 * set the SW aware bit in command register. 1073 * Clear the Fan fault latch bit. 1074 */ 1075 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 1076 i2c_reg.reg_value = (PIC16F819_SW_AWARE_MODE | 1077 PIC16F819_FAN_FAULT_CLEAR); 1078 if (ioctl(fd, I2C_SET_REG, &i2c_reg) == -1) { 1079 if (env_debug) 1080 envd_log(LOG_ERR, 1081 "Error in writing to COMMAND reg. of DIMM FAN controller\n"); 1082 } 1083 } else { 1084 /* Get speed range value */ 1085 if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) { 1086 fanp->speedrange = 1087 adm_speedrange_map[(n >> 6) & 0x03]; 1088 } else { 1089 fanp->speedrange = FAN_RANGE_DEFAULT; 1090 } 1091 } 1092 fanp->present = B_TRUE; 1093 fanp->fanstat = 0; 1094 fanp->cspeed = TACH_UNKNOWN; 1095 fanp->lspeed = TACH_UNKNOWN; 1096 fanp->conccnt = 0; 1097 fancnt++; 1098 } 1099 return (fancnt); 1100 } 1101 1102 static int 1103 envd_setup_disks(void) 1104 { 1105 int ret, i, page_index, page_len; 1106 picl_nodehdl_t tnodeh; 1107 env_disk_t *diskp; 1108 uint_t vendor_id; 1109 uint_t device_id; 1110 uchar_t log_page[256]; 1111 1112 /* 1113 * Check if the SCSi controller on the system is 1010 or 1030 1114 */ 1115 1116 if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH, 1117 &tnodeh) != PICL_SUCCESS) { 1118 if (env_debug) 1119 envd_log(LOG_ERR, 1120 "On-Board SCSI controller not found in the system.\n"); 1121 monitor_disk_temp = 0; 1122 return (-1); 1123 } 1124 1125 if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID, 1126 &vendor_id, 1127 sizeof (vendor_id))) != 0) { 1128 if (env_debug) 1129 envd_log(LOG_ERR, 1130 "Error in getting vendor-id for SCSI controller. ret = %d errno = 0x%d\n", 1131 ret, errno); 1132 monitor_disk_temp = 0; 1133 return (-1); 1134 } 1135 if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID, 1136 &device_id, 1137 sizeof (device_id))) != 0) { 1138 if (env_debug) 1139 envd_log(LOG_ERR, 1140 "Error in getting device-id for SCSI controller. ret = %d errno = 0x%d\n", 1141 ret, errno); 1142 monitor_disk_temp = 0; 1143 return (-1); 1144 } 1145 if (env_debug) 1146 envd_log(LOG_ERR, "vendor-id=0x%x device-id=0x%x\n", 1147 vendor_id, device_id); 1148 if ((vendor_id != LSI1030_VENDOR_ID) || 1149 (device_id != LSI1030_DEVICE_ID)) { 1150 monitor_disk_temp = 0; 1151 return (-1); 1152 } 1153 /* 1154 * We have found LSI1030 SCSi controller onboard. 1155 */ 1156 1157 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 1158 1159 if (ptree_get_node_by_path(diskp->nodepath, 1160 &tnodeh) != PICL_SUCCESS) { 1161 diskp->present = B_FALSE; 1162 if (env_debug) 1163 envd_log(LOG_ERR, 1164 "DISK %d not found in the system.\n", 1165 diskp->id); 1166 continue; 1167 } 1168 diskp->fd = open(diskp->devfs_path, O_RDONLY); 1169 if (diskp->fd == -1) { 1170 diskp->present = B_FALSE; 1171 envd_log(LOG_ERR, 1172 "Error in opening %s errno = 0x%x\n", 1173 diskp->devfs_path, errno); 1174 continue; 1175 } 1176 diskp->present = B_TRUE; 1177 diskp->tpage_supported = B_FALSE; 1178 /* 1179 * Find out if the Temperature page is supported by the disk. 1180 */ 1181 ret = scsi_log_sense(diskp->fd, SUPPORTED_LPAGES, 1182 log_page, sizeof (log_page)); 1183 if (ret != 0) { 1184 continue; 1185 } 1186 page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3]; 1187 1188 for (page_index = LOGPAGEHDRSIZE; 1189 page_index < page_len + LOGPAGEHDRSIZE; page_index++) { 1190 switch (log_page[page_index]) { 1191 case TEMPERATURE_PAGE: 1192 diskp->tpage_supported = B_TRUE; 1193 if (env_debug) 1194 envd_log(LOG_ERR, 1195 "tpage supported for %s\n", 1196 diskp->nodepath); 1197 default: 1198 break; 1199 } 1200 } 1201 diskp->warning_tstamp = 0; 1202 diskp->shutdown_tstamp = 0; 1203 diskp->high_warning = disk_high_warn_temperature; 1204 diskp->low_warning = disk_low_warn_temperature; 1205 diskp->high_shutdown = disk_high_shutdown_temperature; 1206 diskp->low_shutdown = disk_low_shutdown_temperature; 1207 ret = get_disk_temp(diskp); 1208 } 1209 return (0); 1210 } 1211 1212 /* 1213 * Open temperature sensor devices and initialize per sensor data structure. 1214 * Returns #sensors found. 1215 */ 1216 static int 1217 envd_setup_sensors(void) 1218 { 1219 env_sensor_t *sensorp; 1220 sensor_ctrl_blk_t *es_ptr; 1221 table_t *tblp; 1222 char path[PATH_MAX]; 1223 int sensorcnt = 0; 1224 int i, j, nentries; 1225 int16_t tmin = 0; 1226 picl_nodehdl_t tnodeh; 1227 1228 for (i = 0; i < N_ENVD_SENSORS; ++i) { 1229 sensorp = &envd_sensors[i]; 1230 /* Initialize sensor's initial state */ 1231 sensorp->shutdown_initiated = B_FALSE; 1232 sensorp->warning_tstamp = 0; 1233 sensorp->shutdown_tstamp = 0; 1234 sensorp->error = 0; 1235 sensorp->crtbl = NULL; 1236 /* make sure cpu0/1 sensors are present */ 1237 if (sensorp->id == CPU0_SENSOR_ID) { 1238 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 1239 PICL_SUCCESS) { 1240 sensorp->present = B_FALSE; 1241 continue; 1242 } 1243 } 1244 if (sensorp->id == CPU1_SENSOR_ID) { 1245 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 1246 PICL_SUCCESS) { 1247 sensorp->present = B_FALSE; 1248 continue; 1249 } 1250 } 1251 (void) strcpy(path, "/devices"); 1252 (void) strlcat(path, sensorp->devfs_path, 1253 sizeof (path)); 1254 sensorp->fd = open(path, O_RDWR); 1255 if (sensorp->fd == -1) { 1256 envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL, 1257 sensorp->name, sensorp->devfs_path, 1258 errno, strerror(errno)); 1259 sensorp->present = B_FALSE; 1260 continue; 1261 } 1262 sensorp->present = B_TRUE; 1263 sensorcnt++; 1264 1265 /* 1266 * Get Tmin 1267 */ 1268 1269 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE, 1270 &tmin) != -1) { 1271 sensorp->tmin = TMIN(tmin); 1272 } else { 1273 sensorp->tmin = -1; 1274 } 1275 if (env_debug) 1276 envd_log(LOG_ERR, "Sensor %s tmin %d", 1277 sensorp->name, sensorp->tmin); 1278 1279 /* 1280 * Create a correction table 1281 * if correction pairs are present in es 1282 * segment. 1283 */ 1284 es_ptr = sensorp->es_ptr; 1285 1286 if (es_ptr == NULL) { 1287 continue; 1288 } 1289 nentries = es_ptr->correctionEntries; 1290 1291 if (nentries <= 2) { 1292 if (env_debug) 1293 envd_log(LOG_CRIT, "sensor correction <2"); 1294 continue; 1295 } 1296 1297 sensorp->crtbl = init_table(nentries); 1298 if (sensorp->crtbl == NULL) 1299 continue; 1300 tblp = sensorp->crtbl; 1301 tblp->xymap[0].x = 1302 (char)es_ptr->correctionPair[0].measured; 1303 tblp->xymap[0].y = 1304 (char)es_ptr->correctionPair[0].corrected; 1305 1306 for (j = 1; j < nentries; ++j) { 1307 tblp->xymap[j].x = 1308 (char)es_ptr->correctionPair[j].measured; 1309 tblp->xymap[j].y = 1310 (char)es_ptr->correctionPair[j].corrected; 1311 1312 if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) { 1313 fini_table(tblp); 1314 sensorp->crtbl = NULL; 1315 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 1316 FRU_SEEPROM_NAME); 1317 break; 1318 } 1319 } 1320 1321 if (env_debug) { 1322 envd_log(LOG_CRIT, "Sensor correction %s", 1323 sensorp->name); 1324 for (j = 0; j < nentries; j++) 1325 envd_log(LOG_CRIT, " %d %d", 1326 tblp->xymap[j].x, tblp->xymap[j].y); 1327 } 1328 } 1329 return (sensorcnt); 1330 } 1331 1332 /* 1333 * Modify ADM Tmin/ranges depending what power level 1334 * we are from. 1335 */ 1336 static void 1337 updateadm_ranges(char *name, uchar_t cur_lpstate) 1338 { 1339 env_sensor_t *sensorp; 1340 fan_ctrl_blk_t *fanctl; 1341 uchar_t tmin; 1342 uchar_t trange; 1343 uint16_t tdata; 1344 int sysfd; 1345 uchar_t sys_id = SYS_HWM_ID; 1346 uint8_t mode; 1347 static uint16_t tsave[2] = {0, 0}; 1348 /* Index of saved Tmin/Trange for two sensors */ 1349 uint16_t tindex = 0; 1350 1351 sensorp = sensor_lookup(name); 1352 if (sensorp == NULL) 1353 return; 1354 1355 /* 1356 * If there is only one Control pairs then return 1357 */ 1358 fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr; 1359 1360 if (fanctl != NULL && fanctl->no_ctl_pairs <= 1) 1361 return; 1362 1363 /* 1364 * if fan control specifies that ranges are same then 1365 * we skip re-programming adm chip. 1366 */ 1367 1368 tmin = fanctl->fan_ctl_pairs[0].tMin; 1369 trange = fanctl->fan_ctl_pairs[0].tRange; 1370 if ((tmin == fanctl->fan_ctl_pairs[1].tMin) && 1371 (trange == fanctl->fan_ctl_pairs[1].tRange)) 1372 return; 1373 1374 sysfd = open(hwm_devs[sys_id], O_RDWR); 1375 if (sysfd == -1) { 1376 if (env_debug) 1377 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id], 1378 errno, strerror(errno)); 1379 return; 1380 } 1381 tindex = ((strcmp(name, SENSOR_SYS_IN) == 0) ? 0 : 1); 1382 1383 /* Read ADM default value only for the first time */ 1384 if (tsave[tindex] == 0) { 1385 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE, 1386 &tsave[tindex]) == -1) { 1387 if (env_debug) 1388 envd_log(LOG_ERR, 1389 "read tminrange ioctl failed"); 1390 (void) close(sysfd); 1391 return; 1392 } 1393 } 1394 /* 1395 * Need to reinit ADM to manual mode for Tmin range to be 1396 * effective. 1397 */ 1398 mode = ADM1031_MANUAL_MODE; 1399 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) { 1400 if (env_debug) 1401 envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE); 1402 (void) close(sysfd); 1403 return; 1404 } 1405 1406 if (cur_lpstate == 1) { 1407 /* 1408 * ADM 1031 Tmin/Trange register need to be reprogrammed. 1409 */ 1410 tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS) 1411 << TMIN_SHIFT); 1412 /* Need to pack tRange in ADM bits 2:0 */ 1413 switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) { 1414 case 5: 1415 break; 1416 1417 case 10: 1418 tdata |= 1; 1419 break; 1420 1421 case 20: 1422 tdata |= 2; 1423 break; 1424 1425 case 40: 1426 tdata |= 3; 1427 break; 1428 1429 case 80: 1430 tdata |= 4; 1431 break; 1432 } 1433 } else 1434 tdata = tsave[tindex]; 1435 1436 if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE, 1437 &tdata) != -1) 1438 sensorp->tmin = TMIN(tdata); 1439 1440 mode = ADM1031_AUTO_MODE; 1441 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) { 1442 if (env_debug) 1443 envd_log(LOG_ERR, ENV_ADM_AUTO_MODE); 1444 } 1445 (void) close(sysfd); 1446 } 1447 1448 /* ARGSUSED */ 1449 static void * 1450 pmthr(void *args) 1451 { 1452 pm_state_change_t pmstate; 1453 char physpath[PATH_MAX]; 1454 int pre_lpstate; 1455 1456 pmstate.physpath = physpath; 1457 pmstate.size = sizeof (physpath); 1458 cur_lpstate = 0; 1459 pre_lpstate = 1; 1460 1461 pm_fd = open(PM_DEVICE, O_RDWR); 1462 if (pm_fd == -1) { 1463 envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno)); 1464 return (NULL); 1465 } 1466 for (;;) { 1467 /* 1468 * Get PM state change events to check if the system 1469 * is in lowest power state and adjust ADM hardware 1470 * monitor's fan speed settings. 1471 * 1472 * To minimize polling, we use the blocking interface 1473 * to get the power state change event here. 1474 */ 1475 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) { 1476 if (errno != EINTR) 1477 break; 1478 continue; 1479 } 1480 do { 1481 if (env_debug) { 1482 envd_log(LOG_INFO, 1483 "pmstate event:0x%x flags:%x" 1484 "comp:%d oldval:%d newval:%d path:%s\n", 1485 pmstate.event, pmstate.flags, 1486 pmstate.component, 1487 pmstate.old_level, 1488 pmstate.new_level, 1489 pmstate.physpath); 1490 } 1491 cur_lpstate = 1492 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0; 1493 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0); 1494 /* 1495 * Change ADM ranges as per E* Requirements. Update 1496 * happens only for valid state changes. 1497 */ 1498 if (pre_lpstate != cur_lpstate) { 1499 pre_lpstate = cur_lpstate; 1500 updateadm_ranges(SENSOR_SYS_OUT, cur_lpstate); 1501 updateadm_ranges(SENSOR_SYS_IN, cur_lpstate); 1502 } 1503 } 1504 /* Not reached */ 1505 return (NULL); 1506 } 1507 1508 /* 1509 * This function is used to reasonably predict the 1510 * state of the fan (ON/OFF) using tmin and current temperature. 1511 * 1512 * We know the fan is on if temp >= tmin and fan is off if 1513 * temp < (Tmin - Hysterisis). 1514 * 1515 * When the temperature is in between we don't know if the fan is on/off 1516 * because the temperature could be decreasing and not have crossed 1517 * Tmin - hysterisis and vice a versa. 1518 * 1519 * FAN ON 1520 * Tmin 1521 * ------------------------------------------- 1522 * 1523 * FAN ON/OFF 1524 * 1525 * -------------------------------------------- 1526 * Tmin - Hysterisis 1527 * FAN OFF 1528 * 1529 * To solve the problem of finding out if the fan is on/off in our gray region 1530 * we keep track of the last read tach and the current read tach. From 1531 * experimentation and from discussions with analog devices it is unlikely that 1532 * if the fans are on we will get a constant tach reading more than 5 times in 1533 * a row. This is not but the most fool proof approach but the best we can do. 1534 * 1535 * This routine implements the above logic for a sensor with an 1536 * associated fan. The caller garauntees sensorp and fanp are not null. 1537 */ 1538 1539 static void 1540 check_fanstat(env_sensor_t *sensorp) 1541 { 1542 env_fan_t *fanp = sensorp->fanp; 1543 tempr_t temp; 1544 uint8_t fanspeed; 1545 1546 if (get_raw_temperature(sensorp, &temp) == -1) 1547 return; 1548 1549 if (temp < (sensorp->tmin - ADM_HYSTERISIS)) { 1550 1551 fanp->fanstat = 0; /* Fan off */ 1552 fanp->lspeed = TACH_UNKNOWN; /* Reset Last read tach */ 1553 fanp->conccnt = 0; 1554 1555 } else if (temp >= sensorp->tmin) { 1556 1557 fanp->fanstat = 1; /* Fan on */ 1558 fanp->lspeed = TACH_UNKNOWN; 1559 fanp->conccnt = 0; 1560 1561 } else { 1562 if (get_raw_fan_speed(fanp, &fanspeed) == -1) 1563 return; 1564 1565 fanp->cspeed = fanspeed; 1566 /* 1567 * First time in the gray area 1568 * set last read speed to current speed 1569 */ 1570 if (fanp->lspeed == TACH_UNKNOWN) { 1571 fanp->lspeed = fanspeed; 1572 } else { 1573 if (fanp->lspeed != fanp->cspeed) { 1574 fanp->conccnt = 0; 1575 fanp->fanstat = 1; 1576 } else { 1577 fanp->conccnt++; 1578 1579 if (fanp->conccnt >= N_SEQ_TACH) 1580 fanp->fanstat = 0; 1581 } 1582 fanp->lspeed = fanp->cspeed; 1583 } 1584 } 1585 } 1586 /* 1587 * There is an issue with the ADM1031 chip that causes the chip 1588 * to not update the tach register in case the fan stops. The 1589 * fans stop when the temperature measured (temp) drops below 1590 * Tmin - Hysterisis and turn on when the temp >= Tmin. 1591 * 1592 * Since the tach registers don't update and remain stuck at the 1593 * last read tach value our get_fan_speed function always returns 1594 * a non-zero RPM reading. 1595 * 1596 * To fix this we need to figure out when the fans will be on/off 1597 * depending on the current temperature. Currently we poll for 1598 * interrupts, we can use that loop to determine what the current 1599 * temperature is and if the fans should be on/off. 1600 * 1601 * We get current temperature and check the fans. 1602 */ 1603 static void 1604 monitor_fanstat(void) 1605 { 1606 env_sensor_t *sensorp; 1607 env_fan_t *fanp; 1608 int i; 1609 1610 for (i = 0; i < N_ENVD_SENSORS; i++) { 1611 sensorp = &envd_sensors[i]; 1612 1613 if (!sensorp) 1614 continue; 1615 1616 fanp = sensorp->fanp; 1617 1618 if (!(fanp && fanp->present)) 1619 continue; 1620 1621 if (sensorp->tmin != -1) { 1622 check_fanstat(sensorp); 1623 } else { 1624 fanp->fanstat = 1; 1625 } 1626 1627 } 1628 } 1629 1630 static int 1631 handle_overtemp_interrupt(int hwm_id) 1632 { 1633 env_sensor_t *sensorp; 1634 tempr_t temp; 1635 uchar_t smap[MAX_SENSORS]; 1636 time_t ct; 1637 uchar_t i; 1638 char msgbuf[BUFSIZ]; 1639 char syscmd[BUFSIZ]; 1640 boolean_t return_flag; 1641 int ret; 1642 timespec_t to; 1643 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1644 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1645 1646 /* Clear Map of Sensor Entries */ 1647 (void) memset(smap, SENSOR_OK, sizeof (smap)); 1648 1649 for (;;) { 1650 for (i = 0; i < N_ENVD_SENSORS; i++) { 1651 sensorp = &envd_sensors[i]; 1652 1653 /* 1654 * Check whether the sensor belongs to the 1655 * interrupting ADM hardware monitor 1656 */ 1657 if (sensorp->hwm_id != hwm_id) 1658 continue; 1659 1660 if (sensorp->present == B_FALSE) 1661 continue; 1662 /* 1663 * if shutdown is initiated then we simply loop 1664 * through the sensors until shutdown 1665 */ 1666 if (sensorp->shutdown_initiated == B_TRUE) 1667 continue; 1668 1669 /* get current temp for this sensor */ 1670 if (get_temperature(sensorp, &temp) == -1) 1671 continue; 1672 1673 sensorp->cur_temp = temp; 1674 1675 if (env_debug) 1676 envd_log(LOG_ERR, 1677 "sensor name %s, cur temp %d, " 1678 "HW %d LW %d SD %d LS %d\n", 1679 sensorp->name, temp, 1680 sensorp->es_ptr->high_warning, 1681 (int)sensorp->es_ptr->low_warning, 1682 sensorp->es_ptr->high_shutdown, 1683 (int)sensorp->es_ptr->low_shutdown); 1684 1685 if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) { 1686 /* 1687 * Log on warning atmost one second 1688 */ 1689 ct = (time_t)(gethrtime() / NANOSEC); 1690 if ((ct - sensorp->warning_tstamp) >= 1691 warning_interval) { 1692 envd_log(LOG_CRIT, 1693 ENV_WARNING_MSG, sensorp->name, 1694 temp, 1695 sensorp->es_ptr->low_warning, 1696 sensorp->es_ptr->high_warning); 1697 sensorp->warning_tstamp = ct; 1698 } 1699 smap[i] = SENSOR_WARN; 1700 } else { 1701 /* 1702 * We will fall in this caterory only if 1703 * Temperature drops/increases from warning 1704 * threshold. If so we set sensor map to 1705 * OK so that we can exit the loop if 1706 * shutdown not initiated. 1707 */ 1708 smap[i] = SENSOR_OK; 1709 } 1710 1711 if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) && 1712 !shutdown_override) { 1713 ct = (time_t)(gethrtime() / NANOSEC); 1714 if (sensorp->shutdown_tstamp == 0) 1715 sensorp->shutdown_tstamp = ct; 1716 if ((ct - sensorp->shutdown_tstamp) >= 1717 shutdown_interval) { 1718 sensorp->shutdown_initiated = B_TRUE; 1719 (void) snprintf(msgbuf, sizeof (msgbuf), 1720 ENV_SHUTDOWN_MSG, sensorp->name, 1721 temp, 1722 sensorp->es_ptr->low_shutdown, 1723 sensorp->es_ptr->high_shutdown); 1724 envd_log(LOG_ALERT, msgbuf); 1725 } 1726 if (system_shutdown_started == B_FALSE) { 1727 (void) snprintf(syscmd, sizeof (syscmd), 1728 "%s \"%s\"", SHUTDOWN_CMD, msgbuf); 1729 envd_log(LOG_ALERT, syscmd); 1730 system_shutdown_started = B_TRUE; 1731 (void) system(syscmd); 1732 } 1733 } else if (sensorp->shutdown_tstamp != 0) 1734 sensorp->shutdown_tstamp = 0; 1735 } 1736 1737 /* 1738 * Sweep thorugh Sensor Map and if warnings OR shutdown 1739 * are not logged then return to caller. 1740 */ 1741 return_flag = B_TRUE; 1742 for (i = 0; i < N_ENVD_SENSORS; i++) 1743 if (smap[i] == SENSOR_WARN) 1744 return_flag = B_FALSE; 1745 1746 if ((return_flag == B_TRUE) && 1747 (system_shutdown_started == B_FALSE)) { 1748 return (1); 1749 } 1750 1751 wait_till_timeout: 1752 /* 1753 * We use pthread_cond_reltimedwait_np to sleep for 1754 * fixed interval of time. 1755 * earlier implementation used alarm() call which 1756 * fails in Multi threaded environment. If multiple 1757 * threads call alarm() only one of the threads is 1758 * sent the SIGALRM signal. 1759 */ 1760 (void) pthread_mutex_lock(&env_monitor_mutex); 1761 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1762 &env_monitor_mutex, &to); 1763 to.tv_sec = SENSORPOLL_INTERVAL; 1764 to.tv_nsec = 0; 1765 if (ret != ETIMEDOUT) { 1766 (void) pthread_mutex_unlock(&env_monitor_mutex); 1767 goto wait_till_timeout; 1768 } 1769 (void) pthread_mutex_unlock(&env_monitor_mutex); 1770 } 1771 } 1772 1773 /* 1774 * This is env thread which monitors the current temperature when 1775 * warning threshold is exceeded. The job is to make sure it does 1776 * not execced/decrease shutdown threshold. If it does it will start 1777 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt. 1778 * For Enchilada there will be two threads, one for each ADM chip. 1779 */ 1780 static void * 1781 ovtemp_thr(void *args) 1782 { 1783 int fd; 1784 uint8_t stat[2]; 1785 int hwm_id = (int)args; 1786 int err; 1787 env_fan_t *fanp; 1788 timespec_t to; 1789 int ret; 1790 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1791 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1792 1793 fd = open(hwm_devs[hwm_id], O_RDWR); 1794 if (fd == -1) { 1795 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id], 1796 errno, strerror(errno)); 1797 return (NULL); 1798 } 1799 if (env_debug) 1800 envd_log(LOG_ERR, "ovtemp thread for %s running...\n", 1801 hwm_devs[hwm_id]); 1802 1803 for (;;) { 1804 /* 1805 * Sleep for specified seconds before issuing IOCTL 1806 * again. 1807 */ 1808 1809 /* 1810 * We use pthread_cond_reltimedwait_np to sleep for 1811 * fixed interval of time. 1812 * earlier implementation used alarm() call which 1813 * fails in Multi threaded environment. If multiple 1814 * threads call alarm() only one of the threads is 1815 * sent the SIGALRM signal. 1816 */ 1817 (void) pthread_mutex_lock(&env_monitor_mutex); 1818 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1819 &env_monitor_mutex, &to); 1820 to.tv_sec = INTERRUPTPOLL_INTERVAL; 1821 to.tv_nsec = 0; 1822 if (ret != ETIMEDOUT) { 1823 (void) pthread_mutex_unlock(&env_monitor_mutex); 1824 continue; 1825 } 1826 (void) pthread_mutex_unlock(&env_monitor_mutex); 1827 /* 1828 * Monitor the sensors to update fan status 1829 */ 1830 if (mon_fanstat) 1831 monitor_fanstat(); 1832 1833 /* 1834 * Read ADM1031 two Status Registers to determine source 1835 * of Interrupts. 1836 */ 1837 1838 if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1) 1839 err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]); 1840 1841 if (err == -1) { 1842 if (env_debug) 1843 envd_log(LOG_ERR, 1844 "OverTemp: Status Error"); 1845 continue; 1846 } 1847 1848 if (env_debug) 1849 envd_log(LOG_ERR, "INTR %s, Stat1 %x, Stat2 %x", 1850 hwm_devs[hwm_id], stat[0], stat[1]); 1851 1852 if (stat[0] & FANFAULT) { 1853 fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN1]); 1854 if (fanp && fanp->present) 1855 envd_log(LOG_ERR, ENV_FAN_FAULT, 1856 hwm_devs[hwm_id], 1857 hwm_fans[hwm_id][HWM_FAN1]); 1858 } 1859 if (stat[1] & FANFAULT) { 1860 fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN2]); 1861 if (fanp && fanp->present) 1862 envd_log(LOG_ERR, ENV_FAN_FAULT, 1863 hwm_devs[hwm_id], 1864 hwm_fans[hwm_id][HWM_FAN2]); 1865 } 1866 /* 1867 * Check respective Remote/Local High, Low before start 1868 * manual monitoring 1869 */ 1870 if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK)) 1871 (void) handle_overtemp_interrupt(hwm_id); 1872 1873 } /* end of for ever loop */ 1874 /*NOTREACHED*/ 1875 return (NULL); 1876 } 1877 1878 static void * 1879 dimm_fan_thr(void *args) 1880 { 1881 char syscmd[BUFSIZ]; 1882 char msgbuf[BUFSIZ]; 1883 i2c_reg_t i2c_reg; 1884 timespec_t to; 1885 int ret; 1886 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 1887 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 1888 1889 #ifdef __lint 1890 args = args; 1891 #endif 1892 1893 for (;;) { 1894 /* 1895 * Sleep for specified seconds before issuing IOCTL 1896 * again. 1897 */ 1898 (void) pthread_mutex_lock(&env_monitor_mutex); 1899 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1900 &env_monitor_mutex, &to); 1901 to.tv_sec = INTERRUPTPOLL_INTERVAL; 1902 to.tv_nsec = 0; 1903 if (ret != ETIMEDOUT) { 1904 (void) pthread_mutex_unlock(&env_monitor_mutex); 1905 continue; 1906 } 1907 (void) pthread_mutex_unlock(&env_monitor_mutex); 1908 /* 1909 * We write to the comand register periodically 1910 * to inform the PIC firmware that Solaris is 1911 * Monitoring the dimm fan periodically. 1912 */ 1913 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 1914 i2c_reg.reg_value = PIC16F819_SW_AWARE_MODE; 1915 if (ioctl(envd_dimm_fan.fd, 1916 I2C_SET_REG, &i2c_reg) == -1) { 1917 if (env_debug) 1918 envd_log(LOG_ERR, 1919 "Error in writing to COMMAND reg. of DIMM FAN controller\n"); 1920 } 1921 /* 1922 * We initiate shutdown if fan status indicates 1923 * failure. 1924 */ 1925 if (is_dimm_fan_failed() != 0) { 1926 /* 1927 * Mark Dimm fan present as False so that we 1928 * do not WARN the user of the Fan failure 1929 * repeatedly. 1930 */ 1931 envd_dimm_fan.present = B_FALSE; 1932 (void) snprintf(msgbuf, sizeof (msgbuf), 1933 ENV_DIMM_FAN_FAILURE_SHUTDOWN_MSG, 1934 ENV_DIMM_FAN, 1935 dimm_fan_rpm_string, dimm_fan_status_string, 1936 dimm_fan_command_string, 1937 dimm_fan_debug_string); 1938 envd_log(LOG_ALERT, msgbuf); 1939 1940 if (system_shutdown_started == B_FALSE) { 1941 system_shutdown_started = B_TRUE; 1942 (void) snprintf(syscmd, sizeof (syscmd), 1943 "%s \"%s\"", 1944 SHUTDOWN_CMD, 1945 msgbuf); 1946 envd_log(LOG_ALERT, syscmd); 1947 (void) system(syscmd); 1948 } 1949 } 1950 } 1951 /*NOTREACHED*/ 1952 return (NULL); 1953 } 1954 static int 1955 scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, uint16_t pagelen) 1956 { 1957 struct uscsi_cmd ucmd_buf; 1958 uchar_t cdb_buf[CDB_GROUP1]; 1959 struct scsi_extended_sense sense_buf; 1960 int ret_val; 1961 1962 bzero((void *)&cdb_buf, sizeof (cdb_buf)); 1963 bzero((void *)&ucmd_buf, sizeof (ucmd_buf)); 1964 bzero((void *)&sense_buf, sizeof (sense_buf)); 1965 1966 cdb_buf[0] = SCMD_LOG_SENSE_G1; 1967 cdb_buf[2] = (0x01 << 6) | page_code; 1968 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8); 1969 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF); 1970 1971 ucmd_buf.uscsi_cdb = (char *)cdb_buf; 1972 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf); 1973 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf; 1974 ucmd_buf.uscsi_buflen = pagelen; 1975 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; 1976 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); 1977 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT; 1978 ucmd_buf.uscsi_timeout = 60; 1979 1980 ret_val = ioctl(fd, USCSICMD, ucmd_buf); 1981 if (ret_val == 0 && ucmd_buf.uscsi_status == 0) { 1982 if (env_debug) 1983 envd_log(LOG_ERR, 1984 "log sense command for page_code 0x%x succeeded\n", page_code); 1985 return (ret_val); 1986 } 1987 if (env_debug) 1988 envd_log(LOG_ERR, 1989 "log sense command failed.ret_val = 0x%x status = 0x%x errno = 0x%x\n", 1990 ret_val, ucmd_buf.uscsi_status, errno); 1991 return (1); 1992 } 1993 1994 static int 1995 get_disk_temp(env_disk_t *diskp) 1996 { 1997 int ret; 1998 uchar_t tpage[256]; 1999 2000 ret = scsi_log_sense(diskp->fd, 2001 TEMPERATURE_PAGE, 2002 tpage, sizeof (tpage)); 2003 if (ret != 0) { 2004 diskp->current_temp = DISK_INVALID_TEMP; 2005 diskp->ref_temp = DISK_INVALID_TEMP; 2006 return (-1); 2007 } 2008 /* 2009 * For the current temperature verify that the parameter 2010 * length is 0x02 and the parameter code is 0x00 2011 * Temperature value of 255(0xFF) is considered INVALID. 2012 */ 2013 if ((tpage[7] == 0x02) && (tpage[4] == 0x00) && 2014 (tpage[5] == 0x00)) { 2015 if (tpage[9] == 0xFF) { 2016 diskp->current_temp = DISK_INVALID_TEMP; 2017 return (-1); 2018 } else { 2019 diskp->current_temp = tpage[9]; 2020 } 2021 } 2022 2023 /* 2024 * For the reference temperature verify that the parameter 2025 * length is 0x02 and the parameter code is 0x01 2026 * Temperature value of 255(0xFF) is considered INVALID. 2027 */ 2028 if ((tpage[13] == 0x02) && (tpage[10] == 0x00) && 2029 (tpage[11] == 0x01)) { 2030 if (tpage[15] == 0xFF) { 2031 diskp->ref_temp = DISK_INVALID_TEMP; 2032 } else { 2033 diskp->ref_temp = tpage[15]; 2034 } 2035 } 2036 return (0); 2037 } 2038 2039 /* ARGSUSED */ 2040 static void * 2041 disk_temp_thr(void *args) 2042 { 2043 char syscmd[BUFSIZ]; 2044 char msgbuf[BUFSIZ]; 2045 timespec_t to; 2046 int ret, i; 2047 env_disk_t *diskp; 2048 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 2049 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 2050 pm_state_change_t pmstate; 2051 int idle_time; 2052 int disk_pm_fd; 2053 time_t ct; 2054 2055 disk_pm_fd = open(PM_DEVICE, O_RDWR); 2056 if (disk_pm_fd == -1) { 2057 envd_log(LOG_ERR, 2058 DISK_TEMP_THREAD_EXITING, 2059 errno, strerror(errno)); 2060 return (NULL); 2061 } 2062 for (;;) { 2063 /* 2064 * Sleep for specified seconds before issuing IOCTL 2065 * again. 2066 */ 2067 (void) pthread_mutex_lock(&env_monitor_mutex); 2068 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 2069 &env_monitor_mutex, &to); 2070 to.tv_sec = disk_scan_interval; 2071 to.tv_nsec = 0; 2072 if (ret != ETIMEDOUT) { 2073 (void) pthread_mutex_unlock(&env_monitor_mutex); 2074 continue; 2075 } 2076 (void) pthread_mutex_unlock(&env_monitor_mutex); 2077 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 2078 if (diskp->present == B_FALSE) 2079 continue; 2080 if (diskp->tpage_supported == B_FALSE) 2081 continue; 2082 /* 2083 * If the disk temperature is above the warning threshold 2084 * continue monitoring until the temperature drops below 2085 * warning threshold. 2086 * if the temperature is in the NORMAL range monitor only 2087 * when the disk is BUSY. 2088 * We do not want to read the disk temperature if the disk is 2089 * is idling. The reason for this is disk will never get into 2090 * lowest power mode if we scan the disk temperature 2091 * peridoically. To avoid this situation we first determine 2092 * the idle_time of the disk. If the disk has been IDLE since 2093 * we scanned the temperature last time we will not read the 2094 * temperature. 2095 */ 2096 if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 2097 pmstate.physpath = diskp->physpath; 2098 pmstate.size = strlen(diskp->physpath); 2099 pmstate.component = 0; 2100 if ((idle_time = 2101 ioctl(disk_pm_fd, 2102 PM_GET_TIME_IDLE, &pmstate)) == -1) { 2103 if (errno != EINTR) { 2104 if (env_debug) 2105 envd_log(LOG_ERR, 2106 "ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n", 2107 errno); 2108 continue; 2109 } 2110 continue; 2111 } 2112 if (idle_time >= (disk_scan_interval/2)) { 2113 if (env_debug) { 2114 envd_log(LOG_ERR, 2115 "%s idle time = %d\n", 2116 diskp->name, idle_time); 2117 } 2118 continue; 2119 } 2120 } 2121 ret = get_disk_temp(diskp); 2122 if (ret != 0) 2123 continue; 2124 if (env_debug) { 2125 envd_log(LOG_ERR, 2126 "%s temp = %d ref. temp = %d\n", 2127 diskp->name, diskp->current_temp, diskp->ref_temp); 2128 } 2129 /* 2130 * If this disk already triggered system shutdown, don't 2131 * log any more shutdown/warning messages for it. 2132 */ 2133 if (diskp->shutdown_initiated) 2134 continue; 2135 2136 /* 2137 * Check for the temperature in warning and shutdown range 2138 * and take appropriate action. 2139 */ 2140 if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) { 2141 /* 2142 * Check if the temperature has been in warning 2143 * range during last disk_warning_duration interval. 2144 * If so, the temperature is truly in warning 2145 * range and we need to log a warning message, 2146 * but no more than once every disk_warning_interval 2147 * seconds. 2148 */ 2149 time_t wtstamp = diskp->warning_tstamp; 2150 2151 ct = (time_t)(gethrtime() / NANOSEC); 2152 if (diskp->warning_start == 0) 2153 diskp->warning_start = ct; 2154 if (((ct - diskp->warning_start) >= 2155 disk_warning_duration) && (wtstamp == 0 || 2156 (ct - wtstamp) >= disk_warning_interval)) { 2157 envd_log(LOG_CRIT, ENV_WARNING_MSG, 2158 diskp->name, diskp->current_temp, 2159 diskp->low_warning, 2160 diskp->high_warning); 2161 diskp->warning_tstamp = ct; 2162 } 2163 } else if (diskp->warning_start != 0) 2164 diskp->warning_start = 0; 2165 2166 if (!shutdown_override && 2167 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) { 2168 ct = (time_t)(gethrtime() / NANOSEC); 2169 if (diskp->shutdown_tstamp == 0) 2170 diskp->shutdown_tstamp = ct; 2171 2172 /* 2173 * Shutdown the system if the temperature remains 2174 * in the shutdown range for over disk_shutdown_interval 2175 * seconds. 2176 */ 2177 if ((ct - diskp->shutdown_tstamp) >= 2178 disk_shutdown_interval) { 2179 /* log error */ 2180 diskp->shutdown_initiated = B_TRUE; 2181 (void) snprintf(msgbuf, sizeof (msgbuf), 2182 ENV_SHUTDOWN_MSG, diskp->name, 2183 diskp->current_temp, diskp->low_shutdown, 2184 diskp->high_shutdown); 2185 envd_log(LOG_ALERT, msgbuf); 2186 2187 /* shutdown the system (only once) */ 2188 if (system_shutdown_started == B_FALSE) { 2189 (void) snprintf(syscmd, sizeof (syscmd), 2190 "%s \"%s\"", shutdown_cmd, msgbuf); 2191 envd_log(LOG_ALERT, syscmd); 2192 system_shutdown_started = B_TRUE; 2193 (void) system(syscmd); 2194 } 2195 } 2196 } else if (diskp->shutdown_tstamp != 0) 2197 diskp->shutdown_tstamp = 0; 2198 2199 } 2200 } /* end of forever loop */ 2201 } 2202 2203 /* 2204 * Setup envrionmental monitor state and start threads to monitor 2205 * temperature and power management state. 2206 * Returns -1 on error, 0 if successful. 2207 */ 2208 static int 2209 envd_setup(void) 2210 { 2211 int ret; 2212 2213 if (getenv("SUNW_piclenvd_debug") != NULL) 2214 env_debug = 1; 2215 2216 if (pthread_attr_init(&thr_attr) != 0 || 2217 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) { 2218 return (-1); 2219 } 2220 2221 ret = envd_es_setup(); 2222 if (ret < 0) { 2223 ovtemp_monitor = 0; 2224 pm_monitor = 0; 2225 } 2226 2227 /* 2228 * Setup temperature sensors and fail if we can't open 2229 * at least one sensor. 2230 */ 2231 if (envd_setup_sensors() <= 0) { 2232 return (NULL); 2233 } 2234 2235 /* 2236 * Setup fan device (don't fail even if we can't access 2237 * the fan as we can still monitor temeperature. 2238 */ 2239 (void) envd_setup_fans(); 2240 2241 (void) envd_setup_disks(); 2242 2243 /* If ES Segment setup failed,don't create thread */ 2244 2245 if (ovtemp_monitor && ovtemp_thr1_created == B_FALSE) { 2246 if (pthread_create(&ovtemp_thr1_id, &thr_attr, ovtemp_thr, 2247 (void *)CPU_HWM_ID) != 0) 2248 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2249 else 2250 ovtemp_thr1_created = B_TRUE; 2251 } 2252 2253 if (ovtemp_monitor && ovtemp_thr2_created == B_FALSE) { 2254 if (pthread_create(&ovtemp_thr2_id, &thr_attr, ovtemp_thr, 2255 (void *)SYS_HWM_ID) != 0) 2256 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2257 else 2258 ovtemp_thr2_created = B_TRUE; 2259 } 2260 2261 if (envd_dimm_fan.present) { 2262 if (dimm_fan_thr_created == B_FALSE) { 2263 if (pthread_create(&dimm_fan_thr_id, &thr_attr, dimm_fan_thr, 2264 NULL) != 0) 2265 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2266 else 2267 dimm_fan_thr_created = B_TRUE; 2268 } 2269 } 2270 2271 /* 2272 * Create a thread to monitor PM state 2273 */ 2274 if (pm_monitor && pmthr_created == B_FALSE) { 2275 if (pthread_create(&pmthr_tid, &thr_attr, pmthr, 2276 NULL) != 0) 2277 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); 2278 else 2279 pmthr_created = B_TRUE; 2280 } 2281 if (monitor_disk_temp) { 2282 if (disk_temp_thr_created == B_FALSE) { 2283 if (pthread_create(&disk_temp_thr_id, &thr_attr, disk_temp_thr, 2284 NULL) != 0) 2285 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2286 else 2287 disk_temp_thr_created = B_TRUE; 2288 } 2289 } 2290 return (0); 2291 } 2292 2293 static void 2294 piclenvd_register(void) 2295 { 2296 picld_plugin_register(&my_reg_info); 2297 } 2298 2299 static void 2300 piclenvd_init(void) 2301 { 2302 2303 (void) env_picl_setup_tuneables(); 2304 2305 /* 2306 * Setup the environmental data structures 2307 */ 2308 if (envd_setup() != 0) { 2309 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); 2310 return; 2311 } 2312 2313 /* 2314 * Now setup/populate PICL tree 2315 */ 2316 env_picl_setup(); 2317 } 2318 2319 static void 2320 piclenvd_fini(void) 2321 { 2322 2323 /* 2324 * Invoke env_picl_destroy() to remove any PICL nodes/properties 2325 * (including volatile properties) we created. Once this call 2326 * returns, there can't be any more calls from the PICL framework 2327 * to get current temperature or fan speed. 2328 */ 2329 env_picl_destroy(); 2330 envd_close_sensors(); 2331 envd_close_fans(); 2332 envd_es_destroy(); 2333 } 2334 2335 /*VARARGS2*/ 2336 void 2337 envd_log(int pri, const char *fmt, ...) 2338 { 2339 va_list ap; 2340 2341 va_start(ap, fmt); 2342 vsyslog(pri, fmt, ap); 2343 va_end(ap); 2344 } 2345 2346 /* 2347 * Tunables support functions 2348 */ 2349 static env_tuneable_t * 2350 tuneable_lookup(picl_prophdl_t proph) 2351 { 2352 int i; 2353 env_tuneable_t *tuneablep = NULL; 2354 2355 for (i = 0; i < ntuneables; i++) { 2356 tuneablep = &tuneables[i]; 2357 if (tuneablep->proph == proph) 2358 return (tuneablep); 2359 } 2360 2361 return (NULL); 2362 } 2363 2364 static int 2365 get_cpu_tach(ptree_rarg_t *parg, void *buf) 2366 { 2367 picl_prophdl_t proph; 2368 env_tuneable_t *tuneablep; 2369 int fd; 2370 int8_t cfg; 2371 2372 proph = parg->proph; 2373 2374 tuneablep = tuneable_lookup(proph); 2375 2376 if (tuneablep == NULL) 2377 return (PICL_FAILURE); 2378 2379 fd = open(CPU_HWM_DEVFS, O_RDWR); 2380 2381 if (fd == -1) { 2382 return (PICL_FAILURE); 2383 } 2384 2385 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2386 return (PICL_FAILURE); 2387 } 2388 2389 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) { 2390 *((int *)tuneablep->value) = ENABLE; 2391 } else { 2392 *((int *)tuneablep->value) = DISABLE; 2393 } 2394 2395 (void) memcpy(buf, tuneablep->value, 2396 tuneablep->nbytes); 2397 2398 (void) close(fd); 2399 return (PICL_SUCCESS); 2400 } 2401 2402 static int 2403 set_cpu_tach(ptree_warg_t *parg, const void *buf) 2404 { 2405 picl_prophdl_t proph; 2406 env_tuneable_t *tuneablep; 2407 int fd, val; 2408 int8_t cfg; 2409 2410 if (parg->cred.dc_euid != 0) 2411 return (PICL_PERMDENIED); 2412 2413 proph = parg->proph; 2414 2415 tuneablep = tuneable_lookup(proph); 2416 2417 if (tuneablep == NULL) 2418 return (PICL_FAILURE); 2419 2420 2421 fd = open(CPU_HWM_DEVFS, O_RDWR); 2422 2423 if (fd == -1) { 2424 return (PICL_FAILURE); 2425 } 2426 2427 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2428 return (PICL_FAILURE); 2429 } 2430 2431 (void) memcpy(&val, (caddr_t)buf, sizeof (val)); 2432 2433 if (val == ENABLE) { 2434 cfg |= TACH_ENABLE_MASK; 2435 } else if (val == DISABLE) { 2436 cfg &= ~TACH_ENABLE_MASK; 2437 } 2438 2439 2440 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) { 2441 return (PICL_FAILURE); 2442 } 2443 2444 (void) close(fd); 2445 return (PICL_SUCCESS); 2446 } 2447 2448 static int 2449 get_sys_tach(ptree_rarg_t *parg, void *buf) 2450 { 2451 picl_prophdl_t proph; 2452 env_tuneable_t *tuneablep; 2453 int fd; 2454 int8_t cfg; 2455 2456 proph = parg->proph; 2457 2458 tuneablep = tuneable_lookup(proph); 2459 2460 if (tuneablep == NULL) 2461 return (PICL_FAILURE); 2462 2463 fd = open(SYS_HWM_DEVFS, O_RDWR); 2464 2465 if (fd == -1) { 2466 return (PICL_FAILURE); 2467 } 2468 2469 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2470 return (PICL_FAILURE); 2471 } 2472 2473 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) { 2474 *((int *)tuneablep->value) = ENABLE; 2475 } else { 2476 *((int *)tuneablep->value) = DISABLE; 2477 } 2478 2479 (void) memcpy(buf, tuneablep->value, 2480 tuneablep->nbytes); 2481 2482 (void) close(fd); 2483 return (PICL_SUCCESS); 2484 } 2485 2486 static int 2487 set_sys_tach(ptree_warg_t *parg, const void *buf) 2488 { 2489 picl_prophdl_t proph; 2490 env_tuneable_t *tuneablep; 2491 int fd, val; 2492 int8_t cfg; 2493 2494 if (parg->cred.dc_euid != 0) 2495 return (PICL_PERMDENIED); 2496 2497 proph = parg->proph; 2498 2499 tuneablep = tuneable_lookup(proph); 2500 2501 if (tuneablep == NULL) 2502 return (PICL_FAILURE); 2503 2504 2505 fd = open(SYS_HWM_DEVFS, O_RDWR); 2506 2507 if (fd == -1) { 2508 return (PICL_FAILURE); 2509 } 2510 2511 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2512 return (PICL_FAILURE); 2513 } 2514 2515 (void) memcpy(&val, buf, sizeof (val)); 2516 2517 if (val == ENABLE) { 2518 cfg |= TACH_ENABLE_MASK; 2519 } else if (val == DISABLE) { 2520 cfg &= ~TACH_ENABLE_MASK; 2521 } 2522 2523 2524 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) { 2525 return (PICL_FAILURE); 2526 } 2527 2528 (void) close(fd); 2529 return (PICL_SUCCESS); 2530 } 2531 2532 static int 2533 get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf) 2534 { 2535 picl_prophdl_t proph; 2536 env_tuneable_t *tuneablep; 2537 int fd; 2538 int8_t mmode; 2539 2540 proph = parg->proph; 2541 2542 tuneablep = tuneable_lookup(proph); 2543 2544 if (tuneablep == NULL) 2545 return (PICL_FAILURE); 2546 2547 fd = open(CPU_HWM_DEVFS, O_RDWR); 2548 2549 if (fd == -1) { 2550 return (PICL_FAILURE); 2551 } 2552 2553 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) { 2554 return (PICL_FAILURE); 2555 } 2556 2557 if (mmode == ADM1031_AUTO_MODE) { 2558 *((int *)tuneablep->value) = ENABLE; 2559 } else { 2560 *((int *)tuneablep->value) = DISABLE; 2561 } 2562 2563 (void) memcpy(buf, tuneablep->value, 2564 tuneablep->nbytes); 2565 2566 (void) close(fd); 2567 return (PICL_SUCCESS); 2568 } 2569 2570 static int 2571 set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf) 2572 { 2573 picl_prophdl_t proph; 2574 env_tuneable_t *tuneablep; 2575 int fd, val; 2576 int8_t mmode; 2577 2578 if (parg->cred.dc_euid != 0) 2579 return (PICL_PERMDENIED); 2580 2581 proph = parg->proph; 2582 2583 tuneablep = tuneable_lookup(proph); 2584 2585 if (tuneablep == NULL) 2586 return (PICL_FAILURE); 2587 2588 fd = open(CPU_HWM_DEVFS, O_RDWR); 2589 2590 if (fd == -1) { 2591 return (PICL_FAILURE); 2592 } 2593 2594 (void) memcpy(&val, buf, sizeof (val)); 2595 2596 if (val == ENABLE) { 2597 mmode = ADM1031_AUTO_MODE; 2598 } else if (val == DISABLE) { 2599 mmode = ADM1031_MANUAL_MODE; 2600 } 2601 2602 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) { 2603 return (PICL_FAILURE); 2604 } 2605 2606 (void) close(fd); 2607 return (PICL_SUCCESS); 2608 } 2609 2610 static int 2611 get_monitor_sys_mode(ptree_rarg_t *parg, void *buf) 2612 { 2613 picl_prophdl_t proph; 2614 env_tuneable_t *tuneablep; 2615 int fd; 2616 int8_t mmode; 2617 2618 proph = parg->proph; 2619 2620 tuneablep = tuneable_lookup(proph); 2621 2622 if (tuneablep == NULL) 2623 return (PICL_FAILURE); 2624 2625 fd = open(SYS_HWM_DEVFS, O_RDWR); 2626 2627 if (fd == -1) { 2628 return (PICL_FAILURE); 2629 } 2630 2631 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) { 2632 return (PICL_FAILURE); 2633 } 2634 2635 if (mmode == ADM1031_AUTO_MODE) { 2636 *((int *)tuneablep->value) = ENABLE; 2637 } else { 2638 *((int *)tuneablep->value) = DISABLE; 2639 } 2640 2641 (void) memcpy(buf, tuneablep->value, 2642 tuneablep->nbytes); 2643 2644 (void) close(fd); 2645 return (PICL_SUCCESS); 2646 } 2647 2648 static int 2649 set_monitor_sys_mode(ptree_warg_t *parg, const void *buf) 2650 { 2651 picl_prophdl_t proph; 2652 env_tuneable_t *tuneablep; 2653 int fd, val; 2654 int8_t mmode; 2655 2656 if (parg->cred.dc_euid != 0) 2657 return (PICL_PERMDENIED); 2658 2659 proph = parg->proph; 2660 2661 tuneablep = tuneable_lookup(proph); 2662 2663 if (tuneablep == NULL) 2664 return (PICL_FAILURE); 2665 2666 fd = open(SYS_HWM_DEVFS, O_RDWR); 2667 2668 if (fd == -1) { 2669 return (PICL_FAILURE); 2670 } 2671 2672 (void) memcpy(&val, buf, sizeof (val)); 2673 2674 if (val == ENABLE) { 2675 mmode = ADM1031_AUTO_MODE; 2676 } else if (val == DISABLE) { 2677 mmode = ADM1031_MANUAL_MODE; 2678 } 2679 2680 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) { 2681 return (PICL_FAILURE); 2682 } 2683 2684 (void) close(fd); 2685 return (PICL_SUCCESS); 2686 } 2687 2688 static int 2689 get_string_val(ptree_rarg_t *parg, void *buf) 2690 { 2691 picl_prophdl_t proph; 2692 env_tuneable_t *tuneablep; 2693 2694 proph = parg->proph; 2695 2696 tuneablep = tuneable_lookup(proph); 2697 2698 if (tuneablep == NULL) 2699 return (PICL_FAILURE); 2700 2701 (void) memcpy(buf, (caddr_t)tuneablep->value, 2702 tuneablep->nbytes); 2703 2704 return (PICL_SUCCESS); 2705 } 2706 2707 static int 2708 set_string_val(ptree_warg_t *parg, const void *buf) 2709 { 2710 picl_prophdl_t proph; 2711 env_tuneable_t *tuneablep; 2712 2713 if (parg->cred.dc_euid != 0) 2714 return (PICL_PERMDENIED); 2715 2716 proph = parg->proph; 2717 2718 tuneablep = tuneable_lookup(proph); 2719 2720 if (tuneablep == NULL) 2721 return (PICL_FAILURE); 2722 2723 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf, 2724 tuneables->nbytes); 2725 2726 2727 return (PICL_SUCCESS); 2728 } 2729 2730 static int 2731 get_int_val(ptree_rarg_t *parg, void *buf) 2732 { 2733 picl_prophdl_t proph; 2734 env_tuneable_t *tuneablep; 2735 2736 proph = parg->proph; 2737 2738 tuneablep = tuneable_lookup(proph); 2739 2740 if (tuneablep == NULL) 2741 return (PICL_FAILURE); 2742 2743 (void) memcpy((int *)buf, (int *)tuneablep->value, 2744 tuneablep->nbytes); 2745 2746 return (PICL_SUCCESS); 2747 } 2748 2749 static int 2750 set_int_val(ptree_warg_t *parg, const void *buf) 2751 { 2752 picl_prophdl_t proph; 2753 env_tuneable_t *tuneablep; 2754 2755 if (parg->cred.dc_euid != 0) 2756 return (PICL_PERMDENIED); 2757 2758 proph = parg->proph; 2759 2760 tuneablep = tuneable_lookup(proph); 2761 2762 if (tuneablep == NULL) 2763 return (PICL_FAILURE); 2764 2765 (void) memcpy((int *)tuneablep->value, (int *)buf, 2766 tuneablep->nbytes); 2767 2768 return (PICL_SUCCESS); 2769 } 2770 2771 int 2772 get_dimm_fan_speed(int fan_fd, fanspeed_t *fanspeedp) 2773 { 2774 int16_t dimm_fan_period; 2775 i2c_reg_t i2c_reg; 2776 2777 /* 2778 * The dimm fan period is 16 bit value and we need to read 2779 * registers 2 and 3 to get the LSB and MSB values. 2780 */ 2781 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_MSB_REGISTER; 2782 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) { 2783 if (env_debug) 2784 envd_log(LOG_ERR, 2785 "Error in reading FAN_PERIOD MSB REGISTER\n"); 2786 return (-1); 2787 } 2788 dimm_fan_period = (i2c_reg.reg_value << 8); 2789 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_LSB_REGISTER; 2790 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) { 2791 if (env_debug) 2792 envd_log(LOG_ERR, 2793 "Error in reading FAN_PERIOD LSB REGISTER\n"); 2794 return (-1); 2795 } 2796 dimm_fan_period |= i2c_reg.reg_value; 2797 if (env_debug) 2798 envd_log(LOG_ERR, 2799 " dimm fan tach period is 0x%x\n", dimm_fan_period); 2800 if (dimm_fan_period == 0) { 2801 if (env_debug) 2802 envd_log(LOG_ERR, 2803 "dimm fan tach period read as zero. Illegal value.\n"); 2804 return (-1); 2805 } 2806 *fanspeedp = PIC16F819_FAN_TACH_TO_RPM(dimm_fan_period); 2807 return (0); 2808 } 2809 2810 int 2811 is_dimm_fan_failed(void) 2812 { 2813 i2c_reg_t i2c_reg; 2814 fanspeed_t fan_speed; 2815 int retry_count; 2816 2817 if (envd_dimm_fan.fd == -1) 2818 return (-1); 2819 /* 2820 * read register 1 to look at Fan fault bit. 2821 */ 2822 i2c_reg.reg_num = PIC16F819_STATUS_REGISTER; 2823 retry_count = MAX_RETRIES_FOR_PIC16F819_REG_READ; 2824 while (retry_count > 0) { 2825 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2826 retry_count--; 2827 continue; 2828 } else break; 2829 } 2830 if (retry_count != MAX_RETRIES_FOR_PIC16F819_REG_READ) { 2831 if (env_debug) 2832 envd_log(LOG_ERR, 2833 "%d retries attempted in reading STATUS register.\n", 2834 (MAX_RETRIES_FOR_PIC16F819_REG_READ - retry_count)); 2835 } 2836 if (retry_count == 0) { 2837 (void) strncpy(dimm_fan_status_string, NOT_AVAILABLE, 2838 sizeof (dimm_fan_status_string)); 2839 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE, 2840 sizeof (dimm_fan_command_string)); 2841 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE, 2842 sizeof (dimm_fan_debug_string)); 2843 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE, 2844 sizeof (dimm_fan_rpm_string)); 2845 return (-1); 2846 } 2847 if (env_debug) 2848 envd_log(LOG_ERR, 2849 "DIMM FAN STATUS reg = 0x%x\n", i2c_reg.reg_value); 2850 if (i2c_reg.reg_value & PIC16F819_FAN_FAILED) { 2851 (void) snprintf(dimm_fan_status_string, 2852 sizeof (dimm_fan_status_string), "0x%x", 2853 i2c_reg.reg_value); 2854 i2c_reg.reg_num = PIC16F819_DEBUG_REGISTER; 2855 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2856 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE, 2857 sizeof (dimm_fan_debug_string)); 2858 } else { 2859 (void) snprintf(dimm_fan_debug_string, 2860 sizeof (dimm_fan_debug_string), 2861 "0x%x", i2c_reg.reg_value); 2862 } 2863 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 2864 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2865 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE, 2866 sizeof (dimm_fan_command_string)); 2867 } else { 2868 (void) snprintf(dimm_fan_command_string, 2869 sizeof (dimm_fan_command_string), 2870 "0x%x", i2c_reg.reg_value); 2871 } 2872 if (get_dimm_fan_speed(envd_dimm_fan.fd, &fan_speed) == -1) { 2873 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE, 2874 sizeof (dimm_fan_rpm_string)); 2875 } else { 2876 (void) snprintf(dimm_fan_rpm_string, 2877 sizeof (dimm_fan_rpm_string), 2878 "%d", fan_speed); 2879 } 2880 return (1); 2881 } else return (0); 2882 } 2883