17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate * with the License.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate * and limitations under the License.
137c478bd9Sstevel@tonic-gate *
147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate *
207c478bd9Sstevel@tonic-gate * CDDL HEADER END
217c478bd9Sstevel@tonic-gate */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate * This file contains the environmental PICL plug-in module.
297c478bd9Sstevel@tonic-gate */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate * This plugin sets up the PICLTREE for Taco.
337c478bd9Sstevel@tonic-gate * It provides functionality to get/set temperatures
347c478bd9Sstevel@tonic-gate * and fan speeds
357c478bd9Sstevel@tonic-gate *
367c478bd9Sstevel@tonic-gate * The environmental monitoring policy is the default
377c478bd9Sstevel@tonic-gate * auto mode as programmed by OBP at boot time.
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include <stdio.h>
417c478bd9Sstevel@tonic-gate #include <stdlib.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate #include <limits.h>
447c478bd9Sstevel@tonic-gate #include <string.h>
457c478bd9Sstevel@tonic-gate #include <stdarg.h>
467c478bd9Sstevel@tonic-gate #include <alloca.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <sys/processor.h>
497c478bd9Sstevel@tonic-gate #include <syslog.h>
507c478bd9Sstevel@tonic-gate #include <errno.h>
517c478bd9Sstevel@tonic-gate #include <fcntl.h>
527c478bd9Sstevel@tonic-gate #include <picl.h>
537c478bd9Sstevel@tonic-gate #include <picltree.h>
547c478bd9Sstevel@tonic-gate #include <picldefs.h>
557c478bd9Sstevel@tonic-gate #include <pthread.h>
567c478bd9Sstevel@tonic-gate #include <signal.h>
577c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
587c478bd9Sstevel@tonic-gate #include <sys/pm.h>
597c478bd9Sstevel@tonic-gate #include <sys/open.h>
607c478bd9Sstevel@tonic-gate #include <sys/time.h>
617c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
627c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
637c478bd9Sstevel@tonic-gate #include <note.h>
647c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
657c478bd9Sstevel@tonic-gate #include <sys/i2c/clients/adm1031.h>
667c478bd9Sstevel@tonic-gate #include "envd.h"
677c478bd9Sstevel@tonic-gate
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate * PICL plguin entry points
707c478bd9Sstevel@tonic-gate */
717c478bd9Sstevel@tonic-gate static void piclenvd_register(void);
727c478bd9Sstevel@tonic-gate static void piclenvd_init(void);
737c478bd9Sstevel@tonic-gate static void piclenvd_fini(void);
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate * Env setup routines
777c478bd9Sstevel@tonic-gate */
787c478bd9Sstevel@tonic-gate extern void env_picl_setup(void);
797c478bd9Sstevel@tonic-gate extern void env_picl_destroy(void);
807c478bd9Sstevel@tonic-gate extern int env_picl_setup_tuneables(void);
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate * Sleep routine used for polling
847c478bd9Sstevel@tonic-gate */
857c478bd9Sstevel@tonic-gate static uint_t envd_sleep(uint_t);
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate #pragma init(piclenvd_register)
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate * Plugin registration information
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate static picld_plugin_reg_t my_reg_info = {
937c478bd9Sstevel@tonic-gate PICLD_PLUGIN_VERSION,
947c478bd9Sstevel@tonic-gate PICLD_PLUGIN_CRITICAL,
957c478bd9Sstevel@tonic-gate "SUNW_piclenvd",
967c478bd9Sstevel@tonic-gate piclenvd_init,
977c478bd9Sstevel@tonic-gate piclenvd_fini,
987c478bd9Sstevel@tonic-gate };
997c478bd9Sstevel@tonic-gate
1007c478bd9Sstevel@tonic-gate /*
1017c478bd9Sstevel@tonic-gate * ES Segment data structures
1027c478bd9Sstevel@tonic-gate */
1037c478bd9Sstevel@tonic-gate static sensor_ctrl_blk_t sensor_ctrl[MAX_SENSORS];
1047c478bd9Sstevel@tonic-gate static fan_ctrl_blk_t fan_ctrl[MAX_FANS];
1057c478bd9Sstevel@tonic-gate static fruenvseg_t *envfru = NULL;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate * Env thread variables
1097c478bd9Sstevel@tonic-gate */
1107c478bd9Sstevel@tonic-gate static boolean_t system_shutdown_started = B_FALSE;
1117c478bd9Sstevel@tonic-gate static boolean_t ovtemp_thr_created = B_FALSE;
1127c478bd9Sstevel@tonic-gate static pthread_t ovtemp_thr_id;
1137c478bd9Sstevel@tonic-gate static pthread_attr_t thr_attr;
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * PM thread related variabled
1187c478bd9Sstevel@tonic-gate */
1197c478bd9Sstevel@tonic-gate static pthread_t pmthr_tid; /* pmthr thread ID */
1207c478bd9Sstevel@tonic-gate static int pm_fd = -1; /* PM device file descriptor */
1217c478bd9Sstevel@tonic-gate static boolean_t pmthr_created = B_FALSE;
1227c478bd9Sstevel@tonic-gate static int cur_lpstate; /* cur low power state */
1237c478bd9Sstevel@tonic-gate
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
1267c478bd9Sstevel@tonic-gate * Setting the verbose tuneable also enables debugging for better
1277c478bd9Sstevel@tonic-gate * control
1287c478bd9Sstevel@tonic-gate */
1297c478bd9Sstevel@tonic-gate int env_debug = 0;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate * Fan devices
1337c478bd9Sstevel@tonic-gate */
1347c478bd9Sstevel@tonic-gate static env_fan_t envd_sys_out_fan = {
1357c478bd9Sstevel@tonic-gate ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_FAN_DEVFS, NULL,
1367c478bd9Sstevel@tonic-gate SYSTEM_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN,
1377c478bd9Sstevel@tonic-gate SYSTEM_OUT_FAN_SPEED_MAX, -1, -1,
1387c478bd9Sstevel@tonic-gate };
1397c478bd9Sstevel@tonic-gate
1407c478bd9Sstevel@tonic-gate static env_fan_t envd_sys_in_fan = {
1417c478bd9Sstevel@tonic-gate ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_FAN_DEVFS, NULL,
1427c478bd9Sstevel@tonic-gate SYSTEM_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN,
1437c478bd9Sstevel@tonic-gate SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1,
1447c478bd9Sstevel@tonic-gate };
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate static env_fan_t envd_cpu_fan = {
1477c478bd9Sstevel@tonic-gate ENV_CPU_FAN, ENV_CPU_FAN_DEVFS, NULL,
1487c478bd9Sstevel@tonic-gate CPU_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate * NULL terminated array of fans
1537c478bd9Sstevel@tonic-gate */
1547c478bd9Sstevel@tonic-gate static env_fan_t *envd_fans[] = {
1557c478bd9Sstevel@tonic-gate &envd_cpu_fan,
1567c478bd9Sstevel@tonic-gate &envd_sys_in_fan,
1577c478bd9Sstevel@tonic-gate &envd_sys_out_fan,
1587c478bd9Sstevel@tonic-gate NULL
1597c478bd9Sstevel@tonic-gate };
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate * ADM1031 speedrange map is indexed by a 2-bit value
1637c478bd9Sstevel@tonic-gate */
1647c478bd9Sstevel@tonic-gate static int adm_speedrange_map[] = {1, 2, 4, 8};
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate * ADM1031 devices
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate static char *hwm_devs[] = {
1707c478bd9Sstevel@tonic-gate CPU_HWM_DEVFS, /* CPU_HWM_ID */
1717c478bd9Sstevel@tonic-gate };
1727c478bd9Sstevel@tonic-gate
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate * Fan names associated with each ADM1031 hwms - used to
1757c478bd9Sstevel@tonic-gate * print fault messages
1767c478bd9Sstevel@tonic-gate */
1777c478bd9Sstevel@tonic-gate static char *hwm_fans[MAX_HWMS][2] = {
1787c478bd9Sstevel@tonic-gate {ENV_CPU_FAN, ENV_SYSTEM_IN_OUT_FANS}
1797c478bd9Sstevel@tonic-gate };
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * Temperature sensors
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate static env_sensor_t envd_sensors[] = {
1857c478bd9Sstevel@tonic-gate { SENSOR_CPU_DIE, SENSOR_CPU_DIE_DEVFS, NULL,
1867c478bd9Sstevel@tonic-gate CPU_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu_fan, -1},
1877c478bd9Sstevel@tonic-gate { SENSOR_INT_AMB, SENSOR_INT_AMB_DEVFS, NULL,
1887c478bd9Sstevel@tonic-gate INT_AMB_SENSOR_ID, CPU_HWM_ID, NULL, -1},
1897c478bd9Sstevel@tonic-gate { SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL,
1907c478bd9Sstevel@tonic-gate SYS_IN_SENSOR_ID, CPU_HWM_ID, (void *)&envd_sys_in_fan, -1},
1917c478bd9Sstevel@tonic-gate };
1927c478bd9Sstevel@tonic-gate #define N_ENVD_SENSORS (sizeof (envd_sensors)/sizeof (envd_sensors[0]))
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate * ADM1031 macros
1967c478bd9Sstevel@tonic-gate */
1977c478bd9Sstevel@tonic-gate #define TACH_UNKNOWN 255
1987c478bd9Sstevel@tonic-gate #define FAN_OUT_OF_RANGE (TACH_UNKNOWN)
1997c478bd9Sstevel@tonic-gate #define ADM_HYSTERISIS 5
2007c478bd9Sstevel@tonic-gate #define N_SEQ_TACH 15
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate #define TMIN_MASK (0xF8)
2037c478bd9Sstevel@tonic-gate #define TMIN_SHIFT (3)
2047c478bd9Sstevel@tonic-gate #define TMIN_UNITS (4) /* increments of 4 degrees celsius */
2057c478bd9Sstevel@tonic-gate #define TRANGE_MASK (0x7)
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate #define TMIN(regval) (((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
2087c478bd9Sstevel@tonic-gate #define TRANGE(regval) (regval & TRANGE_MASK)
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate #define GET_TMIN_RANGE(tmin, trange) \
2117c478bd9Sstevel@tonic-gate ((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
2127c478bd9Sstevel@tonic-gate (trange & TRANGE_MASK))
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate #define TACH_ENABLE_MASK (0x0C)
2157c478bd9Sstevel@tonic-gate #define MONITOR_ENABLE_MASK (0x01)
2167c478bd9Sstevel@tonic-gate #define ADM_SETFANSPEED_CONV(speed) (15 * speed / 100)
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate * Tuneables
2207c478bd9Sstevel@tonic-gate */
2217c478bd9Sstevel@tonic-gate #define ENABLE 1
2227c478bd9Sstevel@tonic-gate #define DISABLE 0
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate static int get_monitor_mode(ptree_rarg_t *parg, void *buf);
2257c478bd9Sstevel@tonic-gate static int set_monitor_mode(ptree_warg_t *parg, const void *buf);
2267c478bd9Sstevel@tonic-gate static int get_int_val(ptree_rarg_t *parg, void *buf);
2277c478bd9Sstevel@tonic-gate static int set_int_val(ptree_warg_t *parg, const void *buf);
2287c478bd9Sstevel@tonic-gate static int get_string_val(ptree_rarg_t *parg, void *buf);
2297c478bd9Sstevel@tonic-gate static int set_string_val(ptree_warg_t *parg, const void *buf);
2307c478bd9Sstevel@tonic-gate static int get_tach(ptree_rarg_t *parg, void *buf);
2317c478bd9Sstevel@tonic-gate static int set_tach(ptree_warg_t *parg, const void *buf);
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate static int shutdown_override = 0;
234*ada2da53SToomas Soome static int sensor_poll_interval = SENSORPOLL_INTERVAL;
2357c478bd9Sstevel@tonic-gate static int warning_interval = WARNING_INTERVAL;
236*ada2da53SToomas Soome static int shutdown_interval = SHUTDOWN_INTERVAL;
2377c478bd9Sstevel@tonic-gate static int ovtemp_monitor = 1; /* enabled */
2387c478bd9Sstevel@tonic-gate static int pm_monitor = 1; /* enabled */
2397c478bd9Sstevel@tonic-gate static int mon_fanstat = 1; /* enabled */
2407c478bd9Sstevel@tonic-gate
241*ada2da53SToomas Soome static int hwm_mode;
242*ada2da53SToomas Soome static int hwm_tach_enable;
2437c478bd9Sstevel@tonic-gate static char shutdown_cmd[] = SHUTDOWN_CMD;
2447c478bd9Sstevel@tonic-gate
2457c478bd9Sstevel@tonic-gate env_tuneable_t tuneables[] = {
2467c478bd9Sstevel@tonic-gate {"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor,
2477c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val, sizeof (int)},
2487c478bd9Sstevel@tonic-gate
2497c478bd9Sstevel@tonic-gate {"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
2507c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val, sizeof (int)},
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate {"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
2537c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val, sizeof (int)},
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate {"hwm-automode-enable", PICL_PTYPE_INT, &hwm_mode,
2567c478bd9Sstevel@tonic-gate &get_monitor_mode, &set_monitor_mode, sizeof (int)},
2577c478bd9Sstevel@tonic-gate
2587c478bd9Sstevel@tonic-gate {"sensor-poll-interval", PICL_PTYPE_INT,
2597c478bd9Sstevel@tonic-gate &sensor_poll_interval,
2607c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val,
2617c478bd9Sstevel@tonic-gate sizeof (int)},
2627c478bd9Sstevel@tonic-gate
2637c478bd9Sstevel@tonic-gate {"warning-interval", PICL_PTYPE_INT, &warning_interval,
2647c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val,
2657c478bd9Sstevel@tonic-gate sizeof (int)},
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate {"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval,
2687c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val,
2697c478bd9Sstevel@tonic-gate sizeof (int)},
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate {"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
2727c478bd9Sstevel@tonic-gate &get_string_val, &set_string_val,
2737c478bd9Sstevel@tonic-gate sizeof (shutdown_cmd)},
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate {"tach-enable", PICL_PTYPE_INT, &hwm_tach_enable,
2767c478bd9Sstevel@tonic-gate &get_tach, &set_tach,
2777c478bd9Sstevel@tonic-gate sizeof (int)},
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate {"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat,
2807c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val, sizeof (int)},
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate {"verbose", PICL_PTYPE_INT, &env_debug,
2837c478bd9Sstevel@tonic-gate &get_int_val, &set_int_val, sizeof (int)},
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate };
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate * We use this to figure out how many tuneables there are
2897c478bd9Sstevel@tonic-gate * This is variable because the publishing routine needs this info
2907c478bd9Sstevel@tonic-gate * in piclenvsetup.c
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate int ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate /*
2957c478bd9Sstevel@tonic-gate * Table Handling Code
2967c478bd9Sstevel@tonic-gate */
2977c478bd9Sstevel@tonic-gate static void
fini_table(table_t * tblp)2987c478bd9Sstevel@tonic-gate fini_table(table_t *tblp)
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate if (tblp == NULL)
3017c478bd9Sstevel@tonic-gate return;
3027c478bd9Sstevel@tonic-gate free(tblp->xymap);
3037c478bd9Sstevel@tonic-gate free(tblp);
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate static table_t *
init_table(int npoints)3077c478bd9Sstevel@tonic-gate init_table(int npoints)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate table_t *tblp;
3107c478bd9Sstevel@tonic-gate point_t *xy;
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate if (npoints == 0)
3137c478bd9Sstevel@tonic-gate return (NULL);
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate if ((tblp = malloc(sizeof (*tblp))) == NULL)
3167c478bd9Sstevel@tonic-gate return (NULL);
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) {
3197c478bd9Sstevel@tonic-gate free(tblp);
3207c478bd9Sstevel@tonic-gate return (NULL);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate tblp->nentries = npoints;
3247c478bd9Sstevel@tonic-gate tblp->xymap = xy;
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate return (tblp);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * function: calculates y for a given x based on a table of points
3317c478bd9Sstevel@tonic-gate * for monotonically increasing x values.
3327c478bd9Sstevel@tonic-gate * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
3337c478bd9Sstevel@tonic-gate */
3347c478bd9Sstevel@tonic-gate static int
y_of_x(table_t * tbl,int xval)3357c478bd9Sstevel@tonic-gate y_of_x(table_t *tbl, int xval)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate int i;
3387c478bd9Sstevel@tonic-gate int entries;
3397c478bd9Sstevel@tonic-gate point_t *xymap;
3407c478bd9Sstevel@tonic-gate float newval;
3417c478bd9Sstevel@tonic-gate float dy, dx, slope;
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate entries = tbl->nentries;
3447c478bd9Sstevel@tonic-gate xymap = tbl->xymap;
3457c478bd9Sstevel@tonic-gate if (xval <= xymap[0].x)
3467c478bd9Sstevel@tonic-gate return (xymap[0].y);
3477c478bd9Sstevel@tonic-gate else if (xval >= xymap[entries - 1].x)
3487c478bd9Sstevel@tonic-gate return (xymap[entries - 1].y);
3497c478bd9Sstevel@tonic-gate
3507c478bd9Sstevel@tonic-gate for (i = 1; i < entries - 1; i++) {
3517c478bd9Sstevel@tonic-gate if (xval == xymap[i].x)
3527c478bd9Sstevel@tonic-gate return (xymap[i].y);
3537c478bd9Sstevel@tonic-gate if (xval < xymap[i].x)
3547c478bd9Sstevel@tonic-gate break;
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate * Use linear interpolation
3597c478bd9Sstevel@tonic-gate */
3607c478bd9Sstevel@tonic-gate dy = (float)(xymap[i].y - xymap[i-1].y);
3617c478bd9Sstevel@tonic-gate dx = (float)(xymap[i].x - xymap[i-1].x);
3627c478bd9Sstevel@tonic-gate slope = dy/dx;
3637c478bd9Sstevel@tonic-gate newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x);
3647c478bd9Sstevel@tonic-gate return ((int)(newval + (newval >= 0 ? 0.5 : -0.5)));
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate * Get environmental segment from the specified FRU SEEPROM
3697c478bd9Sstevel@tonic-gate */
3707c478bd9Sstevel@tonic-gate static int
get_envseg(int fd,void ** envsegp,int * envseglenp)3717c478bd9Sstevel@tonic-gate get_envseg(int fd, void **envsegp, int *envseglenp)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate int i, segcnt, envseglen;
3747c478bd9Sstevel@tonic-gate section_layout_t section;
3757c478bd9Sstevel@tonic-gate segment_layout_t segment;
3767c478bd9Sstevel@tonic-gate uint8_t *envseg;
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L ||
3797c478bd9Sstevel@tonic-gate read(fd, §ion, sizeof (section)) != sizeof (section)) {
3807c478bd9Sstevel@tonic-gate return (EINVAL);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate * Verify we have the correct section and contents are valid
3857c478bd9Sstevel@tonic-gate * For now, we don't verify the CRC.
3867c478bd9Sstevel@tonic-gate */
3877c478bd9Sstevel@tonic-gate if (section.header_tag != SECTION_HDR_TAG ||
3887c478bd9Sstevel@tonic-gate GET_UNALIGN16(§ion.header_version[0]) != SECTION_HDR_VER) {
3897c478bd9Sstevel@tonic-gate if (env_debug)
3907c478bd9Sstevel@tonic-gate envd_log(LOG_INFO,
3917c478bd9Sstevel@tonic-gate "Invalid section header tag:%x version:%x\n",
3927c478bd9Sstevel@tonic-gate section.header_tag,
3937c478bd9Sstevel@tonic-gate GET_UNALIGN16(§ion.header_version));
3947c478bd9Sstevel@tonic-gate return (EINVAL);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate * Locate our environmental segment
3997c478bd9Sstevel@tonic-gate */
4007c478bd9Sstevel@tonic-gate segcnt = section.segment_count;
4017c478bd9Sstevel@tonic-gate for (i = 0; i < segcnt; i++) {
4027c478bd9Sstevel@tonic-gate if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) {
4037c478bd9Sstevel@tonic-gate return (EINVAL);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate if (env_debug)
4067c478bd9Sstevel@tonic-gate envd_log(LOG_INFO,
4077c478bd9Sstevel@tonic-gate "Seg name: %x desc:%x off:%x len:%x\n",
4087c478bd9Sstevel@tonic-gate GET_UNALIGN16(&segment.name),
4097c478bd9Sstevel@tonic-gate GET_UNALIGN32(&segment.descriptor[0]),
4107c478bd9Sstevel@tonic-gate GET_UNALIGN16(&segment.offset),
4117c478bd9Sstevel@tonic-gate GET_UNALIGN16(&segment.length));
4127c478bd9Sstevel@tonic-gate if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME)
4137c478bd9Sstevel@tonic-gate break;
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate if (i >= segcnt) {
4177c478bd9Sstevel@tonic-gate return (ENOENT);
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate * Allocate memory to hold the environmental segment data.
4227c478bd9Sstevel@tonic-gate */
4237c478bd9Sstevel@tonic-gate envseglen = GET_UNALIGN16(&segment.length);
4247c478bd9Sstevel@tonic-gate if ((envseg = malloc(envseglen)) == NULL) {
4257c478bd9Sstevel@tonic-gate return (ENOMEM);
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L ||
4297c478bd9Sstevel@tonic-gate read(fd, envseg, envseglen) != envseglen) {
4307c478bd9Sstevel@tonic-gate (void) free(envseg);
4317c478bd9Sstevel@tonic-gate return (EIO);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate *envsegp = envseg;
4347c478bd9Sstevel@tonic-gate *envseglenp = envseglen;
4357c478bd9Sstevel@tonic-gate return (0);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate * Get all environmental segments
4407c478bd9Sstevel@tonic-gate */
4417c478bd9Sstevel@tonic-gate static fruenvseg_t *
get_fru_envsegs(void)4427c478bd9Sstevel@tonic-gate get_fru_envsegs(void)
4437c478bd9Sstevel@tonic-gate {
4447c478bd9Sstevel@tonic-gate fruenvseg_t *fruenvsegs;
4457c478bd9Sstevel@tonic-gate envseg_layout_t *envsegp;
4467c478bd9Sstevel@tonic-gate void *envsegbufp;
4477c478bd9Sstevel@tonic-gate int fd, envseglen, hdrlen;
4487c478bd9Sstevel@tonic-gate char path[PATH_MAX];
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate fruenvsegs = NULL;
4517c478bd9Sstevel@tonic-gate fruenvsegs = malloc(sizeof (*fruenvsegs));
4527c478bd9Sstevel@tonic-gate if (fruenvsegs == NULL) {
4537c478bd9Sstevel@tonic-gate return (NULL);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate * Now get the environmental segment from this FRU
4587c478bd9Sstevel@tonic-gate */
4597c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV);
4607c478bd9Sstevel@tonic-gate fd = open(path, O_RDONLY);
4617c478bd9Sstevel@tonic-gate if (fd == -1) {
4627c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path);
4637c478bd9Sstevel@tonic-gate free(fruenvsegs);
4647c478bd9Sstevel@tonic-gate return (NULL);
4657c478bd9Sstevel@tonic-gate }
4667c478bd9Sstevel@tonic-gate
4677c478bd9Sstevel@tonic-gate /*
4687c478bd9Sstevel@tonic-gate * Read environmental segment from this FRU SEEPROM
4697c478bd9Sstevel@tonic-gate */
4707c478bd9Sstevel@tonic-gate if (get_envseg(fd, &envsegbufp, &envseglen) != 0) {
4717c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path);
4727c478bd9Sstevel@tonic-gate free(fruenvsegs);
4737c478bd9Sstevel@tonic-gate (void) close(fd);
4747c478bd9Sstevel@tonic-gate return (NULL);
4757c478bd9Sstevel@tonic-gate }
4767c478bd9Sstevel@tonic-gate
4777c478bd9Sstevel@tonic-gate /*
4787c478bd9Sstevel@tonic-gate * Validate envseg version number and header length
4797c478bd9Sstevel@tonic-gate */
4807c478bd9Sstevel@tonic-gate envsegp = (envseg_layout_t *)envsegbufp;
4817c478bd9Sstevel@tonic-gate hdrlen = sizeof (envseg_layout_t) -
4827c478bd9Sstevel@tonic-gate sizeof (envseg_sensor_t) +
4837c478bd9Sstevel@tonic-gate (envsegp->sensor_count) * sizeof (envseg_sensor_t);
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate if (envsegp->version != ENVSEG_VERSION ||
4867c478bd9Sstevel@tonic-gate envseglen < hdrlen) {
4877c478bd9Sstevel@tonic-gate /*
4887c478bd9Sstevel@tonic-gate * version mismatch or header not big enough
4897c478bd9Sstevel@tonic-gate */
4907c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, path);
4917c478bd9Sstevel@tonic-gate if (envsegbufp != NULL)
4927c478bd9Sstevel@tonic-gate (void) free(envsegbufp);
4937c478bd9Sstevel@tonic-gate free(fruenvsegs);
4947c478bd9Sstevel@tonic-gate (void) close(fd);
4957c478bd9Sstevel@tonic-gate return (NULL);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate fruenvsegs->envseglen = envseglen;
4997c478bd9Sstevel@tonic-gate fruenvsegs->envsegbufp = envsegbufp;
5007c478bd9Sstevel@tonic-gate (void) close(fd);
5017c478bd9Sstevel@tonic-gate return (fruenvsegs);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate static int
process_fru_seeprom(unsigned char * buff)5057c478bd9Sstevel@tonic-gate process_fru_seeprom(unsigned char *buff)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate id_off_t id;
5087c478bd9Sstevel@tonic-gate int i;
5097c478bd9Sstevel@tonic-gate int id_offset = 0;
5107c478bd9Sstevel@tonic-gate int nsensors;
5117c478bd9Sstevel@tonic-gate int nfans;
5127c478bd9Sstevel@tonic-gate env_fan_t *fnodep;
5137c478bd9Sstevel@tonic-gate env_sensor_t *snodep;
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate #define NSENSOR_OFFSET 1
5167c478bd9Sstevel@tonic-gate #define ID_OFF_SIZE 6
5177c478bd9Sstevel@tonic-gate #define NFANS_OFFSET(x) ((x * ID_OFF_SIZE) + 2)
5187c478bd9Sstevel@tonic-gate
5197c478bd9Sstevel@tonic-gate nsensors = (int)buff[NSENSOR_OFFSET];
5207c478bd9Sstevel@tonic-gate if (nsensors != MAX_SENSORS) {
5217c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
5227c478bd9Sstevel@tonic-gate return (-1);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate nfans = (int)buff[NFANS_OFFSET(nsensors)];
5267c478bd9Sstevel@tonic-gate if (nfans != MAX_FANS) {
5277c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
5287c478bd9Sstevel@tonic-gate return (-1);
5297c478bd9Sstevel@tonic-gate }
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate while (nsensors > 0) {
5327c478bd9Sstevel@tonic-gate (void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
5337c478bd9Sstevel@tonic-gate ID_OFF_SIZE);
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate if (env_debug)
5367c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, "\n Sensor Id %x offset %x",
5377c478bd9Sstevel@tonic-gate id.id, id.offset);
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate if (id.id > MAX_SENSOR_ID) {
5407c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
5417c478bd9Sstevel@tonic-gate FRU_SEEPROM_NAME);
5427c478bd9Sstevel@tonic-gate return (-1);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate /*
5467c478bd9Sstevel@tonic-gate * Copy into the sensor control block array according to the
5477c478bd9Sstevel@tonic-gate * sensor ID
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate (void) memcpy((char *)&sensor_ctrl[id.id],
5507c478bd9Sstevel@tonic-gate (char *)&buff[id.offset],
5517c478bd9Sstevel@tonic-gate sizeof (sensor_ctrl_blk_t));
5527c478bd9Sstevel@tonic-gate nsensors--;
5537c478bd9Sstevel@tonic-gate id_offset += ID_OFF_SIZE;
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate * Skip past no of Fan entry(single byte)
5587c478bd9Sstevel@tonic-gate */
5597c478bd9Sstevel@tonic-gate id_offset++;
5607c478bd9Sstevel@tonic-gate while (nfans > 0) {
5617c478bd9Sstevel@tonic-gate (void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
5627c478bd9Sstevel@tonic-gate ID_OFF_SIZE);
5637c478bd9Sstevel@tonic-gate
5647c478bd9Sstevel@tonic-gate if (env_debug)
5657c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id,
5667c478bd9Sstevel@tonic-gate id.offset);
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate (void) memcpy((char *)&fan_ctrl[id.id],
5697c478bd9Sstevel@tonic-gate (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t));
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate nfans--;
5727c478bd9Sstevel@tonic-gate id_offset += ID_OFF_SIZE;
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate * Match Sensor/ES ID and point correct data
5777c478bd9Sstevel@tonic-gate * based on IDs
5787c478bd9Sstevel@tonic-gate */
5797c478bd9Sstevel@tonic-gate for (snodep = envd_sensors; snodep->name != NULL; snodep++)
5807c478bd9Sstevel@tonic-gate snodep->es_ptr = &sensor_ctrl[snodep->id];
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate /*
5837c478bd9Sstevel@tonic-gate * Match Fan/ES ID and point to correct ES Data
5847c478bd9Sstevel@tonic-gate * based on IDs
5857c478bd9Sstevel@tonic-gate */
5867c478bd9Sstevel@tonic-gate for (i = 0; (fnodep = envd_fans[i]) != NULL; i++)
5877c478bd9Sstevel@tonic-gate fnodep->es_ptr = &fan_ctrl[fnodep->id];
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate return (0);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate
5927c478bd9Sstevel@tonic-gate static int
envd_es_setup()5937c478bd9Sstevel@tonic-gate envd_es_setup()
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate envfru = get_fru_envsegs();
5967c478bd9Sstevel@tonic-gate if (envfru == NULL) {
5977c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
5987c478bd9Sstevel@tonic-gate return (-1);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate return (process_fru_seeprom((uchar_t *)envfru->envsegbufp));
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate static void
envd_es_destroy()6047c478bd9Sstevel@tonic-gate envd_es_destroy()
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate if (envfru != NULL)
6077c478bd9Sstevel@tonic-gate free(envfru->envsegbufp);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate /*
6117c478bd9Sstevel@tonic-gate * Lookup fan and return a pointer to env_fan_t data structure.
6127c478bd9Sstevel@tonic-gate */
6137c478bd9Sstevel@tonic-gate env_fan_t *
fan_lookup(char * name)6147c478bd9Sstevel@tonic-gate fan_lookup(char *name)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate int i;
6177c478bd9Sstevel@tonic-gate env_fan_t *fanp;
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
6207c478bd9Sstevel@tonic-gate if (strcmp(fanp->name, name) == 0)
6217c478bd9Sstevel@tonic-gate return (fanp);
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate return (NULL);
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate * Lookup sensor and return a pointer to env_sensor_t data structure.
6287c478bd9Sstevel@tonic-gate */
6297c478bd9Sstevel@tonic-gate env_sensor_t *
sensor_lookup(char * name)6307c478bd9Sstevel@tonic-gate sensor_lookup(char *name)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
6337c478bd9Sstevel@tonic-gate int i;
6347c478bd9Sstevel@tonic-gate
6357c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; ++i) {
6367c478bd9Sstevel@tonic-gate sensorp = &envd_sensors[i];
6377c478bd9Sstevel@tonic-gate if (strcmp(sensorp->name, name) == 0)
6387c478bd9Sstevel@tonic-gate return (sensorp);
6397c478bd9Sstevel@tonic-gate }
6407c478bd9Sstevel@tonic-gate return (NULL);
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate /*
6447c478bd9Sstevel@tonic-gate * Get current temperature
6457c478bd9Sstevel@tonic-gate * Returns -1 on error, 0 if successful
6467c478bd9Sstevel@tonic-gate */
6477c478bd9Sstevel@tonic-gate int
get_temperature(env_sensor_t * sensorp,tempr_t * temp)6487c478bd9Sstevel@tonic-gate get_temperature(env_sensor_t *sensorp, tempr_t *temp)
6497c478bd9Sstevel@tonic-gate {
6507c478bd9Sstevel@tonic-gate int fd = sensorp->fd;
6517c478bd9Sstevel@tonic-gate int retval = 0;
6527c478bd9Sstevel@tonic-gate
6537c478bd9Sstevel@tonic-gate if (fd == -1)
6547c478bd9Sstevel@tonic-gate retval = -1;
6557c478bd9Sstevel@tonic-gate else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
6567c478bd9Sstevel@tonic-gate retval = -1;
6577c478bd9Sstevel@tonic-gate if (sensorp->error == 0) {
6587c478bd9Sstevel@tonic-gate sensorp->error = 1;
6597c478bd9Sstevel@tonic-gate envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
6607c478bd9Sstevel@tonic-gate sensorp->name, errno, strerror(errno));
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate } else if (sensorp->error != 0) {
6637c478bd9Sstevel@tonic-gate sensorp->error = 0;
6647c478bd9Sstevel@tonic-gate envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate if (sensorp->crtbl != NULL) {
6677c478bd9Sstevel@tonic-gate *temp = (tempr_t)y_of_x(sensorp->crtbl, *temp);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate
6707c478bd9Sstevel@tonic-gate return (retval);
6717c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate /*
6747c478bd9Sstevel@tonic-gate * Get uncorrected current temperature
6757c478bd9Sstevel@tonic-gate * Returns -1 on error, 0 if successful
6767c478bd9Sstevel@tonic-gate */
6777c478bd9Sstevel@tonic-gate static int
get_raw_temperature(env_sensor_t * sensorp,tempr_t * temp)6787c478bd9Sstevel@tonic-gate get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate int fd = sensorp->fd;
6817c478bd9Sstevel@tonic-gate int retval = 0;
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate if (fd == -1)
6847c478bd9Sstevel@tonic-gate retval = -1;
6857c478bd9Sstevel@tonic-gate else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
6867c478bd9Sstevel@tonic-gate retval = -1;
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate return (retval);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate * Return Fan RPM given N & tach
6947c478bd9Sstevel@tonic-gate * count and N are retrived from the
6957c478bd9Sstevel@tonic-gate * ADM1031 chip.
6967c478bd9Sstevel@tonic-gate */
6977c478bd9Sstevel@tonic-gate static int
tach_to_rpm(int n,uint8_t tach)6987c478bd9Sstevel@tonic-gate tach_to_rpm(int n, uint8_t tach)
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate if (n * tach == 0)
7017c478bd9Sstevel@tonic-gate return (0);
7027c478bd9Sstevel@tonic-gate return ((ADCSAMPLE * 60) / (n * tach));
7037c478bd9Sstevel@tonic-gate }
7047c478bd9Sstevel@tonic-gate
7057c478bd9Sstevel@tonic-gate static int
get_raw_fan_speed(env_fan_t * fanp,uint8_t * fanspeedp)7067c478bd9Sstevel@tonic-gate get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate int fan_fd;
7097c478bd9Sstevel@tonic-gate int retval = 0;
7107c478bd9Sstevel@tonic-gate
7117c478bd9Sstevel@tonic-gate fan_fd = fanp->fd;
7127c478bd9Sstevel@tonic-gate
7137c478bd9Sstevel@tonic-gate if (fan_fd == -1)
7147c478bd9Sstevel@tonic-gate retval = -1;
7157c478bd9Sstevel@tonic-gate else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) {
7167c478bd9Sstevel@tonic-gate retval = -1;
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate
7207c478bd9Sstevel@tonic-gate return (retval);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate /*
7237c478bd9Sstevel@tonic-gate * Get current fan speed
7247c478bd9Sstevel@tonic-gate * Returns -1 on error, 0 if successful
7257c478bd9Sstevel@tonic-gate */
7267c478bd9Sstevel@tonic-gate int
get_fan_speed(env_fan_t * fanp,fanspeed_t * fanspeedp)7277c478bd9Sstevel@tonic-gate get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate int fan_fd;
7307c478bd9Sstevel@tonic-gate uint8_t tach;
7317c478bd9Sstevel@tonic-gate
7327c478bd9Sstevel@tonic-gate fan_fd = fanp->fd;
7337c478bd9Sstevel@tonic-gate if (fan_fd == -1)
7347c478bd9Sstevel@tonic-gate return (-1);
7357c478bd9Sstevel@tonic-gate else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) {
7367c478bd9Sstevel@tonic-gate return (-1);
7377c478bd9Sstevel@tonic-gate }
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate /*
7407c478bd9Sstevel@tonic-gate * Fanspeeds are reported as 0
7417c478bd9Sstevel@tonic-gate * if the tach is out of range or fan status is off
7427c478bd9Sstevel@tonic-gate * and if monitoring fan status is enabled.
7437c478bd9Sstevel@tonic-gate */
7447c478bd9Sstevel@tonic-gate if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) {
7457c478bd9Sstevel@tonic-gate *fanspeedp = 0;
7467c478bd9Sstevel@tonic-gate } else {
7477c478bd9Sstevel@tonic-gate *fanspeedp =
7487c478bd9Sstevel@tonic-gate tach_to_rpm(fanp->speedrange, tach);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate return (0);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate
7547c478bd9Sstevel@tonic-gate /*
7557c478bd9Sstevel@tonic-gate * Set fan speed
7567c478bd9Sstevel@tonic-gate * Returns -1 on error, 0 if successful
7577c478bd9Sstevel@tonic-gate */
7587c478bd9Sstevel@tonic-gate int
set_fan_speed(env_fan_t * fanp,fanspeed_t fanspeed)7597c478bd9Sstevel@tonic-gate set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
7607c478bd9Sstevel@tonic-gate {
7617c478bd9Sstevel@tonic-gate int fan_fd;
7627c478bd9Sstevel@tonic-gate int retval = 0;
7637c478bd9Sstevel@tonic-gate uint8_t speed;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate fan_fd = fanp->fd;
7667c478bd9Sstevel@tonic-gate if (fan_fd == -1)
7677c478bd9Sstevel@tonic-gate return (-1);
7687c478bd9Sstevel@tonic-gate
7697c478bd9Sstevel@tonic-gate if (fanspeed < 0 || fanspeed > 100)
7707c478bd9Sstevel@tonic-gate return (-2);
7717c478bd9Sstevel@tonic-gate
7727c478bd9Sstevel@tonic-gate speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed);
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) {
7757c478bd9Sstevel@tonic-gate retval = -1;
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate return (retval);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate
7807c478bd9Sstevel@tonic-gate /*
7817c478bd9Sstevel@tonic-gate * close all fan devices
7827c478bd9Sstevel@tonic-gate */
7837c478bd9Sstevel@tonic-gate static void
envd_close_fans(void)7847c478bd9Sstevel@tonic-gate envd_close_fans(void)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate int i;
7877c478bd9Sstevel@tonic-gate env_fan_t *fanp;
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
7907c478bd9Sstevel@tonic-gate if (fanp->fd != -1) {
7917c478bd9Sstevel@tonic-gate (void) close(fanp->fd);
7927c478bd9Sstevel@tonic-gate fanp->fd = -1;
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate }
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate /*
7987c478bd9Sstevel@tonic-gate * Close sensor devices and freeup resources
7997c478bd9Sstevel@tonic-gate */
8007c478bd9Sstevel@tonic-gate static void
envd_close_sensors(void)8017c478bd9Sstevel@tonic-gate envd_close_sensors(void)
8027c478bd9Sstevel@tonic-gate {
8037c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
8047c478bd9Sstevel@tonic-gate int i;
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; ++i) {
8077c478bd9Sstevel@tonic-gate sensorp = &envd_sensors[i];
8087c478bd9Sstevel@tonic-gate if (sensorp->fd != -1) {
8097c478bd9Sstevel@tonic-gate (void) close(sensorp->fd);
8107c478bd9Sstevel@tonic-gate sensorp->fd = -1;
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate if (sensorp->crtbl != NULL)
8137c478bd9Sstevel@tonic-gate fini_table(sensorp->crtbl);
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate }
8167c478bd9Sstevel@tonic-gate
8177c478bd9Sstevel@tonic-gate /*
8187c478bd9Sstevel@tonic-gate * Open fan devices and initialize per fan data structure.
8197c478bd9Sstevel@tonic-gate * Returns #fans found.
8207c478bd9Sstevel@tonic-gate */
8217c478bd9Sstevel@tonic-gate static int
envd_setup_fans(void)8227c478bd9Sstevel@tonic-gate envd_setup_fans(void)
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate int i, fd;
8257c478bd9Sstevel@tonic-gate env_fan_t *fanp;
8267c478bd9Sstevel@tonic-gate char path[PATH_MAX];
8277c478bd9Sstevel@tonic-gate int fancnt = 0;
8287c478bd9Sstevel@tonic-gate uint8_t n = 0;
8297c478bd9Sstevel@tonic-gate
8307c478bd9Sstevel@tonic-gate for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
8317c478bd9Sstevel@tonic-gate (void) strcpy(path, "/devices");
8327c478bd9Sstevel@tonic-gate (void) strlcat(path, fanp->devfs_path, sizeof (path));
8337c478bd9Sstevel@tonic-gate fd = open(path, O_RDWR);
8347c478bd9Sstevel@tonic-gate if (fd == -1) {
8357c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT,
8367c478bd9Sstevel@tonic-gate ENV_FAN_OPEN_FAIL, fanp->name,
8377c478bd9Sstevel@tonic-gate fanp->devfs_path, errno, strerror(errno));
8387c478bd9Sstevel@tonic-gate fanp->present = B_FALSE;
8397c478bd9Sstevel@tonic-gate continue;
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate fanp->fd = fd;
8427c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) {
8437c478bd9Sstevel@tonic-gate fanp->speedrange =
8447c478bd9Sstevel@tonic-gate adm_speedrange_map[(n >> 6) & 0x03];
8457c478bd9Sstevel@tonic-gate } else {
8467c478bd9Sstevel@tonic-gate fanp->speedrange = FAN_RANGE_DEFAULT;
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate fanp->present = B_TRUE;
8507c478bd9Sstevel@tonic-gate fanp->fanstat = 0;
8517c478bd9Sstevel@tonic-gate fanp->cspeed = TACH_UNKNOWN;
8527c478bd9Sstevel@tonic-gate fanp->lspeed = TACH_UNKNOWN;
8537c478bd9Sstevel@tonic-gate fanp->conccnt = 0;
8547c478bd9Sstevel@tonic-gate fancnt++;
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate return (fancnt);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate * Open temperature sensor devices and initialize per sensor data structure.
8617c478bd9Sstevel@tonic-gate * Returns #sensors found.
8627c478bd9Sstevel@tonic-gate */
8637c478bd9Sstevel@tonic-gate static int
envd_setup_sensors(void)8647c478bd9Sstevel@tonic-gate envd_setup_sensors(void)
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
8677c478bd9Sstevel@tonic-gate sensor_ctrl_blk_t *es_ptr;
8687c478bd9Sstevel@tonic-gate table_t *tblp;
8697c478bd9Sstevel@tonic-gate char path[PATH_MAX];
8707c478bd9Sstevel@tonic-gate int sensorcnt = 0;
8717c478bd9Sstevel@tonic-gate int i, j, nentries;
8727c478bd9Sstevel@tonic-gate int16_t tmin = 0;
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; ++i) {
8757c478bd9Sstevel@tonic-gate sensorp = &envd_sensors[i];
8767c478bd9Sstevel@tonic-gate /* Initialize sensor's initial state */
8777c478bd9Sstevel@tonic-gate sensorp->shutdown_initiated = B_FALSE;
8787c478bd9Sstevel@tonic-gate sensorp->warning_tstamp = 0;
8797c478bd9Sstevel@tonic-gate sensorp->shutdown_tstamp = 0;
8807c478bd9Sstevel@tonic-gate sensorp->error = 0;
8817c478bd9Sstevel@tonic-gate sensorp->crtbl = NULL;
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate (void) strcpy(path, "/devices");
8847c478bd9Sstevel@tonic-gate (void) strlcat(path, sensorp->devfs_path,
8857c478bd9Sstevel@tonic-gate sizeof (path));
8867c478bd9Sstevel@tonic-gate sensorp->fd = open(path, O_RDWR);
8877c478bd9Sstevel@tonic-gate if (sensorp->fd == -1) {
8887c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
8897c478bd9Sstevel@tonic-gate sensorp->name, sensorp->devfs_path,
8907c478bd9Sstevel@tonic-gate errno, strerror(errno));
8917c478bd9Sstevel@tonic-gate sensorp->present = B_FALSE;
8927c478bd9Sstevel@tonic-gate continue;
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate sensorp->present = B_TRUE;
8957c478bd9Sstevel@tonic-gate sensorcnt++;
8967c478bd9Sstevel@tonic-gate
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate * Get Tmin
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
902*ada2da53SToomas Soome &tmin) != -1) {
9037c478bd9Sstevel@tonic-gate sensorp->tmin = TMIN(tmin);
9047c478bd9Sstevel@tonic-gate } else {
9057c478bd9Sstevel@tonic-gate sensorp->tmin = -1;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate if (env_debug)
9087c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, "Sensor %s tmin %d",
9097c478bd9Sstevel@tonic-gate sensorp->name, sensorp->tmin);
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate * Create a correction table
9137c478bd9Sstevel@tonic-gate * if correction pairs are present in es
9147c478bd9Sstevel@tonic-gate * segment.
9157c478bd9Sstevel@tonic-gate */
9167c478bd9Sstevel@tonic-gate es_ptr = sensorp->es_ptr;
9177c478bd9Sstevel@tonic-gate
9187c478bd9Sstevel@tonic-gate if (es_ptr == NULL) {
9197c478bd9Sstevel@tonic-gate continue;
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate nentries = es_ptr->correctionEntries;
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate if (nentries < 2) {
9247c478bd9Sstevel@tonic-gate if (env_debug)
9257c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, "sensor correction <2");
9267c478bd9Sstevel@tonic-gate continue;
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate sensorp->crtbl = init_table(nentries);
9307c478bd9Sstevel@tonic-gate if (sensorp->crtbl == NULL)
9317c478bd9Sstevel@tonic-gate continue;
9327c478bd9Sstevel@tonic-gate tblp = sensorp->crtbl;
9337c478bd9Sstevel@tonic-gate tblp->xymap[0].x =
9347c478bd9Sstevel@tonic-gate (char)es_ptr->correctionPair[0].measured;
9357c478bd9Sstevel@tonic-gate tblp->xymap[0].y =
9367c478bd9Sstevel@tonic-gate (char)es_ptr->correctionPair[0].corrected;
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate for (j = 1; j < nentries; ++j) {
9397c478bd9Sstevel@tonic-gate tblp->xymap[j].x =
9407c478bd9Sstevel@tonic-gate (char)es_ptr->correctionPair[j].measured;
9417c478bd9Sstevel@tonic-gate tblp->xymap[j].y =
9427c478bd9Sstevel@tonic-gate (char)es_ptr->correctionPair[j].corrected;
9437c478bd9Sstevel@tonic-gate
9447c478bd9Sstevel@tonic-gate if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) {
9457c478bd9Sstevel@tonic-gate fini_table(tblp);
9467c478bd9Sstevel@tonic-gate sensorp->crtbl = NULL;
9477c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
9487c478bd9Sstevel@tonic-gate FRU_SEEPROM_NAME);
9497c478bd9Sstevel@tonic-gate break;
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate
9537c478bd9Sstevel@tonic-gate if (env_debug) {
9547c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, "Sensor correction %s",
9557c478bd9Sstevel@tonic-gate sensorp->name);
9567c478bd9Sstevel@tonic-gate for (j = 0; j < nentries; j++)
9577c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, " %d %d",
9587c478bd9Sstevel@tonic-gate tblp->xymap[j].x, tblp->xymap[j].y);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate return (sensorcnt);
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate /*
9647c478bd9Sstevel@tonic-gate * Modify ADM Tmin/ranges depending what power level
9657c478bd9Sstevel@tonic-gate * we are from.
9667c478bd9Sstevel@tonic-gate */
9677c478bd9Sstevel@tonic-gate static void
updateadm_ranges(char * name,uchar_t cur_lpstate)9687c478bd9Sstevel@tonic-gate updateadm_ranges(char *name, uchar_t cur_lpstate)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
9717c478bd9Sstevel@tonic-gate fan_ctrl_blk_t *fanctl;
9727c478bd9Sstevel@tonic-gate uchar_t tmin;
9737c478bd9Sstevel@tonic-gate uchar_t trange;
9747c478bd9Sstevel@tonic-gate uint16_t tdata;
9757c478bd9Sstevel@tonic-gate int sysfd;
9767c478bd9Sstevel@tonic-gate uchar_t sys_id = CPU_HWM_ID;
9777c478bd9Sstevel@tonic-gate uint8_t mode;
9787c478bd9Sstevel@tonic-gate static uint16_t tsave = 0;
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate sensorp = sensor_lookup(name);
9817c478bd9Sstevel@tonic-gate if (sensorp == NULL)
9827c478bd9Sstevel@tonic-gate return;
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate /*
9857c478bd9Sstevel@tonic-gate * If there is only one Control pairs then return
9867c478bd9Sstevel@tonic-gate */
9877c478bd9Sstevel@tonic-gate fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr;
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate if (fanctl != NULL && fanctl->no_ctl_pairs <= 1)
9907c478bd9Sstevel@tonic-gate return;
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate * if fan control specifies that ranges are same then
9947c478bd9Sstevel@tonic-gate * we skip re-programming adm chip.
9957c478bd9Sstevel@tonic-gate */
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate tmin = fanctl->fan_ctl_pairs[0].tMin;
9987c478bd9Sstevel@tonic-gate trange = fanctl->fan_ctl_pairs[0].tRange;
9997c478bd9Sstevel@tonic-gate if ((tmin == fanctl->fan_ctl_pairs[1].tMin) &&
10007c478bd9Sstevel@tonic-gate (trange == fanctl->fan_ctl_pairs[1].tRange))
10017c478bd9Sstevel@tonic-gate return;
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate sysfd = open(hwm_devs[sys_id], O_RDWR);
10047c478bd9Sstevel@tonic-gate if (sysfd == -1) {
10057c478bd9Sstevel@tonic-gate if (env_debug)
10067c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id],
1007*ada2da53SToomas Soome errno, strerror(errno));
10087c478bd9Sstevel@tonic-gate return;
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate /* Read ADM default value only for the first time */
10117c478bd9Sstevel@tonic-gate if (tsave == 0) {
10127c478bd9Sstevel@tonic-gate if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1013*ada2da53SToomas Soome &tsave) == -1) {
10147c478bd9Sstevel@tonic-gate if (env_debug)
10157c478bd9Sstevel@tonic-gate envd_log(LOG_ERR,
10167c478bd9Sstevel@tonic-gate "read tminrange ioctl failed");
10177c478bd9Sstevel@tonic-gate (void) close(sysfd);
10187c478bd9Sstevel@tonic-gate return;
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate
10227c478bd9Sstevel@tonic-gate /*
10237c478bd9Sstevel@tonic-gate * Need to reinit ADM to manual mode for Tmin range to be
10247c478bd9Sstevel@tonic-gate * effective.
10257c478bd9Sstevel@tonic-gate */
10267c478bd9Sstevel@tonic-gate mode = ADM1031_MANUAL_MODE;
10277c478bd9Sstevel@tonic-gate if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
10287c478bd9Sstevel@tonic-gate if (env_debug)
10297c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE);
10307c478bd9Sstevel@tonic-gate (void) close(sysfd);
10317c478bd9Sstevel@tonic-gate return;
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate if (cur_lpstate == 1) {
10357c478bd9Sstevel@tonic-gate /*
10367c478bd9Sstevel@tonic-gate * ADM 1031 Tmin/Trange register need to be reprogrammed.
10377c478bd9Sstevel@tonic-gate */
10387c478bd9Sstevel@tonic-gate tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS)
1039*ada2da53SToomas Soome << TMIN_SHIFT);
10407c478bd9Sstevel@tonic-gate /* Need to pack tRange in ADM bits 2:0 */
10417c478bd9Sstevel@tonic-gate switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) {
10427c478bd9Sstevel@tonic-gate case 5:
10437c478bd9Sstevel@tonic-gate break;
10447c478bd9Sstevel@tonic-gate
10457c478bd9Sstevel@tonic-gate case 10:
10467c478bd9Sstevel@tonic-gate tdata |= 1;
10477c478bd9Sstevel@tonic-gate break;
10487c478bd9Sstevel@tonic-gate
10497c478bd9Sstevel@tonic-gate case 20:
10507c478bd9Sstevel@tonic-gate tdata |= 2;
10517c478bd9Sstevel@tonic-gate break;
10527c478bd9Sstevel@tonic-gate
10537c478bd9Sstevel@tonic-gate case 40:
10547c478bd9Sstevel@tonic-gate tdata |= 3;
10557c478bd9Sstevel@tonic-gate break;
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate case 80:
10587c478bd9Sstevel@tonic-gate tdata |= 4;
10597c478bd9Sstevel@tonic-gate break;
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate } else
10627c478bd9Sstevel@tonic-gate tdata = tsave;
10637c478bd9Sstevel@tonic-gate
10647c478bd9Sstevel@tonic-gate if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE,
10657c478bd9Sstevel@tonic-gate &tdata) != -1)
10667c478bd9Sstevel@tonic-gate sensorp->tmin = TMIN(tdata);
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate sensorp->tmin = TMIN(tdata);
10697c478bd9Sstevel@tonic-gate
10707c478bd9Sstevel@tonic-gate mode = ADM1031_AUTO_MODE;
10717c478bd9Sstevel@tonic-gate if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
10727c478bd9Sstevel@tonic-gate if (env_debug)
10737c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_ADM_AUTO_MODE);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate (void) close(sysfd);
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10797c478bd9Sstevel@tonic-gate static void *
pmthr(void * args)10807c478bd9Sstevel@tonic-gate pmthr(void *args)
10817c478bd9Sstevel@tonic-gate {
10827c478bd9Sstevel@tonic-gate pm_state_change_t pmstate;
10837c478bd9Sstevel@tonic-gate char physpath[PATH_MAX];
10847c478bd9Sstevel@tonic-gate int pre_lpstate;
10857c478bd9Sstevel@tonic-gate
10867c478bd9Sstevel@tonic-gate pmstate.physpath = physpath;
10877c478bd9Sstevel@tonic-gate pmstate.size = sizeof (physpath);
10887c478bd9Sstevel@tonic-gate cur_lpstate = 0;
10897c478bd9Sstevel@tonic-gate pre_lpstate = 1;
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate pm_fd = open(PM_DEVICE, O_RDWR);
10927c478bd9Sstevel@tonic-gate if (pm_fd == -1) {
10937c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
10947c478bd9Sstevel@tonic-gate return (NULL);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate for (;;) {
10977c478bd9Sstevel@tonic-gate /*
10987c478bd9Sstevel@tonic-gate * Get PM state change events to check if the system
10997c478bd9Sstevel@tonic-gate * is in lowest power state and adjust ADM hardware
11007c478bd9Sstevel@tonic-gate * monitor's fan speed settings.
11017c478bd9Sstevel@tonic-gate *
11027c478bd9Sstevel@tonic-gate * To minimize polling, we use the blocking interface
11037c478bd9Sstevel@tonic-gate * to get the power state change event here.
11047c478bd9Sstevel@tonic-gate */
11057c478bd9Sstevel@tonic-gate if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
11067c478bd9Sstevel@tonic-gate if (errno != EINTR)
11077c478bd9Sstevel@tonic-gate break;
11087c478bd9Sstevel@tonic-gate continue;
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate do {
11117c478bd9Sstevel@tonic-gate if (env_debug) {
11127c478bd9Sstevel@tonic-gate envd_log(LOG_INFO,
1113*ada2da53SToomas Soome "pmstate event:0x%x flags:%x comp:%d "
1114*ada2da53SToomas Soome "oldval:%d newval:%d path:%s\n",
1115*ada2da53SToomas Soome pmstate.event, pmstate.flags,
1116*ada2da53SToomas Soome pmstate.component,
1117*ada2da53SToomas Soome pmstate.old_level,
1118*ada2da53SToomas Soome pmstate.new_level,
1119*ada2da53SToomas Soome pmstate.physpath);
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate cur_lpstate =
11227c478bd9Sstevel@tonic-gate (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
11237c478bd9Sstevel@tonic-gate } while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
11247c478bd9Sstevel@tonic-gate /*
11257c478bd9Sstevel@tonic-gate * Change ADM ranges as per E* Requirements. Update
11267c478bd9Sstevel@tonic-gate * happens only for valid state changes.
11277c478bd9Sstevel@tonic-gate */
11287c478bd9Sstevel@tonic-gate if (pre_lpstate != cur_lpstate) {
11297c478bd9Sstevel@tonic-gate pre_lpstate = cur_lpstate;
11307c478bd9Sstevel@tonic-gate updateadm_ranges(SENSOR_SYS_IN, cur_lpstate);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate }
11337c478bd9Sstevel@tonic-gate /*NOTREACHED*/
11347c478bd9Sstevel@tonic-gate return (NULL);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate
11377c478bd9Sstevel@tonic-gate /*
11387c478bd9Sstevel@tonic-gate * This function is used to reasonably predict the
11397c478bd9Sstevel@tonic-gate * state of the fan (ON/OFF) using tmin and current temperature.
11407c478bd9Sstevel@tonic-gate *
11417c478bd9Sstevel@tonic-gate * We know the fan is on if temp >= tmin and fan is off if
11427c478bd9Sstevel@tonic-gate * temp < (Tmin - Hysterisis).
11437c478bd9Sstevel@tonic-gate *
11447c478bd9Sstevel@tonic-gate * When the temperature is in between we don't know if the fan is on/off
11457c478bd9Sstevel@tonic-gate * because the temperature could be decreasing and not have crossed
11467c478bd9Sstevel@tonic-gate * Tmin - hysterisis and vice a versa.
11477c478bd9Sstevel@tonic-gate *
11487c478bd9Sstevel@tonic-gate * FAN ON
11497c478bd9Sstevel@tonic-gate * Tmin
1150*ada2da53SToomas Soome * -------------------------------------------
11517c478bd9Sstevel@tonic-gate *
1152*ada2da53SToomas Soome * FAN ON/OFF
11537c478bd9Sstevel@tonic-gate *
1154*ada2da53SToomas Soome * --------------------------------------------
11557c478bd9Sstevel@tonic-gate * Tmin - Hysterisis
11567c478bd9Sstevel@tonic-gate * FAN OFF
11577c478bd9Sstevel@tonic-gate *
11587c478bd9Sstevel@tonic-gate * To solve the problem of finding out if the fan is on/off in our gray region
11597c478bd9Sstevel@tonic-gate * we keep track of the last read tach and the current read tach. From
11607c478bd9Sstevel@tonic-gate * experimentation and from discussions with analog devices it is unlikely that
11617c478bd9Sstevel@tonic-gate * if the fans are on we will get a constant tach reading more than 5 times in
11627c478bd9Sstevel@tonic-gate * a row. This is not the most fool proof approach but the best we can do.
11637c478bd9Sstevel@tonic-gate *
11647c478bd9Sstevel@tonic-gate * This routine implements the above logic for a sensor with an
11657c478bd9Sstevel@tonic-gate * associated fan. The caller garauntees sensorp and fanp are not null.
11667c478bd9Sstevel@tonic-gate */
11677c478bd9Sstevel@tonic-gate static void
check_fanstat(env_sensor_t * sensorp)11687c478bd9Sstevel@tonic-gate check_fanstat(env_sensor_t *sensorp)
11697c478bd9Sstevel@tonic-gate {
11707c478bd9Sstevel@tonic-gate env_fan_t *fanp = sensorp->fanp;
11717c478bd9Sstevel@tonic-gate tempr_t temp;
11727c478bd9Sstevel@tonic-gate uint8_t fanspeed;
11737c478bd9Sstevel@tonic-gate
11747c478bd9Sstevel@tonic-gate if (get_raw_temperature(sensorp, &temp) == -1)
11757c478bd9Sstevel@tonic-gate return;
11767c478bd9Sstevel@tonic-gate
11777c478bd9Sstevel@tonic-gate if (temp < (sensorp->tmin - ADM_HYSTERISIS)) {
11787c478bd9Sstevel@tonic-gate
11797c478bd9Sstevel@tonic-gate fanp->fanstat = 0; /* Fan off */
11807c478bd9Sstevel@tonic-gate fanp->lspeed = TACH_UNKNOWN; /* Reset Last read tach */
11817c478bd9Sstevel@tonic-gate fanp->conccnt = 0;
11827c478bd9Sstevel@tonic-gate
11837c478bd9Sstevel@tonic-gate } else if (temp >= sensorp->tmin) {
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate fanp->fanstat = 1; /* Fan on */
11867c478bd9Sstevel@tonic-gate fanp->lspeed = TACH_UNKNOWN;
11877c478bd9Sstevel@tonic-gate fanp->conccnt = 0;
11887c478bd9Sstevel@tonic-gate
11897c478bd9Sstevel@tonic-gate } else {
11907c478bd9Sstevel@tonic-gate if (get_raw_fan_speed(fanp, &fanspeed) == -1)
11917c478bd9Sstevel@tonic-gate return;
11927c478bd9Sstevel@tonic-gate
11937c478bd9Sstevel@tonic-gate fanp->cspeed = fanspeed;
11947c478bd9Sstevel@tonic-gate /*
11957c478bd9Sstevel@tonic-gate * First time in the gray area
11967c478bd9Sstevel@tonic-gate * set last read speed to current speed
11977c478bd9Sstevel@tonic-gate */
11987c478bd9Sstevel@tonic-gate if (fanp->lspeed == TACH_UNKNOWN) {
11997c478bd9Sstevel@tonic-gate fanp->lspeed = fanspeed;
12007c478bd9Sstevel@tonic-gate } else {
12017c478bd9Sstevel@tonic-gate if (fanp->lspeed != fanp->cspeed) {
12027c478bd9Sstevel@tonic-gate fanp->conccnt = 0;
12037c478bd9Sstevel@tonic-gate fanp->fanstat = 1;
12047c478bd9Sstevel@tonic-gate } else {
12057c478bd9Sstevel@tonic-gate fanp->conccnt++;
12067c478bd9Sstevel@tonic-gate
12077c478bd9Sstevel@tonic-gate if (fanp->conccnt >= N_SEQ_TACH)
12087c478bd9Sstevel@tonic-gate fanp->fanstat = 0;
12097c478bd9Sstevel@tonic-gate }
12107c478bd9Sstevel@tonic-gate fanp->lspeed = fanp->cspeed;
12117c478bd9Sstevel@tonic-gate }
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate /*
12157c478bd9Sstevel@tonic-gate * There is an issue with the ADM1031 chip that causes the chip
12167c478bd9Sstevel@tonic-gate * to not update the tach register in case the fan stops. The
12177c478bd9Sstevel@tonic-gate * fans stop when the temperature measured (temp) drops below
12187c478bd9Sstevel@tonic-gate * Tmin - Hysterisis and turns the fan on when the temp >= tmin.
12197c478bd9Sstevel@tonic-gate *
12207c478bd9Sstevel@tonic-gate * Since the tach registers don't update and remain stuck at the
12217c478bd9Sstevel@tonic-gate * last read tach value our get_fan_speed function always returns
12227c478bd9Sstevel@tonic-gate * a non-zero RPM reading.
12237c478bd9Sstevel@tonic-gate *
12247c478bd9Sstevel@tonic-gate * To fix this we need to figure out when the fans will be on/off
12257c478bd9Sstevel@tonic-gate * depending on the current temperature. Currently we poll for
12267c478bd9Sstevel@tonic-gate * interrupts, we can use that loop to determine what the current
12277c478bd9Sstevel@tonic-gate * temperature is and if the fans should be on/off.
12287c478bd9Sstevel@tonic-gate *
12297c478bd9Sstevel@tonic-gate * We get current temperature and check the fans.
12307c478bd9Sstevel@tonic-gate */
12317c478bd9Sstevel@tonic-gate static void
monitor_fanstat(void)12327c478bd9Sstevel@tonic-gate monitor_fanstat(void)
12337c478bd9Sstevel@tonic-gate {
12347c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
12357c478bd9Sstevel@tonic-gate env_fan_t *fanp;
12367c478bd9Sstevel@tonic-gate int i;
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; i++) {
12397c478bd9Sstevel@tonic-gate sensorp = &envd_sensors[i];
12407c478bd9Sstevel@tonic-gate
12417c478bd9Sstevel@tonic-gate if (!sensorp)
12427c478bd9Sstevel@tonic-gate continue;
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate fanp = sensorp->fanp;
12457c478bd9Sstevel@tonic-gate
12467c478bd9Sstevel@tonic-gate if (!fanp)
12477c478bd9Sstevel@tonic-gate continue;
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate if (sensorp->tmin != -1) {
12507c478bd9Sstevel@tonic-gate check_fanstat(sensorp);
12517c478bd9Sstevel@tonic-gate } else {
12527c478bd9Sstevel@tonic-gate fanp->fanstat = 1;
12537c478bd9Sstevel@tonic-gate }
12547c478bd9Sstevel@tonic-gate }
12557c478bd9Sstevel@tonic-gate /*
12567c478bd9Sstevel@tonic-gate * On Taco both the system fans are driven by one
12577c478bd9Sstevel@tonic-gate * sensor (sys-in) and connected to the sys-in tach.
12587c478bd9Sstevel@tonic-gate */
12597c478bd9Sstevel@tonic-gate envd_sys_out_fan.fanstat = envd_sys_in_fan.fanstat;
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate
12637c478bd9Sstevel@tonic-gate static int
handle_overtemp_interrupt(int hwm_id)12647c478bd9Sstevel@tonic-gate handle_overtemp_interrupt(int hwm_id)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate env_sensor_t *sensorp;
12677c478bd9Sstevel@tonic-gate tempr_t temp;
12687c478bd9Sstevel@tonic-gate uchar_t smap[MAX_SENSORS];
12697c478bd9Sstevel@tonic-gate time_t ct;
12707c478bd9Sstevel@tonic-gate uchar_t i;
12717c478bd9Sstevel@tonic-gate char msgbuf[BUFSIZ];
12727c478bd9Sstevel@tonic-gate char syscmd[BUFSIZ];
12737c478bd9Sstevel@tonic-gate boolean_t return_flag;
12747c478bd9Sstevel@tonic-gate
12757c478bd9Sstevel@tonic-gate /* Clear Map of Sensor Entries */
12767c478bd9Sstevel@tonic-gate (void) memset(smap, SENSOR_OK, sizeof (smap));
12777c478bd9Sstevel@tonic-gate
12787c478bd9Sstevel@tonic-gate for (;;) {
12797c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; i++) {
12807c478bd9Sstevel@tonic-gate sensorp = &envd_sensors[i];
12817c478bd9Sstevel@tonic-gate
12827c478bd9Sstevel@tonic-gate /*
12837c478bd9Sstevel@tonic-gate * Check whether the sensor belongs to the
12847c478bd9Sstevel@tonic-gate * interrupting ADM hardware monitor
12857c478bd9Sstevel@tonic-gate */
12867c478bd9Sstevel@tonic-gate if (sensorp->hwm_id != hwm_id)
12877c478bd9Sstevel@tonic-gate continue;
12887c478bd9Sstevel@tonic-gate
12897c478bd9Sstevel@tonic-gate /*
12907c478bd9Sstevel@tonic-gate * if shutdown is initiated then we simply loop
12917c478bd9Sstevel@tonic-gate * through the sensors until shutdown
12927c478bd9Sstevel@tonic-gate */
12937c478bd9Sstevel@tonic-gate if (sensorp->shutdown_initiated == B_TRUE)
12947c478bd9Sstevel@tonic-gate continue;
12957c478bd9Sstevel@tonic-gate
12967c478bd9Sstevel@tonic-gate /* get current temp for this sensor */
12977c478bd9Sstevel@tonic-gate if (get_temperature(sensorp, &temp) == -1)
12987c478bd9Sstevel@tonic-gate continue;
12997c478bd9Sstevel@tonic-gate
13007c478bd9Sstevel@tonic-gate sensorp->cur_temp = temp;
13017c478bd9Sstevel@tonic-gate
13027c478bd9Sstevel@tonic-gate if (env_debug)
13037c478bd9Sstevel@tonic-gate envd_log(LOG_ERR,
1304*ada2da53SToomas Soome "sensor name %s, cur temp %d, "
1305*ada2da53SToomas Soome "HW %d LW %d SD %d LS %d\n",
1306*ada2da53SToomas Soome sensorp->name, temp,
1307*ada2da53SToomas Soome sensorp->es_ptr->high_warning,
1308*ada2da53SToomas Soome (int)sensorp->es_ptr->low_warning,
1309*ada2da53SToomas Soome sensorp->es_ptr->high_shutdown,
1310*ada2da53SToomas Soome (int)sensorp->es_ptr->low_shutdown);
13117c478bd9Sstevel@tonic-gate
13127c478bd9Sstevel@tonic-gate if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) {
13137c478bd9Sstevel@tonic-gate /*
13147c478bd9Sstevel@tonic-gate * Log on warning atmost one second
13157c478bd9Sstevel@tonic-gate */
13167c478bd9Sstevel@tonic-gate ct = (time_t)(gethrtime() / NANOSEC);
13177c478bd9Sstevel@tonic-gate if ((ct - sensorp->warning_tstamp) >=
13187c478bd9Sstevel@tonic-gate warning_interval) {
13197c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT,
13207c478bd9Sstevel@tonic-gate ENV_WARNING_MSG, sensorp->name,
13217c478bd9Sstevel@tonic-gate temp,
13227c478bd9Sstevel@tonic-gate sensorp->es_ptr->low_warning,
13237c478bd9Sstevel@tonic-gate sensorp->es_ptr->high_warning);
13247c478bd9Sstevel@tonic-gate sensorp->warning_tstamp = ct;
13257c478bd9Sstevel@tonic-gate }
13267c478bd9Sstevel@tonic-gate smap[i] = SENSOR_WARN;
13277c478bd9Sstevel@tonic-gate } else {
13287c478bd9Sstevel@tonic-gate /*
13297c478bd9Sstevel@tonic-gate * We will fall in this caterory only if
13307c478bd9Sstevel@tonic-gate * Temperature drops/increases from warning
13317c478bd9Sstevel@tonic-gate * threshold. If so we set sensor map to
13327c478bd9Sstevel@tonic-gate * OK so that we can exit the loop if
13337c478bd9Sstevel@tonic-gate * shutdown not initiated.
13347c478bd9Sstevel@tonic-gate */
13357c478bd9Sstevel@tonic-gate smap[i] = SENSOR_OK;
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) &&
13397c478bd9Sstevel@tonic-gate !shutdown_override) {
13407c478bd9Sstevel@tonic-gate ct = (time_t)(gethrtime() / NANOSEC);
13417c478bd9Sstevel@tonic-gate if (sensorp->shutdown_tstamp == 0)
13427c478bd9Sstevel@tonic-gate sensorp->shutdown_tstamp = ct;
13437c478bd9Sstevel@tonic-gate if ((ct - sensorp->shutdown_tstamp) >=
13447c478bd9Sstevel@tonic-gate shutdown_interval) {
13457c478bd9Sstevel@tonic-gate sensorp->shutdown_initiated = B_TRUE;
13467c478bd9Sstevel@tonic-gate (void) snprintf(msgbuf, sizeof (msgbuf),
13477c478bd9Sstevel@tonic-gate ENV_SHUTDOWN_MSG, sensorp->name,
13487c478bd9Sstevel@tonic-gate temp,
13497c478bd9Sstevel@tonic-gate sensorp->es_ptr->low_shutdown,
13507c478bd9Sstevel@tonic-gate sensorp->es_ptr->high_shutdown);
13517c478bd9Sstevel@tonic-gate envd_log(LOG_ALERT, msgbuf);
13527c478bd9Sstevel@tonic-gate }
13537c478bd9Sstevel@tonic-gate if (system_shutdown_started == B_FALSE) {
13547c478bd9Sstevel@tonic-gate (void) snprintf(syscmd, sizeof (syscmd),
13557c478bd9Sstevel@tonic-gate "%s \"%s\"", SHUTDOWN_CMD, msgbuf);
13567c478bd9Sstevel@tonic-gate envd_log(LOG_ALERT, syscmd);
13577c478bd9Sstevel@tonic-gate system_shutdown_started = B_TRUE;
13587c478bd9Sstevel@tonic-gate (void) system(syscmd);
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate } else if (sensorp->shutdown_tstamp != 0)
13617c478bd9Sstevel@tonic-gate sensorp->shutdown_tstamp = 0;
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate
13647c478bd9Sstevel@tonic-gate /*
13657c478bd9Sstevel@tonic-gate * Sweep thorugh Sensor Map and if warnings OR shutdown
13667c478bd9Sstevel@tonic-gate * are not logged then return to caller.
13677c478bd9Sstevel@tonic-gate */
13687c478bd9Sstevel@tonic-gate return_flag = B_TRUE;
13697c478bd9Sstevel@tonic-gate for (i = 0; i < N_ENVD_SENSORS; i++)
13707c478bd9Sstevel@tonic-gate if (smap[i] == SENSOR_WARN)
13717c478bd9Sstevel@tonic-gate return_flag = B_FALSE;
13727c478bd9Sstevel@tonic-gate
13737c478bd9Sstevel@tonic-gate if ((return_flag == B_TRUE) &&
13747c478bd9Sstevel@tonic-gate (system_shutdown_started == B_FALSE)) {
13757c478bd9Sstevel@tonic-gate return (1);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate (void) envd_sleep(SENSORPOLL_INTERVAL);
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate * This is env thread which monitors the current temperature when
13847c478bd9Sstevel@tonic-gate * warning threshold is exceeded. The job is to make sure it does
13857c478bd9Sstevel@tonic-gate * not execced/decrease shutdown threshold. If it does it will start
13867c478bd9Sstevel@tonic-gate * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
13877c478bd9Sstevel@tonic-gate * For Taco there will be one thread for the ADM chip.
13887c478bd9Sstevel@tonic-gate */
13897c478bd9Sstevel@tonic-gate static void *
ovtemp_thr(void * args)13907c478bd9Sstevel@tonic-gate ovtemp_thr(void *args)
13917c478bd9Sstevel@tonic-gate {
13927c478bd9Sstevel@tonic-gate int fd;
13937c478bd9Sstevel@tonic-gate uint8_t stat[2];
13947c478bd9Sstevel@tonic-gate int hwm_id = (int)args;
13957c478bd9Sstevel@tonic-gate int err;
13967c478bd9Sstevel@tonic-gate
13977c478bd9Sstevel@tonic-gate fd = open(hwm_devs[hwm_id], O_RDWR);
13987c478bd9Sstevel@tonic-gate if (fd == -1) {
13997c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id],
14007c478bd9Sstevel@tonic-gate errno, strerror(errno));
14017c478bd9Sstevel@tonic-gate return (NULL);
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate
14047c478bd9Sstevel@tonic-gate for (;;) {
14057c478bd9Sstevel@tonic-gate
14067c478bd9Sstevel@tonic-gate /*
14077c478bd9Sstevel@tonic-gate * Monitor the sensors to update status
14087c478bd9Sstevel@tonic-gate */
14097c478bd9Sstevel@tonic-gate if (mon_fanstat)
14107c478bd9Sstevel@tonic-gate monitor_fanstat();
14117c478bd9Sstevel@tonic-gate
14127c478bd9Sstevel@tonic-gate /*
14137c478bd9Sstevel@tonic-gate * Sleep for specified seconds before issuing IOCTL
14147c478bd9Sstevel@tonic-gate * again.
14157c478bd9Sstevel@tonic-gate */
14167c478bd9Sstevel@tonic-gate (void) envd_sleep(INTERRUPTPOLL_INTERVAL);
14177c478bd9Sstevel@tonic-gate
14187c478bd9Sstevel@tonic-gate /*
14197c478bd9Sstevel@tonic-gate * Read ADM1031 two Status Register to determine source of
14207c478bd9Sstevel@tonic-gate * Interrupts.
14217c478bd9Sstevel@tonic-gate */
14227c478bd9Sstevel@tonic-gate if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1)
14237c478bd9Sstevel@tonic-gate err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]);
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate if (err == -1) {
14267c478bd9Sstevel@tonic-gate if (env_debug)
14277c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, "OverTemp: Status Error");
14287c478bd9Sstevel@tonic-gate continue;
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate if (env_debug)
14327c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, "INTR %s Stat1 %x, Stat2 %x",
14337c478bd9Sstevel@tonic-gate hwm_devs[hwm_id], stat[0], stat[1]);
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate if (stat[0] & FANFAULT)
14367c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_FAN_FAULT,
14377c478bd9Sstevel@tonic-gate hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN1]);
14387c478bd9Sstevel@tonic-gate
14397c478bd9Sstevel@tonic-gate if (stat[1] & FANFAULT)
14407c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENV_FAN_FAULT,
14417c478bd9Sstevel@tonic-gate hwm_devs[hwm_id], hwm_fans[hwm_id][HWM_FAN2]);
14427c478bd9Sstevel@tonic-gate
14437c478bd9Sstevel@tonic-gate /*
14447c478bd9Sstevel@tonic-gate * Check respective Remote/Local High, Low before start
14457c478bd9Sstevel@tonic-gate * manual monitoring
14467c478bd9Sstevel@tonic-gate */
14477c478bd9Sstevel@tonic-gate if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK))
14487c478bd9Sstevel@tonic-gate (void) handle_overtemp_interrupt(hwm_id);
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate /*NOTREACHED*/
14517c478bd9Sstevel@tonic-gate return (NULL);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate * Setup envrionmental monitor state and start threads to monitor
14567c478bd9Sstevel@tonic-gate * temperature and power management state.
14577c478bd9Sstevel@tonic-gate * Returns -1 on error, 0 if successful.
14587c478bd9Sstevel@tonic-gate */
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate static int
envd_setup(void)14617c478bd9Sstevel@tonic-gate envd_setup(void)
14627c478bd9Sstevel@tonic-gate {
14637c478bd9Sstevel@tonic-gate int ret;
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate if (getenv("SUNW_piclenvd_debug") != NULL)
14667c478bd9Sstevel@tonic-gate env_debug = 1;
14677c478bd9Sstevel@tonic-gate
14687c478bd9Sstevel@tonic-gate if (pthread_attr_init(&thr_attr) != 0 ||
14697c478bd9Sstevel@tonic-gate pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
14707c478bd9Sstevel@tonic-gate return (-1);
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate
14737c478bd9Sstevel@tonic-gate ret = envd_es_setup();
14747c478bd9Sstevel@tonic-gate if (ret < 0) {
14757c478bd9Sstevel@tonic-gate ovtemp_monitor = 0;
14767c478bd9Sstevel@tonic-gate pm_monitor = 0;
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate * Setup temperature sensors and fail if we can't open
14827c478bd9Sstevel@tonic-gate * at least one sensor.
14837c478bd9Sstevel@tonic-gate */
14847c478bd9Sstevel@tonic-gate if (envd_setup_sensors() <= 0) {
1485*ada2da53SToomas Soome return (0);
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate
14887c478bd9Sstevel@tonic-gate /*
14897c478bd9Sstevel@tonic-gate * Setup fan device (don't fail even if we can't access
14907c478bd9Sstevel@tonic-gate * the fan as we can still monitor temeperature.
14917c478bd9Sstevel@tonic-gate */
14927c478bd9Sstevel@tonic-gate (void) envd_setup_fans();
14937c478bd9Sstevel@tonic-gate
14947c478bd9Sstevel@tonic-gate /* If ES Segment setup failed,don't create thread */
14957c478bd9Sstevel@tonic-gate
14967c478bd9Sstevel@tonic-gate if (ovtemp_monitor && ovtemp_thr_created == B_FALSE) {
14977c478bd9Sstevel@tonic-gate if (pthread_create(&ovtemp_thr_id, &thr_attr, ovtemp_thr,
14987c478bd9Sstevel@tonic-gate (void *)CPU_HWM_ID) != 0)
14997c478bd9Sstevel@tonic-gate envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
15007c478bd9Sstevel@tonic-gate else
15017c478bd9Sstevel@tonic-gate ovtemp_thr_created = B_TRUE;
15027c478bd9Sstevel@tonic-gate }
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * Create a thread to monitor PM state
15067c478bd9Sstevel@tonic-gate */
15077c478bd9Sstevel@tonic-gate if (pm_monitor && pmthr_created == B_FALSE) {
15087c478bd9Sstevel@tonic-gate if (pthread_create(&pmthr_tid, &thr_attr, pmthr,
15097c478bd9Sstevel@tonic-gate NULL) != 0)
15107c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
15117c478bd9Sstevel@tonic-gate else
15127c478bd9Sstevel@tonic-gate pmthr_created = B_TRUE;
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate return (0);
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate static void
piclenvd_register(void)15187c478bd9Sstevel@tonic-gate piclenvd_register(void)
15197c478bd9Sstevel@tonic-gate {
15207c478bd9Sstevel@tonic-gate picld_plugin_register(&my_reg_info);
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate
15237c478bd9Sstevel@tonic-gate static void
piclenvd_init(void)15247c478bd9Sstevel@tonic-gate piclenvd_init(void)
15257c478bd9Sstevel@tonic-gate {
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate (void) env_picl_setup_tuneables();
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /*
15307c478bd9Sstevel@tonic-gate * Setup the environmental data structures
15317c478bd9Sstevel@tonic-gate */
15327c478bd9Sstevel@tonic-gate if (envd_setup() != 0) {
15337c478bd9Sstevel@tonic-gate envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
15347c478bd9Sstevel@tonic-gate return;
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate
15377c478bd9Sstevel@tonic-gate /*
15387c478bd9Sstevel@tonic-gate * Now setup/populate PICL tree
15397c478bd9Sstevel@tonic-gate */
15407c478bd9Sstevel@tonic-gate env_picl_setup();
15417c478bd9Sstevel@tonic-gate }
15427c478bd9Sstevel@tonic-gate
15437c478bd9Sstevel@tonic-gate static void
piclenvd_fini(void)15447c478bd9Sstevel@tonic-gate piclenvd_fini(void)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate
15477c478bd9Sstevel@tonic-gate /*
15487c478bd9Sstevel@tonic-gate * Invoke env_picl_destroy() to remove any PICL nodes/properties
15497c478bd9Sstevel@tonic-gate * (including volatile properties) we created. Once this call
15507c478bd9Sstevel@tonic-gate * returns, there can't be any more calls from the PICL framework
15517c478bd9Sstevel@tonic-gate * to get current temperature or fan speed.
15527c478bd9Sstevel@tonic-gate */
15537c478bd9Sstevel@tonic-gate env_picl_destroy();
15547c478bd9Sstevel@tonic-gate envd_close_sensors();
15557c478bd9Sstevel@tonic-gate envd_close_fans();
15567c478bd9Sstevel@tonic-gate envd_es_destroy();
15577c478bd9Sstevel@tonic-gate }
15587c478bd9Sstevel@tonic-gate
15597c478bd9Sstevel@tonic-gate /*VARARGS2*/
15607c478bd9Sstevel@tonic-gate void
envd_log(int pri,const char * fmt,...)15617c478bd9Sstevel@tonic-gate envd_log(int pri, const char *fmt, ...)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate va_list ap;
15647c478bd9Sstevel@tonic-gate
15657c478bd9Sstevel@tonic-gate va_start(ap, fmt);
15667c478bd9Sstevel@tonic-gate vsyslog(pri, fmt, ap);
15677c478bd9Sstevel@tonic-gate va_end(ap);
15687c478bd9Sstevel@tonic-gate }
15697c478bd9Sstevel@tonic-gate
15707c478bd9Sstevel@tonic-gate #ifdef __lint
15717c478bd9Sstevel@tonic-gate /*
15727c478bd9Sstevel@tonic-gate * Redefine sigwait to posix style external declaration so that LINT
15737c478bd9Sstevel@tonic-gate * does not check against libc version of sigwait() and complain as
15747c478bd9Sstevel@tonic-gate * it uses different number of arguments.
15757c478bd9Sstevel@tonic-gate */
15767c478bd9Sstevel@tonic-gate #define sigwait my_posix_sigwait
15777c478bd9Sstevel@tonic-gate extern int my_posix_sigwait(const sigset_t *set, int *sig);
15787c478bd9Sstevel@tonic-gate #endif
15797c478bd9Sstevel@tonic-gate
15807c478bd9Sstevel@tonic-gate static uint_t
envd_sleep(uint_t sleep_tm)15817c478bd9Sstevel@tonic-gate envd_sleep(uint_t sleep_tm)
15827c478bd9Sstevel@tonic-gate {
15837c478bd9Sstevel@tonic-gate int sig;
15847c478bd9Sstevel@tonic-gate uint_t unslept;
15857c478bd9Sstevel@tonic-gate sigset_t alrm_mask;
15867c478bd9Sstevel@tonic-gate
15877c478bd9Sstevel@tonic-gate if (sleep_tm == 0)
15887c478bd9Sstevel@tonic-gate return (0);
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate (void) sigemptyset(&alrm_mask);
15917c478bd9Sstevel@tonic-gate (void) sigaddset(&alrm_mask, SIGALRM);
15927c478bd9Sstevel@tonic-gate
15937c478bd9Sstevel@tonic-gate (void) alarm(sleep_tm);
15947c478bd9Sstevel@tonic-gate (void) sigwait(&alrm_mask, &sig);
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate unslept = alarm(0);
15977c478bd9Sstevel@tonic-gate return (unslept);
15987c478bd9Sstevel@tonic-gate }
15997c478bd9Sstevel@tonic-gate
16007c478bd9Sstevel@tonic-gate /*
16017c478bd9Sstevel@tonic-gate * Tunables support functions
16027c478bd9Sstevel@tonic-gate */
16037c478bd9Sstevel@tonic-gate static env_tuneable_t *
tuneable_lookup(picl_prophdl_t proph)16047c478bd9Sstevel@tonic-gate tuneable_lookup(picl_prophdl_t proph)
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate int i;
16077c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep = NULL;
16087c478bd9Sstevel@tonic-gate
16097c478bd9Sstevel@tonic-gate for (i = 0; i < ntuneables; i++) {
16107c478bd9Sstevel@tonic-gate tuneablep = &tuneables[i];
16117c478bd9Sstevel@tonic-gate if (tuneablep->proph == proph)
16127c478bd9Sstevel@tonic-gate return (tuneablep);
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
16157c478bd9Sstevel@tonic-gate return (NULL);
16167c478bd9Sstevel@tonic-gate }
16177c478bd9Sstevel@tonic-gate
16187c478bd9Sstevel@tonic-gate static int
get_tach(ptree_rarg_t * parg,void * buf)16197c478bd9Sstevel@tonic-gate get_tach(ptree_rarg_t *parg, void *buf)
16207c478bd9Sstevel@tonic-gate {
16217c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
16227c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
16237c478bd9Sstevel@tonic-gate int fd;
16247c478bd9Sstevel@tonic-gate int8_t cfg;
16257c478bd9Sstevel@tonic-gate
16267c478bd9Sstevel@tonic-gate proph = parg->proph;
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
16297c478bd9Sstevel@tonic-gate
16307c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
16317c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate fd = open(CPU_HWM_DEVFS, O_RDWR);
16347c478bd9Sstevel@tonic-gate
16357c478bd9Sstevel@tonic-gate if (fd == -1) {
16367c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
16407c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16417c478bd9Sstevel@tonic-gate }
16427c478bd9Sstevel@tonic-gate
16437c478bd9Sstevel@tonic-gate if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
16447c478bd9Sstevel@tonic-gate *((int *)tuneablep->value) = ENABLE;
16457c478bd9Sstevel@tonic-gate
16467c478bd9Sstevel@tonic-gate } else {
16477c478bd9Sstevel@tonic-gate *((int *)tuneablep->value) = DISABLE;
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate
16507c478bd9Sstevel@tonic-gate (void) memcpy(buf, tuneablep->value,
16517c478bd9Sstevel@tonic-gate tuneablep->nbytes);
16527c478bd9Sstevel@tonic-gate
16537c478bd9Sstevel@tonic-gate (void) close(fd);
16547c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate
16577c478bd9Sstevel@tonic-gate static int
set_tach(ptree_warg_t * parg,const void * buf)16587c478bd9Sstevel@tonic-gate set_tach(ptree_warg_t *parg, const void *buf)
16597c478bd9Sstevel@tonic-gate {
16607c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
16617c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
16627c478bd9Sstevel@tonic-gate int fd, val;
16637c478bd9Sstevel@tonic-gate int8_t cfg;
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate if (parg->cred.dc_euid != 0)
16667c478bd9Sstevel@tonic-gate return (PICL_PERMDENIED);
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate proph = parg->proph;
16697c478bd9Sstevel@tonic-gate
16707c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
16737c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate fd = open(CPU_HWM_DEVFS, O_RDWR);
16767c478bd9Sstevel@tonic-gate
16777c478bd9Sstevel@tonic-gate if (fd == -1) {
16787c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16797c478bd9Sstevel@tonic-gate }
16807c478bd9Sstevel@tonic-gate
16817c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
16827c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate (void) memcpy(&val, (caddr_t)buf, sizeof (val));
16867c478bd9Sstevel@tonic-gate
16877c478bd9Sstevel@tonic-gate if (val == ENABLE) {
16887c478bd9Sstevel@tonic-gate cfg |= TACH_ENABLE_MASK;
16897c478bd9Sstevel@tonic-gate } else if (val == DISABLE) {
16907c478bd9Sstevel@tonic-gate cfg &= ~TACH_ENABLE_MASK;
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate
16937c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
16947c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate (void) close(fd);
16987c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate static int
get_monitor_mode(ptree_rarg_t * parg,void * buf)17027c478bd9Sstevel@tonic-gate get_monitor_mode(ptree_rarg_t *parg, void *buf)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
17057c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
17067c478bd9Sstevel@tonic-gate int fd;
17077c478bd9Sstevel@tonic-gate int8_t mmode;
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate proph = parg->proph;
17107c478bd9Sstevel@tonic-gate
17117c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
17147c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate fd = open(CPU_HWM_DEVFS, O_RDWR);
17177c478bd9Sstevel@tonic-gate
17187c478bd9Sstevel@tonic-gate if (fd == -1) {
17197c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate
17227c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
17237c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate
17267c478bd9Sstevel@tonic-gate if (mmode == ADM1031_AUTO_MODE) {
17277c478bd9Sstevel@tonic-gate *((int *)tuneablep->value) = ENABLE;
17287c478bd9Sstevel@tonic-gate } else {
17297c478bd9Sstevel@tonic-gate *((int *)tuneablep->value) = DISABLE;
17307c478bd9Sstevel@tonic-gate }
17317c478bd9Sstevel@tonic-gate
17327c478bd9Sstevel@tonic-gate (void) memcpy(buf, tuneablep->value,
17337c478bd9Sstevel@tonic-gate tuneablep->nbytes);
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate (void) close(fd);
17367c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate static int
set_monitor_mode(ptree_warg_t * parg,const void * buf)17407c478bd9Sstevel@tonic-gate set_monitor_mode(ptree_warg_t *parg, const void *buf)
17417c478bd9Sstevel@tonic-gate {
17427c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
17437c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
17447c478bd9Sstevel@tonic-gate int fd, val;
17457c478bd9Sstevel@tonic-gate int8_t mmode;
17467c478bd9Sstevel@tonic-gate
17477c478bd9Sstevel@tonic-gate if (parg->cred.dc_euid != 0)
17487c478bd9Sstevel@tonic-gate return (PICL_PERMDENIED);
17497c478bd9Sstevel@tonic-gate
17507c478bd9Sstevel@tonic-gate proph = parg->proph;
17517c478bd9Sstevel@tonic-gate
17527c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
17557c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17567c478bd9Sstevel@tonic-gate
17577c478bd9Sstevel@tonic-gate fd = open(CPU_HWM_DEVFS, O_RDWR);
17587c478bd9Sstevel@tonic-gate if (fd == -1) {
17597c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17607c478bd9Sstevel@tonic-gate }
17617c478bd9Sstevel@tonic-gate (void) memcpy(&val, buf, sizeof (val));
17627c478bd9Sstevel@tonic-gate if (val == ENABLE) {
17637c478bd9Sstevel@tonic-gate mmode = ADM1031_AUTO_MODE;
17647c478bd9Sstevel@tonic-gate } else if (val == DISABLE) {
17657c478bd9Sstevel@tonic-gate mmode = ADM1031_MANUAL_MODE;
17667c478bd9Sstevel@tonic-gate }
17677c478bd9Sstevel@tonic-gate
17687c478bd9Sstevel@tonic-gate if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
17697c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17707c478bd9Sstevel@tonic-gate }
17717c478bd9Sstevel@tonic-gate
17727c478bd9Sstevel@tonic-gate (void) close(fd);
17737c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate
17767c478bd9Sstevel@tonic-gate static int
get_string_val(ptree_rarg_t * parg,void * buf)17777c478bd9Sstevel@tonic-gate get_string_val(ptree_rarg_t *parg, void *buf)
17787c478bd9Sstevel@tonic-gate {
17797c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
17807c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
17817c478bd9Sstevel@tonic-gate
17827c478bd9Sstevel@tonic-gate proph = parg->proph;
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
17857c478bd9Sstevel@tonic-gate
17867c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
17877c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
17887c478bd9Sstevel@tonic-gate
17897c478bd9Sstevel@tonic-gate (void) memcpy(buf, (caddr_t)tuneablep->value,
17907c478bd9Sstevel@tonic-gate tuneablep->nbytes);
17917c478bd9Sstevel@tonic-gate
17927c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
17937c478bd9Sstevel@tonic-gate }
17947c478bd9Sstevel@tonic-gate
17957c478bd9Sstevel@tonic-gate static int
set_string_val(ptree_warg_t * parg,const void * buf)17967c478bd9Sstevel@tonic-gate set_string_val(ptree_warg_t *parg, const void *buf)
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
17997c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate proph = parg->proph;
18027c478bd9Sstevel@tonic-gate
18037c478bd9Sstevel@tonic-gate if (parg->cred.dc_euid != 0)
18047c478bd9Sstevel@tonic-gate return (PICL_PERMDENIED);
18057c478bd9Sstevel@tonic-gate
18067c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
18077c478bd9Sstevel@tonic-gate
18087c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
18097c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
18107c478bd9Sstevel@tonic-gate
18117c478bd9Sstevel@tonic-gate (void) memcpy((caddr_t)tuneables->value, (caddr_t)buf,
18127c478bd9Sstevel@tonic-gate tuneables->nbytes);
18137c478bd9Sstevel@tonic-gate
18147c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate
18177c478bd9Sstevel@tonic-gate static int
get_int_val(ptree_rarg_t * parg,void * buf)18187c478bd9Sstevel@tonic-gate get_int_val(ptree_rarg_t *parg, void *buf)
18197c478bd9Sstevel@tonic-gate {
18207c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
18217c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate proph = parg->proph;
18247c478bd9Sstevel@tonic-gate
18257c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
18267c478bd9Sstevel@tonic-gate
18277c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
18287c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
18297c478bd9Sstevel@tonic-gate
18307c478bd9Sstevel@tonic-gate (void) memcpy((int *)buf, (int *)tuneablep->value,
18317c478bd9Sstevel@tonic-gate tuneablep->nbytes);
18327c478bd9Sstevel@tonic-gate
18337c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
18347c478bd9Sstevel@tonic-gate }
18357c478bd9Sstevel@tonic-gate
18367c478bd9Sstevel@tonic-gate static int
set_int_val(ptree_warg_t * parg,const void * buf)18377c478bd9Sstevel@tonic-gate set_int_val(ptree_warg_t *parg, const void *buf)
18387c478bd9Sstevel@tonic-gate {
18397c478bd9Sstevel@tonic-gate picl_prophdl_t proph;
18407c478bd9Sstevel@tonic-gate env_tuneable_t *tuneablep;
18417c478bd9Sstevel@tonic-gate
18427c478bd9Sstevel@tonic-gate if (parg->cred.dc_euid != 0)
18437c478bd9Sstevel@tonic-gate return (PICL_PERMDENIED);
18447c478bd9Sstevel@tonic-gate
18457c478bd9Sstevel@tonic-gate proph = parg->proph;
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate tuneablep = tuneable_lookup(proph);
18487c478bd9Sstevel@tonic-gate
18497c478bd9Sstevel@tonic-gate if (tuneablep == NULL)
18507c478bd9Sstevel@tonic-gate return (PICL_FAILURE);
18517c478bd9Sstevel@tonic-gate
18527c478bd9Sstevel@tonic-gate (void) memcpy((int *)tuneablep->value, (int *)buf,
18537c478bd9Sstevel@tonic-gate tuneablep->nbytes);
18547c478bd9Sstevel@tonic-gate
18557c478bd9Sstevel@tonic-gate return (PICL_SUCCESS);
18567c478bd9Sstevel@tonic-gate }
1857