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 /* 28 * This file contains the environmental PICL plug-in module. 29 */ 30 31 /* 32 * This plugin sets up the PICLTREE for Enchilada WS. 33 * It provides functionality to get/set temperatures and 34 * fan speeds. 35 * 36 * The environmental policy defaults to the auto mode 37 * as programmed by OBP at boot time. 38 */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <sys/sysmacros.h> 43 #include <limits.h> 44 #include <string.h> 45 #include <strings.h> 46 #include <stdarg.h> 47 #include <alloca.h> 48 #include <unistd.h> 49 #include <sys/processor.h> 50 #include <syslog.h> 51 #include <errno.h> 52 #include <fcntl.h> 53 #include <picl.h> 54 #include <picltree.h> 55 #include <picldefs.h> 56 #include <pthread.h> 57 #include <signal.h> 58 #include <libdevinfo.h> 59 #include <sys/pm.h> 60 #include <sys/open.h> 61 #include <sys/time.h> 62 #include <sys/utsname.h> 63 #include <sys/systeminfo.h> 64 #include <note.h> 65 #include <sys/i2c/clients/i2c_client.h> 66 #include <sys/i2c/clients/adm1031.h> 67 #include <sys/i2c/clients/pic16f819_reg.h> 68 #include "envd.h" 69 #include <sys/scsi/scsi.h> 70 #include <sys/scsi/generic/commands.h> 71 72 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 /* 88 * Sleep routine used for polling 89 */ 90 static int get_dimm_fan_speed(int, fanspeed_t *); 91 static int is_dimm_fan_failed(void); 92 93 #pragma init(piclenvd_register) 94 95 /* 96 * Plugin registration information 97 */ 98 static picld_plugin_reg_t my_reg_info = { 99 PICLD_PLUGIN_VERSION, 100 PICLD_PLUGIN_CRITICAL, 101 "SUNW_piclenvd", 102 piclenvd_init, 103 piclenvd_fini, 104 }; 105 106 #define REGISTER_INFORMATION_STRING_LENGTH 16 107 static char dimm_fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 108 static char dimm_fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 109 static char dimm_fan_command_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 110 static char dimm_fan_debug_string[REGISTER_INFORMATION_STRING_LENGTH] = {0}; 111 112 static int scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, 113 uint16_t pagelen); 114 static int get_disk_temp(env_disk_t *); 115 /* 116 * ES Segment data structures 117 */ 118 static sensor_ctrl_blk_t sensor_ctrl[MAX_SENSORS]; 119 static fan_ctrl_blk_t fan_ctrl[MAX_FANS]; 120 static fruenvseg_t *envfru = NULL; 121 122 /* 123 * Env thread variables 124 */ 125 static boolean_t system_shutdown_started = B_FALSE; 126 static boolean_t ovtemp_thr1_created = B_FALSE; 127 static pthread_t ovtemp_thr1_id; 128 static pthread_attr_t thr_attr; 129 static boolean_t ovtemp_thr2_created = B_FALSE; 130 static pthread_t ovtemp_thr2_id; 131 static boolean_t dimm_fan_thr_created = B_FALSE; 132 static pthread_t dimm_fan_thr_id; 133 static boolean_t disk_temp_thr_created = B_FALSE; 134 static pthread_t disk_temp_thr_id; 135 136 /* 137 * PM thread related variables 138 */ 139 static pthread_t pmthr_tid; /* pmthr thread ID */ 140 static int pm_fd = -1; /* PM device file descriptor */ 141 static boolean_t pmthr_created = B_FALSE; 142 static int cur_lpstate; /* cur low power state */ 143 144 /* 145 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var 146 * Setting the verbose tuneable also enables debugging for better 147 * control 148 */ 149 int env_debug = 0; 150 151 /* 152 * Fan devices 153 */ 154 static env_fan_t envd_sys_out_fan = { 155 ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_OUT_FAN_DEVFS, NULL, 156 SYSTEM_OUT_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN, SYSTEM_OUT_FAN_SPEED_MAX, 157 -1, -1, 158 }; 159 160 static env_fan_t envd_sys_in_fan = { 161 ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_INTAKE_FAN_DEVFS, NULL, 162 SYSTEM_INTAKE_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN, 163 SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1, 164 }; 165 166 static env_fan_t envd_cpu0_fan = { 167 ENV_CPU0_FAN, ENV_CPU0_FAN_DEVFS, NULL, 168 CPU0_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1, 169 }; 170 171 static env_fan_t envd_cpu1_fan = { 172 ENV_CPU1_FAN, ENV_CPU1_FAN_DEVFS, NULL, 173 CPU1_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1, 174 }; 175 176 static env_fan_t envd_dimm_fan = { 177 ENV_DIMM_FAN, ENV_DIMM_FAN_DEVFS, NULL, 178 DIMM_FAN_ID, 100, 100, -1, -1, 179 }; 180 181 static env_disk_t envd_disk0 = { 182 ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH, 183 DISK0_ID, -1, -1, 184 }; 185 186 static env_disk_t envd_disk1 = { 187 ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH, 188 DISK1_ID, -1, -1, 189 }; 190 191 /* 192 * The vendor-id and device-id are the properties associated with 193 * the SCSI controller. This is used to identify a particular controller 194 * like LSI1030. 195 */ 196 #define VENDOR_ID "vendor-id" 197 #define DEVICE_ID "device-id" 198 199 /* 200 * The implementation for SCSI disk drives to supply info. about 201 * temperature is not mandatory. Hence we first determine if the 202 * temperature page is supported. To do this we need to scan the list 203 * of pages supported. 204 */ 205 #define SUPPORTED_LPAGES 0 206 #define TEMPERATURE_PAGE 0x0D 207 #define LOGPAGEHDRSIZE 4 208 209 /* 210 * NULL terminated array of fans 211 */ 212 static env_fan_t *envd_fans[] = { 213 &envd_cpu0_fan, 214 &envd_cpu1_fan, 215 &envd_sys_out_fan, 216 &envd_sys_in_fan, 217 &envd_dimm_fan, 218 NULL 219 }; 220 221 static env_disk_t *envd_disks[] = { 222 &envd_disk0, 223 &envd_disk1, 224 NULL 225 }; 226 227 /* 228 * ADM1031 speedrange map is indexed by a 2-bit value 229 */ 230 static int adm_speedrange_map[] = {1, 2, 4, 8}; 231 232 /* 233 * ADM1031 devices 234 */ 235 static char *hwm_devs[] = { 236 CPU_HWM_DEVFS, /* CPU_HWM_ID */ 237 SYS_HWM_DEVFS /* SYS_HWM_ID */ 238 }; 239 240 /* 241 * Fan names associated with each ADM1031 hwms - used to 242 * print fault messages. 243 */ 244 static char *hwm_fans[MAX_HWMS][2] = { 245 {ENV_CPU0_FAN, ENV_CPU1_FAN}, 246 {ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_OUT_FAN} 247 }; 248 249 /* 250 * Temperature sensors 251 */ 252 static env_sensor_t envd_sensors[] = { 253 { SENSOR_CPU0_DIE, SENSOR_CPU0_DIE_DEVFS, NULL, 254 CPU0_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu0_fan, -1}, 255 { SENSOR_CPU1_DIE, SENSOR_CPU1_DIE_DEVFS, NULL, 256 CPU1_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu1_fan, -1}, 257 { SENSOR_INT_AMB_0, SENSOR_INT_AMB_0_DEVFS, NULL, 258 INT_AMB0_SENSOR_ID, CPU_HWM_ID, NULL, -1}, 259 { SENSOR_SYS_OUT, SENSOR_SYS_OUT_DEVFS, NULL, 260 SYS_OUT_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_out_fan, -1}, 261 { SENSOR_INT_AMB_1, SENSOR_INT_AMB_1_DEVFS, NULL, 262 INT_AMB1_SENSOR_ID, SYS_HWM_ID, NULL, -1}, 263 { SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL, 264 SYS_IN_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_in_fan, -1}, 265 }; 266 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0])) 267 268 #define NOT_AVAILABLE "NA" 269 270 /* 271 * ADM1031 macros 272 */ 273 #define TACH_UNKNOWN 255 274 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN) 275 #define ADM_HYSTERISIS 5 276 #define N_SEQ_TACH 15 277 278 #define TMIN_MASK (0xF8) 279 #define TMIN_SHIFT (3) 280 #define TMIN_UNITS (4) /* increments of 4 degrees celsius */ 281 #define TRANGE_MASK (0x7) 282 283 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS) 284 #define TRANGE(regval) (regval & TRANGE_MASK) 285 286 #define GET_TMIN_RANGE(tmin, trange) \ 287 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \ 288 (trange & TRANGE_MASK)) 289 290 #define TACH_ENABLE_MASK (0x0C) 291 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100) 292 293 /* 294 * Tuneables 295 */ 296 #define ENABLE 1 297 #define DISABLE 0 298 299 int monitor_disk_temp = 1; /* enabled */ 300 static int disk_high_warn_temperature = DISK_HIGH_WARN_TEMPERATURE; 301 static int disk_low_warn_temperature = DISK_LOW_WARN_TEMPERATURE; 302 static int disk_high_shutdown_temperature = 303 DISK_HIGH_SHUTDOWN_TEMPERATURE; 304 static int disk_low_shutdown_temperature = DISK_LOW_SHUTDOWN_TEMPERATURE; 305 static int disk_scan_interval = DISK_SCAN_INTERVAL; 306 307 static int get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf); 308 static int set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf); 309 static int get_monitor_sys_mode(ptree_rarg_t *parg, void *buf); 310 static int set_monitor_sys_mode(ptree_warg_t *parg, const void *buf); 311 static int get_int_val(ptree_rarg_t *parg, void *buf); 312 static int set_int_val(ptree_warg_t *parg, const void *buf); 313 static int get_string_val(ptree_rarg_t *parg, void *buf); 314 static int set_string_val(ptree_warg_t *parg, const void *buf); 315 static int get_cpu_tach(ptree_rarg_t *parg, void *buf); 316 static int set_cpu_tach(ptree_warg_t *parg, const void *buf); 317 static int get_sys_tach(ptree_rarg_t *parg, void *buf); 318 static int set_sys_tach(ptree_warg_t *parg, const void *buf); 319 320 static int shutdown_override = 0; 321 static int sensor_poll_interval = SENSORPOLL_INTERVAL; 322 static int warning_interval = WARNING_INTERVAL; 323 static int disk_warning_interval = DISK_WARNING_INTERVAL; 324 static int disk_warning_duration = DISK_WARNING_DURATION; 325 static int shutdown_interval = SHUTDOWN_INTERVAL; 326 static int disk_shutdown_interval = DISK_SHUTDOWN_INTERVAL; 327 static int ovtemp_monitor = 1; /* enabled */ 328 static int pm_monitor = 1; /* enabled */ 329 static int mon_fanstat = 1; /* enabled */ 330 331 static int cpu_mode; 332 static int sys_mode; 333 static int cpu_tach; 334 static int sys_tach; 335 static char shutdown_cmd[] = SHUTDOWN_CMD; 336 337 env_tuneable_t tuneables[] = { 338 {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor, 339 &get_int_val, &set_int_val, sizeof (int)}, 340 341 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor, 342 &get_int_val, &set_int_val, sizeof (int)}, 343 344 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override, 345 &get_int_val, &set_int_val, sizeof (int)}, 346 347 {"cpu-hm-automode-enable", PICL_PTYPE_INT, &cpu_mode, 348 &get_monitor_cpu_mode, &set_monitor_cpu_mode, 349 sizeof (int)}, 350 351 {"sys-hm-automode-enable", PICL_PTYPE_INT, &sys_mode, 352 &get_monitor_sys_mode, &set_monitor_sys_mode, 353 sizeof (int)}, 354 355 {"sensor-poll-interval", PICL_PTYPE_INT, 356 &sensor_poll_interval, 357 &get_int_val, &set_int_val, 358 sizeof (int)}, 359 360 {"disk-scan-interval", PICL_PTYPE_INT, 361 &disk_scan_interval, 362 &get_int_val, &set_int_val, 363 sizeof (int)}, 364 365 {"warning-interval", PICL_PTYPE_INT, &warning_interval, 366 &get_int_val, &set_int_val, 367 sizeof (int)}, 368 369 {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval, 370 &get_int_val, &set_int_val, 371 sizeof (int)}, 372 373 {"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval, 374 &get_int_val, &set_int_val, 375 sizeof (int)}, 376 377 {"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration, 378 &get_int_val, &set_int_val, 379 sizeof (int)}, 380 381 {"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval, 382 &get_int_val, &set_int_val, 383 sizeof (int)}, 384 385 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd, 386 &get_string_val, &set_string_val, 387 sizeof (shutdown_cmd)}, 388 389 {"cpu-tach-enable", PICL_PTYPE_INT, &cpu_tach, 390 &get_cpu_tach, &set_cpu_tach, 391 sizeof (int)}, 392 393 {"sys-tach-enable", PICL_PTYPE_INT, &sys_tach, 394 &get_sys_tach, &set_sys_tach, 395 sizeof (int)}, 396 397 {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat, 398 &get_int_val, &set_int_val, sizeof (int)}, 399 400 {"monitor-disk-temp", PICL_PTYPE_INT, &monitor_disk_temp, 401 &get_int_val, &set_int_val, sizeof (int)}, 402 403 {"disk-high-warn-temperature", PICL_PTYPE_INT, 404 &disk_high_warn_temperature, &get_int_val, 405 &set_int_val, sizeof (int)}, 406 407 {"disk-low-warn-temperature", PICL_PTYPE_INT, 408 &disk_low_warn_temperature, &get_int_val, 409 &set_int_val, sizeof (int)}, 410 411 {"disk-high-shutdown-temperature", PICL_PTYPE_INT, 412 &disk_high_shutdown_temperature, &get_int_val, 413 &set_int_val, sizeof (int)}, 414 415 {"disk-low-shutdown-temperature", PICL_PTYPE_INT, 416 &disk_low_shutdown_temperature, &get_int_val, 417 &set_int_val, sizeof (int)}, 418 419 {"verbose", PICL_PTYPE_INT, &env_debug, 420 &get_int_val, &set_int_val, sizeof (int)}, 421 422 423 }; 424 425 /* 426 * We use this to figure out how many tuneables there are 427 * This is variable because the publishing routine needs this info 428 * in piclenvsetup.c 429 */ 430 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0])); 431 432 /* 433 * Table Handling Code 434 */ 435 static void 436 fini_table(table_t *tblp) 437 { 438 if (tblp == NULL) 439 return; 440 free(tblp->xymap); 441 free(tblp); 442 } 443 444 static table_t * 445 init_table(int npoints) 446 { 447 table_t *tblp; 448 point_t *xy; 449 450 if (npoints == 0) 451 return (NULL); 452 453 if ((tblp = malloc(sizeof (*tblp))) == NULL) 454 return (NULL); 455 456 if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) { 457 free(tblp); 458 return (NULL); 459 } 460 461 tblp->nentries = npoints; 462 tblp->xymap = xy; 463 464 return (tblp); 465 } 466 467 /* 468 * function: calculates y for a given x based on a table of points 469 * for monotonically increasing x values. 470 * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y' 471 */ 472 static int 473 y_of_x(table_t *tbl, int xval) 474 { 475 int i; 476 int entries; 477 point_t *xymap; 478 float newval; 479 float dy, dx, slope; 480 481 entries = tbl->nentries; 482 xymap = tbl->xymap; 483 /* 484 * If the temperature is outside the correction table 485 * then simply return the original value. 486 */ 487 if ((xval < xymap[0].x) || (xval > xymap[entries - 1].x)) 488 return (xval); 489 if (xval == xymap[0].x) 490 return (xymap[0].y); 491 if (xval == xymap[entries - 1].x) 492 return (xymap[entries - 1].y); 493 494 for (i = 1; i < entries - 1; i++) { 495 if (xval == xymap[i].x) 496 return (xymap[i].y); 497 if (xval < xymap[i].x) 498 break; 499 } 500 501 /* 502 * Use linear interpolation 503 */ 504 dy = (float)(xymap[i].y - xymap[i-1].y); 505 dx = (float)(xymap[i].x - xymap[i-1].x); 506 slope = dy/dx; 507 newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x); 508 return ((int)(newval + (newval >= 0 ? 0.5 : -0.5))); 509 } 510 511 /* 512 * Get environmental segment from the specified FRU SEEPROM 513 */ 514 static int 515 get_envseg(int fd, void **envsegp, int *envseglenp) 516 { 517 int i, segcnt, envseglen; 518 section_layout_t section; 519 segment_layout_t segment; 520 uint8_t *envseg; 521 522 if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L || 523 read(fd, §ion, sizeof (section)) != sizeof (section)) { 524 return (EINVAL); 525 } 526 527 /* 528 * Verify we have the correct section and contents are valid 529 * For now, we don't verify the CRC. 530 */ 531 if (section.header_tag != SECTION_HDR_TAG || 532 GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) { 533 if (env_debug) 534 envd_log(LOG_INFO, 535 "Invalid section header tag:%x version:%x\n", 536 section.header_tag, 537 GET_UNALIGN16(§ion.header_version)); 538 return (EINVAL); 539 } 540 541 /* 542 * Locate our environmental segment 543 */ 544 segcnt = section.segment_count; 545 for (i = 0; i < segcnt; i++) { 546 if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) { 547 return (EINVAL); 548 } 549 if (env_debug) 550 envd_log(LOG_INFO, 551 "Seg name: %x desc:%x off:%x len:%x\n", 552 GET_UNALIGN16(&segment.name), 553 GET_UNALIGN32(&segment.descriptor[0]), 554 GET_UNALIGN16(&segment.offset), 555 GET_UNALIGN16(&segment.length)); 556 if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME) 557 break; 558 } 559 560 if (i >= segcnt) { 561 return (ENOENT); 562 } 563 564 /* 565 * Allocate memory to hold the environmental segment data. 566 */ 567 envseglen = GET_UNALIGN16(&segment.length); 568 if ((envseg = malloc(envseglen)) == NULL) { 569 return (ENOMEM); 570 } 571 572 if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L || 573 read(fd, envseg, envseglen) != envseglen) { 574 (void) free(envseg); 575 return (EIO); 576 } 577 *envsegp = envseg; 578 *envseglenp = envseglen; 579 return (0); 580 } 581 582 /* 583 * Get all environmental segments 584 * Return NULL on error 585 */ 586 static fruenvseg_t * 587 get_fru_envsegs(void) 588 { 589 fruenvseg_t *fruenvsegs; 590 envseg_layout_t *envsegp; 591 void *envsegbufp; 592 int fd, envseglen, hdrlen; 593 char path[PATH_MAX]; 594 595 fruenvsegs = NULL; 596 fruenvsegs = malloc(sizeof (*fruenvsegs)); 597 if (fruenvsegs == NULL) { 598 return (NULL); 599 } 600 601 /* 602 * Now get the environmental segment from this FRU 603 */ 604 (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV); 605 fd = open(path, O_RDONLY); 606 if (fd == -1) { 607 envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path); 608 free(fruenvsegs); 609 return (NULL); 610 } 611 612 /* 613 * Read environmental segment from this FRU SEEPROM 614 */ 615 if (get_envseg(fd, &envsegbufp, &envseglen) != 0) { 616 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path); 617 free(fruenvsegs); 618 (void) close(fd); 619 return (NULL); 620 } 621 622 /* 623 * Validate envseg version number and header length 624 */ 625 envsegp = (envseg_layout_t *)envsegbufp; 626 hdrlen = sizeof (envseg_layout_t) - 627 sizeof (envseg_sensor_t) + 628 (envsegp->sensor_count) * sizeof (envseg_sensor_t); 629 630 if (envsegp->version != ENVSEG_VERSION || 631 envseglen < hdrlen) { 632 /* 633 * version mismatch or header not big enough 634 */ 635 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 636 if (envsegbufp != NULL) 637 (void) free(envsegbufp); 638 free(fruenvsegs); 639 (void) close(fd); 640 return (NULL); 641 } 642 643 fruenvsegs->envseglen = envseglen; 644 fruenvsegs->envsegbufp = envsegbufp; 645 (void) close(fd); 646 return (fruenvsegs); 647 } 648 649 static int 650 process_fru_seeprom(unsigned char *buff) 651 { 652 id_off_t id; 653 int i; 654 int id_offset = 0; 655 int nsensors; 656 int nfans; 657 env_fan_t *fnodep; 658 env_sensor_t *snodep; 659 660 #define NSENSOR_OFFSET 1 661 #define ID_OFF_SIZE 6 662 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2) 663 664 nsensors = (int)buff[NSENSOR_OFFSET]; 665 if (nsensors != MAX_SENSORS) { 666 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 667 return (-1); 668 } 669 670 nfans = (int)buff[NFANS_OFFSET(nsensors)]; 671 if (nfans != MAX_FANS) { 672 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 673 return (-1); 674 } 675 676 while (nsensors > 0) { 677 (void) memcpy((char *)&id, 678 (char *)&buff[id_offset + 2], 679 ID_OFF_SIZE); 680 681 if (env_debug) 682 envd_log(LOG_ERR, "\n Sensor Id %x offset %x", 683 id.id, id.offset); 684 685 if (id.id > MAX_SENSOR_ID) { 686 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 687 FRU_SEEPROM_NAME); 688 return (-1); 689 } 690 691 /* 692 * Copy into the sensor control block array according to the 693 * sensor ID 694 */ 695 (void) memcpy((char *)&sensor_ctrl[id.id], 696 (char *)&buff[id.offset], 697 sizeof (sensor_ctrl_blk_t)); 698 nsensors--; 699 id_offset += ID_OFF_SIZE; 700 } 701 702 /* 703 * Skip past no of Fan entry(single byte) 704 */ 705 id_offset++; 706 while (nfans > 0) { 707 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], 708 ID_OFF_SIZE); 709 710 if (env_debug) 711 envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id, 712 id.offset); 713 714 if (id.id > 3) { 715 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 716 FRU_SEEPROM_NAME); 717 return (-1); 718 } 719 720 (void) memcpy((char *)&fan_ctrl[id.id], 721 (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t)); 722 723 nfans--; 724 id_offset += ID_OFF_SIZE; 725 } 726 727 /* 728 * Match Sensor/ES ID and point correct data 729 * based on IDs 730 */ 731 for (i = 0; i < N_ENVD_SENSORS; i++) { 732 snodep = &envd_sensors[i]; 733 snodep->es_ptr = &sensor_ctrl[snodep->id]; 734 } 735 736 /* 737 * Match Fan/ES ID and point to correct ES Data 738 * based on IDs 739 */ 740 for (i = 0; (fnodep = envd_fans[i]) != NULL; i++) 741 fnodep->es_ptr = &fan_ctrl[fnodep->id]; 742 743 return (0); 744 } 745 746 static int 747 envd_es_setup(void) 748 { 749 envfru = get_fru_envsegs(); 750 if (envfru == NULL) { 751 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 752 return (-1); 753 } 754 return (process_fru_seeprom((uchar_t *)envfru->envsegbufp)); 755 } 756 757 static void 758 envd_es_destroy(void) 759 { 760 if (envfru != NULL) 761 free(envfru->envsegbufp); 762 } 763 764 /* 765 * Lookup fan and return a pointer to env_fan_t data structure. 766 */ 767 env_fan_t * 768 fan_lookup(char *name) 769 { 770 int i; 771 env_fan_t *fanp; 772 773 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 774 if (strcmp(fanp->name, name) == 0) 775 return (fanp); 776 } 777 return (NULL); 778 } 779 780 /* 781 * Lookup sensor and return a pointer to env_sensor_t data structure. 782 */ 783 env_sensor_t * 784 sensor_lookup(char *name) 785 { 786 env_sensor_t *sensorp; 787 int i; 788 789 for (i = 0; i < N_ENVD_SENSORS; ++i) { 790 sensorp = &envd_sensors[i]; 791 if (strcmp(sensorp->name, name) == 0) 792 return (sensorp); 793 } 794 return (NULL); 795 } 796 797 /* 798 * Lookup disk and return a pointer to env_disk_t data structure. 799 */ 800 env_disk_t * 801 disk_lookup(char *name) 802 { 803 int i; 804 env_disk_t *diskp; 805 806 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 807 if (strncmp(diskp->name, name, strlen(name)) == 0) 808 return (diskp); 809 } 810 return (NULL); 811 } 812 813 /* 814 * Get current temperature 815 * Returns -1 on error, 0 if successful 816 */ 817 int 818 get_temperature(env_sensor_t *sensorp, tempr_t *temp) 819 { 820 int fd = sensorp->fd; 821 int retval = 0; 822 823 if (fd == -1) 824 retval = -1; 825 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 826 827 retval = -1; 828 829 if (sensorp->error == 0) { 830 sensorp->error = 1; 831 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, 832 sensorp->name, errno, strerror(errno)); 833 } 834 } else if (sensorp->error != 0) { 835 sensorp->error = 0; 836 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name); 837 } 838 if (sensorp->crtbl != NULL) { 839 *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp); 840 } 841 842 return (retval); 843 } 844 845 /* 846 * Get current disk temperature 847 * Returns -1 on error, 0 if successful 848 */ 849 int 850 disk_temperature(env_disk_t *diskp, tempr_t *temp) 851 { 852 int retval = 0; 853 854 if (diskp == NULL) 855 retval = -1; 856 else { 857 *temp = diskp->current_temp; 858 } 859 return (retval); 860 } 861 862 /* 863 * Get uncorrected current temperature 864 * Returns -1 on error, 0 if successful 865 */ 866 static int 867 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp) 868 { 869 int fd = sensorp->fd; 870 int retval = 0; 871 872 if (fd == -1) 873 retval = -1; 874 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 875 retval = -1; 876 } 877 878 return (retval); 879 } 880 881 /* 882 * Return Fan RPM given N & tach 883 * count and N are retrived from the 884 * ADM1031 chip. 885 */ 886 static int 887 tach_to_rpm(int n, uint8_t tach) 888 { 889 if (n * tach == 0) 890 return (0); 891 return ((ADCSAMPLE * 60) / (n * tach)); 892 } 893 894 static int 895 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp) 896 { 897 int fan_fd; 898 int retval = 0; 899 900 fan_fd = fanp->fd; 901 902 if (fan_fd == -1) 903 retval = -1; 904 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) { 905 retval = -1; 906 } 907 908 909 return (retval); 910 } 911 912 /* 913 * Get current fan speed 914 * This function returns a RPM value for fanspeed 915 * in fanspeedp. 916 * Returns -1 on error, 0 if successful 917 */ 918 int 919 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp) 920 { 921 int fan_fd; 922 uint8_t tach; 923 924 fan_fd = fanp->fd; 925 926 if (fan_fd == -1) 927 return (-1); 928 if (fanp->id == DIMM_FAN_ID) { 929 return (get_dimm_fan_speed(fan_fd, fanspeedp)); 930 } 931 if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) { 932 return (-1); 933 } 934 935 /* 936 * Fanspeeds are reported as 0 937 * if the tach is out of range or fan status is off 938 * and if monitoring fan status is enabled. 939 */ 940 if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) { 941 *fanspeedp = 0; 942 } else { 943 *fanspeedp = 944 tach_to_rpm(fanp->speedrange, tach); 945 } 946 947 return (0); 948 } 949 950 /* 951 * Set fan speed 952 * This function accepts a percentage of fan speed 953 * from 0-100 and programs the HW monitor fans to the corresponding 954 * fanspeed value. 955 * Returns -1 on error, -2 on invalid args passed, 0 if successful 956 */ 957 int 958 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed) 959 { 960 int fan_fd; 961 int retval = 0; 962 uint8_t speed; 963 964 fan_fd = fanp->fd; 965 if (fan_fd == -1) 966 return (-1); 967 968 if (fanspeed < 0 || fanspeed > 100) 969 return (-2); 970 971 speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed); 972 973 if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) { 974 retval = -1; 975 } 976 return (retval); 977 } 978 979 /* 980 * close all fan devices 981 */ 982 static void 983 envd_close_fans(void) 984 { 985 int i; 986 env_fan_t *fanp; 987 988 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 989 if (fanp->fd != -1) { 990 (void) close(fanp->fd); 991 fanp->fd = -1; 992 } 993 } 994 } 995 996 /* 997 * Close sensor devices and freeup resources 998 */ 999 static void 1000 envd_close_sensors(void) 1001 { 1002 env_sensor_t *sensorp; 1003 int i; 1004 1005 for (i = 0; i < N_ENVD_SENSORS; ++i) { 1006 sensorp = &envd_sensors[i]; 1007 if (sensorp->fd != -1) { 1008 (void) close(sensorp->fd); 1009 sensorp->fd = -1; 1010 } 1011 if (sensorp->crtbl != NULL) 1012 fini_table(sensorp->crtbl); 1013 } 1014 } 1015 1016 /* 1017 * Open fan devices and initialize per fan data structure. 1018 * Returns #fans found. 1019 */ 1020 static int 1021 envd_setup_fans(void) 1022 { 1023 int i, fd; 1024 env_fan_t *fanp; 1025 char path[PATH_MAX]; 1026 int fancnt = 0; 1027 uint8_t n = 0; 1028 picl_nodehdl_t tnodeh; 1029 i2c_reg_t i2c_reg; 1030 1031 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 1032 /* make sure cpu0/1 present for validating cpu fans */ 1033 if (fanp->id == CPU0_FAN_ID) { 1034 if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) != 1035 PICL_SUCCESS) { 1036 fanp->present = B_FALSE; 1037 continue; 1038 } 1039 } 1040 if (fanp->id == CPU1_FAN_ID) { 1041 if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) != 1042 PICL_SUCCESS) { 1043 fanp->present = B_FALSE; 1044 continue; 1045 } 1046 } 1047 if (fanp->id == DIMM_FAN_ID) { 1048 if (ptree_get_node_by_path(DIMM_FAN_CONTROLLER_PATH, 1049 &tnodeh) != PICL_SUCCESS) { 1050 if (env_debug) 1051 envd_log(LOG_ERR, 1052 "dimm Fan not found in the " 1053 "system.\n"); 1054 fanp->present = B_FALSE; 1055 continue; 1056 } 1057 } 1058 (void) strcpy(path, "/devices"); 1059 (void) strlcat(path, fanp->devfs_path, sizeof (path)); 1060 fd = open(path, O_RDWR); 1061 if (fd == -1) { 1062 envd_log(LOG_CRIT, 1063 ENV_FAN_OPEN_FAIL, fanp->name, 1064 fanp->devfs_path, errno, strerror(errno)); 1065 fanp->present = B_FALSE; 1066 continue; 1067 } 1068 fanp->fd = fd; 1069 if (fanp->id == DIMM_FAN_ID) { 1070 /* 1071 * set the SW aware bit in command register. 1072 * Clear the Fan fault latch bit. 1073 */ 1074 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 1075 i2c_reg.reg_value = (PIC16F819_SW_AWARE_MODE | 1076 PIC16F819_FAN_FAULT_CLEAR); 1077 if (ioctl(fd, I2C_SET_REG, &i2c_reg) == -1) { 1078 if (env_debug) 1079 envd_log(LOG_ERR, 1080 "Error in writing to COMMAND reg. " 1081 "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 " 1121 "in the system.\n"); 1122 monitor_disk_temp = 0; 1123 return (-1); 1124 } 1125 1126 if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID, 1127 &vendor_id, sizeof (vendor_id))) != 0) { 1128 if (env_debug) 1129 envd_log(LOG_ERR, 1130 "Error in getting vendor-id for SCSI controller. " 1131 "ret = %d errno = 0x%d\n", 1132 ret, errno); 1133 monitor_disk_temp = 0; 1134 return (-1); 1135 } 1136 if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID, 1137 &device_id, sizeof (device_id))) != 0) { 1138 if (env_debug) 1139 envd_log(LOG_ERR, 1140 "Error in getting device-id for SCSI controller. " 1141 "ret = %d errno = 0x%d\n", 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 for (;;) { 1890 /* 1891 * Sleep for specified seconds before issuing IOCTL 1892 * again. 1893 */ 1894 (void) pthread_mutex_lock(&env_monitor_mutex); 1895 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 1896 &env_monitor_mutex, &to); 1897 to.tv_sec = INTERRUPTPOLL_INTERVAL; 1898 to.tv_nsec = 0; 1899 if (ret != ETIMEDOUT) { 1900 (void) pthread_mutex_unlock(&env_monitor_mutex); 1901 continue; 1902 } 1903 (void) pthread_mutex_unlock(&env_monitor_mutex); 1904 /* 1905 * We write to the comand register periodically 1906 * to inform the PIC firmware that Solaris is 1907 * Monitoring the dimm fan periodically. 1908 */ 1909 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 1910 i2c_reg.reg_value = PIC16F819_SW_AWARE_MODE; 1911 if (ioctl(envd_dimm_fan.fd, 1912 I2C_SET_REG, &i2c_reg) == -1) { 1913 if (env_debug) 1914 envd_log(LOG_ERR, 1915 "Error in writing to COMMAND reg. " 1916 "of DIMM FAN controller\n"); 1917 } 1918 /* 1919 * We initiate shutdown if fan status indicates 1920 * failure. 1921 */ 1922 if (is_dimm_fan_failed() != 0) { 1923 /* 1924 * Mark Dimm fan present as False so that we 1925 * do not WARN the user of the Fan failure 1926 * repeatedly. 1927 */ 1928 envd_dimm_fan.present = B_FALSE; 1929 (void) snprintf(msgbuf, sizeof (msgbuf), 1930 ENV_DIMM_FAN_FAILURE_SHUTDOWN_MSG, 1931 ENV_DIMM_FAN, 1932 dimm_fan_rpm_string, dimm_fan_status_string, 1933 dimm_fan_command_string, 1934 dimm_fan_debug_string); 1935 envd_log(LOG_ALERT, msgbuf); 1936 1937 if (system_shutdown_started == B_FALSE) { 1938 system_shutdown_started = B_TRUE; 1939 (void) snprintf(syscmd, sizeof (syscmd), 1940 "%s \"%s\"", 1941 SHUTDOWN_CMD, 1942 msgbuf); 1943 envd_log(LOG_ALERT, syscmd); 1944 (void) system(syscmd); 1945 } 1946 } 1947 } 1948 /*NOTREACHED*/ 1949 return (NULL); 1950 } 1951 static int 1952 scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, uint16_t pagelen) 1953 { 1954 struct uscsi_cmd ucmd_buf; 1955 uchar_t cdb_buf[CDB_GROUP1]; 1956 struct scsi_extended_sense sense_buf; 1957 int ret_val; 1958 1959 bzero((void *)&cdb_buf, sizeof (cdb_buf)); 1960 bzero((void *)&ucmd_buf, sizeof (ucmd_buf)); 1961 bzero((void *)&sense_buf, sizeof (sense_buf)); 1962 1963 cdb_buf[0] = SCMD_LOG_SENSE_G1; 1964 cdb_buf[2] = (0x01 << 6) | page_code; 1965 cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8); 1966 cdb_buf[8] = (uchar_t)(pagelen & 0x00FF); 1967 1968 ucmd_buf.uscsi_cdb = (char *)cdb_buf; 1969 ucmd_buf.uscsi_cdblen = sizeof (cdb_buf); 1970 ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf; 1971 ucmd_buf.uscsi_buflen = pagelen; 1972 ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf; 1973 ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense); 1974 ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT; 1975 ucmd_buf.uscsi_timeout = 60; 1976 1977 ret_val = ioctl(fd, USCSICMD, ucmd_buf); 1978 if (ret_val == 0 && ucmd_buf.uscsi_status == 0) { 1979 if (env_debug) 1980 envd_log(LOG_ERR, 1981 "log sense command for page_code 0x%x succeeded\n", 1982 page_code); 1983 return (ret_val); 1984 } 1985 if (env_debug) 1986 envd_log(LOG_ERR, 1987 "log sense command failed.ret_val = 0x%x status = 0x%x " 1988 "errno = 0x%x\n", 1989 ret_val, ucmd_buf.uscsi_status, errno); 1990 return (1); 1991 } 1992 1993 static int 1994 get_disk_temp(env_disk_t *diskp) 1995 { 1996 int ret; 1997 uchar_t tpage[256]; 1998 1999 ret = scsi_log_sense(diskp->fd, 2000 TEMPERATURE_PAGE, 2001 tpage, sizeof (tpage)); 2002 if (ret != 0) { 2003 diskp->current_temp = DISK_INVALID_TEMP; 2004 diskp->ref_temp = DISK_INVALID_TEMP; 2005 return (-1); 2006 } 2007 /* 2008 * For the current temperature verify that the parameter 2009 * length is 0x02 and the parameter code is 0x00 2010 * Temperature value of 255(0xFF) is considered INVALID. 2011 */ 2012 if ((tpage[7] == 0x02) && (tpage[4] == 0x00) && 2013 (tpage[5] == 0x00)) { 2014 if (tpage[9] == 0xFF) { 2015 diskp->current_temp = DISK_INVALID_TEMP; 2016 return (-1); 2017 } else { 2018 diskp->current_temp = tpage[9]; 2019 } 2020 } 2021 2022 /* 2023 * For the reference temperature verify that the parameter 2024 * length is 0x02 and the parameter code is 0x01 2025 * Temperature value of 255(0xFF) is considered INVALID. 2026 */ 2027 if ((tpage[13] == 0x02) && (tpage[10] == 0x00) && 2028 (tpage[11] == 0x01)) { 2029 if (tpage[15] == 0xFF) { 2030 diskp->ref_temp = DISK_INVALID_TEMP; 2031 } else { 2032 diskp->ref_temp = tpage[15]; 2033 } 2034 } 2035 return (0); 2036 } 2037 2038 /* ARGSUSED */ 2039 static void * 2040 disk_temp_thr(void *args) 2041 { 2042 char syscmd[BUFSIZ]; 2043 char msgbuf[BUFSIZ]; 2044 timespec_t to; 2045 int ret, i; 2046 env_disk_t *diskp; 2047 pthread_mutex_t env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER; 2048 pthread_cond_t env_monitor_cv = PTHREAD_COND_INITIALIZER; 2049 pm_state_change_t pmstate; 2050 int idle_time; 2051 int disk_pm_fd; 2052 time_t ct; 2053 2054 disk_pm_fd = open(PM_DEVICE, O_RDWR); 2055 if (disk_pm_fd == -1) { 2056 envd_log(LOG_ERR, 2057 DISK_TEMP_THREAD_EXITING, 2058 errno, strerror(errno)); 2059 return (NULL); 2060 } 2061 for (;;) { 2062 /* 2063 * Sleep for specified seconds before issuing IOCTL 2064 * again. 2065 */ 2066 (void) pthread_mutex_lock(&env_monitor_mutex); 2067 ret = pthread_cond_reltimedwait_np(&env_monitor_cv, 2068 &env_monitor_mutex, &to); 2069 to.tv_sec = disk_scan_interval; 2070 to.tv_nsec = 0; 2071 if (ret != ETIMEDOUT) { 2072 (void) pthread_mutex_unlock(&env_monitor_mutex); 2073 continue; 2074 } 2075 (void) pthread_mutex_unlock(&env_monitor_mutex); 2076 for (i = 0; (diskp = envd_disks[i]) != NULL; i++) { 2077 if (diskp->present == B_FALSE) 2078 continue; 2079 if (diskp->tpage_supported == B_FALSE) 2080 continue; 2081 /* 2082 * If the disk temperature is above the warning 2083 * threshold continue monitoring until the temperature 2084 * drops below warning threshold. 2085 * If the temperature is in the NORMAL range monitor 2086 * only when the disk is BUSY. 2087 * We do not want to read the disk temperature if the 2088 * disk is is idling. The reason for this is disk will 2089 * never get into lowest power mode if we scan the disk 2090 * temperature peridoically. 2091 * To avoid this situation we first determine 2092 * the idle_time of the disk. If the disk has been 2093 * IDLE since we scanned the temperature last time 2094 * we will not read the temperature. 2095 */ 2096 if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, 2097 diskp)) { 2098 pmstate.physpath = diskp->physpath; 2099 pmstate.size = strlen(diskp->physpath); 2100 pmstate.component = 0; 2101 if ((idle_time = 2102 ioctl(disk_pm_fd, 2103 PM_GET_TIME_IDLE, &pmstate)) == -1) { 2104 if (errno != EINTR) { 2105 if (env_debug) { 2106 envd_log(LOG_ERR, 2107 "ioctl " 2108 "PM_GET_TIME_IDLE " 2109 "failed for DISK0." 2110 " errno=0x%x\n", 2111 errno); 2112 } 2113 continue; 2114 } 2115 continue; 2116 } 2117 if (idle_time >= (disk_scan_interval/2)) { 2118 if (env_debug) { 2119 envd_log(LOG_ERR, 2120 "%s idle time = %d\n", 2121 diskp->name, idle_time); 2122 } 2123 continue; 2124 } 2125 } 2126 ret = get_disk_temp(diskp); 2127 if (ret != 0) 2128 continue; 2129 if (env_debug) { 2130 envd_log(LOG_ERR, 2131 "%s temp = %d ref. temp = %d\n", 2132 diskp->name, diskp->current_temp, 2133 diskp->ref_temp); 2134 } 2135 /* 2136 * If this disk already triggered system shutdown, don't 2137 * log any more shutdown/warning messages for it. 2138 */ 2139 if (diskp->shutdown_initiated) 2140 continue; 2141 2142 /* 2143 * Check for the temperature in warning and shutdown 2144 * range and take appropriate action. 2145 */ 2146 if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, 2147 diskp)) { 2148 /* 2149 * Check if the temperature has been in warning 2150 * range during last disk_warning_duration 2151 * interval. 2152 * If so, the temperature is truly in warning 2153 * range and we need to log a warning message, 2154 * but no more than once every 2155 * disk_warning_interval seconds. 2156 */ 2157 time_t wtstamp = diskp->warning_tstamp; 2158 2159 ct = (time_t)(gethrtime() / NANOSEC); 2160 if (diskp->warning_start == 0) 2161 diskp->warning_start = ct; 2162 if (((ct - diskp->warning_start) >= 2163 disk_warning_duration) && (wtstamp == 0 || 2164 (ct - wtstamp) >= disk_warning_interval)) { 2165 envd_log(LOG_CRIT, ENV_WARNING_MSG, 2166 diskp->name, diskp->current_temp, 2167 diskp->low_warning, 2168 diskp->high_warning); 2169 diskp->warning_tstamp = ct; 2170 } 2171 } else if (diskp->warning_start != 0) 2172 diskp->warning_start = 0; 2173 2174 if (!shutdown_override && 2175 DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, 2176 diskp)) { 2177 ct = (time_t)(gethrtime() / NANOSEC); 2178 if (diskp->shutdown_tstamp == 0) 2179 diskp->shutdown_tstamp = ct; 2180 2181 /* 2182 * Shutdown the system if the temperature 2183 * remains in the shutdown range for over 2184 * disk_shutdown_interval seconds. 2185 */ 2186 if ((ct - diskp->shutdown_tstamp) >= 2187 disk_shutdown_interval) { 2188 /* log error */ 2189 diskp->shutdown_initiated = B_TRUE; 2190 (void) snprintf(msgbuf, sizeof (msgbuf), 2191 ENV_SHUTDOWN_MSG, diskp->name, 2192 diskp->current_temp, 2193 diskp->low_shutdown, 2194 diskp->high_shutdown); 2195 envd_log(LOG_ALERT, msgbuf); 2196 2197 /* shutdown the system (only once) */ 2198 if (system_shutdown_started == 2199 B_FALSE) { 2200 (void) snprintf(syscmd, 2201 sizeof (syscmd), 2202 "%s \"%s\"", shutdown_cmd, 2203 msgbuf); 2204 envd_log(LOG_ALERT, syscmd); 2205 system_shutdown_started = 2206 B_TRUE; 2207 (void) system(syscmd); 2208 } 2209 } 2210 } else if (diskp->shutdown_tstamp != 0) 2211 diskp->shutdown_tstamp = 0; 2212 2213 } 2214 } /* end of forever loop */ 2215 } 2216 2217 /* 2218 * Setup envrionmental monitor state and start threads to monitor 2219 * temperature and power management state. 2220 * Returns -1 on error, 0 if successful. 2221 */ 2222 static int 2223 envd_setup(void) 2224 { 2225 int ret; 2226 2227 if (getenv("SUNW_piclenvd_debug") != NULL) 2228 env_debug = 1; 2229 2230 if (pthread_attr_init(&thr_attr) != 0 || 2231 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) { 2232 return (-1); 2233 } 2234 2235 ret = envd_es_setup(); 2236 if (ret < 0) { 2237 ovtemp_monitor = 0; 2238 pm_monitor = 0; 2239 } 2240 2241 /* 2242 * Setup temperature sensors and fail if we can't open 2243 * at least one sensor. 2244 */ 2245 if (envd_setup_sensors() <= 0) { 2246 return (0); 2247 } 2248 2249 /* 2250 * Setup fan device (don't fail even if we can't access 2251 * the fan as we can still monitor temeperature. 2252 */ 2253 (void) envd_setup_fans(); 2254 2255 (void) envd_setup_disks(); 2256 2257 /* If ES Segment setup failed,don't create thread */ 2258 2259 if (ovtemp_monitor && ovtemp_thr1_created == B_FALSE) { 2260 if (pthread_create(&ovtemp_thr1_id, &thr_attr, ovtemp_thr, 2261 (void *)CPU_HWM_ID) != 0) 2262 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2263 else 2264 ovtemp_thr1_created = B_TRUE; 2265 } 2266 2267 if (ovtemp_monitor && ovtemp_thr2_created == B_FALSE) { 2268 if (pthread_create(&ovtemp_thr2_id, &thr_attr, ovtemp_thr, 2269 (void *)SYS_HWM_ID) != 0) 2270 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2271 else 2272 ovtemp_thr2_created = B_TRUE; 2273 } 2274 2275 if (envd_dimm_fan.present) { 2276 if (dimm_fan_thr_created == B_FALSE) { 2277 if (pthread_create(&dimm_fan_thr_id, &thr_attr, 2278 dimm_fan_thr, NULL) != 0) 2279 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2280 else 2281 dimm_fan_thr_created = B_TRUE; 2282 } 2283 } 2284 2285 /* 2286 * Create a thread to monitor PM state 2287 */ 2288 if (pm_monitor && pmthr_created == B_FALSE) { 2289 if (pthread_create(&pmthr_tid, &thr_attr, pmthr, 2290 NULL) != 0) 2291 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); 2292 else 2293 pmthr_created = B_TRUE; 2294 } 2295 if (monitor_disk_temp) { 2296 if (disk_temp_thr_created == B_FALSE) { 2297 if (pthread_create(&disk_temp_thr_id, &thr_attr, 2298 disk_temp_thr, NULL) != 0) 2299 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 2300 else 2301 disk_temp_thr_created = B_TRUE; 2302 } 2303 } 2304 return (0); 2305 } 2306 2307 static void 2308 piclenvd_register(void) 2309 { 2310 picld_plugin_register(&my_reg_info); 2311 } 2312 2313 static void 2314 piclenvd_init(void) 2315 { 2316 2317 (void) env_picl_setup_tuneables(); 2318 2319 /* 2320 * Setup the environmental data structures 2321 */ 2322 if (envd_setup() != 0) { 2323 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); 2324 return; 2325 } 2326 2327 /* 2328 * Now setup/populate PICL tree 2329 */ 2330 env_picl_setup(); 2331 } 2332 2333 static void 2334 piclenvd_fini(void) 2335 { 2336 2337 /* 2338 * Invoke env_picl_destroy() to remove any PICL nodes/properties 2339 * (including volatile properties) we created. Once this call 2340 * returns, there can't be any more calls from the PICL framework 2341 * to get current temperature or fan speed. 2342 */ 2343 env_picl_destroy(); 2344 envd_close_sensors(); 2345 envd_close_fans(); 2346 envd_es_destroy(); 2347 } 2348 2349 /*VARARGS2*/ 2350 void 2351 envd_log(int pri, const char *fmt, ...) 2352 { 2353 va_list ap; 2354 2355 va_start(ap, fmt); 2356 vsyslog(pri, fmt, ap); 2357 va_end(ap); 2358 } 2359 2360 /* 2361 * Tunables support functions 2362 */ 2363 static env_tuneable_t * 2364 tuneable_lookup(picl_prophdl_t proph) 2365 { 2366 int i; 2367 env_tuneable_t *tuneablep = NULL; 2368 2369 for (i = 0; i < ntuneables; i++) { 2370 tuneablep = &tuneables[i]; 2371 if (tuneablep->proph == proph) 2372 return (tuneablep); 2373 } 2374 2375 return (NULL); 2376 } 2377 2378 static int 2379 get_cpu_tach(ptree_rarg_t *parg, void *buf) 2380 { 2381 picl_prophdl_t proph; 2382 env_tuneable_t *tuneablep; 2383 int fd; 2384 int8_t cfg; 2385 2386 proph = parg->proph; 2387 2388 tuneablep = tuneable_lookup(proph); 2389 2390 if (tuneablep == NULL) 2391 return (PICL_FAILURE); 2392 2393 fd = open(CPU_HWM_DEVFS, O_RDWR); 2394 2395 if (fd == -1) { 2396 return (PICL_FAILURE); 2397 } 2398 2399 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2400 return (PICL_FAILURE); 2401 } 2402 2403 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) { 2404 *((int *)tuneablep->value) = ENABLE; 2405 } else { 2406 *((int *)tuneablep->value) = DISABLE; 2407 } 2408 2409 (void) memcpy(buf, tuneablep->value, 2410 tuneablep->nbytes); 2411 2412 (void) close(fd); 2413 return (PICL_SUCCESS); 2414 } 2415 2416 static int 2417 set_cpu_tach(ptree_warg_t *parg, const void *buf) 2418 { 2419 picl_prophdl_t proph; 2420 env_tuneable_t *tuneablep; 2421 int fd, val; 2422 int8_t cfg; 2423 2424 if (parg->cred.dc_euid != 0) 2425 return (PICL_PERMDENIED); 2426 2427 proph = parg->proph; 2428 2429 tuneablep = tuneable_lookup(proph); 2430 2431 if (tuneablep == NULL) 2432 return (PICL_FAILURE); 2433 2434 2435 fd = open(CPU_HWM_DEVFS, O_RDWR); 2436 2437 if (fd == -1) { 2438 return (PICL_FAILURE); 2439 } 2440 2441 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2442 return (PICL_FAILURE); 2443 } 2444 2445 (void) memcpy(&val, (caddr_t)buf, sizeof (val)); 2446 2447 if (val == ENABLE) { 2448 cfg |= TACH_ENABLE_MASK; 2449 } else if (val == DISABLE) { 2450 cfg &= ~TACH_ENABLE_MASK; 2451 } 2452 2453 2454 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) { 2455 return (PICL_FAILURE); 2456 } 2457 2458 (void) close(fd); 2459 return (PICL_SUCCESS); 2460 } 2461 2462 static int 2463 get_sys_tach(ptree_rarg_t *parg, void *buf) 2464 { 2465 picl_prophdl_t proph; 2466 env_tuneable_t *tuneablep; 2467 int fd; 2468 int8_t cfg; 2469 2470 proph = parg->proph; 2471 2472 tuneablep = tuneable_lookup(proph); 2473 2474 if (tuneablep == NULL) 2475 return (PICL_FAILURE); 2476 2477 fd = open(SYS_HWM_DEVFS, O_RDWR); 2478 2479 if (fd == -1) { 2480 return (PICL_FAILURE); 2481 } 2482 2483 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2484 return (PICL_FAILURE); 2485 } 2486 2487 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) { 2488 *((int *)tuneablep->value) = ENABLE; 2489 } else { 2490 *((int *)tuneablep->value) = DISABLE; 2491 } 2492 2493 (void) memcpy(buf, tuneablep->value, 2494 tuneablep->nbytes); 2495 2496 (void) close(fd); 2497 return (PICL_SUCCESS); 2498 } 2499 2500 static int 2501 set_sys_tach(ptree_warg_t *parg, const void *buf) 2502 { 2503 picl_prophdl_t proph; 2504 env_tuneable_t *tuneablep; 2505 int fd, val; 2506 int8_t cfg; 2507 2508 if (parg->cred.dc_euid != 0) 2509 return (PICL_PERMDENIED); 2510 2511 proph = parg->proph; 2512 2513 tuneablep = tuneable_lookup(proph); 2514 2515 if (tuneablep == NULL) 2516 return (PICL_FAILURE); 2517 2518 2519 fd = open(SYS_HWM_DEVFS, O_RDWR); 2520 2521 if (fd == -1) { 2522 return (PICL_FAILURE); 2523 } 2524 2525 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 2526 return (PICL_FAILURE); 2527 } 2528 2529 (void) memcpy(&val, buf, sizeof (val)); 2530 2531 if (val == ENABLE) { 2532 cfg |= TACH_ENABLE_MASK; 2533 } else if (val == DISABLE) { 2534 cfg &= ~TACH_ENABLE_MASK; 2535 } 2536 2537 2538 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) { 2539 return (PICL_FAILURE); 2540 } 2541 2542 (void) close(fd); 2543 return (PICL_SUCCESS); 2544 } 2545 2546 static int 2547 get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf) 2548 { 2549 picl_prophdl_t proph; 2550 env_tuneable_t *tuneablep; 2551 int fd; 2552 int8_t mmode; 2553 2554 proph = parg->proph; 2555 2556 tuneablep = tuneable_lookup(proph); 2557 2558 if (tuneablep == NULL) 2559 return (PICL_FAILURE); 2560 2561 fd = open(CPU_HWM_DEVFS, O_RDWR); 2562 2563 if (fd == -1) { 2564 return (PICL_FAILURE); 2565 } 2566 2567 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) { 2568 return (PICL_FAILURE); 2569 } 2570 2571 if (mmode == ADM1031_AUTO_MODE) { 2572 *((int *)tuneablep->value) = ENABLE; 2573 } else { 2574 *((int *)tuneablep->value) = DISABLE; 2575 } 2576 2577 (void) memcpy(buf, tuneablep->value, 2578 tuneablep->nbytes); 2579 2580 (void) close(fd); 2581 return (PICL_SUCCESS); 2582 } 2583 2584 static int 2585 set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf) 2586 { 2587 picl_prophdl_t proph; 2588 env_tuneable_t *tuneablep; 2589 int fd, val; 2590 int8_t mmode; 2591 2592 if (parg->cred.dc_euid != 0) 2593 return (PICL_PERMDENIED); 2594 2595 proph = parg->proph; 2596 2597 tuneablep = tuneable_lookup(proph); 2598 2599 if (tuneablep == NULL) 2600 return (PICL_FAILURE); 2601 2602 fd = open(CPU_HWM_DEVFS, O_RDWR); 2603 2604 if (fd == -1) { 2605 return (PICL_FAILURE); 2606 } 2607 2608 (void) memcpy(&val, buf, sizeof (val)); 2609 2610 if (val == ENABLE) { 2611 mmode = ADM1031_AUTO_MODE; 2612 } else if (val == DISABLE) { 2613 mmode = ADM1031_MANUAL_MODE; 2614 } 2615 2616 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) { 2617 return (PICL_FAILURE); 2618 } 2619 2620 (void) close(fd); 2621 return (PICL_SUCCESS); 2622 } 2623 2624 static int 2625 get_monitor_sys_mode(ptree_rarg_t *parg, void *buf) 2626 { 2627 picl_prophdl_t proph; 2628 env_tuneable_t *tuneablep; 2629 int fd; 2630 int8_t mmode; 2631 2632 proph = parg->proph; 2633 2634 tuneablep = tuneable_lookup(proph); 2635 2636 if (tuneablep == NULL) 2637 return (PICL_FAILURE); 2638 2639 fd = open(SYS_HWM_DEVFS, O_RDWR); 2640 2641 if (fd == -1) { 2642 return (PICL_FAILURE); 2643 } 2644 2645 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) { 2646 return (PICL_FAILURE); 2647 } 2648 2649 if (mmode == ADM1031_AUTO_MODE) { 2650 *((int *)tuneablep->value) = ENABLE; 2651 } else { 2652 *((int *)tuneablep->value) = DISABLE; 2653 } 2654 2655 (void) memcpy(buf, tuneablep->value, 2656 tuneablep->nbytes); 2657 2658 (void) close(fd); 2659 return (PICL_SUCCESS); 2660 } 2661 2662 static int 2663 set_monitor_sys_mode(ptree_warg_t *parg, const void *buf) 2664 { 2665 picl_prophdl_t proph; 2666 env_tuneable_t *tuneablep; 2667 int fd, val; 2668 int8_t mmode; 2669 2670 if (parg->cred.dc_euid != 0) 2671 return (PICL_PERMDENIED); 2672 2673 proph = parg->proph; 2674 2675 tuneablep = tuneable_lookup(proph); 2676 2677 if (tuneablep == NULL) 2678 return (PICL_FAILURE); 2679 2680 fd = open(SYS_HWM_DEVFS, O_RDWR); 2681 2682 if (fd == -1) { 2683 return (PICL_FAILURE); 2684 } 2685 2686 (void) memcpy(&val, buf, sizeof (val)); 2687 2688 if (val == ENABLE) { 2689 mmode = ADM1031_AUTO_MODE; 2690 } else if (val == DISABLE) { 2691 mmode = ADM1031_MANUAL_MODE; 2692 } 2693 2694 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) { 2695 return (PICL_FAILURE); 2696 } 2697 2698 (void) close(fd); 2699 return (PICL_SUCCESS); 2700 } 2701 2702 static int 2703 get_string_val(ptree_rarg_t *parg, void *buf) 2704 { 2705 picl_prophdl_t proph; 2706 env_tuneable_t *tuneablep; 2707 2708 proph = parg->proph; 2709 2710 tuneablep = tuneable_lookup(proph); 2711 2712 if (tuneablep == NULL) 2713 return (PICL_FAILURE); 2714 2715 (void) memcpy(buf, (caddr_t)tuneablep->value, 2716 tuneablep->nbytes); 2717 2718 return (PICL_SUCCESS); 2719 } 2720 2721 static int 2722 set_string_val(ptree_warg_t *parg, const void *buf) 2723 { 2724 picl_prophdl_t proph; 2725 env_tuneable_t *tuneablep; 2726 2727 if (parg->cred.dc_euid != 0) 2728 return (PICL_PERMDENIED); 2729 2730 proph = parg->proph; 2731 2732 tuneablep = tuneable_lookup(proph); 2733 2734 if (tuneablep == NULL) 2735 return (PICL_FAILURE); 2736 2737 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf, 2738 tuneables->nbytes); 2739 2740 2741 return (PICL_SUCCESS); 2742 } 2743 2744 static int 2745 get_int_val(ptree_rarg_t *parg, void *buf) 2746 { 2747 picl_prophdl_t proph; 2748 env_tuneable_t *tuneablep; 2749 2750 proph = parg->proph; 2751 2752 tuneablep = tuneable_lookup(proph); 2753 2754 if (tuneablep == NULL) 2755 return (PICL_FAILURE); 2756 2757 (void) memcpy((int *)buf, (int *)tuneablep->value, 2758 tuneablep->nbytes); 2759 2760 return (PICL_SUCCESS); 2761 } 2762 2763 static int 2764 set_int_val(ptree_warg_t *parg, const void *buf) 2765 { 2766 picl_prophdl_t proph; 2767 env_tuneable_t *tuneablep; 2768 2769 if (parg->cred.dc_euid != 0) 2770 return (PICL_PERMDENIED); 2771 2772 proph = parg->proph; 2773 2774 tuneablep = tuneable_lookup(proph); 2775 2776 if (tuneablep == NULL) 2777 return (PICL_FAILURE); 2778 2779 (void) memcpy((int *)tuneablep->value, (int *)buf, 2780 tuneablep->nbytes); 2781 2782 return (PICL_SUCCESS); 2783 } 2784 2785 int 2786 get_dimm_fan_speed(int fan_fd, fanspeed_t *fanspeedp) 2787 { 2788 int16_t dimm_fan_period; 2789 i2c_reg_t i2c_reg; 2790 2791 /* 2792 * The dimm fan period is 16 bit value and we need to read 2793 * registers 2 and 3 to get the LSB and MSB values. 2794 */ 2795 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_MSB_REGISTER; 2796 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) { 2797 if (env_debug) 2798 envd_log(LOG_ERR, 2799 "Error in reading FAN_PERIOD MSB REGISTER\n"); 2800 return (-1); 2801 } 2802 dimm_fan_period = (i2c_reg.reg_value << 8); 2803 i2c_reg.reg_num = PIC16F819_FAN_PERIOD_LSB_REGISTER; 2804 if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) { 2805 if (env_debug) 2806 envd_log(LOG_ERR, 2807 "Error in reading FAN_PERIOD LSB REGISTER\n"); 2808 return (-1); 2809 } 2810 dimm_fan_period |= i2c_reg.reg_value; 2811 if (env_debug) 2812 envd_log(LOG_ERR, 2813 " dimm fan tach period is 0x%x\n", dimm_fan_period); 2814 if (dimm_fan_period == 0) { 2815 if (env_debug) 2816 envd_log(LOG_ERR, 2817 "dimm fan tach period read as zero. Illegal value.\n"); 2818 return (-1); 2819 } 2820 *fanspeedp = PIC16F819_FAN_TACH_TO_RPM(dimm_fan_period); 2821 return (0); 2822 } 2823 2824 int 2825 is_dimm_fan_failed(void) 2826 { 2827 i2c_reg_t i2c_reg; 2828 fanspeed_t fan_speed; 2829 int retry_count; 2830 2831 if (envd_dimm_fan.fd == -1) 2832 return (-1); 2833 /* 2834 * read register 1 to look at Fan fault bit. 2835 */ 2836 i2c_reg.reg_num = PIC16F819_STATUS_REGISTER; 2837 retry_count = MAX_RETRIES_FOR_PIC16F819_REG_READ; 2838 while (retry_count > 0) { 2839 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2840 retry_count--; 2841 continue; 2842 } else break; 2843 } 2844 if (retry_count != MAX_RETRIES_FOR_PIC16F819_REG_READ) { 2845 if (env_debug) 2846 envd_log(LOG_ERR, 2847 "%d retries attempted in reading STATUS " 2848 "register.\n", 2849 (MAX_RETRIES_FOR_PIC16F819_REG_READ - retry_count)); 2850 } 2851 if (retry_count == 0) { 2852 (void) strncpy(dimm_fan_status_string, NOT_AVAILABLE, 2853 sizeof (dimm_fan_status_string)); 2854 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE, 2855 sizeof (dimm_fan_command_string)); 2856 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE, 2857 sizeof (dimm_fan_debug_string)); 2858 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE, 2859 sizeof (dimm_fan_rpm_string)); 2860 return (-1); 2861 } 2862 if (env_debug) 2863 envd_log(LOG_ERR, 2864 "DIMM FAN STATUS reg = 0x%x\n", i2c_reg.reg_value); 2865 if (i2c_reg.reg_value & PIC16F819_FAN_FAILED) { 2866 (void) snprintf(dimm_fan_status_string, 2867 sizeof (dimm_fan_status_string), "0x%x", 2868 i2c_reg.reg_value); 2869 i2c_reg.reg_num = PIC16F819_DEBUG_REGISTER; 2870 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2871 (void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE, 2872 sizeof (dimm_fan_debug_string)); 2873 } else { 2874 (void) snprintf(dimm_fan_debug_string, 2875 sizeof (dimm_fan_debug_string), 2876 "0x%x", i2c_reg.reg_value); 2877 } 2878 i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER; 2879 if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) { 2880 (void) strncpy(dimm_fan_command_string, NOT_AVAILABLE, 2881 sizeof (dimm_fan_command_string)); 2882 } else { 2883 (void) snprintf(dimm_fan_command_string, 2884 sizeof (dimm_fan_command_string), 2885 "0x%x", i2c_reg.reg_value); 2886 } 2887 if (get_dimm_fan_speed(envd_dimm_fan.fd, &fan_speed) == -1) { 2888 (void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE, 2889 sizeof (dimm_fan_rpm_string)); 2890 } else { 2891 (void) snprintf(dimm_fan_rpm_string, 2892 sizeof (dimm_fan_rpm_string), 2893 "%d", fan_speed); 2894 } 2895 return (1); 2896 } else return (0); 2897 } 2898