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, &section, 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(&section.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(&section.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