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 2003 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 Taco. 33 * It provides functionality to get/set temperatures 34 * and fan speeds 35 * 36 * The environmental monitoring policy is the default 37 * auto mode 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 <stdarg.h> 46 #include <alloca.h> 47 #include <unistd.h> 48 #include <sys/processor.h> 49 #include <syslog.h> 50 #include <errno.h> 51 #include <fcntl.h> 52 #include <picl.h> 53 #include <picltree.h> 54 #include <picldefs.h> 55 #include <pthread.h> 56 #include <signal.h> 57 #include <libdevinfo.h> 58 #include <sys/pm.h> 59 #include <sys/open.h> 60 #include <sys/time.h> 61 #include <sys/utsname.h> 62 #include <sys/systeminfo.h> 63 #include <note.h> 64 #include <sys/i2c/clients/i2c_client.h> 65 #include <sys/i2c/clients/adm1031.h> 66 #include "envd.h" 67 68 /* 69 * PICL plguin entry points 70 */ 71 static void piclenvd_register(void); 72 static void piclenvd_init(void); 73 static void piclenvd_fini(void); 74 75 /* 76 * Env setup routines 77 */ 78 extern void env_picl_setup(void); 79 extern void env_picl_destroy(void); 80 extern int env_picl_setup_tuneables(void); 81 82 /* 83 * Sleep routine used for polling 84 */ 85 static uint_t envd_sleep(uint_t); 86 87 #pragma init(piclenvd_register) 88 89 /* 90 * Plugin registration information 91 */ 92 static picld_plugin_reg_t my_reg_info = { 93 PICLD_PLUGIN_VERSION, 94 PICLD_PLUGIN_CRITICAL, 95 "SUNW_piclenvd", 96 piclenvd_init, 97 piclenvd_fini, 98 }; 99 100 /* 101 * ES Segment data structures 102 */ 103 static sensor_ctrl_blk_t sensor_ctrl[MAX_SENSORS]; 104 static fan_ctrl_blk_t fan_ctrl[MAX_FANS]; 105 static fruenvseg_t *envfru = NULL; 106 107 /* 108 * Env thread variables 109 */ 110 static boolean_t system_shutdown_started = B_FALSE; 111 static boolean_t ovtemp_thr_created = B_FALSE; 112 static pthread_t ovtemp_thr_id; 113 static pthread_attr_t thr_attr; 114 115 116 /* 117 * PM thread related variabled 118 */ 119 static pthread_t pmthr_tid; /* pmthr thread ID */ 120 static int pm_fd = -1; /* PM device file descriptor */ 121 static boolean_t pmthr_created = B_FALSE; 122 static int cur_lpstate; /* cur low power state */ 123 124 /* 125 * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var 126 * Setting the verbose tuneable also enables debugging for better 127 * control 128 */ 129 int env_debug = 0; 130 131 /* 132 * Fan devices 133 */ 134 static env_fan_t envd_sys_out_fan = { 135 ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_FAN_DEVFS, NULL, 136 SYSTEM_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN, 137 SYSTEM_OUT_FAN_SPEED_MAX, -1, -1, 138 }; 139 140 static env_fan_t envd_sys_in_fan = { 141 ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_FAN_DEVFS, NULL, 142 SYSTEM_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN, 143 SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1, 144 }; 145 146 static env_fan_t envd_cpu_fan = { 147 ENV_CPU_FAN, ENV_CPU_FAN_DEVFS, NULL, 148 CPU_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1, 149 }; 150 151 /* 152 * NULL terminated array of fans 153 */ 154 static env_fan_t *envd_fans[] = { 155 &envd_cpu_fan, 156 &envd_sys_in_fan, 157 &envd_sys_out_fan, 158 NULL 159 }; 160 161 /* 162 * ADM1031 speedrange map is indexed by a 2-bit value 163 */ 164 static int adm_speedrange_map[] = {1, 2, 4, 8}; 165 166 /* 167 * ADM1031 devices 168 */ 169 static char *hwm_devs[] = { 170 CPU_HWM_DEVFS, /* CPU_HWM_ID */ 171 }; 172 173 /* 174 * Fan names associated with each ADM1031 hwms - used to 175 * print fault messages 176 */ 177 static char *hwm_fans[MAX_HWMS][2] = { 178 {ENV_CPU_FAN, ENV_SYSTEM_IN_OUT_FANS} 179 }; 180 181 /* 182 * Temperature sensors 183 */ 184 static env_sensor_t envd_sensors[] = { 185 { SENSOR_CPU_DIE, SENSOR_CPU_DIE_DEVFS, NULL, 186 CPU_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu_fan, -1}, 187 { SENSOR_INT_AMB, SENSOR_INT_AMB_DEVFS, NULL, 188 INT_AMB_SENSOR_ID, CPU_HWM_ID, NULL, -1}, 189 { SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL, 190 SYS_IN_SENSOR_ID, CPU_HWM_ID, (void *)&envd_sys_in_fan, -1}, 191 }; 192 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0])) 193 194 /* 195 * ADM1031 macros 196 */ 197 #define TACH_UNKNOWN 255 198 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN) 199 #define ADM_HYSTERISIS 5 200 #define N_SEQ_TACH 15 201 202 #define TMIN_MASK (0xF8) 203 #define TMIN_SHIFT (3) 204 #define TMIN_UNITS (4) /* increments of 4 degrees celsius */ 205 #define TRANGE_MASK (0x7) 206 207 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS) 208 #define TRANGE(regval) (regval & TRANGE_MASK) 209 210 #define GET_TMIN_RANGE(tmin, trange) \ 211 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \ 212 (trange & TRANGE_MASK)) 213 214 #define TACH_ENABLE_MASK (0x0C) 215 #define MONITOR_ENABLE_MASK (0x01) 216 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100) 217 218 /* 219 * Tuneables 220 */ 221 #define ENABLE 1 222 #define DISABLE 0 223 224 static int get_monitor_mode(ptree_rarg_t *parg, void *buf); 225 static int set_monitor_mode(ptree_warg_t *parg, const void *buf); 226 static int get_int_val(ptree_rarg_t *parg, void *buf); 227 static int set_int_val(ptree_warg_t *parg, const void *buf); 228 static int get_string_val(ptree_rarg_t *parg, void *buf); 229 static int set_string_val(ptree_warg_t *parg, const void *buf); 230 static int get_tach(ptree_rarg_t *parg, void *buf); 231 static int set_tach(ptree_warg_t *parg, const void *buf); 232 233 static int shutdown_override = 0; 234 static int sensor_poll_interval = SENSORPOLL_INTERVAL; 235 static int warning_interval = WARNING_INTERVAL; 236 static int shutdown_interval = SHUTDOWN_INTERVAL; 237 static int ovtemp_monitor = 1; /* enabled */ 238 static int pm_monitor = 1; /* enabled */ 239 static int mon_fanstat = 1; /* enabled */ 240 241 static int hwm_mode; 242 static int hwm_tach_enable; 243 static char shutdown_cmd[] = SHUTDOWN_CMD; 244 245 env_tuneable_t tuneables[] = { 246 {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor, 247 &get_int_val, &set_int_val, sizeof (int)}, 248 249 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor, 250 &get_int_val, &set_int_val, sizeof (int)}, 251 252 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override, 253 &get_int_val, &set_int_val, sizeof (int)}, 254 255 {"hwm-automode-enable", PICL_PTYPE_INT, &hwm_mode, 256 &get_monitor_mode, &set_monitor_mode, sizeof (int)}, 257 258 {"sensor-poll-interval", PICL_PTYPE_INT, 259 &sensor_poll_interval, 260 &get_int_val, &set_int_val, 261 sizeof (int)}, 262 263 {"warning-interval", PICL_PTYPE_INT, &warning_interval, 264 &get_int_val, &set_int_val, 265 sizeof (int)}, 266 267 {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval, 268 &get_int_val, &set_int_val, 269 sizeof (int)}, 270 271 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd, 272 &get_string_val, &set_string_val, 273 sizeof (shutdown_cmd)}, 274 275 {"tach-enable", PICL_PTYPE_INT, &hwm_tach_enable, 276 &get_tach, &set_tach, 277 sizeof (int)}, 278 279 {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat, 280 &get_int_val, &set_int_val, sizeof (int)}, 281 282 {"verbose", PICL_PTYPE_INT, &env_debug, 283 &get_int_val, &set_int_val, sizeof (int)}, 284 285 }; 286 287 /* 288 * We use this to figure out how many tuneables there are 289 * This is variable because the publishing routine needs this info 290 * in piclenvsetup.c 291 */ 292 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0])); 293 294 /* 295 * Table Handling Code 296 */ 297 static void 298 fini_table(table_t *tblp) 299 { 300 if (tblp == NULL) 301 return; 302 free(tblp->xymap); 303 free(tblp); 304 } 305 306 static table_t * 307 init_table(int npoints) 308 { 309 table_t *tblp; 310 point_t *xy; 311 312 if (npoints == 0) 313 return (NULL); 314 315 if ((tblp = malloc(sizeof (*tblp))) == NULL) 316 return (NULL); 317 318 if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) { 319 free(tblp); 320 return (NULL); 321 } 322 323 tblp->nentries = npoints; 324 tblp->xymap = xy; 325 326 return (tblp); 327 } 328 329 /* 330 * function: calculates y for a given x based on a table of points 331 * for monotonically increasing x values. 332 * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y' 333 */ 334 static int 335 y_of_x(table_t *tbl, int xval) 336 { 337 int i; 338 int entries; 339 point_t *xymap; 340 float newval; 341 float dy, dx, slope; 342 343 entries = tbl->nentries; 344 xymap = tbl->xymap; 345 if (xval <= xymap[0].x) 346 return (xymap[0].y); 347 else if (xval >= xymap[entries - 1].x) 348 return (xymap[entries - 1].y); 349 350 for (i = 1; i < entries - 1; i++) { 351 if (xval == xymap[i].x) 352 return (xymap[i].y); 353 if (xval < xymap[i].x) 354 break; 355 } 356 357 /* 358 * Use linear interpolation 359 */ 360 dy = (float)(xymap[i].y - xymap[i-1].y); 361 dx = (float)(xymap[i].x - xymap[i-1].x); 362 slope = dy/dx; 363 newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x); 364 return ((int)(newval + (newval >= 0 ? 0.5 : -0.5))); 365 } 366 367 /* 368 * Get environmental segment from the specified FRU SEEPROM 369 */ 370 static int 371 get_envseg(int fd, void **envsegp, int *envseglenp) 372 { 373 int i, segcnt, envseglen; 374 section_layout_t section; 375 segment_layout_t segment; 376 uint8_t *envseg; 377 378 if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L || 379 read(fd, §ion, sizeof (section)) != sizeof (section)) { 380 return (EINVAL); 381 } 382 383 /* 384 * Verify we have the correct section and contents are valid 385 * For now, we don't verify the CRC. 386 */ 387 if (section.header_tag != SECTION_HDR_TAG || 388 GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) { 389 if (env_debug) 390 envd_log(LOG_INFO, 391 "Invalid section header tag:%x version:%x\n", 392 section.header_tag, 393 GET_UNALIGN16(§ion.header_version)); 394 return (EINVAL); 395 } 396 397 /* 398 * Locate our environmental segment 399 */ 400 segcnt = section.segment_count; 401 for (i = 0; i < segcnt; i++) { 402 if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) { 403 return (EINVAL); 404 } 405 if (env_debug) 406 envd_log(LOG_INFO, 407 "Seg name: %x desc:%x off:%x len:%x\n", 408 GET_UNALIGN16(&segment.name), 409 GET_UNALIGN32(&segment.descriptor[0]), 410 GET_UNALIGN16(&segment.offset), 411 GET_UNALIGN16(&segment.length)); 412 if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME) 413 break; 414 } 415 416 if (i >= segcnt) { 417 return (ENOENT); 418 } 419 420 /* 421 * Allocate memory to hold the environmental segment data. 422 */ 423 envseglen = GET_UNALIGN16(&segment.length); 424 if ((envseg = malloc(envseglen)) == NULL) { 425 return (ENOMEM); 426 } 427 428 if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L || 429 read(fd, envseg, envseglen) != envseglen) { 430 (void) free(envseg); 431 return (EIO); 432 } 433 *envsegp = envseg; 434 *envseglenp = envseglen; 435 return (0); 436 } 437 438 /* 439 * Get all environmental segments 440 */ 441 static fruenvseg_t * 442 get_fru_envsegs(void) 443 { 444 fruenvseg_t *fruenvsegs; 445 envseg_layout_t *envsegp; 446 void *envsegbufp; 447 int fd, envseglen, hdrlen; 448 char path[PATH_MAX]; 449 450 fruenvsegs = NULL; 451 fruenvsegs = malloc(sizeof (*fruenvsegs)); 452 if (fruenvsegs == NULL) { 453 return (NULL); 454 } 455 456 /* 457 * Now get the environmental segment from this FRU 458 */ 459 (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV); 460 fd = open(path, O_RDONLY); 461 if (fd == -1) { 462 envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path); 463 free(fruenvsegs); 464 return (NULL); 465 } 466 467 /* 468 * Read environmental segment from this FRU SEEPROM 469 */ 470 if (get_envseg(fd, &envsegbufp, &envseglen) != 0) { 471 envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path); 472 free(fruenvsegs); 473 (void) close(fd); 474 return (NULL); 475 } 476 477 /* 478 * Validate envseg version number and header length 479 */ 480 envsegp = (envseg_layout_t *)envsegbufp; 481 hdrlen = sizeof (envseg_layout_t) - 482 sizeof (envseg_sensor_t) + 483 (envsegp->sensor_count) * sizeof (envseg_sensor_t); 484 485 if (envsegp->version != ENVSEG_VERSION || 486 envseglen < hdrlen) { 487 /* 488 * version mismatch or header not big enough 489 */ 490 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, path); 491 if (envsegbufp != NULL) 492 (void) free(envsegbufp); 493 free(fruenvsegs); 494 (void) close(fd); 495 return (NULL); 496 } 497 498 fruenvsegs->envseglen = envseglen; 499 fruenvsegs->envsegbufp = envsegbufp; 500 (void) close(fd); 501 return (fruenvsegs); 502 } 503 504 static int 505 process_fru_seeprom(unsigned char *buff) 506 { 507 id_off_t id; 508 int i; 509 int id_offset = 0; 510 int nsensors; 511 int nfans; 512 env_fan_t *fnodep; 513 env_sensor_t *snodep; 514 515 #define NSENSOR_OFFSET 1 516 #define ID_OFF_SIZE 6 517 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2) 518 519 nsensors = (int)buff[NSENSOR_OFFSET]; 520 if (nsensors != MAX_SENSORS) { 521 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 522 return (-1); 523 } 524 525 nfans = (int)buff[NFANS_OFFSET(nsensors)]; 526 if (nfans != MAX_FANS) { 527 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 528 return (-1); 529 } 530 531 while (nsensors > 0) { 532 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], 533 ID_OFF_SIZE); 534 535 if (env_debug) 536 envd_log(LOG_ERR, "\n Sensor Id %x offset %x", 537 id.id, id.offset); 538 539 if (id.id > MAX_SENSOR_ID) { 540 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 541 FRU_SEEPROM_NAME); 542 return (-1); 543 } 544 545 /* 546 * Copy into the sensor control block array according to the 547 * sensor ID 548 */ 549 (void) memcpy((char *)&sensor_ctrl[id.id], 550 (char *)&buff[id.offset], 551 sizeof (sensor_ctrl_blk_t)); 552 nsensors--; 553 id_offset += ID_OFF_SIZE; 554 } 555 556 /* 557 * Skip past no of Fan entry(single byte) 558 */ 559 id_offset++; 560 while (nfans > 0) { 561 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2], 562 ID_OFF_SIZE); 563 564 if (env_debug) 565 envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id, 566 id.offset); 567 568 (void) memcpy((char *)&fan_ctrl[id.id], 569 (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t)); 570 571 nfans--; 572 id_offset += ID_OFF_SIZE; 573 } 574 575 /* 576 * Match Sensor/ES ID and point correct data 577 * based on IDs 578 */ 579 for (snodep = envd_sensors; snodep->name != NULL; snodep++) 580 snodep->es_ptr = &sensor_ctrl[snodep->id]; 581 582 /* 583 * Match Fan/ES ID and point to correct ES Data 584 * based on IDs 585 */ 586 for (i = 0; (fnodep = envd_fans[i]) != NULL; i++) 587 fnodep->es_ptr = &fan_ctrl[fnodep->id]; 588 589 return (0); 590 } 591 592 static int 593 envd_es_setup() 594 { 595 envfru = get_fru_envsegs(); 596 if (envfru == NULL) { 597 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME); 598 return (-1); 599 } 600 return (process_fru_seeprom((uchar_t *)envfru->envsegbufp)); 601 } 602 603 static void 604 envd_es_destroy() 605 { 606 if (envfru != NULL) 607 free(envfru->envsegbufp); 608 } 609 610 /* 611 * Lookup fan and return a pointer to env_fan_t data structure. 612 */ 613 env_fan_t * 614 fan_lookup(char *name) 615 { 616 int i; 617 env_fan_t *fanp; 618 619 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 620 if (strcmp(fanp->name, name) == 0) 621 return (fanp); 622 } 623 return (NULL); 624 } 625 626 /* 627 * Lookup sensor and return a pointer to env_sensor_t data structure. 628 */ 629 env_sensor_t * 630 sensor_lookup(char *name) 631 { 632 env_sensor_t *sensorp; 633 int i; 634 635 for (i = 0; i < N_ENVD_SENSORS; ++i) { 636 sensorp = &envd_sensors[i]; 637 if (strcmp(sensorp->name, name) == 0) 638 return (sensorp); 639 } 640 return (NULL); 641 } 642 643 /* 644 * Get current temperature 645 * Returns -1 on error, 0 if successful 646 */ 647 int 648 get_temperature(env_sensor_t *sensorp, tempr_t *temp) 649 { 650 int fd = sensorp->fd; 651 int retval = 0; 652 653 if (fd == -1) 654 retval = -1; 655 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 656 retval = -1; 657 if (sensorp->error == 0) { 658 sensorp->error = 1; 659 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL, 660 sensorp->name, errno, strerror(errno)); 661 } 662 } else if (sensorp->error != 0) { 663 sensorp->error = 0; 664 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name); 665 } 666 if (sensorp->crtbl != NULL) { 667 *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp); 668 } 669 670 return (retval); 671 } 672 673 /* 674 * Get uncorrected current temperature 675 * Returns -1 on error, 0 if successful 676 */ 677 static int 678 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp) 679 { 680 int fd = sensorp->fd; 681 int retval = 0; 682 683 if (fd == -1) 684 retval = -1; 685 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) { 686 retval = -1; 687 } 688 689 return (retval); 690 } 691 692 /* 693 * Return Fan RPM given N & tach 694 * count and N are retrived from the 695 * ADM1031 chip. 696 */ 697 static int 698 tach_to_rpm(int n, uint8_t tach) 699 { 700 if (n * tach == 0) 701 return (0); 702 return ((ADCSAMPLE * 60) / (n * tach)); 703 } 704 705 static int 706 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp) 707 { 708 int fan_fd; 709 int retval = 0; 710 711 fan_fd = fanp->fd; 712 713 if (fan_fd == -1) 714 retval = -1; 715 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) { 716 retval = -1; 717 } 718 719 720 return (retval); 721 } 722 /* 723 * Get current fan speed 724 * Returns -1 on error, 0 if successful 725 */ 726 int 727 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp) 728 { 729 int fan_fd; 730 uint8_t tach; 731 732 fan_fd = fanp->fd; 733 if (fan_fd == -1) 734 return (-1); 735 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) { 736 return (-1); 737 } 738 739 /* 740 * Fanspeeds are reported as 0 741 * if the tach is out of range or fan status is off 742 * and if monitoring fan status is enabled. 743 */ 744 if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) { 745 *fanspeedp = 0; 746 } else { 747 *fanspeedp = 748 tach_to_rpm(fanp->speedrange, tach); 749 } 750 751 return (0); 752 } 753 754 /* 755 * Set fan speed 756 * Returns -1 on error, 0 if successful 757 */ 758 int 759 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed) 760 { 761 int fan_fd; 762 int retval = 0; 763 uint8_t speed; 764 765 fan_fd = fanp->fd; 766 if (fan_fd == -1) 767 return (-1); 768 769 if (fanspeed < 0 || fanspeed > 100) 770 return (-2); 771 772 speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed); 773 774 if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) { 775 retval = -1; 776 } 777 return (retval); 778 } 779 780 /* 781 * close all fan devices 782 */ 783 static void 784 envd_close_fans(void) 785 { 786 int i; 787 env_fan_t *fanp; 788 789 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 790 if (fanp->fd != -1) { 791 (void) close(fanp->fd); 792 fanp->fd = -1; 793 } 794 } 795 } 796 797 /* 798 * Close sensor devices and freeup resources 799 */ 800 static void 801 envd_close_sensors(void) 802 { 803 env_sensor_t *sensorp; 804 int i; 805 806 for (i = 0; i < N_ENVD_SENSORS; ++i) { 807 sensorp = &envd_sensors[i]; 808 if (sensorp->fd != -1) { 809 (void) close(sensorp->fd); 810 sensorp->fd = -1; 811 } 812 if (sensorp->crtbl != NULL) 813 fini_table(sensorp->crtbl); 814 } 815 } 816 817 /* 818 * Open fan devices and initialize per fan data structure. 819 * Returns #fans found. 820 */ 821 static int 822 envd_setup_fans(void) 823 { 824 int i, fd; 825 env_fan_t *fanp; 826 char path[PATH_MAX]; 827 int fancnt = 0; 828 uint8_t n = 0; 829 830 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) { 831 (void) strcpy(path, "/devices"); 832 (void) strlcat(path, fanp->devfs_path, sizeof (path)); 833 fd = open(path, O_RDWR); 834 if (fd == -1) { 835 envd_log(LOG_CRIT, 836 ENV_FAN_OPEN_FAIL, fanp->name, 837 fanp->devfs_path, errno, strerror(errno)); 838 fanp->present = B_FALSE; 839 continue; 840 } 841 fanp->fd = fd; 842 if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) { 843 fanp->speedrange = 844 adm_speedrange_map[(n >> 6) & 0x03]; 845 } else { 846 fanp->speedrange = FAN_RANGE_DEFAULT; 847 } 848 849 fanp->present = B_TRUE; 850 fanp->fanstat = 0; 851 fanp->cspeed = TACH_UNKNOWN; 852 fanp->lspeed = TACH_UNKNOWN; 853 fanp->conccnt = 0; 854 fancnt++; 855 } 856 return (fancnt); 857 } 858 859 /* 860 * Open temperature sensor devices and initialize per sensor data structure. 861 * Returns #sensors found. 862 */ 863 static int 864 envd_setup_sensors(void) 865 { 866 env_sensor_t *sensorp; 867 sensor_ctrl_blk_t *es_ptr; 868 table_t *tblp; 869 char path[PATH_MAX]; 870 int sensorcnt = 0; 871 int i, j, nentries; 872 int16_t tmin = 0; 873 874 for (i = 0; i < N_ENVD_SENSORS; ++i) { 875 sensorp = &envd_sensors[i]; 876 /* Initialize sensor's initial state */ 877 sensorp->shutdown_initiated = B_FALSE; 878 sensorp->warning_tstamp = 0; 879 sensorp->shutdown_tstamp = 0; 880 sensorp->error = 0; 881 sensorp->crtbl = NULL; 882 883 (void) strcpy(path, "/devices"); 884 (void) strlcat(path, sensorp->devfs_path, 885 sizeof (path)); 886 sensorp->fd = open(path, O_RDWR); 887 if (sensorp->fd == -1) { 888 envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL, 889 sensorp->name, sensorp->devfs_path, 890 errno, strerror(errno)); 891 sensorp->present = B_FALSE; 892 continue; 893 } 894 sensorp->present = B_TRUE; 895 sensorcnt++; 896 897 /* 898 * Get Tmin 899 */ 900 901 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE, 902 &tmin) != -1) { 903 sensorp->tmin = TMIN(tmin); 904 } else { 905 sensorp->tmin = -1; 906 } 907 if (env_debug) 908 envd_log(LOG_ERR, "Sensor %s tmin %d", 909 sensorp->name, sensorp->tmin); 910 911 /* 912 * Create a correction table 913 * if correction pairs are present in es 914 * segment. 915 */ 916 es_ptr = sensorp->es_ptr; 917 918 if (es_ptr == NULL) { 919 continue; 920 } 921 nentries = es_ptr->correctionEntries; 922 923 if (nentries < 2) { 924 if (env_debug) 925 envd_log(LOG_CRIT, "sensor correction <2"); 926 continue; 927 } 928 929 sensorp->crtbl = init_table(nentries); 930 if (sensorp->crtbl == NULL) 931 continue; 932 tblp = sensorp->crtbl; 933 tblp->xymap[0].x = 934 (char)es_ptr->correctionPair[0].measured; 935 tblp->xymap[0].y = 936 (char)es_ptr->correctionPair[0].corrected; 937 938 for (j = 1; j < nentries; ++j) { 939 tblp->xymap[j].x = 940 (char)es_ptr->correctionPair[j].measured; 941 tblp->xymap[j].y = 942 (char)es_ptr->correctionPair[j].corrected; 943 944 if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) { 945 fini_table(tblp); 946 sensorp->crtbl = NULL; 947 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, 948 FRU_SEEPROM_NAME); 949 break; 950 } 951 } 952 953 if (env_debug) { 954 envd_log(LOG_CRIT, "Sensor correction %s", 955 sensorp->name); 956 for (j = 0; j < nentries; j++) 957 envd_log(LOG_CRIT, " %d %d", 958 tblp->xymap[j].x, tblp->xymap[j].y); 959 } 960 } 961 return (sensorcnt); 962 } 963 /* 964 * Modify ADM Tmin/ranges depending what power level 965 * we are from. 966 */ 967 static void 968 updateadm_ranges(char *name, uchar_t cur_lpstate) 969 { 970 env_sensor_t *sensorp; 971 fan_ctrl_blk_t *fanctl; 972 uchar_t tmin; 973 uchar_t trange; 974 uint16_t tdata; 975 int sysfd; 976 uchar_t sys_id = CPU_HWM_ID; 977 uint8_t mode; 978 static uint16_t tsave = 0; 979 980 sensorp = sensor_lookup(name); 981 if (sensorp == NULL) 982 return; 983 984 /* 985 * If there is only one Control pairs then return 986 */ 987 fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr; 988 989 if (fanctl != NULL && fanctl->no_ctl_pairs <= 1) 990 return; 991 992 /* 993 * if fan control specifies that ranges are same then 994 * we skip re-programming adm chip. 995 */ 996 997 tmin = fanctl->fan_ctl_pairs[0].tMin; 998 trange = fanctl->fan_ctl_pairs[0].tRange; 999 if ((tmin == fanctl->fan_ctl_pairs[1].tMin) && 1000 (trange == fanctl->fan_ctl_pairs[1].tRange)) 1001 return; 1002 1003 sysfd = open(hwm_devs[sys_id], O_RDWR); 1004 if (sysfd == -1) { 1005 if (env_debug) 1006 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id], 1007 errno, strerror(errno)); 1008 return; 1009 } 1010 /* Read ADM default value only for the first time */ 1011 if (tsave == 0) { 1012 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE, 1013 &tsave) == -1) { 1014 if (env_debug) 1015 envd_log(LOG_ERR, 1016 "read tminrange ioctl failed"); 1017 (void) close(sysfd); 1018 return; 1019 } 1020 } 1021 1022 /* 1023 * Need to reinit ADM to manual mode for Tmin range to be 1024 * effective. 1025 */ 1026 mode = ADM1031_MANUAL_MODE; 1027 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) { 1028 if (env_debug) 1029 envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE); 1030 (void) close(sysfd); 1031 return; 1032 } 1033 1034 if (cur_lpstate == 1) { 1035 /* 1036 * ADM 1031 Tmin/Trange register need to be reprogrammed. 1037 */ 1038 tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS) 1039 << TMIN_SHIFT); 1040 /* Need to pack tRange in ADM bits 2:0 */ 1041 switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) { 1042 case 5: 1043 break; 1044 1045 case 10: 1046 tdata |= 1; 1047 break; 1048 1049 case 20: 1050 tdata |= 2; 1051 break; 1052 1053 case 40: 1054 tdata |= 3; 1055 break; 1056 1057 case 80: 1058 tdata |= 4; 1059 break; 1060 } 1061 } else 1062 tdata = tsave; 1063 1064 if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE, 1065 &tdata) != -1) 1066 sensorp->tmin = TMIN(tdata); 1067 1068 sensorp->tmin = TMIN(tdata); 1069 1070 mode = ADM1031_AUTO_MODE; 1071 if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) { 1072 if (env_debug) 1073 envd_log(LOG_ERR, ENV_ADM_AUTO_MODE); 1074 } 1075 (void) close(sysfd); 1076 } 1077 1078 /*ARGSUSED*/ 1079 static void * 1080 pmthr(void *args) 1081 { 1082 pm_state_change_t pmstate; 1083 char physpath[PATH_MAX]; 1084 int pre_lpstate; 1085 1086 pmstate.physpath = physpath; 1087 pmstate.size = sizeof (physpath); 1088 cur_lpstate = 0; 1089 pre_lpstate = 1; 1090 1091 pm_fd = open(PM_DEVICE, O_RDWR); 1092 if (pm_fd == -1) { 1093 envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno)); 1094 return (NULL); 1095 } 1096 for (;;) { 1097 /* 1098 * Get PM state change events to check if the system 1099 * is in lowest power state and adjust ADM hardware 1100 * monitor's fan speed settings. 1101 * 1102 * To minimize polling, we use the blocking interface 1103 * to get the power state change event here. 1104 */ 1105 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) { 1106 if (errno != EINTR) 1107 break; 1108 continue; 1109 } 1110 do { 1111 if (env_debug) { 1112 envd_log(LOG_INFO, 1113 "pmstate event:0x%x flags:%x comp:%d " 1114 "oldval:%d newval:%d path:%s\n", 1115 pmstate.event, pmstate.flags, 1116 pmstate.component, 1117 pmstate.old_level, 1118 pmstate.new_level, 1119 pmstate.physpath); 1120 } 1121 cur_lpstate = 1122 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0; 1123 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0); 1124 /* 1125 * Change ADM ranges as per E* Requirements. Update 1126 * happens only for valid state changes. 1127 */ 1128 if (pre_lpstate != cur_lpstate) { 1129 pre_lpstate = cur_lpstate; 1130 updateadm_ranges(SENSOR_SYS_IN, cur_lpstate); 1131 } 1132 } 1133 /*NOTREACHED*/ 1134 return (NULL); 1135 } 1136 1137 /* 1138 * This function is used to reasonably predict the 1139 * state of the fan (ON/OFF) using tmin and current temperature. 1140 * 1141 * We know the fan is on if temp >= tmin and fan is off if 1142 * temp < (Tmin - Hysterisis). 1143 * 1144 * When the temperature is in between we don't know if the fan is on/off 1145 * because the temperature could be decreasing and not have crossed 1146 * Tmin - hysterisis and vice a versa. 1147 * 1148 * FAN ON 1149 * Tmin 1150 * ------------------------------------------- 1151 * 1152 * FAN ON/OFF 1153 * 1154 * -------------------------------------------- 1155 * Tmin - Hysterisis 1156 * FAN OFF 1157 * 1158 * To solve the problem of finding out if the fan is on/off in our gray region 1159 * we keep track of the last read tach and the current read tach. From 1160 * experimentation and from discussions with analog devices it is unlikely that 1161 * if the fans are on we will get a constant tach reading more than 5 times in 1162 * a row. This is not the most fool proof approach but the best we can do. 1163 * 1164 * This routine implements the above logic for a sensor with an 1165 * associated fan. The caller garauntees sensorp and fanp are not null. 1166 */ 1167 static void 1168 check_fanstat(env_sensor_t *sensorp) 1169 { 1170 env_fan_t *fanp = sensorp->fanp; 1171 tempr_t temp; 1172 uint8_t fanspeed; 1173 1174 if (get_raw_temperature(sensorp, &temp) == -1) 1175 return; 1176 1177 if (temp < (sensorp->tmin - ADM_HYSTERISIS)) { 1178 1179 fanp->fanstat = 0; /* Fan off */ 1180 fanp->lspeed = TACH_UNKNOWN; /* Reset Last read tach */ 1181 fanp->conccnt = 0; 1182 1183 } else if (temp >= sensorp->tmin) { 1184 1185 fanp->fanstat = 1; /* Fan on */ 1186 fanp->lspeed = TACH_UNKNOWN; 1187 fanp->conccnt = 0; 1188 1189 } else { 1190 if (get_raw_fan_speed(fanp, &fanspeed) == -1) 1191 return; 1192 1193 fanp->cspeed = fanspeed; 1194 /* 1195 * First time in the gray area 1196 * set last read speed to current speed 1197 */ 1198 if (fanp->lspeed == TACH_UNKNOWN) { 1199 fanp->lspeed = fanspeed; 1200 } else { 1201 if (fanp->lspeed != fanp->cspeed) { 1202 fanp->conccnt = 0; 1203 fanp->fanstat = 1; 1204 } else { 1205 fanp->conccnt++; 1206 1207 if (fanp->conccnt >= N_SEQ_TACH) 1208 fanp->fanstat = 0; 1209 } 1210 fanp->lspeed = fanp->cspeed; 1211 } 1212 } 1213 } 1214 /* 1215 * There is an issue with the ADM1031 chip that causes the chip 1216 * to not update the tach register in case the fan stops. The 1217 * fans stop when the temperature measured (temp) drops below 1218 * Tmin - Hysterisis and turns the fan on when the temp >= tmin. 1219 * 1220 * Since the tach registers don't update and remain stuck at the 1221 * last read tach value our get_fan_speed function always returns 1222 * a non-zero RPM reading. 1223 * 1224 * To fix this we need to figure out when the fans will be on/off 1225 * depending on the current temperature. Currently we poll for 1226 * interrupts, we can use that loop to determine what the current 1227 * temperature is and if the fans should be on/off. 1228 * 1229 * We get current temperature and check the fans. 1230 */ 1231 static void 1232 monitor_fanstat(void) 1233 { 1234 env_sensor_t *sensorp; 1235 env_fan_t *fanp; 1236 int i; 1237 1238 for (i = 0; i < N_ENVD_SENSORS; i++) { 1239 sensorp = &envd_sensors[i]; 1240 1241 if (!sensorp) 1242 continue; 1243 1244 fanp = sensorp->fanp; 1245 1246 if (!fanp) 1247 continue; 1248 1249 if (sensorp->tmin != -1) { 1250 check_fanstat(sensorp); 1251 } else { 1252 fanp->fanstat = 1; 1253 } 1254 } 1255 /* 1256 * On Taco both the system fans are driven by one 1257 * sensor (sys-in) and connected to the sys-in tach. 1258 */ 1259 envd_sys_out_fan.fanstat = envd_sys_in_fan.fanstat; 1260 1261 } 1262 1263 static int 1264 handle_overtemp_interrupt(int hwm_id) 1265 { 1266 env_sensor_t *sensorp; 1267 tempr_t temp; 1268 uchar_t smap[MAX_SENSORS]; 1269 time_t ct; 1270 uchar_t i; 1271 char msgbuf[BUFSIZ]; 1272 char syscmd[BUFSIZ]; 1273 boolean_t return_flag; 1274 1275 /* Clear Map of Sensor Entries */ 1276 (void) memset(smap, SENSOR_OK, sizeof (smap)); 1277 1278 for (;;) { 1279 for (i = 0; i < N_ENVD_SENSORS; i++) { 1280 sensorp = &envd_sensors[i]; 1281 1282 /* 1283 * Check whether the sensor belongs to the 1284 * interrupting ADM hardware monitor 1285 */ 1286 if (sensorp->hwm_id != hwm_id) 1287 continue; 1288 1289 /* 1290 * if shutdown is initiated then we simply loop 1291 * through the sensors until shutdown 1292 */ 1293 if (sensorp->shutdown_initiated == B_TRUE) 1294 continue; 1295 1296 /* get current temp for this sensor */ 1297 if (get_temperature(sensorp, &temp) == -1) 1298 continue; 1299 1300 sensorp->cur_temp = temp; 1301 1302 if (env_debug) 1303 envd_log(LOG_ERR, 1304 "sensor name %s, cur temp %d, " 1305 "HW %d LW %d SD %d LS %d\n", 1306 sensorp->name, temp, 1307 sensorp->es_ptr->high_warning, 1308 (int)sensorp->es_ptr->low_warning, 1309 sensorp->es_ptr->high_shutdown, 1310 (int)sensorp->es_ptr->low_shutdown); 1311 1312 if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) { 1313 /* 1314 * Log on warning atmost one second 1315 */ 1316 ct = (time_t)(gethrtime() / NANOSEC); 1317 if ((ct - sensorp->warning_tstamp) >= 1318 warning_interval) { 1319 envd_log(LOG_CRIT, 1320 ENV_WARNING_MSG, sensorp->name, 1321 temp, 1322 sensorp->es_ptr->low_warning, 1323 sensorp->es_ptr->high_warning); 1324 sensorp->warning_tstamp = ct; 1325 } 1326 smap[i] = SENSOR_WARN; 1327 } else { 1328 /* 1329 * We will fall in this caterory only if 1330 * Temperature drops/increases from warning 1331 * threshold. If so we set sensor map to 1332 * OK so that we can exit the loop if 1333 * shutdown not initiated. 1334 */ 1335 smap[i] = SENSOR_OK; 1336 } 1337 1338 if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) && 1339 !shutdown_override) { 1340 ct = (time_t)(gethrtime() / NANOSEC); 1341 if (sensorp->shutdown_tstamp == 0) 1342 sensorp->shutdown_tstamp = ct; 1343 if ((ct - sensorp->shutdown_tstamp) >= 1344 shutdown_interval) { 1345 sensorp->shutdown_initiated = B_TRUE; 1346 (void) snprintf(msgbuf, sizeof (msgbuf), 1347 ENV_SHUTDOWN_MSG, sensorp->name, 1348 temp, 1349 sensorp->es_ptr->low_shutdown, 1350 sensorp->es_ptr->high_shutdown); 1351 envd_log(LOG_ALERT, msgbuf); 1352 } 1353 if (system_shutdown_started == B_FALSE) { 1354 (void) snprintf(syscmd, sizeof (syscmd), 1355 "%s \"%s\"", SHUTDOWN_CMD, msgbuf); 1356 envd_log(LOG_ALERT, syscmd); 1357 system_shutdown_started = B_TRUE; 1358 (void) system(syscmd); 1359 } 1360 } else if (sensorp->shutdown_tstamp != 0) 1361 sensorp->shutdown_tstamp = 0; 1362 } 1363 1364 /* 1365 * Sweep thorugh Sensor Map and if warnings OR shutdown 1366 * are not logged then return to caller. 1367 */ 1368 return_flag = B_TRUE; 1369 for (i = 0; i < N_ENVD_SENSORS; i++) 1370 if (smap[i] == SENSOR_WARN) 1371 return_flag = B_FALSE; 1372 1373 if ((return_flag == B_TRUE) && 1374 (system_shutdown_started == B_FALSE)) { 1375 return (1); 1376 } 1377 1378 (void) envd_sleep(SENSORPOLL_INTERVAL); 1379 } 1380 } 1381 1382 /* 1383 * This is env thread which monitors the current temperature when 1384 * warning threshold is exceeded. The job is to make sure it does 1385 * not execced/decrease shutdown threshold. If it does it will start 1386 * forced shutdown to avoid reaching hardware poweroff via THERM interrupt. 1387 * For Taco there will be one thread for the ADM chip. 1388 */ 1389 static void * 1390 ovtemp_thr(void *args) 1391 { 1392 int fd; 1393 uint8_t stat[2]; 1394 int hwm_id = (int)args; 1395 int err; 1396 1397 fd = open(hwm_devs[hwm_id], O_RDWR); 1398 if (fd == -1) { 1399 envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id], 1400 errno, strerror(errno)); 1401 return (NULL); 1402 } 1403 1404 for (;;) { 1405 1406 /* 1407 * Monitor the sensors to update status 1408 */ 1409 if (mon_fanstat) 1410 monitor_fanstat(); 1411 1412 /* 1413 * Sleep for specified seconds before issuing IOCTL 1414 * again. 1415 */ 1416 (void) envd_sleep(INTERRUPTPOLL_INTERVAL); 1417 1418 /* 1419 * Read ADM1031 two Status Register to determine source of 1420 * Interrupts. 1421 */ 1422 if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1) 1423 err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]); 1424 1425 if (err == -1) { 1426 if (env_debug) 1427 envd_log(LOG_ERR, "OverTemp: Status Error"); 1428 continue; 1429 } 1430 1431 if (env_debug) 1432 envd_log(LOG_ERR, "INTR %s Stat1 %x, Stat2 %x", 1433 hwm_devs[hwm_id], stat[0], stat[1]); 1434 1435 if (stat[0] & FANFAULT) 1436 envd_log(LOG_ERR, ENV_FAN_FAULT, 1437 hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN1]); 1438 1439 if (stat[1] & FANFAULT) 1440 envd_log(LOG_ERR, ENV_FAN_FAULT, 1441 hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN2]); 1442 1443 /* 1444 * Check respective Remote/Local High, Low before start 1445 * manual monitoring 1446 */ 1447 if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK)) 1448 (void) handle_overtemp_interrupt(hwm_id); 1449 } 1450 /*NOTREACHED*/ 1451 return (NULL); 1452 } 1453 1454 /* 1455 * Setup envrionmental monitor state and start threads to monitor 1456 * temperature and power management state. 1457 * Returns -1 on error, 0 if successful. 1458 */ 1459 1460 static int 1461 envd_setup(void) 1462 { 1463 int ret; 1464 1465 if (getenv("SUNW_piclenvd_debug") != NULL) 1466 env_debug = 1; 1467 1468 if (pthread_attr_init(&thr_attr) != 0 || 1469 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) { 1470 return (-1); 1471 } 1472 1473 ret = envd_es_setup(); 1474 if (ret < 0) { 1475 ovtemp_monitor = 0; 1476 pm_monitor = 0; 1477 } 1478 1479 1480 /* 1481 * Setup temperature sensors and fail if we can't open 1482 * at least one sensor. 1483 */ 1484 if (envd_setup_sensors() <= 0) { 1485 return (0); 1486 } 1487 1488 /* 1489 * Setup fan device (don't fail even if we can't access 1490 * the fan as we can still monitor temeperature. 1491 */ 1492 (void) envd_setup_fans(); 1493 1494 /* If ES Segment setup failed,don't create thread */ 1495 1496 if (ovtemp_monitor && ovtemp_thr_created == B_FALSE) { 1497 if (pthread_create(&ovtemp_thr_id, &thr_attr, ovtemp_thr, 1498 (void *)CPU_HWM_ID) != 0) 1499 envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED); 1500 else 1501 ovtemp_thr_created = B_TRUE; 1502 } 1503 1504 /* 1505 * Create a thread to monitor PM state 1506 */ 1507 if (pm_monitor && pmthr_created == B_FALSE) { 1508 if (pthread_create(&pmthr_tid, &thr_attr, pmthr, 1509 NULL) != 0) 1510 envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED); 1511 else 1512 pmthr_created = B_TRUE; 1513 } 1514 return (0); 1515 } 1516 1517 static void 1518 piclenvd_register(void) 1519 { 1520 picld_plugin_register(&my_reg_info); 1521 } 1522 1523 static void 1524 piclenvd_init(void) 1525 { 1526 1527 (void) env_picl_setup_tuneables(); 1528 1529 /* 1530 * Setup the environmental data structures 1531 */ 1532 if (envd_setup() != 0) { 1533 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED); 1534 return; 1535 } 1536 1537 /* 1538 * Now setup/populate PICL tree 1539 */ 1540 env_picl_setup(); 1541 } 1542 1543 static void 1544 piclenvd_fini(void) 1545 { 1546 1547 /* 1548 * Invoke env_picl_destroy() to remove any PICL nodes/properties 1549 * (including volatile properties) we created. Once this call 1550 * returns, there can't be any more calls from the PICL framework 1551 * to get current temperature or fan speed. 1552 */ 1553 env_picl_destroy(); 1554 envd_close_sensors(); 1555 envd_close_fans(); 1556 envd_es_destroy(); 1557 } 1558 1559 /*VARARGS2*/ 1560 void 1561 envd_log(int pri, const char *fmt, ...) 1562 { 1563 va_list ap; 1564 1565 va_start(ap, fmt); 1566 vsyslog(pri, fmt, ap); 1567 va_end(ap); 1568 } 1569 1570 #ifdef __lint 1571 /* 1572 * Redefine sigwait to posix style external declaration so that LINT 1573 * does not check against libc version of sigwait() and complain as 1574 * it uses different number of arguments. 1575 */ 1576 #define sigwait my_posix_sigwait 1577 extern int my_posix_sigwait(const sigset_t *set, int *sig); 1578 #endif 1579 1580 static uint_t 1581 envd_sleep(uint_t sleep_tm) 1582 { 1583 int sig; 1584 uint_t unslept; 1585 sigset_t alrm_mask; 1586 1587 if (sleep_tm == 0) 1588 return (0); 1589 1590 (void) sigemptyset(&alrm_mask); 1591 (void) sigaddset(&alrm_mask, SIGALRM); 1592 1593 (void) alarm(sleep_tm); 1594 (void) sigwait(&alrm_mask, &sig); 1595 1596 unslept = alarm(0); 1597 return (unslept); 1598 } 1599 1600 /* 1601 * Tunables support functions 1602 */ 1603 static env_tuneable_t * 1604 tuneable_lookup(picl_prophdl_t proph) 1605 { 1606 int i; 1607 env_tuneable_t *tuneablep = NULL; 1608 1609 for (i = 0; i < ntuneables; i++) { 1610 tuneablep = &tuneables[i]; 1611 if (tuneablep->proph == proph) 1612 return (tuneablep); 1613 } 1614 1615 return (NULL); 1616 } 1617 1618 static int 1619 get_tach(ptree_rarg_t *parg, void *buf) 1620 { 1621 picl_prophdl_t proph; 1622 env_tuneable_t *tuneablep; 1623 int fd; 1624 int8_t cfg; 1625 1626 proph = parg->proph; 1627 1628 tuneablep = tuneable_lookup(proph); 1629 1630 if (tuneablep == NULL) 1631 return (PICL_FAILURE); 1632 1633 fd = open(CPU_HWM_DEVFS, O_RDWR); 1634 1635 if (fd == -1) { 1636 return (PICL_FAILURE); 1637 } 1638 1639 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 1640 return (PICL_FAILURE); 1641 } 1642 1643 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) { 1644 *((int *)tuneablep->value) = ENABLE; 1645 1646 } else { 1647 *((int *)tuneablep->value) = DISABLE; 1648 } 1649 1650 (void) memcpy(buf, tuneablep->value, 1651 tuneablep->nbytes); 1652 1653 (void) close(fd); 1654 return (PICL_SUCCESS); 1655 } 1656 1657 static int 1658 set_tach(ptree_warg_t *parg, const void *buf) 1659 { 1660 picl_prophdl_t proph; 1661 env_tuneable_t *tuneablep; 1662 int fd, val; 1663 int8_t cfg; 1664 1665 if (parg->cred.dc_euid != 0) 1666 return (PICL_PERMDENIED); 1667 1668 proph = parg->proph; 1669 1670 tuneablep = tuneable_lookup(proph); 1671 1672 if (tuneablep == NULL) 1673 return (PICL_FAILURE); 1674 1675 fd = open(CPU_HWM_DEVFS, O_RDWR); 1676 1677 if (fd == -1) { 1678 return (PICL_FAILURE); 1679 } 1680 1681 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) { 1682 return (PICL_FAILURE); 1683 } 1684 1685 (void) memcpy(&val, (caddr_t)buf, sizeof (val)); 1686 1687 if (val == ENABLE) { 1688 cfg |= TACH_ENABLE_MASK; 1689 } else if (val == DISABLE) { 1690 cfg &= ~TACH_ENABLE_MASK; 1691 } 1692 1693 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) { 1694 return (PICL_FAILURE); 1695 } 1696 1697 (void) close(fd); 1698 return (PICL_SUCCESS); 1699 } 1700 1701 static int 1702 get_monitor_mode(ptree_rarg_t *parg, void *buf) 1703 { 1704 picl_prophdl_t proph; 1705 env_tuneable_t *tuneablep; 1706 int fd; 1707 int8_t mmode; 1708 1709 proph = parg->proph; 1710 1711 tuneablep = tuneable_lookup(proph); 1712 1713 if (tuneablep == NULL) 1714 return (PICL_FAILURE); 1715 1716 fd = open(CPU_HWM_DEVFS, O_RDWR); 1717 1718 if (fd == -1) { 1719 return (PICL_FAILURE); 1720 } 1721 1722 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) { 1723 return (PICL_FAILURE); 1724 } 1725 1726 if (mmode == ADM1031_AUTO_MODE) { 1727 *((int *)tuneablep->value) = ENABLE; 1728 } else { 1729 *((int *)tuneablep->value) = DISABLE; 1730 } 1731 1732 (void) memcpy(buf, tuneablep->value, 1733 tuneablep->nbytes); 1734 1735 (void) close(fd); 1736 return (PICL_SUCCESS); 1737 } 1738 1739 static int 1740 set_monitor_mode(ptree_warg_t *parg, const void *buf) 1741 { 1742 picl_prophdl_t proph; 1743 env_tuneable_t *tuneablep; 1744 int fd, val; 1745 int8_t mmode; 1746 1747 if (parg->cred.dc_euid != 0) 1748 return (PICL_PERMDENIED); 1749 1750 proph = parg->proph; 1751 1752 tuneablep = tuneable_lookup(proph); 1753 1754 if (tuneablep == NULL) 1755 return (PICL_FAILURE); 1756 1757 fd = open(CPU_HWM_DEVFS, O_RDWR); 1758 if (fd == -1) { 1759 return (PICL_FAILURE); 1760 } 1761 (void) memcpy(&val, buf, sizeof (val)); 1762 if (val == ENABLE) { 1763 mmode = ADM1031_AUTO_MODE; 1764 } else if (val == DISABLE) { 1765 mmode = ADM1031_MANUAL_MODE; 1766 } 1767 1768 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) { 1769 return (PICL_FAILURE); 1770 } 1771 1772 (void) close(fd); 1773 return (PICL_SUCCESS); 1774 } 1775 1776 static int 1777 get_string_val(ptree_rarg_t *parg, void *buf) 1778 { 1779 picl_prophdl_t proph; 1780 env_tuneable_t *tuneablep; 1781 1782 proph = parg->proph; 1783 1784 tuneablep = tuneable_lookup(proph); 1785 1786 if (tuneablep == NULL) 1787 return (PICL_FAILURE); 1788 1789 (void) memcpy(buf, (caddr_t)tuneablep->value, 1790 tuneablep->nbytes); 1791 1792 return (PICL_SUCCESS); 1793 } 1794 1795 static int 1796 set_string_val(ptree_warg_t *parg, const void *buf) 1797 { 1798 picl_prophdl_t proph; 1799 env_tuneable_t *tuneablep; 1800 1801 proph = parg->proph; 1802 1803 if (parg->cred.dc_euid != 0) 1804 return (PICL_PERMDENIED); 1805 1806 tuneablep = tuneable_lookup(proph); 1807 1808 if (tuneablep == NULL) 1809 return (PICL_FAILURE); 1810 1811 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf, 1812 tuneables->nbytes); 1813 1814 return (PICL_SUCCESS); 1815 } 1816 1817 static int 1818 get_int_val(ptree_rarg_t *parg, void *buf) 1819 { 1820 picl_prophdl_t proph; 1821 env_tuneable_t *tuneablep; 1822 1823 proph = parg->proph; 1824 1825 tuneablep = tuneable_lookup(proph); 1826 1827 if (tuneablep == NULL) 1828 return (PICL_FAILURE); 1829 1830 (void) memcpy((int *)buf, (int *)tuneablep->value, 1831 tuneablep->nbytes); 1832 1833 return (PICL_SUCCESS); 1834 } 1835 1836 static int 1837 set_int_val(ptree_warg_t *parg, const void *buf) 1838 { 1839 picl_prophdl_t proph; 1840 env_tuneable_t *tuneablep; 1841 1842 if (parg->cred.dc_euid != 0) 1843 return (PICL_PERMDENIED); 1844 1845 proph = parg->proph; 1846 1847 tuneablep = tuneable_lookup(proph); 1848 1849 if (tuneablep == NULL) 1850 return (PICL_FAILURE); 1851 1852 (void) memcpy((int *)tuneablep->value, (int *)buf, 1853 tuneablep->nbytes); 1854 1855 return (PICL_SUCCESS); 1856 } 1857