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