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