8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / picl / plugins / sun4u / taco / envd / piclenvd.c
blob538e156510df5d2ed7b72d442101e05cd31d31a0
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * This file contains the environmental PICL plug-in module.
34 * This plugin sets up the PICLTREE for Taco.
35 * It provides functionality to get/set temperatures
36 * and fan speeds
38 * The environmental monitoring policy is the default
39 * auto mode as programmed by OBP at boot time.
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"
71 * PICL plguin entry points
73 static void piclenvd_register(void);
74 static void piclenvd_init(void);
75 static void piclenvd_fini(void);
78 * Env setup routines
80 extern void env_picl_setup(void);
81 extern void env_picl_destroy(void);
82 extern int env_picl_setup_tuneables(void);
85 * Sleep routine used for polling
87 static uint_t envd_sleep(uint_t);
89 #pragma init(piclenvd_register)
92 * Plugin registration information
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,
103 * ES Segment data structures
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;
110 * Env thread variables
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;
119 * PM thread related variabled
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 */
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
131 int env_debug = 0;
134 * Fan devices
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,
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,
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,
154 * NULL terminated array of fans
156 static env_fan_t *envd_fans[] = {
157 &envd_cpu_fan,
158 &envd_sys_in_fan,
159 &envd_sys_out_fan,
160 NULL
164 * ADM1031 speedrange map is indexed by a 2-bit value
166 static int adm_speedrange_map[] = {1, 2, 4, 8};
169 * ADM1031 devices
171 static char *hwm_devs[] = {
172 CPU_HWM_DEVFS, /* CPU_HWM_ID */
176 * Fan names associated with each ADM1031 hwms - used to
177 * print fault messages
179 static char *hwm_fans[MAX_HWMS][2] = {
180 {ENV_CPU_FAN, ENV_SYSTEM_IN_OUT_FANS}
184 * Temperature sensors
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},
194 #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0]))
197 * ADM1031 macros
199 #define TACH_UNKNOWN 255
200 #define FAN_OUT_OF_RANGE (TACH_UNKNOWN)
201 #define ADM_HYSTERISIS 5
202 #define N_SEQ_TACH 15
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)
209 #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
210 #define TRANGE(regval) (regval & TRANGE_MASK)
212 #define GET_TMIN_RANGE(tmin, trange) \
213 ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
214 (trange & TRANGE_MASK))
216 #define TACH_ENABLE_MASK (0x0C)
217 #define MONITOR_ENABLE_MASK (0x01)
218 #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100)
221 * Tuneables
223 #define ENABLE 1
224 #define DISABLE 0
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);
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 */
243 static int hwm_mode;
244 static int hwm_tach_enable;
245 static char shutdown_cmd[] = SHUTDOWN_CMD;
247 env_tuneable_t tuneables[] = {
248 {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor,
249 &get_int_val, &set_int_val, sizeof (int)},
251 {"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
252 &get_int_val, &set_int_val, sizeof (int)},
254 {"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
255 &get_int_val, &set_int_val, sizeof (int)},
257 {"hwm-automode-enable", PICL_PTYPE_INT, &hwm_mode,
258 &get_monitor_mode, &set_monitor_mode, sizeof (int)},
260 {"sensor-poll-interval", PICL_PTYPE_INT,
261 &sensor_poll_interval,
262 &get_int_val, &set_int_val,
263 sizeof (int)},
265 {"warning-interval", PICL_PTYPE_INT, &warning_interval,
266 &get_int_val, &set_int_val,
267 sizeof (int)},
269 {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval,
270 &get_int_val, &set_int_val,
271 sizeof (int)},
273 {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
274 &get_string_val, &set_string_val,
275 sizeof (shutdown_cmd)},
277 {"tach-enable", PICL_PTYPE_INT, &hwm_tach_enable,
278 &get_tach, &set_tach,
279 sizeof (int)},
281 {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat,
282 &get_int_val, &set_int_val, sizeof (int)},
284 {"verbose", PICL_PTYPE_INT, &env_debug,
285 &get_int_val, &set_int_val, sizeof (int)},
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
294 int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
297 * Table Handling Code
299 static void
300 fini_table(table_t *tblp)
302 if (tblp == NULL)
303 return;
304 free(tblp->xymap);
305 free(tblp);
308 static table_t *
309 init_table(int npoints)
311 table_t *tblp;
312 point_t *xy;
314 if (npoints == 0)
315 return (NULL);
317 if ((tblp = malloc(sizeof (*tblp))) == NULL)
318 return (NULL);
320 if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) {
321 free(tblp);
322 return (NULL);
325 tblp->nentries = npoints;
326 tblp->xymap = xy;
328 return (tblp);
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'
336 static int
337 y_of_x(table_t *tbl, int xval)
339 int i;
340 int entries;
341 point_t *xymap;
342 float newval;
343 float dy, dx, slope;
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);
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;
360 * Use linear interpolation
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)));
370 * Get environmental segment from the specified FRU SEEPROM
372 static int
373 get_envseg(int fd, void **envsegp, int *envseglenp)
375 int i, segcnt, envseglen;
376 section_layout_t section;
377 segment_layout_t segment;
378 uint8_t *envseg;
380 if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L ||
381 read(fd, &section, sizeof (section)) != sizeof (section)) {
382 return (EINVAL);
386 * Verify we have the correct section and contents are valid
387 * For now, we don't verify the CRC.
389 if (section.header_tag != SECTION_HDR_TAG ||
390 GET_UNALIGN16(&section.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(&section.header_version));
396 return (EINVAL);
400 * Locate our environmental segment
402 segcnt = section.segment_count;
403 for (i = 0; i < segcnt; i++) {
404 if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) {
405 return (EINVAL);
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;
418 if (i >= segcnt) {
419 return (ENOENT);
423 * Allocate memory to hold the environmental segment data.
425 envseglen = GET_UNALIGN16(&segment.length);
426 if ((envseg = malloc(envseglen)) == NULL) {
427 return (ENOMEM);
430 if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L ||
431 read(fd, envseg, envseglen) != envseglen) {
432 (void) free(envseg);
433 return (EIO);
435 *envsegp = envseg;
436 *envseglenp = envseglen;
437 return (0);
441 * Get all environmental segments
443 static fruenvseg_t *
444 get_fru_envsegs(void)
446 fruenvseg_t *fruenvsegs;
447 envseg_layout_t *envsegp;
448 void *envsegbufp;
449 int fd, envseglen, hdrlen;
450 char path[PATH_MAX];
452 fruenvsegs = NULL;
453 fruenvsegs = malloc(sizeof (*fruenvsegs));
454 if (fruenvsegs == NULL) {
455 return (NULL);
459 * Now get the environmental segment from this FRU
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);
470 * Read environmental segment from this FRU SEEPROM
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);
480 * Validate envseg version number and header length
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);
487 if (envsegp->version != ENVSEG_VERSION ||
488 envseglen < hdrlen) {
490 * version mismatch or header not big enough
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);
500 fruenvsegs->envseglen = envseglen;
501 fruenvsegs->envsegbufp = envsegbufp;
502 (void) close(fd);
503 return (fruenvsegs);
506 static int
507 process_fru_seeprom(unsigned char *buff)
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;
517 #define NSENSOR_OFFSET 1
518 #define ID_OFF_SIZE 6
519 #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2)
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);
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);
533 while (nsensors > 0) {
534 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
535 ID_OFF_SIZE);
537 if (env_debug)
538 envd_log(LOG_ERR, "\n Sensor Id %x offset %x",
539 id.id, id.offset);
541 if (id.id > MAX_SENSOR_ID) {
542 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
543 FRU_SEEPROM_NAME);
544 return (-1);
548 * Copy into the sensor control block array according to the
549 * sensor ID
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;
559 * Skip past no of Fan entry(single byte)
561 id_offset++;
562 while (nfans > 0) {
563 (void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
564 ID_OFF_SIZE);
566 if (env_debug)
567 envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id,
568 id.offset);
570 (void) memcpy((char *)&fan_ctrl[id.id],
571 (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t));
573 nfans--;
574 id_offset += ID_OFF_SIZE;
578 * Match Sensor/ES ID and point correct data
579 * based on IDs
581 for (snodep = envd_sensors; snodep->name != NULL; snodep++)
582 snodep->es_ptr = &sensor_ctrl[snodep->id];
585 * Match Fan/ES ID and point to correct ES Data
586 * based on IDs
588 for (i = 0; (fnodep = envd_fans[i]) != NULL; i++)
589 fnodep->es_ptr = &fan_ctrl[fnodep->id];
591 return (0);
594 static int
595 envd_es_setup()
597 envfru = get_fru_envsegs();
598 if (envfru == NULL) {
599 envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
600 return (-1);
602 return (process_fru_seeprom((uchar_t *)envfru->envsegbufp));
605 static void
606 envd_es_destroy()
608 if (envfru != NULL)
609 free(envfru->envsegbufp);
613 * Lookup fan and return a pointer to env_fan_t data structure.
615 env_fan_t *
616 fan_lookup(char *name)
618 int i;
619 env_fan_t *fanp;
621 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
622 if (strcmp(fanp->name, name) == 0)
623 return (fanp);
625 return (NULL);
629 * Lookup sensor and return a pointer to env_sensor_t data structure.
631 env_sensor_t *
632 sensor_lookup(char *name)
634 env_sensor_t *sensorp;
635 int i;
637 for (i = 0; i < N_ENVD_SENSORS; ++i) {
638 sensorp = &envd_sensors[i];
639 if (strcmp(sensorp->name, name) == 0)
640 return (sensorp);
642 return (NULL);
646 * Get current temperature
647 * Returns -1 on error, 0 if successful
650 get_temperature(env_sensor_t *sensorp, tempr_t *temp)
652 int fd = sensorp->fd;
653 int retval = 0;
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));
664 } else if (sensorp->error != 0) {
665 sensorp->error = 0;
666 envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name);
668 if (sensorp->crtbl != NULL) {
669 *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp);
672 return (retval);
676 * Get uncorrected current temperature
677 * Returns -1 on error, 0 if successful
679 static int
680 get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp)
682 int fd = sensorp->fd;
683 int retval = 0;
685 if (fd == -1)
686 retval = -1;
687 else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
688 retval = -1;
691 return (retval);
695 * Return Fan RPM given N & tach
696 * count and N are retrived from the
697 * ADM1031 chip.
699 static int
700 tach_to_rpm(int n, uint8_t tach)
702 if (n * tach == 0)
703 return (0);
704 return ((ADCSAMPLE * 60) / (n * tach));
707 static int
708 get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp)
710 int fan_fd;
711 int retval = 0;
713 fan_fd = fanp->fd;
715 if (fan_fd == -1)
716 retval = -1;
717 else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) {
718 retval = -1;
722 return (retval);
725 * Get current fan speed
726 * Returns -1 on error, 0 if successful
729 get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
731 int fan_fd;
732 uint8_t tach;
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);
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.
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);
753 return (0);
757 * Set fan speed
758 * Returns -1 on error, 0 if successful
761 set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
763 int fan_fd;
764 int retval = 0;
765 uint8_t speed;
767 fan_fd = fanp->fd;
768 if (fan_fd == -1)
769 return (-1);
771 if (fanspeed < 0 || fanspeed > 100)
772 return (-2);
774 speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed);
776 if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) {
777 retval = -1;
779 return (retval);
783 * close all fan devices
785 static void
786 envd_close_fans(void)
788 int i;
789 env_fan_t *fanp;
791 for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
792 if (fanp->fd != -1) {
793 (void) close(fanp->fd);
794 fanp->fd = -1;
800 * Close sensor devices and freeup resources
802 static void
803 envd_close_sensors(void)
805 env_sensor_t *sensorp;
806 int i;
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;
814 if (sensorp->crtbl != NULL)
815 fini_table(sensorp->crtbl);
820 * Open fan devices and initialize per fan data structure.
821 * Returns #fans found.
823 static int
824 envd_setup_fans(void)
826 int i, fd;
827 env_fan_t *fanp;
828 char path[PATH_MAX];
829 int fancnt = 0;
830 uint8_t n = 0;
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;
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;
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++;
858 return (fancnt);
862 * Open temperature sensor devices and initialize per sensor data structure.
863 * Returns #sensors found.
865 static int
866 envd_setup_sensors(void)
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;
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;
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;
896 sensorp->present = B_TRUE;
897 sensorcnt++;
900 * Get Tmin
903 if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
904 &tmin) != -1) {
905 sensorp->tmin = TMIN(tmin);
906 } else {
907 sensorp->tmin = -1;
909 if (env_debug)
910 envd_log(LOG_ERR, "Sensor %s tmin %d",
911 sensorp->name, sensorp->tmin);
914 * Create a correction table
915 * if correction pairs are present in es
916 * segment.
918 es_ptr = sensorp->es_ptr;
920 if (es_ptr == NULL) {
921 continue;
923 nentries = es_ptr->correctionEntries;
925 if (nentries < 2) {
926 if (env_debug)
927 envd_log(LOG_CRIT, "sensor correction <2");
928 continue;
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;
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;
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;
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);
963 return (sensorcnt);
966 * Modify ADM Tmin/ranges depending what power level
967 * we are from.
969 static void
970 updateadm_ranges(char *name, uchar_t cur_lpstate)
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;
982 sensorp = sensor_lookup(name);
983 if (sensorp == NULL)
984 return;
987 * If there is only one Control pairs then return
989 fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr;
991 if (fanctl != NULL && fanctl->no_ctl_pairs <= 1)
992 return;
995 * if fan control specifies that ranges are same then
996 * we skip re-programming adm chip.
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;
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;
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;
1025 * Need to reinit ADM to manual mode for Tmin range to be
1026 * effective.
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;
1036 if (cur_lpstate == 1) {
1038 * ADM 1031 Tmin/Trange register need to be reprogrammed.
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;
1047 case 10:
1048 tdata |= 1;
1049 break;
1051 case 20:
1052 tdata |= 2;
1053 break;
1055 case 40:
1056 tdata |= 3;
1057 break;
1059 case 80:
1060 tdata |= 4;
1061 break;
1063 } else
1064 tdata = tsave;
1066 if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE,
1067 &tdata) != -1)
1068 sensorp->tmin = TMIN(tdata);
1070 sensorp->tmin = TMIN(tdata);
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);
1077 (void) close(sysfd);
1080 /*ARGSUSED*/
1081 static void *
1082 pmthr(void *args)
1084 pm_state_change_t pmstate;
1085 char physpath[PATH_MAX];
1086 int pre_lpstate;
1088 pmstate.physpath = physpath;
1089 pmstate.size = sizeof (physpath);
1090 cur_lpstate = 0;
1091 pre_lpstate = 1;
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);
1098 for (;;) {
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.
1104 * To minimize polling, we use the blocking interface
1105 * to get the power state change event here.
1107 if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
1108 if (errno != EINTR)
1109 break;
1110 continue;
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);
1123 cur_lpstate =
1124 (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
1125 } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
1127 * Change ADM ranges as per E* Requirements. Update
1128 * happens only for valid state changes.
1130 if (pre_lpstate != cur_lpstate) {
1131 pre_lpstate = cur_lpstate;
1132 updateadm_ranges(SENSOR_SYS_IN, cur_lpstate);
1135 /*NOTREACHED*/
1136 return (NULL);
1140 * This function is used to reasonably predict the
1141 * state of the fan (ON/OFF) using tmin and current temperature.
1143 * We know the fan is on if temp >= tmin and fan is off if
1144 * temp < (Tmin - Hysterisis).
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.
1150 * FAN ON
1151 * Tmin
1152 * -------------------------------------------
1154 * FAN ON/OFF
1156 * --------------------------------------------
1157 * Tmin - Hysterisis
1158 * FAN OFF
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.
1166 * This routine implements the above logic for a sensor with an
1167 * associated fan. The caller garauntees sensorp and fanp are not null.
1169 static void
1170 check_fanstat(env_sensor_t *sensorp)
1172 env_fan_t *fanp = sensorp->fanp;
1173 tempr_t temp;
1174 uint8_t fanspeed;
1176 if (get_raw_temperature(sensorp, &temp) == -1)
1177 return;
1179 if (temp < (sensorp->tmin - ADM_HYSTERISIS)) {
1181 fanp->fanstat = 0; /* Fan off */
1182 fanp->lspeed = TACH_UNKNOWN; /* Reset Last read tach */
1183 fanp->conccnt = 0;
1185 } else if (temp >= sensorp->tmin) {
1187 fanp->fanstat = 1; /* Fan on */
1188 fanp->lspeed = TACH_UNKNOWN;
1189 fanp->conccnt = 0;
1191 } else {
1192 if (get_raw_fan_speed(fanp, &fanspeed) == -1)
1193 return;
1195 fanp->cspeed = fanspeed;
1197 * First time in the gray area
1198 * set last read speed to current speed
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++;
1209 if (fanp->conccnt >= N_SEQ_TACH)
1210 fanp->fanstat = 0;
1212 fanp->lspeed = fanp->cspeed;
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.
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.
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.
1231 * We get current temperature and check the fans.
1233 static void
1234 monitor_fanstat(void)
1236 env_sensor_t *sensorp;
1237 env_fan_t *fanp;
1238 int i;
1240 for (i = 0; i < N_ENVD_SENSORS; i++) {
1241 sensorp = &envd_sensors[i];
1243 if (!sensorp)
1244 continue;
1246 fanp = sensorp->fanp;
1248 if (!fanp)
1249 continue;
1251 if (sensorp->tmin != -1) {
1252 check_fanstat(sensorp);
1253 } else {
1254 fanp->fanstat = 1;
1258 * On Taco both the system fans are driven by one
1259 * sensor (sys-in) and connected to the sys-in tach.
1261 envd_sys_out_fan.fanstat = envd_sys_in_fan.fanstat;
1265 static int
1266 handle_overtemp_interrupt(int hwm_id)
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;
1277 /* Clear Map of Sensor Entries */
1278 (void) memset(smap, SENSOR_OK, sizeof (smap));
1280 for (;;) {
1281 for (i = 0; i < N_ENVD_SENSORS; i++) {
1282 sensorp = &envd_sensors[i];
1285 * Check whether the sensor belongs to the
1286 * interrupting ADM hardware monitor
1288 if (sensorp->hwm_id != hwm_id)
1289 continue;
1292 * if shutdown is initiated then we simply loop
1293 * through the sensors until shutdown
1295 if (sensorp->shutdown_initiated == B_TRUE)
1296 continue;
1298 /* get current temp for this sensor */
1299 if (get_temperature(sensorp, &temp) == -1)
1300 continue;
1302 sensorp->cur_temp = temp;
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);
1314 if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) {
1316 * Log on warning atmost one second
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;
1328 smap[i] = SENSOR_WARN;
1329 } else {
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.
1337 smap[i] = SENSOR_OK;
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);
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);
1362 } else if (sensorp->shutdown_tstamp != 0)
1363 sensorp->shutdown_tstamp = 0;
1367 * Sweep thorugh Sensor Map and if warnings OR shutdown
1368 * are not logged then return to caller.
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;
1375 if ((return_flag == B_TRUE) &&
1376 (system_shutdown_started == B_FALSE)) {
1377 return (1);
1380 (void) envd_sleep(SENSORPOLL_INTERVAL);
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.
1391 static void *
1392 ovtemp_thr(void *args)
1394 int fd;
1395 uint8_t stat[2];
1396 int hwm_id = (int)args;
1397 int err;
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);
1406 for (;;) {
1409 * Monitor the sensors to update status
1411 if (mon_fanstat)
1412 monitor_fanstat();
1415 * Sleep for specified seconds before issuing IOCTL
1416 * again.
1418 (void) envd_sleep(INTERRUPTPOLL_INTERVAL);
1421 * Read ADM1031 two Status Register to determine source of
1422 * Interrupts.
1424 if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1)
1425 err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]);
1427 if (err == -1) {
1428 if (env_debug)
1429 envd_log(LOG_ERR, "OverTemp: Status Error");
1430 continue;
1433 if (env_debug)
1434 envd_log(LOG_ERR, "INTR %s Stat1 %x, Stat2 %x",
1435 hwm_devs[hwm_id], stat[0], stat[1]);
1437 if (stat[0] & FANFAULT)
1438 envd_log(LOG_ERR, ENV_FAN_FAULT,
1439 hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN1]);
1441 if (stat[1] & FANFAULT)
1442 envd_log(LOG_ERR, ENV_FAN_FAULT,
1443 hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN2]);
1446 * Check respective Remote/Local High, Low before start
1447 * manual monitoring
1449 if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK))
1450 (void) handle_overtemp_interrupt(hwm_id);
1452 /*NOTREACHED*/
1453 return (NULL);
1457 * Setup envrionmental monitor state and start threads to monitor
1458 * temperature and power management state.
1459 * Returns -1 on error, 0 if successful.
1462 static int
1463 envd_setup(void)
1465 int ret;
1467 if (getenv("SUNW_piclenvd_debug") != NULL)
1468 env_debug = 1;
1470 if (pthread_attr_init(&thr_attr) != 0 ||
1471 pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
1472 return (-1);
1475 ret = envd_es_setup();
1476 if (ret < 0) {
1477 ovtemp_monitor = 0;
1478 pm_monitor = 0;
1483 * Setup temperature sensors and fail if we can't open
1484 * at least one sensor.
1486 if (envd_setup_sensors() <= 0) {
1487 return (NULL);
1491 * Setup fan device (don't fail even if we can't access
1492 * the fan as we can still monitor temeperature.
1494 (void) envd_setup_fans();
1496 /* If ES Segment setup failed,don't create thread */
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;
1507 * Create a thread to monitor PM state
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;
1516 return (0);
1519 static void
1520 piclenvd_register(void)
1522 picld_plugin_register(&my_reg_info);
1525 static void
1526 piclenvd_init(void)
1529 (void) env_picl_setup_tuneables();
1532 * Setup the environmental data structures
1534 if (envd_setup() != 0) {
1535 envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
1536 return;
1540 * Now setup/populate PICL tree
1542 env_picl_setup();
1545 static void
1546 piclenvd_fini(void)
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.
1555 env_picl_destroy();
1556 envd_close_sensors();
1557 envd_close_fans();
1558 envd_es_destroy();
1561 /*VARARGS2*/
1562 void
1563 envd_log(int pri, const char *fmt, ...)
1565 va_list ap;
1567 va_start(ap, fmt);
1568 vsyslog(pri, fmt, ap);
1569 va_end(ap);
1572 #ifdef __lint
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.
1578 #define sigwait my_posix_sigwait
1579 extern int my_posix_sigwait(const sigset_t *set, int *sig);
1580 #endif
1582 static uint_t
1583 envd_sleep(uint_t sleep_tm)
1585 int sig;
1586 uint_t unslept;
1587 sigset_t alrm_mask;
1589 if (sleep_tm == 0)
1590 return (0);
1592 (void) sigemptyset(&alrm_mask);
1593 (void) sigaddset(&alrm_mask, SIGALRM);
1595 (void) alarm(sleep_tm);
1596 (void) sigwait(&alrm_mask, &sig);
1598 unslept = alarm(0);
1599 return (unslept);
1603 * Tunables support functions
1605 static env_tuneable_t *
1606 tuneable_lookup(picl_prophdl_t proph)
1608 int i;
1609 env_tuneable_t *tuneablep = NULL;
1611 for (i = 0; i < ntuneables; i++) {
1612 tuneablep = &tuneables[i];
1613 if (tuneablep->proph == proph)
1614 return (tuneablep);
1617 return (NULL);
1620 static int
1621 get_tach(ptree_rarg_t *parg, void *buf)
1623 picl_prophdl_t proph;
1624 env_tuneable_t *tuneablep;
1625 int fd;
1626 int8_t cfg;
1628 proph = parg->proph;
1630 tuneablep = tuneable_lookup(proph);
1632 if (tuneablep == NULL)
1633 return (PICL_FAILURE);
1635 fd = open(CPU_HWM_DEVFS, O_RDWR);
1637 if (fd == -1) {
1638 return (PICL_FAILURE);
1641 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
1642 return (PICL_FAILURE);
1645 if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
1646 *((int *)tuneablep->value) = ENABLE;
1648 } else {
1649 *((int *)tuneablep->value) = DISABLE;
1652 (void) memcpy(buf, tuneablep->value,
1653 tuneablep->nbytes);
1655 (void) close(fd);
1656 return (PICL_SUCCESS);
1659 static int
1660 set_tach(ptree_warg_t *parg, const void *buf)
1662 picl_prophdl_t proph;
1663 env_tuneable_t *tuneablep;
1664 int fd, val;
1665 int8_t cfg;
1667 if (parg->cred.dc_euid != 0)
1668 return (PICL_PERMDENIED);
1670 proph = parg->proph;
1672 tuneablep = tuneable_lookup(proph);
1674 if (tuneablep == NULL)
1675 return (PICL_FAILURE);
1677 fd = open(CPU_HWM_DEVFS, O_RDWR);
1679 if (fd == -1) {
1680 return (PICL_FAILURE);
1683 if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
1684 return (PICL_FAILURE);
1687 (void) memcpy(&val, (caddr_t)buf, sizeof (val));
1689 if (val == ENABLE) {
1690 cfg |= TACH_ENABLE_MASK;
1691 } else if (val == DISABLE) {
1692 cfg &= ~TACH_ENABLE_MASK;
1695 if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
1696 return (PICL_FAILURE);
1699 (void) close(fd);
1700 return (PICL_SUCCESS);
1703 static int
1704 get_monitor_mode(ptree_rarg_t *parg, void *buf)
1706 picl_prophdl_t proph;
1707 env_tuneable_t *tuneablep;
1708 int fd;
1709 int8_t mmode;
1711 proph = parg->proph;
1713 tuneablep = tuneable_lookup(proph);
1715 if (tuneablep == NULL)
1716 return (PICL_FAILURE);
1718 fd = open(CPU_HWM_DEVFS, O_RDWR);
1720 if (fd == -1) {
1721 return (PICL_FAILURE);
1724 if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
1725 return (PICL_FAILURE);
1728 if (mmode == ADM1031_AUTO_MODE) {
1729 *((int *)tuneablep->value) = ENABLE;
1730 } else {
1731 *((int *)tuneablep->value) = DISABLE;
1734 (void) memcpy(buf, tuneablep->value,
1735 tuneablep->nbytes);
1737 (void) close(fd);
1738 return (PICL_SUCCESS);
1741 static int
1742 set_monitor_mode(ptree_warg_t *parg, const void *buf)
1744 picl_prophdl_t proph;
1745 env_tuneable_t *tuneablep;
1746 int fd, val;
1747 int8_t mmode;
1749 if (parg->cred.dc_euid != 0)
1750 return (PICL_PERMDENIED);
1752 proph = parg->proph;
1754 tuneablep = tuneable_lookup(proph);
1756 if (tuneablep == NULL)
1757 return (PICL_FAILURE);
1759 fd = open(CPU_HWM_DEVFS, O_RDWR);
1760 if (fd == -1) {
1761 return (PICL_FAILURE);
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;
1770 if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
1771 return (PICL_FAILURE);
1774 (void) close(fd);
1775 return (PICL_SUCCESS);
1778 static int
1779 get_string_val(ptree_rarg_t *parg, void *buf)
1781 picl_prophdl_t proph;
1782 env_tuneable_t *tuneablep;
1784 proph = parg->proph;
1786 tuneablep = tuneable_lookup(proph);
1788 if (tuneablep == NULL)
1789 return (PICL_FAILURE);
1791 (void) memcpy(buf, (caddr_t)tuneablep->value,
1792 tuneablep->nbytes);
1794 return (PICL_SUCCESS);
1797 static int
1798 set_string_val(ptree_warg_t *parg, const void *buf)
1800 picl_prophdl_t proph;
1801 env_tuneable_t *tuneablep;
1803 proph = parg->proph;
1805 if (parg->cred.dc_euid != 0)
1806 return (PICL_PERMDENIED);
1808 tuneablep = tuneable_lookup(proph);
1810 if (tuneablep == NULL)
1811 return (PICL_FAILURE);
1813 (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf,
1814 tuneables->nbytes);
1816 return (PICL_SUCCESS);
1819 static int
1820 get_int_val(ptree_rarg_t *parg, void *buf)
1822 picl_prophdl_t proph;
1823 env_tuneable_t *tuneablep;
1825 proph = parg->proph;
1827 tuneablep = tuneable_lookup(proph);
1829 if (tuneablep == NULL)
1830 return (PICL_FAILURE);
1832 (void) memcpy((int *)buf, (int *)tuneablep->value,
1833 tuneablep->nbytes);
1835 return (PICL_SUCCESS);
1838 static int
1839 set_int_val(ptree_warg_t *parg, const void *buf)
1841 picl_prophdl_t proph;
1842 env_tuneable_t *tuneablep;
1844 if (parg->cred.dc_euid != 0)
1845 return (PICL_PERMDENIED);
1847 proph = parg->proph;
1849 tuneablep = tuneable_lookup(proph);
1851 if (tuneablep == NULL)
1852 return (PICL_FAILURE);
1854 (void) memcpy((int *)tuneablep->value, (int *)buf,
1855 tuneablep->nbytes);
1857 return (PICL_SUCCESS);