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 2004 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 Enchilada WS.
35*0Sstevel@tonic-gate  * It provides functionality to get/set temperatures and
36*0Sstevel@tonic-gate  * fan speeds.
37*0Sstevel@tonic-gate  *
38*0Sstevel@tonic-gate  * The environmental policy defaults to the auto mode
39*0Sstevel@tonic-gate  * 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 <strings.h>
48*0Sstevel@tonic-gate #include <stdarg.h>
49*0Sstevel@tonic-gate #include <alloca.h>
50*0Sstevel@tonic-gate #include <unistd.h>
51*0Sstevel@tonic-gate #include <sys/processor.h>
52*0Sstevel@tonic-gate #include <syslog.h>
53*0Sstevel@tonic-gate #include <errno.h>
54*0Sstevel@tonic-gate #include <fcntl.h>
55*0Sstevel@tonic-gate #include <picl.h>
56*0Sstevel@tonic-gate #include <picltree.h>
57*0Sstevel@tonic-gate #include <picldefs.h>
58*0Sstevel@tonic-gate #include <pthread.h>
59*0Sstevel@tonic-gate #include <signal.h>
60*0Sstevel@tonic-gate #include <libdevinfo.h>
61*0Sstevel@tonic-gate #include <sys/pm.h>
62*0Sstevel@tonic-gate #include <sys/open.h>
63*0Sstevel@tonic-gate #include <sys/time.h>
64*0Sstevel@tonic-gate #include <sys/utsname.h>
65*0Sstevel@tonic-gate #include <sys/systeminfo.h>
66*0Sstevel@tonic-gate #include <note.h>
67*0Sstevel@tonic-gate #include <sys/i2c/clients/i2c_client.h>
68*0Sstevel@tonic-gate #include <sys/i2c/clients/adm1031.h>
69*0Sstevel@tonic-gate #include <sys/i2c/clients/pic16f819_reg.h>
70*0Sstevel@tonic-gate #include "envd.h"
71*0Sstevel@tonic-gate #include <sys/scsi/scsi.h>
72*0Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate /*
76*0Sstevel@tonic-gate  * PICL plugin entry points
77*0Sstevel@tonic-gate  */
78*0Sstevel@tonic-gate static void piclenvd_register(void);
79*0Sstevel@tonic-gate static void piclenvd_init(void);
80*0Sstevel@tonic-gate static void piclenvd_fini(void);
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  * Env setup routines
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate extern void env_picl_setup(void);
86*0Sstevel@tonic-gate extern void env_picl_destroy(void);
87*0Sstevel@tonic-gate extern int env_picl_setup_tuneables(void);
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * Sleep routine used for polling
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static int get_dimm_fan_speed(int, fanspeed_t *);
93*0Sstevel@tonic-gate static int is_dimm_fan_failed(void);
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate #pragma	init(piclenvd_register)
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /*
98*0Sstevel@tonic-gate  * Plugin registration information
99*0Sstevel@tonic-gate  */
100*0Sstevel@tonic-gate static picld_plugin_reg_t my_reg_info = {
101*0Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION,
102*0Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
103*0Sstevel@tonic-gate 	"SUNW_piclenvd",
104*0Sstevel@tonic-gate 	piclenvd_init,
105*0Sstevel@tonic-gate 	piclenvd_fini,
106*0Sstevel@tonic-gate };
107*0Sstevel@tonic-gate 
108*0Sstevel@tonic-gate #define	REGISTER_INFORMATION_STRING_LENGTH	16
109*0Sstevel@tonic-gate static char dimm_fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
110*0Sstevel@tonic-gate static char dimm_fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
111*0Sstevel@tonic-gate static char dimm_fan_command_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
112*0Sstevel@tonic-gate static char dimm_fan_debug_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate static int	scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf,
115*0Sstevel@tonic-gate 			uint16_t pagelen);
116*0Sstevel@tonic-gate static int	get_disk_temp(env_disk_t *);
117*0Sstevel@tonic-gate /*
118*0Sstevel@tonic-gate  * ES Segment data structures
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate static sensor_ctrl_blk_t	sensor_ctrl[MAX_SENSORS];
121*0Sstevel@tonic-gate static fan_ctrl_blk_t		fan_ctrl[MAX_FANS];
122*0Sstevel@tonic-gate static fruenvseg_t		*envfru = NULL;
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate /*
125*0Sstevel@tonic-gate  * Env thread variables
126*0Sstevel@tonic-gate  */
127*0Sstevel@tonic-gate static boolean_t  system_shutdown_started = B_FALSE;
128*0Sstevel@tonic-gate static boolean_t  ovtemp_thr1_created = B_FALSE;
129*0Sstevel@tonic-gate static pthread_t  ovtemp_thr1_id;
130*0Sstevel@tonic-gate static pthread_attr_t thr_attr;
131*0Sstevel@tonic-gate static boolean_t  ovtemp_thr2_created = B_FALSE;
132*0Sstevel@tonic-gate static pthread_t  ovtemp_thr2_id;
133*0Sstevel@tonic-gate static boolean_t  dimm_fan_thr_created = B_FALSE;
134*0Sstevel@tonic-gate static pthread_t  dimm_fan_thr_id;
135*0Sstevel@tonic-gate static boolean_t  disk_temp_thr_created = B_FALSE;
136*0Sstevel@tonic-gate static pthread_t  disk_temp_thr_id;
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate /*
139*0Sstevel@tonic-gate  * PM thread related variables
140*0Sstevel@tonic-gate  */
141*0Sstevel@tonic-gate static pthread_t	pmthr_tid;	/* pmthr thread ID */
142*0Sstevel@tonic-gate static int		pm_fd = -1;	/* PM device file descriptor */
143*0Sstevel@tonic-gate static boolean_t	pmthr_created = B_FALSE;
144*0Sstevel@tonic-gate static int		cur_lpstate;	/* cur low power state */
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate /*
147*0Sstevel@tonic-gate  * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
148*0Sstevel@tonic-gate  * Setting the verbose tuneable also enables debugging for better
149*0Sstevel@tonic-gate  * control
150*0Sstevel@tonic-gate  */
151*0Sstevel@tonic-gate int	env_debug = 0;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate  * Fan devices
155*0Sstevel@tonic-gate  */
156*0Sstevel@tonic-gate static env_fan_t envd_sys_out_fan = {
157*0Sstevel@tonic-gate 	ENV_SYSTEM_OUT_FAN, ENV_SYSTEM_OUT_FAN_DEVFS, NULL,
158*0Sstevel@tonic-gate 	SYSTEM_OUT_FAN_ID, SYSTEM_OUT_FAN_SPEED_MIN, SYSTEM_OUT_FAN_SPEED_MAX,
159*0Sstevel@tonic-gate 	-1, -1,
160*0Sstevel@tonic-gate };
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static env_fan_t envd_sys_in_fan = {
163*0Sstevel@tonic-gate 	ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_INTAKE_FAN_DEVFS, NULL,
164*0Sstevel@tonic-gate 	SYSTEM_INTAKE_FAN_ID, SYSTEM_INTAKE_FAN_SPEED_MIN,
165*0Sstevel@tonic-gate 	SYSTEM_INTAKE_FAN_SPEED_MAX, -1, -1,
166*0Sstevel@tonic-gate };
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate static env_fan_t envd_cpu0_fan = {
169*0Sstevel@tonic-gate 	ENV_CPU0_FAN, ENV_CPU0_FAN_DEVFS, NULL,
170*0Sstevel@tonic-gate 	CPU0_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
171*0Sstevel@tonic-gate };
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate static env_fan_t envd_cpu1_fan = {
174*0Sstevel@tonic-gate 	ENV_CPU1_FAN, ENV_CPU1_FAN_DEVFS, NULL,
175*0Sstevel@tonic-gate 	CPU1_FAN_ID, CPU_FAN_SPEED_MIN, CPU_FAN_SPEED_MAX, -1, -1,
176*0Sstevel@tonic-gate };
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate static env_fan_t envd_dimm_fan = {
179*0Sstevel@tonic-gate 	ENV_DIMM_FAN, ENV_DIMM_FAN_DEVFS, NULL,
180*0Sstevel@tonic-gate 	DIMM_FAN_ID, 100, 100, -1, -1,
181*0Sstevel@tonic-gate };
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate static env_disk_t envd_disk0 = {
184*0Sstevel@tonic-gate 	ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH,
185*0Sstevel@tonic-gate 	DISK0_ID, -1, -1,
186*0Sstevel@tonic-gate };
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate static env_disk_t envd_disk1 = {
189*0Sstevel@tonic-gate 	ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH,
190*0Sstevel@tonic-gate 	DISK1_ID, -1, -1,
191*0Sstevel@tonic-gate };
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate /*
194*0Sstevel@tonic-gate  * The vendor-id and device-id are the properties associated with
195*0Sstevel@tonic-gate  * the SCSI controller. This is used to identify a particular controller
196*0Sstevel@tonic-gate  * like LSI1030.
197*0Sstevel@tonic-gate  */
198*0Sstevel@tonic-gate #define	VENDOR_ID	"vendor-id"
199*0Sstevel@tonic-gate #define	DEVICE_ID	"device-id"
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate /*
202*0Sstevel@tonic-gate  * The implementation for SCSI disk drives to supply info. about
203*0Sstevel@tonic-gate  * temperature is not mandatory. Hence we first determine if the
204*0Sstevel@tonic-gate  * temperature page is supported. To do this we need to scan the list
205*0Sstevel@tonic-gate  * of pages supported.
206*0Sstevel@tonic-gate  */
207*0Sstevel@tonic-gate #define	SUPPORTED_LPAGES	0
208*0Sstevel@tonic-gate #define	TEMPERATURE_PAGE	0x0D
209*0Sstevel@tonic-gate #define	LOGPAGEHDRSIZE	4
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate /*
212*0Sstevel@tonic-gate  * NULL terminated array of fans
213*0Sstevel@tonic-gate  */
214*0Sstevel@tonic-gate static env_fan_t *envd_fans[] = {
215*0Sstevel@tonic-gate 	&envd_cpu0_fan,
216*0Sstevel@tonic-gate 	&envd_cpu1_fan,
217*0Sstevel@tonic-gate 	&envd_sys_out_fan,
218*0Sstevel@tonic-gate 	&envd_sys_in_fan,
219*0Sstevel@tonic-gate 	&envd_dimm_fan,
220*0Sstevel@tonic-gate 	NULL
221*0Sstevel@tonic-gate };
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate static	env_disk_t	*envd_disks[] = {
224*0Sstevel@tonic-gate 	&envd_disk0,
225*0Sstevel@tonic-gate 	&envd_disk1,
226*0Sstevel@tonic-gate 	NULL
227*0Sstevel@tonic-gate };
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate /*
230*0Sstevel@tonic-gate  * ADM1031 speedrange map is indexed by a 2-bit value
231*0Sstevel@tonic-gate  */
232*0Sstevel@tonic-gate static int	adm_speedrange_map[] = {1, 2, 4, 8};
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate /*
235*0Sstevel@tonic-gate  * ADM1031 devices
236*0Sstevel@tonic-gate  */
237*0Sstevel@tonic-gate static char	*hwm_devs[] = {
238*0Sstevel@tonic-gate 	CPU_HWM_DEVFS,	/* CPU_HWM_ID */
239*0Sstevel@tonic-gate 	SYS_HWM_DEVFS	/* SYS_HWM_ID */
240*0Sstevel@tonic-gate };
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate /*
243*0Sstevel@tonic-gate  * Fan names associated with each ADM1031 hwms - used to
244*0Sstevel@tonic-gate  * print fault messages.
245*0Sstevel@tonic-gate  */
246*0Sstevel@tonic-gate static char	*hwm_fans[MAX_HWMS][2] = {
247*0Sstevel@tonic-gate 	{ENV_CPU0_FAN, ENV_CPU1_FAN},
248*0Sstevel@tonic-gate 	{ENV_SYSTEM_INTAKE_FAN, ENV_SYSTEM_OUT_FAN}
249*0Sstevel@tonic-gate };
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate /*
252*0Sstevel@tonic-gate  * Temperature sensors
253*0Sstevel@tonic-gate  */
254*0Sstevel@tonic-gate static env_sensor_t envd_sensors[] = {
255*0Sstevel@tonic-gate 	{ SENSOR_CPU0_DIE, SENSOR_CPU0_DIE_DEVFS, NULL,
256*0Sstevel@tonic-gate 	    CPU0_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu0_fan, -1},
257*0Sstevel@tonic-gate 	{ SENSOR_CPU1_DIE, SENSOR_CPU1_DIE_DEVFS, NULL,
258*0Sstevel@tonic-gate 	    CPU1_SENSOR_ID, CPU_HWM_ID, (void *)&envd_cpu1_fan, -1},
259*0Sstevel@tonic-gate 	{ SENSOR_INT_AMB_0, SENSOR_INT_AMB_0_DEVFS, NULL,
260*0Sstevel@tonic-gate 	    INT_AMB0_SENSOR_ID, CPU_HWM_ID, NULL, -1},
261*0Sstevel@tonic-gate 	{ SENSOR_SYS_OUT, SENSOR_SYS_OUT_DEVFS, NULL,
262*0Sstevel@tonic-gate 	    SYS_OUT_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_out_fan, -1},
263*0Sstevel@tonic-gate 	{ SENSOR_INT_AMB_1, SENSOR_INT_AMB_1_DEVFS, NULL,
264*0Sstevel@tonic-gate 	    INT_AMB1_SENSOR_ID, SYS_HWM_ID, NULL, -1},
265*0Sstevel@tonic-gate 	{ SENSOR_SYS_IN, SENSOR_SYS_IN_DEVFS, NULL,
266*0Sstevel@tonic-gate 	    SYS_IN_SENSOR_ID, SYS_HWM_ID, (void *)&envd_sys_in_fan, -1},
267*0Sstevel@tonic-gate };
268*0Sstevel@tonic-gate #define	N_ENVD_SENSORS	(sizeof (envd_sensors)/sizeof (envd_sensors[0]))
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate #define	NOT_AVAILABLE	"NA"
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate /*
273*0Sstevel@tonic-gate  * ADM1031 macros
274*0Sstevel@tonic-gate  */
275*0Sstevel@tonic-gate #define	TACH_UNKNOWN	255
276*0Sstevel@tonic-gate #define	FAN_OUT_OF_RANGE	(TACH_UNKNOWN)
277*0Sstevel@tonic-gate #define	ADM_HYSTERISIS	5
278*0Sstevel@tonic-gate #define	N_SEQ_TACH	15
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate #define	TMIN_MASK	(0xF8)
281*0Sstevel@tonic-gate #define	TMIN_SHIFT	(3)
282*0Sstevel@tonic-gate #define	TMIN_UNITS	(4)	/* increments of 4 degrees celsius */
283*0Sstevel@tonic-gate #define	TRANGE_MASK	(0x7)
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate #define	TMIN(regval)	(((regval & TMIN_MASK) >> TMIN_SHIFT) * TMIN_UNITS)
286*0Sstevel@tonic-gate #define	TRANGE(regval)	(regval & TRANGE_MASK)
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate #define	GET_TMIN_RANGE(tmin, trange) \
289*0Sstevel@tonic-gate 	((((tmin / TMIN_UNITS) & TMIN_MASK) << TMIN_SHIFT) | \
290*0Sstevel@tonic-gate 	(trange & TRANGE_MASK))
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate #define	TACH_ENABLE_MASK		(0x0C)
293*0Sstevel@tonic-gate #define	ADM_SETFANSPEED_CONV(speed)	(15 * speed / 100)
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate /*
296*0Sstevel@tonic-gate  * Tuneables
297*0Sstevel@tonic-gate  */
298*0Sstevel@tonic-gate #define	ENABLE	1
299*0Sstevel@tonic-gate #define	DISABLE	0
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate int	monitor_disk_temp	= 1;	/* enabled */
302*0Sstevel@tonic-gate static	int	disk_high_warn_temperature	= DISK_HIGH_WARN_TEMPERATURE;
303*0Sstevel@tonic-gate static	int	disk_low_warn_temperature	= DISK_LOW_WARN_TEMPERATURE;
304*0Sstevel@tonic-gate static	int	disk_high_shutdown_temperature	=
305*0Sstevel@tonic-gate 						DISK_HIGH_SHUTDOWN_TEMPERATURE;
306*0Sstevel@tonic-gate static	int	disk_low_shutdown_temperature	= DISK_LOW_SHUTDOWN_TEMPERATURE;
307*0Sstevel@tonic-gate static	int	disk_scan_interval		= DISK_SCAN_INTERVAL;
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate static int get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf);
310*0Sstevel@tonic-gate static int set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf);
311*0Sstevel@tonic-gate static int get_monitor_sys_mode(ptree_rarg_t *parg, void *buf);
312*0Sstevel@tonic-gate static int set_monitor_sys_mode(ptree_warg_t *parg, const void *buf);
313*0Sstevel@tonic-gate static int get_int_val(ptree_rarg_t *parg, void *buf);
314*0Sstevel@tonic-gate static int set_int_val(ptree_warg_t *parg, const void *buf);
315*0Sstevel@tonic-gate static int get_string_val(ptree_rarg_t *parg, void *buf);
316*0Sstevel@tonic-gate static int set_string_val(ptree_warg_t *parg, const void *buf);
317*0Sstevel@tonic-gate static int get_cpu_tach(ptree_rarg_t *parg, void *buf);
318*0Sstevel@tonic-gate static int set_cpu_tach(ptree_warg_t *parg, const void *buf);
319*0Sstevel@tonic-gate static int get_sys_tach(ptree_rarg_t *parg, void *buf);
320*0Sstevel@tonic-gate static int set_sys_tach(ptree_warg_t *parg, const void *buf);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate static int 	shutdown_override	= 0;
323*0Sstevel@tonic-gate static int 	sensor_poll_interval	= SENSORPOLL_INTERVAL;
324*0Sstevel@tonic-gate static int	warning_interval	= WARNING_INTERVAL;
325*0Sstevel@tonic-gate static int	disk_warning_interval	= DISK_WARNING_INTERVAL;
326*0Sstevel@tonic-gate static int	disk_warning_duration	= DISK_WARNING_DURATION;
327*0Sstevel@tonic-gate static int 	shutdown_interval	= SHUTDOWN_INTERVAL;
328*0Sstevel@tonic-gate static int 	disk_shutdown_interval	= DISK_SHUTDOWN_INTERVAL;
329*0Sstevel@tonic-gate static int	ovtemp_monitor		= 1;	/* enabled */
330*0Sstevel@tonic-gate static int	pm_monitor		= 1;	/* enabled */
331*0Sstevel@tonic-gate static int	mon_fanstat		= 1;	/* enabled */
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate static int 	cpu_mode;
334*0Sstevel@tonic-gate static int 	sys_mode;
335*0Sstevel@tonic-gate static int 	cpu_tach;
336*0Sstevel@tonic-gate static int 	sys_tach;
337*0Sstevel@tonic-gate static char	shutdown_cmd[] = SHUTDOWN_CMD;
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate env_tuneable_t tuneables[] = {
340*0Sstevel@tonic-gate 	{"ovtemp-monitor", PICL_PTYPE_INT, &ovtemp_monitor,
341*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	{"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
344*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 	{"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
347*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 	{"cpu-hm-automode-enable", PICL_PTYPE_INT, &cpu_mode,
350*0Sstevel@tonic-gate 	    &get_monitor_cpu_mode, &set_monitor_cpu_mode,
351*0Sstevel@tonic-gate 	    sizeof (int)},
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 	{"sys-hm-automode-enable", PICL_PTYPE_INT, &sys_mode,
354*0Sstevel@tonic-gate 	    &get_monitor_sys_mode, &set_monitor_sys_mode,
355*0Sstevel@tonic-gate 	    sizeof (int)},
356*0Sstevel@tonic-gate 
357*0Sstevel@tonic-gate 	{"sensor-poll-interval", PICL_PTYPE_INT,
358*0Sstevel@tonic-gate 	    &sensor_poll_interval,
359*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
360*0Sstevel@tonic-gate 	    sizeof (int)},
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	{"disk-scan-interval", PICL_PTYPE_INT,
363*0Sstevel@tonic-gate 	    &disk_scan_interval,
364*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
365*0Sstevel@tonic-gate 	    sizeof (int)},
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 	{"warning-interval", PICL_PTYPE_INT, &warning_interval,
368*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
369*0Sstevel@tonic-gate 	    sizeof (int)},
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	{"shutdown-interval", PICL_PTYPE_INT, &shutdown_interval,
372*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
373*0Sstevel@tonic-gate 	    sizeof (int)},
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	{"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval,
376*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
377*0Sstevel@tonic-gate 	    sizeof (int)},
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	{"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration,
380*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
381*0Sstevel@tonic-gate 	    sizeof (int)},
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	{"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval,
384*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
385*0Sstevel@tonic-gate 	    sizeof (int)},
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	{"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
388*0Sstevel@tonic-gate 	    &get_string_val, &set_string_val,
389*0Sstevel@tonic-gate 	    sizeof (shutdown_cmd)},
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	{"cpu-tach-enable", PICL_PTYPE_INT, &cpu_tach,
392*0Sstevel@tonic-gate 	    &get_cpu_tach, &set_cpu_tach,
393*0Sstevel@tonic-gate 	    sizeof (int)},
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	{"sys-tach-enable", PICL_PTYPE_INT, &sys_tach,
396*0Sstevel@tonic-gate 	    &get_sys_tach, &set_sys_tach,
397*0Sstevel@tonic-gate 	    sizeof (int)},
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	{"monitor-fanstat", PICL_PTYPE_INT, &mon_fanstat,
400*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	{"monitor-disk-temp", PICL_PTYPE_INT, &monitor_disk_temp,
403*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	{"disk-high-warn-temperature", PICL_PTYPE_INT,
406*0Sstevel@tonic-gate 	    &disk_high_warn_temperature, &get_int_val,
407*0Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 	{"disk-low-warn-temperature", PICL_PTYPE_INT,
410*0Sstevel@tonic-gate 	    &disk_low_warn_temperature, &get_int_val,
411*0Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	{"disk-high-shutdown-temperature", PICL_PTYPE_INT,
414*0Sstevel@tonic-gate 	    &disk_high_shutdown_temperature, &get_int_val,
415*0Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	{"disk-low-shutdown-temperature", PICL_PTYPE_INT,
418*0Sstevel@tonic-gate 	    &disk_low_shutdown_temperature, &get_int_val,
419*0Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	{"verbose", PICL_PTYPE_INT, &env_debug,
422*0Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate };
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate /*
428*0Sstevel@tonic-gate  * We use this to figure out how many tuneables there are
429*0Sstevel@tonic-gate  * This is variable because the publishing routine needs this info
430*0Sstevel@tonic-gate  * in piclenvsetup.c
431*0Sstevel@tonic-gate  */
432*0Sstevel@tonic-gate int	ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate /*
435*0Sstevel@tonic-gate  * Table Handling Code
436*0Sstevel@tonic-gate  */
437*0Sstevel@tonic-gate static void
fini_table(table_t * tblp)438*0Sstevel@tonic-gate fini_table(table_t *tblp)
439*0Sstevel@tonic-gate {
440*0Sstevel@tonic-gate 	if (tblp == NULL)
441*0Sstevel@tonic-gate 		return;
442*0Sstevel@tonic-gate 	free(tblp->xymap);
443*0Sstevel@tonic-gate 	free(tblp);
444*0Sstevel@tonic-gate }
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate static table_t *
init_table(int npoints)447*0Sstevel@tonic-gate init_table(int npoints)
448*0Sstevel@tonic-gate {
449*0Sstevel@tonic-gate 	table_t		*tblp;
450*0Sstevel@tonic-gate 	point_t		*xy;
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	if (npoints == 0)
453*0Sstevel@tonic-gate 		return (NULL);
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	if ((tblp = malloc(sizeof (*tblp))) == NULL)
456*0Sstevel@tonic-gate 		return (NULL);
457*0Sstevel@tonic-gate 
458*0Sstevel@tonic-gate 	if ((xy = malloc(sizeof (*xy) * npoints)) == NULL) {
459*0Sstevel@tonic-gate 		free(tblp);
460*0Sstevel@tonic-gate 		return (NULL);
461*0Sstevel@tonic-gate 	}
462*0Sstevel@tonic-gate 
463*0Sstevel@tonic-gate 	tblp->nentries = npoints;
464*0Sstevel@tonic-gate 	tblp->xymap = xy;
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	return (tblp);
467*0Sstevel@tonic-gate }
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate /*
470*0Sstevel@tonic-gate  * function: calculates y for a given x based on a table of points
471*0Sstevel@tonic-gate  * for monotonically increasing x values.
472*0Sstevel@tonic-gate  * 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
473*0Sstevel@tonic-gate  */
474*0Sstevel@tonic-gate static int
y_of_x(table_t * tbl,int xval)475*0Sstevel@tonic-gate y_of_x(table_t *tbl, int xval)
476*0Sstevel@tonic-gate {
477*0Sstevel@tonic-gate 	int		i;
478*0Sstevel@tonic-gate 	int		entries;
479*0Sstevel@tonic-gate 	point_t		*xymap;
480*0Sstevel@tonic-gate 	float		newval;
481*0Sstevel@tonic-gate 	float		dy, dx, slope;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	entries = tbl->nentries;
484*0Sstevel@tonic-gate 	xymap = tbl->xymap;
485*0Sstevel@tonic-gate 	/*
486*0Sstevel@tonic-gate 	 * If the temperature is outside the correction table
487*0Sstevel@tonic-gate 	 * then simply return the original value.
488*0Sstevel@tonic-gate 	 */
489*0Sstevel@tonic-gate 	if ((xval < xymap[0].x) || (xval > xymap[entries - 1].x))
490*0Sstevel@tonic-gate 		return (xval);
491*0Sstevel@tonic-gate 	if (xval == xymap[0].x)
492*0Sstevel@tonic-gate 		return (xymap[0].y);
493*0Sstevel@tonic-gate 	if (xval == xymap[entries - 1].x)
494*0Sstevel@tonic-gate 		return (xymap[entries - 1].y);
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 	for (i = 1; i < entries - 1; i++) {
497*0Sstevel@tonic-gate 		if (xval == xymap[i].x)
498*0Sstevel@tonic-gate 			return (xymap[i].y);
499*0Sstevel@tonic-gate 		if (xval < xymap[i].x)
500*0Sstevel@tonic-gate 			break;
501*0Sstevel@tonic-gate 	}
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	/*
504*0Sstevel@tonic-gate 	 * Use linear interpolation
505*0Sstevel@tonic-gate 	 */
506*0Sstevel@tonic-gate 	dy = (float)(xymap[i].y - xymap[i-1].y);
507*0Sstevel@tonic-gate 	dx = (float)(xymap[i].x - xymap[i-1].x);
508*0Sstevel@tonic-gate 	slope = dy/dx;
509*0Sstevel@tonic-gate 	newval = xymap[i - 1].y + slope * (xval - xymap[i - 1].x);
510*0Sstevel@tonic-gate 	return ((int)(newval + (newval >= 0 ? 0.5 : -0.5)));
511*0Sstevel@tonic-gate }
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate /*
514*0Sstevel@tonic-gate  * Get environmental segment from the specified FRU SEEPROM
515*0Sstevel@tonic-gate  */
516*0Sstevel@tonic-gate static int
get_envseg(int fd,void ** envsegp,int * envseglenp)517*0Sstevel@tonic-gate get_envseg(int fd, void **envsegp, int *envseglenp)
518*0Sstevel@tonic-gate {
519*0Sstevel@tonic-gate 	int			i, segcnt, envseglen;
520*0Sstevel@tonic-gate 	section_layout_t	section;
521*0Sstevel@tonic-gate 	segment_layout_t	segment;
522*0Sstevel@tonic-gate 	uint8_t			*envseg;
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	if (lseek(fd, (long)SECTION_HDR_OFFSET, 0) == -1L ||
525*0Sstevel@tonic-gate 	    read(fd, &section, sizeof (section)) != sizeof (section)) {
526*0Sstevel@tonic-gate 		return (EINVAL);
527*0Sstevel@tonic-gate 	}
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	/*
530*0Sstevel@tonic-gate 	 * Verify we have the correct section and contents are valid
531*0Sstevel@tonic-gate 	 * For now, we don't verify the CRC.
532*0Sstevel@tonic-gate 	 */
533*0Sstevel@tonic-gate 	if (section.header_tag != SECTION_HDR_TAG ||
534*0Sstevel@tonic-gate 	    GET_UNALIGN16(&section.header_version[0]) != SECTION_HDR_VER) {
535*0Sstevel@tonic-gate 		if (env_debug)
536*0Sstevel@tonic-gate 			envd_log(LOG_INFO,
537*0Sstevel@tonic-gate 			    "Invalid section header tag:%x  version:%x\n",
538*0Sstevel@tonic-gate 			    section.header_tag,
539*0Sstevel@tonic-gate 			    GET_UNALIGN16(&section.header_version));
540*0Sstevel@tonic-gate 		return (EINVAL);
541*0Sstevel@tonic-gate 	}
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 	/*
544*0Sstevel@tonic-gate 	 * Locate our environmental segment
545*0Sstevel@tonic-gate 	 */
546*0Sstevel@tonic-gate 	segcnt = section.segment_count;
547*0Sstevel@tonic-gate 	for (i = 0; i < segcnt; i++) {
548*0Sstevel@tonic-gate 		if (read(fd, &segment, sizeof (segment)) != sizeof (segment)) {
549*0Sstevel@tonic-gate 			return (EINVAL);
550*0Sstevel@tonic-gate 		}
551*0Sstevel@tonic-gate 		if (env_debug)
552*0Sstevel@tonic-gate 			envd_log(LOG_INFO,
553*0Sstevel@tonic-gate 			    "Seg name: %x  desc:%x off:%x  len:%x\n",
554*0Sstevel@tonic-gate 			    GET_UNALIGN16(&segment.name),
555*0Sstevel@tonic-gate 			    GET_UNALIGN32(&segment.descriptor[0]),
556*0Sstevel@tonic-gate 			    GET_UNALIGN16(&segment.offset),
557*0Sstevel@tonic-gate 			    GET_UNALIGN16(&segment.length));
558*0Sstevel@tonic-gate 		if (GET_UNALIGN16(&segment.name) == ENVSEG_NAME)
559*0Sstevel@tonic-gate 			break;
560*0Sstevel@tonic-gate 	}
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if (i >= segcnt) {
563*0Sstevel@tonic-gate 		return (ENOENT);
564*0Sstevel@tonic-gate 	}
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	/*
567*0Sstevel@tonic-gate 	 * Allocate memory to hold the environmental segment data.
568*0Sstevel@tonic-gate 	 */
569*0Sstevel@tonic-gate 	envseglen = GET_UNALIGN16(&segment.length);
570*0Sstevel@tonic-gate 	if ((envseg = malloc(envseglen)) == NULL) {
571*0Sstevel@tonic-gate 		return (ENOMEM);
572*0Sstevel@tonic-gate 	}
573*0Sstevel@tonic-gate 
574*0Sstevel@tonic-gate 	if (lseek(fd, (long)GET_UNALIGN16(&segment.offset), 0) == -1L ||
575*0Sstevel@tonic-gate 	    read(fd, envseg, envseglen) != envseglen) {
576*0Sstevel@tonic-gate 		(void) free(envseg);
577*0Sstevel@tonic-gate 		return (EIO);
578*0Sstevel@tonic-gate 	}
579*0Sstevel@tonic-gate 	*envsegp = envseg;
580*0Sstevel@tonic-gate 	*envseglenp = envseglen;
581*0Sstevel@tonic-gate 	return (0);
582*0Sstevel@tonic-gate }
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate /*
585*0Sstevel@tonic-gate  * Get all environmental segments
586*0Sstevel@tonic-gate  * Return NULL on error
587*0Sstevel@tonic-gate  */
588*0Sstevel@tonic-gate static fruenvseg_t *
get_fru_envsegs(void)589*0Sstevel@tonic-gate get_fru_envsegs(void)
590*0Sstevel@tonic-gate {
591*0Sstevel@tonic-gate 	fruenvseg_t		*fruenvsegs;
592*0Sstevel@tonic-gate 	envseg_layout_t		*envsegp;
593*0Sstevel@tonic-gate 	void			*envsegbufp;
594*0Sstevel@tonic-gate 	int			fd, envseglen, hdrlen;
595*0Sstevel@tonic-gate 	char			path[PATH_MAX];
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 	fruenvsegs = NULL;
598*0Sstevel@tonic-gate 	fruenvsegs = malloc(sizeof (*fruenvsegs));
599*0Sstevel@tonic-gate 	if (fruenvsegs == NULL) {
600*0Sstevel@tonic-gate 		return (NULL);
601*0Sstevel@tonic-gate 	}
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/*
604*0Sstevel@tonic-gate 	 * Now get the environmental segment from this FRU
605*0Sstevel@tonic-gate 	 */
606*0Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s", I2C_DEVFS, MBFRU_DEV);
607*0Sstevel@tonic-gate 	fd = open(path, O_RDONLY);
608*0Sstevel@tonic-gate 	if (fd == -1) {
609*0Sstevel@tonic-gate 		envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, errno, path);
610*0Sstevel@tonic-gate 		free(fruenvsegs);
611*0Sstevel@tonic-gate 		return (NULL);
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	/*
615*0Sstevel@tonic-gate 	 * Read environmental segment from this FRU SEEPROM
616*0Sstevel@tonic-gate 	 */
617*0Sstevel@tonic-gate 	if (get_envseg(fd, &envsegbufp, &envseglen) != 0) {
618*0Sstevel@tonic-gate 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, path);
619*0Sstevel@tonic-gate 		free(fruenvsegs);
620*0Sstevel@tonic-gate 		(void) close(fd);
621*0Sstevel@tonic-gate 		return (NULL);
622*0Sstevel@tonic-gate 	}
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	/*
625*0Sstevel@tonic-gate 	 * Validate envseg version number and header length
626*0Sstevel@tonic-gate 	 */
627*0Sstevel@tonic-gate 	envsegp = (envseg_layout_t *)envsegbufp;
628*0Sstevel@tonic-gate 	hdrlen = sizeof (envseg_layout_t) -
629*0Sstevel@tonic-gate 	    sizeof (envseg_sensor_t) +
630*0Sstevel@tonic-gate 	    (envsegp->sensor_count) * sizeof (envseg_sensor_t);
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate 	if (envsegp->version != ENVSEG_VERSION ||
633*0Sstevel@tonic-gate 	    envseglen < hdrlen) {
634*0Sstevel@tonic-gate 		/*
635*0Sstevel@tonic-gate 		 * version mismatch or header not big enough
636*0Sstevel@tonic-gate 		 */
637*0Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
638*0Sstevel@tonic-gate 		if (envsegbufp != NULL)
639*0Sstevel@tonic-gate 			(void) free(envsegbufp);
640*0Sstevel@tonic-gate 		free(fruenvsegs);
641*0Sstevel@tonic-gate 		(void) close(fd);
642*0Sstevel@tonic-gate 		return (NULL);
643*0Sstevel@tonic-gate 	}
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	fruenvsegs->envseglen = envseglen;
646*0Sstevel@tonic-gate 	fruenvsegs->envsegbufp = envsegbufp;
647*0Sstevel@tonic-gate 	(void) close(fd);
648*0Sstevel@tonic-gate 	return (fruenvsegs);
649*0Sstevel@tonic-gate }
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate static int
process_fru_seeprom(unsigned char * buff)652*0Sstevel@tonic-gate process_fru_seeprom(unsigned char *buff)
653*0Sstevel@tonic-gate {
654*0Sstevel@tonic-gate 	id_off_t id;
655*0Sstevel@tonic-gate 	int  i;
656*0Sstevel@tonic-gate 	int  id_offset = 0;
657*0Sstevel@tonic-gate 	int  nsensors;
658*0Sstevel@tonic-gate 	int  nfans;
659*0Sstevel@tonic-gate 	env_fan_t *fnodep;
660*0Sstevel@tonic-gate 	env_sensor_t *snodep;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate #define	NSENSOR_OFFSET	1
663*0Sstevel@tonic-gate #define	ID_OFF_SIZE	6
664*0Sstevel@tonic-gate #define	NFANS_OFFSET(x)	((x * ID_OFF_SIZE) + 2)
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	nsensors = (int)buff[NSENSOR_OFFSET];
667*0Sstevel@tonic-gate 	if (nsensors != MAX_SENSORS) {
668*0Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
669*0Sstevel@tonic-gate 		return (-1);
670*0Sstevel@tonic-gate 	}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	nfans = (int)buff[NFANS_OFFSET(nsensors)];
673*0Sstevel@tonic-gate 	if (nfans != MAX_FANS) {
674*0Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
675*0Sstevel@tonic-gate 		return (-1);
676*0Sstevel@tonic-gate 	}
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	while (nsensors > 0) {
679*0Sstevel@tonic-gate 		(void) memcpy((char *)&id,
680*0Sstevel@tonic-gate 		    (char *)&buff[id_offset + 2],
681*0Sstevel@tonic-gate 		    ID_OFF_SIZE);
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate 		if (env_debug)
684*0Sstevel@tonic-gate 			envd_log(LOG_ERR, "\n Sensor Id %x offset %x",
685*0Sstevel@tonic-gate 			    id.id, id.offset);
686*0Sstevel@tonic-gate 
687*0Sstevel@tonic-gate 		if (id.id > MAX_SENSOR_ID) {
688*0Sstevel@tonic-gate 			envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
689*0Sstevel@tonic-gate 			    FRU_SEEPROM_NAME);
690*0Sstevel@tonic-gate 			return (-1);
691*0Sstevel@tonic-gate 		}
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 		/*
694*0Sstevel@tonic-gate 		 * Copy into the sensor control block array according to the
695*0Sstevel@tonic-gate 		 * sensor ID
696*0Sstevel@tonic-gate 		 */
697*0Sstevel@tonic-gate 		(void) memcpy((char *)&sensor_ctrl[id.id],
698*0Sstevel@tonic-gate 		    (char *)&buff[id.offset],
699*0Sstevel@tonic-gate 		    sizeof (sensor_ctrl_blk_t));
700*0Sstevel@tonic-gate 		nsensors--;
701*0Sstevel@tonic-gate 		id_offset += ID_OFF_SIZE;
702*0Sstevel@tonic-gate 	}
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	/*
705*0Sstevel@tonic-gate 	 * Skip past no of Fan entry(single byte)
706*0Sstevel@tonic-gate 	 */
707*0Sstevel@tonic-gate 	id_offset++;
708*0Sstevel@tonic-gate 	while (nfans > 0) {
709*0Sstevel@tonic-gate 		(void) memcpy((char *)&id, (char *)&buff[id_offset + 2],
710*0Sstevel@tonic-gate 		    ID_OFF_SIZE);
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 		if (env_debug)
713*0Sstevel@tonic-gate 			envd_log(LOG_ERR, "\n Fan Id %x offset %x", id.id,
714*0Sstevel@tonic-gate 			    id.offset);
715*0Sstevel@tonic-gate 
716*0Sstevel@tonic-gate 		if (id.id > 3) {
717*0Sstevel@tonic-gate 			envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
718*0Sstevel@tonic-gate 			    FRU_SEEPROM_NAME);
719*0Sstevel@tonic-gate 			return (-1);
720*0Sstevel@tonic-gate 		}
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 		(void) memcpy((char *)&fan_ctrl[id.id],
723*0Sstevel@tonic-gate 		    (char *)&buff[id.offset], sizeof (fan_ctrl_blk_t));
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		nfans--;
726*0Sstevel@tonic-gate 		id_offset += ID_OFF_SIZE;
727*0Sstevel@tonic-gate 	}
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	/*
730*0Sstevel@tonic-gate 	 * Match Sensor/ES ID and point correct data
731*0Sstevel@tonic-gate 	 * based on IDs
732*0Sstevel@tonic-gate 	 */
733*0Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; i++) {
734*0Sstevel@tonic-gate 		snodep = &envd_sensors[i];
735*0Sstevel@tonic-gate 		snodep->es_ptr = &sensor_ctrl[snodep->id];
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	/*
739*0Sstevel@tonic-gate 	 * Match Fan/ES ID and point to correct ES Data
740*0Sstevel@tonic-gate 	 * based on IDs
741*0Sstevel@tonic-gate 	 */
742*0Sstevel@tonic-gate 	for (i = 0; (fnodep = envd_fans[i]) != NULL; i++)
743*0Sstevel@tonic-gate 		fnodep->es_ptr = &fan_ctrl[fnodep->id];
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	return (0);
746*0Sstevel@tonic-gate }
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate static int
envd_es_setup(void)749*0Sstevel@tonic-gate envd_es_setup(void)
750*0Sstevel@tonic-gate {
751*0Sstevel@tonic-gate 	envfru = get_fru_envsegs();
752*0Sstevel@tonic-gate 	if (envfru == NULL) {
753*0Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG, FRU_SEEPROM_NAME);
754*0Sstevel@tonic-gate 		return (-1);
755*0Sstevel@tonic-gate 	}
756*0Sstevel@tonic-gate 	return (process_fru_seeprom((uchar_t *)envfru->envsegbufp));
757*0Sstevel@tonic-gate }
758*0Sstevel@tonic-gate 
759*0Sstevel@tonic-gate static void
envd_es_destroy(void)760*0Sstevel@tonic-gate envd_es_destroy(void)
761*0Sstevel@tonic-gate {
762*0Sstevel@tonic-gate 	if (envfru != NULL)
763*0Sstevel@tonic-gate 		free(envfru->envsegbufp);
764*0Sstevel@tonic-gate }
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate /*
767*0Sstevel@tonic-gate  * Lookup fan and return a pointer to env_fan_t data structure.
768*0Sstevel@tonic-gate  */
769*0Sstevel@tonic-gate env_fan_t *
fan_lookup(char * name)770*0Sstevel@tonic-gate fan_lookup(char *name)
771*0Sstevel@tonic-gate {
772*0Sstevel@tonic-gate 	int		i;
773*0Sstevel@tonic-gate 	env_fan_t	*fanp;
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
776*0Sstevel@tonic-gate 		if (strcmp(fanp->name, name) == 0)
777*0Sstevel@tonic-gate 			return (fanp);
778*0Sstevel@tonic-gate 	}
779*0Sstevel@tonic-gate 	return (NULL);
780*0Sstevel@tonic-gate }
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate /*
783*0Sstevel@tonic-gate  * Lookup sensor and return a pointer to env_sensor_t data structure.
784*0Sstevel@tonic-gate  */
785*0Sstevel@tonic-gate env_sensor_t *
sensor_lookup(char * name)786*0Sstevel@tonic-gate sensor_lookup(char *name)
787*0Sstevel@tonic-gate {
788*0Sstevel@tonic-gate 	env_sensor_t	*sensorp;
789*0Sstevel@tonic-gate 	int		i;
790*0Sstevel@tonic-gate 
791*0Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
792*0Sstevel@tonic-gate 		sensorp = &envd_sensors[i];
793*0Sstevel@tonic-gate 		if (strcmp(sensorp->name, name) == 0)
794*0Sstevel@tonic-gate 			return (sensorp);
795*0Sstevel@tonic-gate 	}
796*0Sstevel@tonic-gate 	return (NULL);
797*0Sstevel@tonic-gate }
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate /*
800*0Sstevel@tonic-gate  * Lookup disk and return a pointer to env_disk_t data structure.
801*0Sstevel@tonic-gate  */
802*0Sstevel@tonic-gate env_disk_t *
disk_lookup(char * name)803*0Sstevel@tonic-gate disk_lookup(char *name)
804*0Sstevel@tonic-gate {
805*0Sstevel@tonic-gate 	int		i;
806*0Sstevel@tonic-gate 	env_disk_t	*diskp;
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
809*0Sstevel@tonic-gate 		if (strncmp(diskp->name, name, strlen(name)) == 0)
810*0Sstevel@tonic-gate 			return (diskp);
811*0Sstevel@tonic-gate 	}
812*0Sstevel@tonic-gate 	return (NULL);
813*0Sstevel@tonic-gate }
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate /*
816*0Sstevel@tonic-gate  * Get current temperature
817*0Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
818*0Sstevel@tonic-gate  */
819*0Sstevel@tonic-gate int
get_temperature(env_sensor_t * sensorp,tempr_t * temp)820*0Sstevel@tonic-gate get_temperature(env_sensor_t *sensorp, tempr_t *temp)
821*0Sstevel@tonic-gate {
822*0Sstevel@tonic-gate 	int	fd = sensorp->fd;
823*0Sstevel@tonic-gate 	int	retval = 0;
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	if (fd == -1)
826*0Sstevel@tonic-gate 		retval = -1;
827*0Sstevel@tonic-gate 	else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 		retval = -1;
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 		if (sensorp->error == 0) {
832*0Sstevel@tonic-gate 			sensorp->error = 1;
833*0Sstevel@tonic-gate 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
834*0Sstevel@tonic-gate 			    sensorp->name, errno, strerror(errno));
835*0Sstevel@tonic-gate 		}
836*0Sstevel@tonic-gate 	} else if (sensorp->error != 0) {
837*0Sstevel@tonic-gate 		sensorp->error = 0;
838*0Sstevel@tonic-gate 		envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK, sensorp->name);
839*0Sstevel@tonic-gate 	}
840*0Sstevel@tonic-gate 	if (sensorp->crtbl != NULL) {
841*0Sstevel@tonic-gate 		*temp = (tempr_t)y_of_x(sensorp->crtbl, *temp);
842*0Sstevel@tonic-gate 	}
843*0Sstevel@tonic-gate 
844*0Sstevel@tonic-gate 	return (retval);
845*0Sstevel@tonic-gate }
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate /*
848*0Sstevel@tonic-gate  * Get current disk temperature
849*0Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
850*0Sstevel@tonic-gate  */
851*0Sstevel@tonic-gate int
disk_temperature(env_disk_t * diskp,tempr_t * temp)852*0Sstevel@tonic-gate disk_temperature(env_disk_t *diskp, tempr_t *temp)
853*0Sstevel@tonic-gate {
854*0Sstevel@tonic-gate 	int	retval = 0;
855*0Sstevel@tonic-gate 
856*0Sstevel@tonic-gate 	if (diskp == NULL)
857*0Sstevel@tonic-gate 		retval = -1;
858*0Sstevel@tonic-gate 	else  {
859*0Sstevel@tonic-gate 		*temp = diskp->current_temp;
860*0Sstevel@tonic-gate 	}
861*0Sstevel@tonic-gate 	return (retval);
862*0Sstevel@tonic-gate }
863*0Sstevel@tonic-gate 
864*0Sstevel@tonic-gate /*
865*0Sstevel@tonic-gate  * Get uncorrected current temperature
866*0Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
867*0Sstevel@tonic-gate  */
868*0Sstevel@tonic-gate static int
get_raw_temperature(env_sensor_t * sensorp,tempr_t * temp)869*0Sstevel@tonic-gate get_raw_temperature(env_sensor_t *sensorp, tempr_t *temp)
870*0Sstevel@tonic-gate {
871*0Sstevel@tonic-gate 	int	fd = sensorp->fd;
872*0Sstevel@tonic-gate 	int	retval = 0;
873*0Sstevel@tonic-gate 
874*0Sstevel@tonic-gate 	if (fd == -1)
875*0Sstevel@tonic-gate 		retval = -1;
876*0Sstevel@tonic-gate 	else if (ioctl(fd, I2C_GET_TEMPERATURE, temp) == -1) {
877*0Sstevel@tonic-gate 		retval = -1;
878*0Sstevel@tonic-gate 	}
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	return (retval);
881*0Sstevel@tonic-gate }
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate /*
884*0Sstevel@tonic-gate  * Return Fan RPM given N & tach
885*0Sstevel@tonic-gate  * count and N are retrived from the
886*0Sstevel@tonic-gate  * ADM1031 chip.
887*0Sstevel@tonic-gate  */
888*0Sstevel@tonic-gate static int
tach_to_rpm(int n,uint8_t tach)889*0Sstevel@tonic-gate tach_to_rpm(int n, uint8_t tach)
890*0Sstevel@tonic-gate {
891*0Sstevel@tonic-gate 	if (n * tach == 0)
892*0Sstevel@tonic-gate 		return (0);
893*0Sstevel@tonic-gate 	return ((ADCSAMPLE * 60) / (n * tach));
894*0Sstevel@tonic-gate }
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate static int
get_raw_fan_speed(env_fan_t * fanp,uint8_t * fanspeedp)897*0Sstevel@tonic-gate get_raw_fan_speed(env_fan_t *fanp, uint8_t *fanspeedp)
898*0Sstevel@tonic-gate {
899*0Sstevel@tonic-gate 	int	fan_fd;
900*0Sstevel@tonic-gate 	int	retval = 0;
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	fan_fd = fanp->fd;
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 	if (fan_fd == -1)
905*0Sstevel@tonic-gate 		retval = -1;
906*0Sstevel@tonic-gate 	else if (ioctl(fan_fd, I2C_GET_FAN_SPEED, fanspeedp) == -1) {
907*0Sstevel@tonic-gate 		retval = -1;
908*0Sstevel@tonic-gate 	}
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate 
911*0Sstevel@tonic-gate 	return (retval);
912*0Sstevel@tonic-gate }
913*0Sstevel@tonic-gate 
914*0Sstevel@tonic-gate /*
915*0Sstevel@tonic-gate  * Get current fan speed
916*0Sstevel@tonic-gate  * This function returns a RPM value for fanspeed
917*0Sstevel@tonic-gate  * in fanspeedp.
918*0Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
919*0Sstevel@tonic-gate  */
920*0Sstevel@tonic-gate int
get_fan_speed(env_fan_t * fanp,fanspeed_t * fanspeedp)921*0Sstevel@tonic-gate get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
922*0Sstevel@tonic-gate {
923*0Sstevel@tonic-gate 	int	fan_fd;
924*0Sstevel@tonic-gate 	uint8_t tach;
925*0Sstevel@tonic-gate 
926*0Sstevel@tonic-gate 	fan_fd = fanp->fd;
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 	if (fan_fd == -1)
929*0Sstevel@tonic-gate 		return (-1);
930*0Sstevel@tonic-gate 	if (fanp->id == DIMM_FAN_ID) {
931*0Sstevel@tonic-gate 		return (get_dimm_fan_speed(fan_fd, fanspeedp));
932*0Sstevel@tonic-gate 	}
933*0Sstevel@tonic-gate 	if (ioctl(fan_fd, I2C_GET_FAN_SPEED, &tach) == -1) {
934*0Sstevel@tonic-gate 		return (-1);
935*0Sstevel@tonic-gate 	}
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	/*
938*0Sstevel@tonic-gate 	 * Fanspeeds are reported as 0
939*0Sstevel@tonic-gate 	 * if the tach is out of range or fan status is off
940*0Sstevel@tonic-gate 	 * and if monitoring fan status is enabled.
941*0Sstevel@tonic-gate 	 */
942*0Sstevel@tonic-gate 	if (mon_fanstat && (!fanp->fanstat || tach == FAN_OUT_OF_RANGE)) {
943*0Sstevel@tonic-gate 		*fanspeedp = 0;
944*0Sstevel@tonic-gate 	} else {
945*0Sstevel@tonic-gate 		*fanspeedp =
946*0Sstevel@tonic-gate 		    tach_to_rpm(fanp->speedrange, tach);
947*0Sstevel@tonic-gate 	}
948*0Sstevel@tonic-gate 
949*0Sstevel@tonic-gate 	return (0);
950*0Sstevel@tonic-gate }
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate /*
953*0Sstevel@tonic-gate  * Set fan speed
954*0Sstevel@tonic-gate  * This function accepts a percentage of fan speed
955*0Sstevel@tonic-gate  * from 0-100 and programs the HW monitor fans to the corresponding
956*0Sstevel@tonic-gate  * fanspeed value.
957*0Sstevel@tonic-gate  * Returns -1 on error, -2 on invalid args passed, 0 if successful
958*0Sstevel@tonic-gate  */
959*0Sstevel@tonic-gate int
set_fan_speed(env_fan_t * fanp,fanspeed_t fanspeed)960*0Sstevel@tonic-gate set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
961*0Sstevel@tonic-gate {
962*0Sstevel@tonic-gate 	int	fan_fd;
963*0Sstevel@tonic-gate 	int	retval = 0;
964*0Sstevel@tonic-gate 	uint8_t	speed;
965*0Sstevel@tonic-gate 
966*0Sstevel@tonic-gate 	fan_fd = fanp->fd;
967*0Sstevel@tonic-gate 	if (fan_fd == -1)
968*0Sstevel@tonic-gate 		return (-1);
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 	if (fanspeed < 0 || fanspeed > 100)
971*0Sstevel@tonic-gate 		return (-2);
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate 	speed = (uint8_t)ADM_SETFANSPEED_CONV(fanspeed);
974*0Sstevel@tonic-gate 
975*0Sstevel@tonic-gate 	if (ioctl(fan_fd, I2C_SET_FAN_SPEED, &speed) == -1) {
976*0Sstevel@tonic-gate 		retval = -1;
977*0Sstevel@tonic-gate 	}
978*0Sstevel@tonic-gate 	return (retval);
979*0Sstevel@tonic-gate }
980*0Sstevel@tonic-gate 
981*0Sstevel@tonic-gate /*
982*0Sstevel@tonic-gate  * close all fan devices
983*0Sstevel@tonic-gate  */
984*0Sstevel@tonic-gate static void
envd_close_fans(void)985*0Sstevel@tonic-gate envd_close_fans(void)
986*0Sstevel@tonic-gate {
987*0Sstevel@tonic-gate 	int		i;
988*0Sstevel@tonic-gate 	env_fan_t	*fanp;
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
991*0Sstevel@tonic-gate 		if (fanp->fd != -1) {
992*0Sstevel@tonic-gate 			(void) close(fanp->fd);
993*0Sstevel@tonic-gate 			fanp->fd = -1;
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 	}
996*0Sstevel@tonic-gate }
997*0Sstevel@tonic-gate 
998*0Sstevel@tonic-gate /*
999*0Sstevel@tonic-gate  * Close sensor devices and freeup resources
1000*0Sstevel@tonic-gate  */
1001*0Sstevel@tonic-gate static void
envd_close_sensors(void)1002*0Sstevel@tonic-gate envd_close_sensors(void)
1003*0Sstevel@tonic-gate {
1004*0Sstevel@tonic-gate 	env_sensor_t	*sensorp;
1005*0Sstevel@tonic-gate 	int		i;
1006*0Sstevel@tonic-gate 
1007*0Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
1008*0Sstevel@tonic-gate 		sensorp = &envd_sensors[i];
1009*0Sstevel@tonic-gate 		if (sensorp->fd != -1) {
1010*0Sstevel@tonic-gate 			(void) close(sensorp->fd);
1011*0Sstevel@tonic-gate 			sensorp->fd = -1;
1012*0Sstevel@tonic-gate 		}
1013*0Sstevel@tonic-gate 		if (sensorp->crtbl != NULL)
1014*0Sstevel@tonic-gate 			fini_table(sensorp->crtbl);
1015*0Sstevel@tonic-gate 	}
1016*0Sstevel@tonic-gate }
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate /*
1019*0Sstevel@tonic-gate  * Open fan devices and initialize per fan data structure.
1020*0Sstevel@tonic-gate  * Returns #fans found.
1021*0Sstevel@tonic-gate  */
1022*0Sstevel@tonic-gate static int
envd_setup_fans(void)1023*0Sstevel@tonic-gate envd_setup_fans(void)
1024*0Sstevel@tonic-gate {
1025*0Sstevel@tonic-gate 	int		i, fd;
1026*0Sstevel@tonic-gate 	env_fan_t	*fanp;
1027*0Sstevel@tonic-gate 	char		path[PATH_MAX];
1028*0Sstevel@tonic-gate 	int		fancnt = 0;
1029*0Sstevel@tonic-gate 	uint8_t		n = 0;
1030*0Sstevel@tonic-gate 	picl_nodehdl_t tnodeh;
1031*0Sstevel@tonic-gate 	i2c_reg_t	i2c_reg;
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
1034*0Sstevel@tonic-gate 		/* make sure cpu0/1 present for validating cpu fans */
1035*0Sstevel@tonic-gate 		if (fanp->id == CPU0_FAN_ID) {
1036*0Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
1037*0Sstevel@tonic-gate 				PICL_SUCCESS) {
1038*0Sstevel@tonic-gate 					fanp->present = B_FALSE;
1039*0Sstevel@tonic-gate 					continue;
1040*0Sstevel@tonic-gate 			}
1041*0Sstevel@tonic-gate 		}
1042*0Sstevel@tonic-gate 		if (fanp->id == CPU1_FAN_ID) {
1043*0Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
1044*0Sstevel@tonic-gate 				PICL_SUCCESS) {
1045*0Sstevel@tonic-gate 					fanp->present = B_FALSE;
1046*0Sstevel@tonic-gate 					continue;
1047*0Sstevel@tonic-gate 			}
1048*0Sstevel@tonic-gate 		}
1049*0Sstevel@tonic-gate 		if (fanp->id == DIMM_FAN_ID) {
1050*0Sstevel@tonic-gate 			if (ptree_get_node_by_path(DIMM_FAN_CONTROLLER_PATH,
1051*0Sstevel@tonic-gate 				&tnodeh) != PICL_SUCCESS) {
1052*0Sstevel@tonic-gate 					if (env_debug)
1053*0Sstevel@tonic-gate 						envd_log(LOG_ERR,
1054*0Sstevel@tonic-gate 				"dimm Fan not found in the system.\n");
1055*0Sstevel@tonic-gate 					fanp->present = B_FALSE;
1056*0Sstevel@tonic-gate 					continue;
1057*0Sstevel@tonic-gate 			}
1058*0Sstevel@tonic-gate 		}
1059*0Sstevel@tonic-gate 		(void) strcpy(path, "/devices");
1060*0Sstevel@tonic-gate 		(void) strlcat(path, fanp->devfs_path, sizeof (path));
1061*0Sstevel@tonic-gate 		fd = open(path, O_RDWR);
1062*0Sstevel@tonic-gate 		if (fd == -1) {
1063*0Sstevel@tonic-gate 			envd_log(LOG_CRIT,
1064*0Sstevel@tonic-gate 			    ENV_FAN_OPEN_FAIL, fanp->name,
1065*0Sstevel@tonic-gate 			    fanp->devfs_path, errno, strerror(errno));
1066*0Sstevel@tonic-gate 			fanp->present = B_FALSE;
1067*0Sstevel@tonic-gate 			continue;
1068*0Sstevel@tonic-gate 		}
1069*0Sstevel@tonic-gate 		fanp->fd = fd;
1070*0Sstevel@tonic-gate 		if (fanp->id == DIMM_FAN_ID) {
1071*0Sstevel@tonic-gate 			/*
1072*0Sstevel@tonic-gate 			 * set the SW aware bit in command register.
1073*0Sstevel@tonic-gate 			 * Clear the Fan fault latch bit.
1074*0Sstevel@tonic-gate 			 */
1075*0Sstevel@tonic-gate 			i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
1076*0Sstevel@tonic-gate 			i2c_reg.reg_value = (PIC16F819_SW_AWARE_MODE |
1077*0Sstevel@tonic-gate 				PIC16F819_FAN_FAULT_CLEAR);
1078*0Sstevel@tonic-gate 			if (ioctl(fd, I2C_SET_REG, &i2c_reg) == -1) {
1079*0Sstevel@tonic-gate 				if (env_debug)
1080*0Sstevel@tonic-gate 					envd_log(LOG_ERR,
1081*0Sstevel@tonic-gate 		"Error in writing to COMMAND reg. of DIMM FAN controller\n");
1082*0Sstevel@tonic-gate 			}
1083*0Sstevel@tonic-gate 		} else {
1084*0Sstevel@tonic-gate 			/* Get speed range value */
1085*0Sstevel@tonic-gate 			if (ioctl(fd, ADM1031_GET_FAN_FEATURE, &n) != -1) {
1086*0Sstevel@tonic-gate 				fanp->speedrange =
1087*0Sstevel@tonic-gate 				    adm_speedrange_map[(n >> 6) & 0x03];
1088*0Sstevel@tonic-gate 			} else {
1089*0Sstevel@tonic-gate 				fanp->speedrange = FAN_RANGE_DEFAULT;
1090*0Sstevel@tonic-gate 			}
1091*0Sstevel@tonic-gate 		}
1092*0Sstevel@tonic-gate 		fanp->present = B_TRUE;
1093*0Sstevel@tonic-gate 		fanp->fanstat = 0;
1094*0Sstevel@tonic-gate 		fanp->cspeed = TACH_UNKNOWN;
1095*0Sstevel@tonic-gate 		fanp->lspeed = TACH_UNKNOWN;
1096*0Sstevel@tonic-gate 		fanp->conccnt = 0;
1097*0Sstevel@tonic-gate 		fancnt++;
1098*0Sstevel@tonic-gate 	}
1099*0Sstevel@tonic-gate 	return (fancnt);
1100*0Sstevel@tonic-gate }
1101*0Sstevel@tonic-gate 
1102*0Sstevel@tonic-gate static int
envd_setup_disks(void)1103*0Sstevel@tonic-gate envd_setup_disks(void)
1104*0Sstevel@tonic-gate {
1105*0Sstevel@tonic-gate 	int	ret, i, page_index, page_len;
1106*0Sstevel@tonic-gate 	picl_nodehdl_t tnodeh;
1107*0Sstevel@tonic-gate 	env_disk_t	*diskp;
1108*0Sstevel@tonic-gate 	uint_t	vendor_id;
1109*0Sstevel@tonic-gate 	uint_t	device_id;
1110*0Sstevel@tonic-gate 	uchar_t	log_page[256];
1111*0Sstevel@tonic-gate 
1112*0Sstevel@tonic-gate 	/*
1113*0Sstevel@tonic-gate 	 * Check if the SCSi controller on the system is 1010 or 1030
1114*0Sstevel@tonic-gate 	 */
1115*0Sstevel@tonic-gate 
1116*0Sstevel@tonic-gate 	if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH,
1117*0Sstevel@tonic-gate 				&tnodeh) != PICL_SUCCESS) {
1118*0Sstevel@tonic-gate 		if (env_debug)
1119*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
1120*0Sstevel@tonic-gate 			"On-Board SCSI controller not found in the system.\n");
1121*0Sstevel@tonic-gate 		monitor_disk_temp = 0;
1122*0Sstevel@tonic-gate 		return (-1);
1123*0Sstevel@tonic-gate 	}
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID,
1126*0Sstevel@tonic-gate 				&vendor_id,
1127*0Sstevel@tonic-gate 				sizeof (vendor_id))) != 0) {
1128*0Sstevel@tonic-gate 		if (env_debug)
1129*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
1130*0Sstevel@tonic-gate "Error in getting vendor-id for SCSI controller. ret = %d errno = 0x%d\n",
1131*0Sstevel@tonic-gate 				ret, errno);
1132*0Sstevel@tonic-gate 		monitor_disk_temp = 0;
1133*0Sstevel@tonic-gate 		return (-1);
1134*0Sstevel@tonic-gate 	}
1135*0Sstevel@tonic-gate 	if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID,
1136*0Sstevel@tonic-gate 				&device_id,
1137*0Sstevel@tonic-gate 				sizeof (device_id))) != 0) {
1138*0Sstevel@tonic-gate 		if (env_debug)
1139*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
1140*0Sstevel@tonic-gate "Error in getting device-id for SCSI controller. ret = %d errno = 0x%d\n",
1141*0Sstevel@tonic-gate 				ret, errno);
1142*0Sstevel@tonic-gate 		monitor_disk_temp = 0;
1143*0Sstevel@tonic-gate 		return (-1);
1144*0Sstevel@tonic-gate 	}
1145*0Sstevel@tonic-gate 	if (env_debug)
1146*0Sstevel@tonic-gate 		envd_log(LOG_ERR, "vendor-id=0x%x device-id=0x%x\n",
1147*0Sstevel@tonic-gate 			vendor_id, device_id);
1148*0Sstevel@tonic-gate 	if ((vendor_id != LSI1030_VENDOR_ID) ||
1149*0Sstevel@tonic-gate 		(device_id != LSI1030_DEVICE_ID)) {
1150*0Sstevel@tonic-gate 		monitor_disk_temp = 0;
1151*0Sstevel@tonic-gate 		return (-1);
1152*0Sstevel@tonic-gate 	}
1153*0Sstevel@tonic-gate 	/*
1154*0Sstevel@tonic-gate 	 * We have found LSI1030 SCSi controller onboard.
1155*0Sstevel@tonic-gate 	 */
1156*0Sstevel@tonic-gate 
1157*0Sstevel@tonic-gate 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
1158*0Sstevel@tonic-gate 
1159*0Sstevel@tonic-gate 		if (ptree_get_node_by_path(diskp->nodepath,
1160*0Sstevel@tonic-gate 				&tnodeh) != PICL_SUCCESS) {
1161*0Sstevel@tonic-gate 			diskp->present = B_FALSE;
1162*0Sstevel@tonic-gate 			if (env_debug)
1163*0Sstevel@tonic-gate 				envd_log(LOG_ERR,
1164*0Sstevel@tonic-gate 					"DISK %d not found in the system.\n",
1165*0Sstevel@tonic-gate 					diskp->id);
1166*0Sstevel@tonic-gate 			continue;
1167*0Sstevel@tonic-gate 		}
1168*0Sstevel@tonic-gate 		diskp->fd = open(diskp->devfs_path, O_RDONLY);
1169*0Sstevel@tonic-gate 		if (diskp->fd == -1) {
1170*0Sstevel@tonic-gate 			diskp->present = B_FALSE;
1171*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
1172*0Sstevel@tonic-gate 				"Error in opening %s errno = 0x%x\n",
1173*0Sstevel@tonic-gate 				diskp->devfs_path, errno);
1174*0Sstevel@tonic-gate 			continue;
1175*0Sstevel@tonic-gate 		}
1176*0Sstevel@tonic-gate 		diskp->present = B_TRUE;
1177*0Sstevel@tonic-gate 		diskp->tpage_supported = B_FALSE;
1178*0Sstevel@tonic-gate 		/*
1179*0Sstevel@tonic-gate 		 * Find out if the Temperature page is supported by the disk.
1180*0Sstevel@tonic-gate 		 */
1181*0Sstevel@tonic-gate 		ret = scsi_log_sense(diskp->fd, SUPPORTED_LPAGES,
1182*0Sstevel@tonic-gate 				log_page, sizeof (log_page));
1183*0Sstevel@tonic-gate 		if (ret != 0) {
1184*0Sstevel@tonic-gate 			continue;
1185*0Sstevel@tonic-gate 		}
1186*0Sstevel@tonic-gate 		page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3];
1187*0Sstevel@tonic-gate 
1188*0Sstevel@tonic-gate 		for (page_index = LOGPAGEHDRSIZE;
1189*0Sstevel@tonic-gate 			page_index < page_len + LOGPAGEHDRSIZE; page_index++) {
1190*0Sstevel@tonic-gate 			switch (log_page[page_index]) {
1191*0Sstevel@tonic-gate 				case TEMPERATURE_PAGE:
1192*0Sstevel@tonic-gate 					diskp->tpage_supported = B_TRUE;
1193*0Sstevel@tonic-gate 				if (env_debug)
1194*0Sstevel@tonic-gate 					envd_log(LOG_ERR,
1195*0Sstevel@tonic-gate 						"tpage supported for %s\n",
1196*0Sstevel@tonic-gate 						diskp->nodepath);
1197*0Sstevel@tonic-gate 				default:
1198*0Sstevel@tonic-gate 					break;
1199*0Sstevel@tonic-gate 			}
1200*0Sstevel@tonic-gate 		}
1201*0Sstevel@tonic-gate 		diskp->warning_tstamp = 0;
1202*0Sstevel@tonic-gate 		diskp->shutdown_tstamp = 0;
1203*0Sstevel@tonic-gate 		diskp->high_warning = disk_high_warn_temperature;
1204*0Sstevel@tonic-gate 		diskp->low_warning = disk_low_warn_temperature;
1205*0Sstevel@tonic-gate 		diskp->high_shutdown = disk_high_shutdown_temperature;
1206*0Sstevel@tonic-gate 		diskp->low_shutdown = disk_low_shutdown_temperature;
1207*0Sstevel@tonic-gate 		ret = get_disk_temp(diskp);
1208*0Sstevel@tonic-gate 	}
1209*0Sstevel@tonic-gate 	return (0);
1210*0Sstevel@tonic-gate }
1211*0Sstevel@tonic-gate 
1212*0Sstevel@tonic-gate /*
1213*0Sstevel@tonic-gate  * Open temperature sensor devices and initialize per sensor data structure.
1214*0Sstevel@tonic-gate  * Returns #sensors found.
1215*0Sstevel@tonic-gate  */
1216*0Sstevel@tonic-gate static int
envd_setup_sensors(void)1217*0Sstevel@tonic-gate envd_setup_sensors(void)
1218*0Sstevel@tonic-gate {
1219*0Sstevel@tonic-gate 	env_sensor_t	*sensorp;
1220*0Sstevel@tonic-gate 	sensor_ctrl_blk_t *es_ptr;
1221*0Sstevel@tonic-gate 	table_t		*tblp;
1222*0Sstevel@tonic-gate 	char		path[PATH_MAX];
1223*0Sstevel@tonic-gate 	int		sensorcnt = 0;
1224*0Sstevel@tonic-gate 	int		i, j, nentries;
1225*0Sstevel@tonic-gate 	int16_t		tmin = 0;
1226*0Sstevel@tonic-gate 	picl_nodehdl_t tnodeh;
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
1229*0Sstevel@tonic-gate 		sensorp = &envd_sensors[i];
1230*0Sstevel@tonic-gate 		/* Initialize sensor's initial state */
1231*0Sstevel@tonic-gate 		sensorp->shutdown_initiated = B_FALSE;
1232*0Sstevel@tonic-gate 		sensorp->warning_tstamp = 0;
1233*0Sstevel@tonic-gate 		sensorp->shutdown_tstamp = 0;
1234*0Sstevel@tonic-gate 		sensorp->error = 0;
1235*0Sstevel@tonic-gate 		sensorp->crtbl = NULL;
1236*0Sstevel@tonic-gate 		/* make sure cpu0/1 sensors are present */
1237*0Sstevel@tonic-gate 		if (sensorp->id == CPU0_SENSOR_ID) {
1238*0Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
1239*0Sstevel@tonic-gate 				PICL_SUCCESS) {
1240*0Sstevel@tonic-gate 				sensorp->present = B_FALSE;
1241*0Sstevel@tonic-gate 				continue;
1242*0Sstevel@tonic-gate 			}
1243*0Sstevel@tonic-gate 		}
1244*0Sstevel@tonic-gate 		if (sensorp->id == CPU1_SENSOR_ID) {
1245*0Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
1246*0Sstevel@tonic-gate 				PICL_SUCCESS) {
1247*0Sstevel@tonic-gate 				sensorp->present = B_FALSE;
1248*0Sstevel@tonic-gate 				continue;
1249*0Sstevel@tonic-gate 			}
1250*0Sstevel@tonic-gate 		}
1251*0Sstevel@tonic-gate 		(void) strcpy(path, "/devices");
1252*0Sstevel@tonic-gate 		(void) strlcat(path, sensorp->devfs_path,
1253*0Sstevel@tonic-gate 		    sizeof (path));
1254*0Sstevel@tonic-gate 		sensorp->fd = open(path, O_RDWR);
1255*0Sstevel@tonic-gate 		if (sensorp->fd == -1) {
1256*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
1257*0Sstevel@tonic-gate 			    sensorp->name, sensorp->devfs_path,
1258*0Sstevel@tonic-gate 			    errno, strerror(errno));
1259*0Sstevel@tonic-gate 			sensorp->present = B_FALSE;
1260*0Sstevel@tonic-gate 			continue;
1261*0Sstevel@tonic-gate 		}
1262*0Sstevel@tonic-gate 		sensorp->present = B_TRUE;
1263*0Sstevel@tonic-gate 		sensorcnt++;
1264*0Sstevel@tonic-gate 
1265*0Sstevel@tonic-gate 		/*
1266*0Sstevel@tonic-gate 		 * Get Tmin
1267*0Sstevel@tonic-gate 		 */
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 		if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1270*0Sstevel@tonic-gate 			&tmin) != -1) {
1271*0Sstevel@tonic-gate 			sensorp->tmin = TMIN(tmin);
1272*0Sstevel@tonic-gate 		} else {
1273*0Sstevel@tonic-gate 			sensorp->tmin = -1;
1274*0Sstevel@tonic-gate 		}
1275*0Sstevel@tonic-gate 		if (env_debug)
1276*0Sstevel@tonic-gate 			envd_log(LOG_ERR, "Sensor %s tmin %d",
1277*0Sstevel@tonic-gate 			    sensorp->name, sensorp->tmin);
1278*0Sstevel@tonic-gate 
1279*0Sstevel@tonic-gate 		/*
1280*0Sstevel@tonic-gate 		 * Create a correction table
1281*0Sstevel@tonic-gate 		 * if correction pairs are present in es
1282*0Sstevel@tonic-gate 		 * segment.
1283*0Sstevel@tonic-gate 		 */
1284*0Sstevel@tonic-gate 		es_ptr = sensorp->es_ptr;
1285*0Sstevel@tonic-gate 
1286*0Sstevel@tonic-gate 		if (es_ptr == NULL) {
1287*0Sstevel@tonic-gate 			continue;
1288*0Sstevel@tonic-gate 		}
1289*0Sstevel@tonic-gate 		nentries = es_ptr->correctionEntries;
1290*0Sstevel@tonic-gate 
1291*0Sstevel@tonic-gate 		if (nentries <= 2) {
1292*0Sstevel@tonic-gate 			if (env_debug)
1293*0Sstevel@tonic-gate 				envd_log(LOG_CRIT, "sensor correction <2");
1294*0Sstevel@tonic-gate 			continue;
1295*0Sstevel@tonic-gate 		}
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 		sensorp->crtbl = init_table(nentries);
1298*0Sstevel@tonic-gate 		if (sensorp->crtbl == NULL)
1299*0Sstevel@tonic-gate 			continue;
1300*0Sstevel@tonic-gate 		tblp = sensorp->crtbl;
1301*0Sstevel@tonic-gate 		tblp->xymap[0].x =
1302*0Sstevel@tonic-gate 		    (char)es_ptr->correctionPair[0].measured;
1303*0Sstevel@tonic-gate 		tblp->xymap[0].y =
1304*0Sstevel@tonic-gate 		    (char)es_ptr->correctionPair[0].corrected;
1305*0Sstevel@tonic-gate 
1306*0Sstevel@tonic-gate 		for (j = 1; j < nentries; ++j) {
1307*0Sstevel@tonic-gate 			tblp->xymap[j].x =
1308*0Sstevel@tonic-gate 			    (char)es_ptr->correctionPair[j].measured;
1309*0Sstevel@tonic-gate 			tblp->xymap[j].y =
1310*0Sstevel@tonic-gate 			    (char)es_ptr->correctionPair[j].corrected;
1311*0Sstevel@tonic-gate 
1312*0Sstevel@tonic-gate 			if (tblp->xymap[j].x <= tblp->xymap[j - 1].x) {
1313*0Sstevel@tonic-gate 				fini_table(tblp);
1314*0Sstevel@tonic-gate 				sensorp->crtbl = NULL;
1315*0Sstevel@tonic-gate 				envd_log(LOG_CRIT, ENV_FRU_BAD_ENVSEG,
1316*0Sstevel@tonic-gate 				    FRU_SEEPROM_NAME);
1317*0Sstevel@tonic-gate 				break;
1318*0Sstevel@tonic-gate 			}
1319*0Sstevel@tonic-gate 		}
1320*0Sstevel@tonic-gate 
1321*0Sstevel@tonic-gate 		if (env_debug) {
1322*0Sstevel@tonic-gate 			envd_log(LOG_CRIT, "Sensor correction  %s",
1323*0Sstevel@tonic-gate 			    sensorp->name);
1324*0Sstevel@tonic-gate 			for (j = 0; j < nentries; j++)
1325*0Sstevel@tonic-gate 				envd_log(LOG_CRIT, " %d	%d",
1326*0Sstevel@tonic-gate 				    tblp->xymap[j].x, tblp->xymap[j].y);
1327*0Sstevel@tonic-gate 		}
1328*0Sstevel@tonic-gate 	}
1329*0Sstevel@tonic-gate 	return (sensorcnt);
1330*0Sstevel@tonic-gate }
1331*0Sstevel@tonic-gate 
1332*0Sstevel@tonic-gate /*
1333*0Sstevel@tonic-gate  * Modify ADM Tmin/ranges depending what power level
1334*0Sstevel@tonic-gate  * we are from.
1335*0Sstevel@tonic-gate  */
1336*0Sstevel@tonic-gate static void
updateadm_ranges(char * name,uchar_t cur_lpstate)1337*0Sstevel@tonic-gate updateadm_ranges(char *name, uchar_t cur_lpstate)
1338*0Sstevel@tonic-gate {
1339*0Sstevel@tonic-gate 	env_sensor_t *sensorp;
1340*0Sstevel@tonic-gate 	fan_ctrl_blk_t *fanctl;
1341*0Sstevel@tonic-gate 	uchar_t tmin;
1342*0Sstevel@tonic-gate 	uchar_t trange;
1343*0Sstevel@tonic-gate 	uint16_t tdata;
1344*0Sstevel@tonic-gate 	int sysfd;
1345*0Sstevel@tonic-gate 	uchar_t sys_id = SYS_HWM_ID;
1346*0Sstevel@tonic-gate 	uint8_t mode;
1347*0Sstevel@tonic-gate 	static uint16_t tsave[2] = {0, 0};
1348*0Sstevel@tonic-gate 	/* Index of saved Tmin/Trange for two sensors */
1349*0Sstevel@tonic-gate 	uint16_t tindex = 0;
1350*0Sstevel@tonic-gate 
1351*0Sstevel@tonic-gate 	sensorp = sensor_lookup(name);
1352*0Sstevel@tonic-gate 	if (sensorp == NULL)
1353*0Sstevel@tonic-gate 		return;
1354*0Sstevel@tonic-gate 
1355*0Sstevel@tonic-gate 	/*
1356*0Sstevel@tonic-gate 	 * If there is only one Control pairs then return
1357*0Sstevel@tonic-gate 	 */
1358*0Sstevel@tonic-gate 	fanctl = ((env_fan_t *)sensorp->fanp)->es_ptr;
1359*0Sstevel@tonic-gate 
1360*0Sstevel@tonic-gate 	if (fanctl != NULL && fanctl->no_ctl_pairs <= 1)
1361*0Sstevel@tonic-gate 		return;
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	/*
1364*0Sstevel@tonic-gate 	 * if fan control specifies that ranges are same then
1365*0Sstevel@tonic-gate 	 * we skip re-programming adm chip.
1366*0Sstevel@tonic-gate 	 */
1367*0Sstevel@tonic-gate 
1368*0Sstevel@tonic-gate 	tmin = fanctl->fan_ctl_pairs[0].tMin;
1369*0Sstevel@tonic-gate 	trange = fanctl->fan_ctl_pairs[0].tRange;
1370*0Sstevel@tonic-gate 	if ((tmin == fanctl->fan_ctl_pairs[1].tMin) &&
1371*0Sstevel@tonic-gate 	    (trange == fanctl->fan_ctl_pairs[1].tRange))
1372*0Sstevel@tonic-gate 			return;
1373*0Sstevel@tonic-gate 
1374*0Sstevel@tonic-gate 	sysfd = open(hwm_devs[sys_id], O_RDWR);
1375*0Sstevel@tonic-gate 	if (sysfd == -1) {
1376*0Sstevel@tonic-gate 		if (env_debug)
1377*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[sys_id],
1378*0Sstevel@tonic-gate 			    errno, strerror(errno));
1379*0Sstevel@tonic-gate 		return;
1380*0Sstevel@tonic-gate 	}
1381*0Sstevel@tonic-gate 	tindex = ((strcmp(name, SENSOR_SYS_IN) == 0) ? 0 : 1);
1382*0Sstevel@tonic-gate 
1383*0Sstevel@tonic-gate 	/* Read ADM default value only for the first time */
1384*0Sstevel@tonic-gate 	if (tsave[tindex] == 0) {
1385*0Sstevel@tonic-gate 		if (ioctl(sensorp->fd, ADM1031_GET_TEMP_MIN_RANGE,
1386*0Sstevel@tonic-gate 			&tsave[tindex]) == -1) {
1387*0Sstevel@tonic-gate 			if (env_debug)
1388*0Sstevel@tonic-gate 				envd_log(LOG_ERR,
1389*0Sstevel@tonic-gate 				    "read tminrange ioctl failed");
1390*0Sstevel@tonic-gate 			(void) close(sysfd);
1391*0Sstevel@tonic-gate 			return;
1392*0Sstevel@tonic-gate 		}
1393*0Sstevel@tonic-gate 	}
1394*0Sstevel@tonic-gate 	/*
1395*0Sstevel@tonic-gate 	 * Need to reinit ADM to manual mode for Tmin range to be
1396*0Sstevel@tonic-gate 	 * effective.
1397*0Sstevel@tonic-gate 	 */
1398*0Sstevel@tonic-gate 	mode = ADM1031_MANUAL_MODE;
1399*0Sstevel@tonic-gate 	if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1400*0Sstevel@tonic-gate 		if (env_debug)
1401*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENV_ADM_MANUAL_MODE);
1402*0Sstevel@tonic-gate 		(void) close(sysfd);
1403*0Sstevel@tonic-gate 		return;
1404*0Sstevel@tonic-gate 	}
1405*0Sstevel@tonic-gate 
1406*0Sstevel@tonic-gate 	if (cur_lpstate == 1) {
1407*0Sstevel@tonic-gate 		/*
1408*0Sstevel@tonic-gate 		 * ADM 1031 Tmin/Trange register need to be reprogrammed.
1409*0Sstevel@tonic-gate 		 */
1410*0Sstevel@tonic-gate 		tdata = ((fanctl->fan_ctl_pairs[cur_lpstate].tMin / TMIN_UNITS)
1411*0Sstevel@tonic-gate 				<< TMIN_SHIFT);
1412*0Sstevel@tonic-gate 		/* Need to pack tRange in ADM bits 2:0 */
1413*0Sstevel@tonic-gate 		switch (fanctl->fan_ctl_pairs[cur_lpstate].tRange) {
1414*0Sstevel@tonic-gate 			case 5:
1415*0Sstevel@tonic-gate 				break;
1416*0Sstevel@tonic-gate 
1417*0Sstevel@tonic-gate 			case 10:
1418*0Sstevel@tonic-gate 				tdata |= 1;
1419*0Sstevel@tonic-gate 				break;
1420*0Sstevel@tonic-gate 
1421*0Sstevel@tonic-gate 			case 20:
1422*0Sstevel@tonic-gate 				tdata |= 2;
1423*0Sstevel@tonic-gate 				break;
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 			case 40:
1426*0Sstevel@tonic-gate 				tdata |= 3;
1427*0Sstevel@tonic-gate 				break;
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 			case 80:
1430*0Sstevel@tonic-gate 				tdata |= 4;
1431*0Sstevel@tonic-gate 				break;
1432*0Sstevel@tonic-gate 		}
1433*0Sstevel@tonic-gate 	} else
1434*0Sstevel@tonic-gate 		tdata = tsave[tindex];
1435*0Sstevel@tonic-gate 
1436*0Sstevel@tonic-gate 	if (ioctl(sensorp->fd, ADM1031_SET_TEMP_MIN_RANGE,
1437*0Sstevel@tonic-gate 	    &tdata) != -1)
1438*0Sstevel@tonic-gate 		sensorp->tmin = TMIN(tdata);
1439*0Sstevel@tonic-gate 
1440*0Sstevel@tonic-gate 	mode = ADM1031_AUTO_MODE;
1441*0Sstevel@tonic-gate 	if (ioctl(sysfd, ADM1031_SET_MONITOR_MODE, &mode) == -1) {
1442*0Sstevel@tonic-gate 		if (env_debug)
1443*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENV_ADM_AUTO_MODE);
1444*0Sstevel@tonic-gate 	}
1445*0Sstevel@tonic-gate 	(void) close(sysfd);
1446*0Sstevel@tonic-gate }
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate /* ARGSUSED */
1449*0Sstevel@tonic-gate static void *
pmthr(void * args)1450*0Sstevel@tonic-gate pmthr(void *args)
1451*0Sstevel@tonic-gate {
1452*0Sstevel@tonic-gate 	pm_state_change_t	pmstate;
1453*0Sstevel@tonic-gate 	char			physpath[PATH_MAX];
1454*0Sstevel@tonic-gate 	int				pre_lpstate;
1455*0Sstevel@tonic-gate 
1456*0Sstevel@tonic-gate 	pmstate.physpath = physpath;
1457*0Sstevel@tonic-gate 	pmstate.size = sizeof (physpath);
1458*0Sstevel@tonic-gate 	cur_lpstate = 0;
1459*0Sstevel@tonic-gate 	pre_lpstate = 1;
1460*0Sstevel@tonic-gate 
1461*0Sstevel@tonic-gate 	pm_fd = open(PM_DEVICE, O_RDWR);
1462*0Sstevel@tonic-gate 	if (pm_fd == -1) {
1463*0Sstevel@tonic-gate 		envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
1464*0Sstevel@tonic-gate 		return (NULL);
1465*0Sstevel@tonic-gate 	}
1466*0Sstevel@tonic-gate 	for (;;) {
1467*0Sstevel@tonic-gate 		/*
1468*0Sstevel@tonic-gate 		 * Get PM state change events to check if the system
1469*0Sstevel@tonic-gate 		 * is in lowest power state and adjust ADM hardware
1470*0Sstevel@tonic-gate 		 * monitor's fan speed settings.
1471*0Sstevel@tonic-gate 		 *
1472*0Sstevel@tonic-gate 		 * To minimize polling, we use the blocking interface
1473*0Sstevel@tonic-gate 		 * to get the power state change event here.
1474*0Sstevel@tonic-gate 		 */
1475*0Sstevel@tonic-gate 		if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
1476*0Sstevel@tonic-gate 			if (errno != EINTR)
1477*0Sstevel@tonic-gate 				break;
1478*0Sstevel@tonic-gate 			continue;
1479*0Sstevel@tonic-gate 		}
1480*0Sstevel@tonic-gate 		do {
1481*0Sstevel@tonic-gate 			if (env_debug)  {
1482*0Sstevel@tonic-gate 				envd_log(LOG_INFO,
1483*0Sstevel@tonic-gate 					"pmstate event:0x%x flags:%x"
1484*0Sstevel@tonic-gate 					"comp:%d oldval:%d newval:%d path:%s\n",
1485*0Sstevel@tonic-gate 						pmstate.event, pmstate.flags,
1486*0Sstevel@tonic-gate 						pmstate.component,
1487*0Sstevel@tonic-gate 						pmstate.old_level,
1488*0Sstevel@tonic-gate 						pmstate.new_level,
1489*0Sstevel@tonic-gate 						pmstate.physpath);
1490*0Sstevel@tonic-gate 			}
1491*0Sstevel@tonic-gate 			cur_lpstate =
1492*0Sstevel@tonic-gate 			    (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
1493*0Sstevel@tonic-gate 		} while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
1494*0Sstevel@tonic-gate 		/*
1495*0Sstevel@tonic-gate 		 * Change ADM ranges as per E* Requirements. Update
1496*0Sstevel@tonic-gate 		 * happens only for valid state changes.
1497*0Sstevel@tonic-gate 		 */
1498*0Sstevel@tonic-gate 		if (pre_lpstate != cur_lpstate) {
1499*0Sstevel@tonic-gate 			pre_lpstate = cur_lpstate;
1500*0Sstevel@tonic-gate 			updateadm_ranges(SENSOR_SYS_OUT, cur_lpstate);
1501*0Sstevel@tonic-gate 			updateadm_ranges(SENSOR_SYS_IN, cur_lpstate);
1502*0Sstevel@tonic-gate 		}
1503*0Sstevel@tonic-gate 	}
1504*0Sstevel@tonic-gate 	/* Not reached */
1505*0Sstevel@tonic-gate 	return (NULL);
1506*0Sstevel@tonic-gate }
1507*0Sstevel@tonic-gate 
1508*0Sstevel@tonic-gate /*
1509*0Sstevel@tonic-gate  * This function is used to reasonably predict the
1510*0Sstevel@tonic-gate  * state of the fan (ON/OFF) using tmin and current temperature.
1511*0Sstevel@tonic-gate  *
1512*0Sstevel@tonic-gate  * We know the fan is on  if temp >= tmin and fan is off if
1513*0Sstevel@tonic-gate  * temp < (Tmin - Hysterisis).
1514*0Sstevel@tonic-gate  *
1515*0Sstevel@tonic-gate  * When the temperature is in between we don't know if the fan is on/off
1516*0Sstevel@tonic-gate  * because the temperature could be decreasing and not have crossed
1517*0Sstevel@tonic-gate  * Tmin - hysterisis and vice a versa.
1518*0Sstevel@tonic-gate  *
1519*0Sstevel@tonic-gate  *			FAN ON
1520*0Sstevel@tonic-gate  * Tmin
1521*0Sstevel@tonic-gate  * 	-------------------------------------------
1522*0Sstevel@tonic-gate  *
1523*0Sstevel@tonic-gate  * 			FAN ON/OFF
1524*0Sstevel@tonic-gate  *
1525*0Sstevel@tonic-gate  * 	--------------------------------------------
1526*0Sstevel@tonic-gate  * Tmin - Hysterisis
1527*0Sstevel@tonic-gate  *			FAN OFF
1528*0Sstevel@tonic-gate  *
1529*0Sstevel@tonic-gate  * To solve the problem of finding out if the fan is on/off in our gray region
1530*0Sstevel@tonic-gate  * we keep track of the last read tach and the current read tach. From
1531*0Sstevel@tonic-gate  * experimentation and from discussions with analog devices it is unlikely that
1532*0Sstevel@tonic-gate  * if the fans are on we will get a constant tach reading  more than 5 times in
1533*0Sstevel@tonic-gate  * a row. This is not but the most fool proof approach but the  best we can do.
1534*0Sstevel@tonic-gate  *
1535*0Sstevel@tonic-gate  * This routine implements the above logic for a sensor with an
1536*0Sstevel@tonic-gate  * associated fan. The caller garauntees sensorp and fanp are not null.
1537*0Sstevel@tonic-gate  */
1538*0Sstevel@tonic-gate 
1539*0Sstevel@tonic-gate static void
check_fanstat(env_sensor_t * sensorp)1540*0Sstevel@tonic-gate check_fanstat(env_sensor_t *sensorp)
1541*0Sstevel@tonic-gate {
1542*0Sstevel@tonic-gate 	env_fan_t *fanp = sensorp->fanp;
1543*0Sstevel@tonic-gate 	tempr_t	temp;
1544*0Sstevel@tonic-gate 	uint8_t fanspeed;
1545*0Sstevel@tonic-gate 
1546*0Sstevel@tonic-gate 	if (get_raw_temperature(sensorp, &temp) == -1)
1547*0Sstevel@tonic-gate 		return;
1548*0Sstevel@tonic-gate 
1549*0Sstevel@tonic-gate 	if (temp < (sensorp->tmin - ADM_HYSTERISIS)) {
1550*0Sstevel@tonic-gate 
1551*0Sstevel@tonic-gate 		fanp->fanstat = 0;		/* Fan off */
1552*0Sstevel@tonic-gate 		fanp->lspeed = TACH_UNKNOWN;	/* Reset Last read tach */
1553*0Sstevel@tonic-gate 		fanp->conccnt = 0;
1554*0Sstevel@tonic-gate 
1555*0Sstevel@tonic-gate 	} else if (temp >= sensorp->tmin) {
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 		fanp->fanstat = 1;		/* Fan on */
1558*0Sstevel@tonic-gate 		fanp->lspeed = TACH_UNKNOWN;
1559*0Sstevel@tonic-gate 		fanp->conccnt = 0;
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate 	} else {
1562*0Sstevel@tonic-gate 		if (get_raw_fan_speed(fanp, &fanspeed) == -1)
1563*0Sstevel@tonic-gate 			return;
1564*0Sstevel@tonic-gate 
1565*0Sstevel@tonic-gate 		fanp->cspeed = fanspeed;
1566*0Sstevel@tonic-gate 		/*
1567*0Sstevel@tonic-gate 		 * First time in the gray area
1568*0Sstevel@tonic-gate 		 * set last read speed to current speed
1569*0Sstevel@tonic-gate 		 */
1570*0Sstevel@tonic-gate 		if (fanp->lspeed == TACH_UNKNOWN) {
1571*0Sstevel@tonic-gate 			fanp->lspeed = fanspeed;
1572*0Sstevel@tonic-gate 		} else {
1573*0Sstevel@tonic-gate 			if (fanp->lspeed != fanp->cspeed) {
1574*0Sstevel@tonic-gate 				fanp->conccnt = 0;
1575*0Sstevel@tonic-gate 				fanp->fanstat = 1;
1576*0Sstevel@tonic-gate 			} else {
1577*0Sstevel@tonic-gate 				fanp->conccnt++;
1578*0Sstevel@tonic-gate 
1579*0Sstevel@tonic-gate 				if (fanp->conccnt >= N_SEQ_TACH)
1580*0Sstevel@tonic-gate 					fanp->fanstat = 0;
1581*0Sstevel@tonic-gate 			}
1582*0Sstevel@tonic-gate 			fanp->lspeed = fanp->cspeed;
1583*0Sstevel@tonic-gate 		}
1584*0Sstevel@tonic-gate 	}
1585*0Sstevel@tonic-gate }
1586*0Sstevel@tonic-gate /*
1587*0Sstevel@tonic-gate  * There is an issue with the ADM1031 chip that causes the chip
1588*0Sstevel@tonic-gate  * to not update the tach register in case the fan stops. The
1589*0Sstevel@tonic-gate  * fans stop when the temperature measured (temp) drops below
1590*0Sstevel@tonic-gate  * Tmin - Hysterisis  and turn on when the temp >= Tmin.
1591*0Sstevel@tonic-gate  *
1592*0Sstevel@tonic-gate  * Since the tach registers don't update and remain stuck at the
1593*0Sstevel@tonic-gate  * last read tach value our get_fan_speed function always returns
1594*0Sstevel@tonic-gate  * a non-zero RPM reading.
1595*0Sstevel@tonic-gate  *
1596*0Sstevel@tonic-gate  * To fix this we need to figure out when the fans will be on/off
1597*0Sstevel@tonic-gate  * depending on the current temperature. Currently we poll for
1598*0Sstevel@tonic-gate  * interrupts, we can use that loop to determine what the current
1599*0Sstevel@tonic-gate  * temperature is and if the fans should be on/off.
1600*0Sstevel@tonic-gate  *
1601*0Sstevel@tonic-gate  * We get current temperature and check the fans.
1602*0Sstevel@tonic-gate  */
1603*0Sstevel@tonic-gate static void
monitor_fanstat(void)1604*0Sstevel@tonic-gate monitor_fanstat(void)
1605*0Sstevel@tonic-gate {
1606*0Sstevel@tonic-gate 	env_sensor_t *sensorp;
1607*0Sstevel@tonic-gate 	env_fan_t *fanp;
1608*0Sstevel@tonic-gate 	int i;
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1611*0Sstevel@tonic-gate 		sensorp = &envd_sensors[i];
1612*0Sstevel@tonic-gate 
1613*0Sstevel@tonic-gate 		if (!sensorp)
1614*0Sstevel@tonic-gate 			continue;
1615*0Sstevel@tonic-gate 
1616*0Sstevel@tonic-gate 		fanp = sensorp->fanp;
1617*0Sstevel@tonic-gate 
1618*0Sstevel@tonic-gate 		if (!(fanp && fanp->present))
1619*0Sstevel@tonic-gate 			continue;
1620*0Sstevel@tonic-gate 
1621*0Sstevel@tonic-gate 		if (sensorp->tmin != -1) {
1622*0Sstevel@tonic-gate 			check_fanstat(sensorp);
1623*0Sstevel@tonic-gate 		} else {
1624*0Sstevel@tonic-gate 			fanp->fanstat = 1;
1625*0Sstevel@tonic-gate 		}
1626*0Sstevel@tonic-gate 
1627*0Sstevel@tonic-gate 	}
1628*0Sstevel@tonic-gate }
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate static int
handle_overtemp_interrupt(int hwm_id)1631*0Sstevel@tonic-gate handle_overtemp_interrupt(int hwm_id)
1632*0Sstevel@tonic-gate {
1633*0Sstevel@tonic-gate 	env_sensor_t *sensorp;
1634*0Sstevel@tonic-gate 	tempr_t  temp;
1635*0Sstevel@tonic-gate 	uchar_t smap[MAX_SENSORS];
1636*0Sstevel@tonic-gate 	time_t  ct;
1637*0Sstevel@tonic-gate 	uchar_t i;
1638*0Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
1639*0Sstevel@tonic-gate 	char syscmd[BUFSIZ];
1640*0Sstevel@tonic-gate 	boolean_t return_flag;
1641*0Sstevel@tonic-gate 	int	ret;
1642*0Sstevel@tonic-gate 	timespec_t	to;
1643*0Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1644*0Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1645*0Sstevel@tonic-gate 
1646*0Sstevel@tonic-gate 	/* Clear Map of Sensor Entries */
1647*0Sstevel@tonic-gate 	(void) memset(smap, SENSOR_OK, sizeof (smap));
1648*0Sstevel@tonic-gate 
1649*0Sstevel@tonic-gate 	for (;;) {
1650*0Sstevel@tonic-gate 		for (i = 0; i < N_ENVD_SENSORS; i++) {
1651*0Sstevel@tonic-gate 			sensorp = &envd_sensors[i];
1652*0Sstevel@tonic-gate 
1653*0Sstevel@tonic-gate 			/*
1654*0Sstevel@tonic-gate 			 * Check whether the sensor belongs to the
1655*0Sstevel@tonic-gate 			 * interrupting ADM hardware monitor
1656*0Sstevel@tonic-gate 			 */
1657*0Sstevel@tonic-gate 			if (sensorp->hwm_id != hwm_id)
1658*0Sstevel@tonic-gate 				continue;
1659*0Sstevel@tonic-gate 
1660*0Sstevel@tonic-gate 			if (sensorp->present == B_FALSE)
1661*0Sstevel@tonic-gate 				continue;
1662*0Sstevel@tonic-gate 			/*
1663*0Sstevel@tonic-gate 			 * if shutdown is initiated then we simply loop
1664*0Sstevel@tonic-gate 			 * through the sensors until shutdown
1665*0Sstevel@tonic-gate 			 */
1666*0Sstevel@tonic-gate 			if (sensorp->shutdown_initiated == B_TRUE)
1667*0Sstevel@tonic-gate 				continue;
1668*0Sstevel@tonic-gate 
1669*0Sstevel@tonic-gate 			/* get current temp for this sensor */
1670*0Sstevel@tonic-gate 			if (get_temperature(sensorp, &temp) == -1)
1671*0Sstevel@tonic-gate 				continue;
1672*0Sstevel@tonic-gate 
1673*0Sstevel@tonic-gate 			sensorp->cur_temp = temp;
1674*0Sstevel@tonic-gate 
1675*0Sstevel@tonic-gate 			if (env_debug)
1676*0Sstevel@tonic-gate 				envd_log(LOG_ERR,
1677*0Sstevel@tonic-gate 					"sensor name %s, cur temp %d, "
1678*0Sstevel@tonic-gate 					"HW %d LW %d SD %d LS %d\n",
1679*0Sstevel@tonic-gate 					    sensorp->name, temp,
1680*0Sstevel@tonic-gate 					    sensorp->es_ptr->high_warning,
1681*0Sstevel@tonic-gate 					    (int)sensorp->es_ptr->low_warning,
1682*0Sstevel@tonic-gate 					    sensorp->es_ptr->high_shutdown,
1683*0Sstevel@tonic-gate 					    (int)sensorp->es_ptr->low_shutdown);
1684*0Sstevel@tonic-gate 
1685*0Sstevel@tonic-gate 			if (TEMP_IN_WARNING_RANGE(sensorp->cur_temp, sensorp)) {
1686*0Sstevel@tonic-gate 				/*
1687*0Sstevel@tonic-gate 				 * Log on warning atmost one second
1688*0Sstevel@tonic-gate 				 */
1689*0Sstevel@tonic-gate 				ct = (time_t)(gethrtime() / NANOSEC);
1690*0Sstevel@tonic-gate 				if ((ct - sensorp->warning_tstamp) >=
1691*0Sstevel@tonic-gate 				    warning_interval) {
1692*0Sstevel@tonic-gate 					envd_log(LOG_CRIT,
1693*0Sstevel@tonic-gate 					    ENV_WARNING_MSG, sensorp->name,
1694*0Sstevel@tonic-gate 					    temp,
1695*0Sstevel@tonic-gate 					    sensorp->es_ptr->low_warning,
1696*0Sstevel@tonic-gate 					    sensorp->es_ptr->high_warning);
1697*0Sstevel@tonic-gate 					sensorp->warning_tstamp = ct;
1698*0Sstevel@tonic-gate 				}
1699*0Sstevel@tonic-gate 				smap[i] = SENSOR_WARN;
1700*0Sstevel@tonic-gate 			} else {
1701*0Sstevel@tonic-gate 				/*
1702*0Sstevel@tonic-gate 				 * We will fall in this caterory only if
1703*0Sstevel@tonic-gate 				 * Temperature drops/increases from warning
1704*0Sstevel@tonic-gate 				 * threshold. If so we set sensor map to
1705*0Sstevel@tonic-gate 				 * OK so that we can exit the loop if
1706*0Sstevel@tonic-gate 				 * shutdown not initiated.
1707*0Sstevel@tonic-gate 				 */
1708*0Sstevel@tonic-gate 				smap[i] = SENSOR_OK;
1709*0Sstevel@tonic-gate 			}
1710*0Sstevel@tonic-gate 
1711*0Sstevel@tonic-gate 			if (TEMP_IN_SHUTDOWN_RANGE(temp, sensorp) &&
1712*0Sstevel@tonic-gate 			    !shutdown_override) {
1713*0Sstevel@tonic-gate 				ct = (time_t)(gethrtime() / NANOSEC);
1714*0Sstevel@tonic-gate 				if (sensorp->shutdown_tstamp == 0)
1715*0Sstevel@tonic-gate 					sensorp->shutdown_tstamp = ct;
1716*0Sstevel@tonic-gate 				if ((ct - sensorp->shutdown_tstamp) >=
1717*0Sstevel@tonic-gate 				    shutdown_interval) {
1718*0Sstevel@tonic-gate 					sensorp->shutdown_initiated = B_TRUE;
1719*0Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
1720*0Sstevel@tonic-gate 					    ENV_SHUTDOWN_MSG, sensorp->name,
1721*0Sstevel@tonic-gate 					    temp,
1722*0Sstevel@tonic-gate 					    sensorp->es_ptr->low_shutdown,
1723*0Sstevel@tonic-gate 					    sensorp->es_ptr->high_shutdown);
1724*0Sstevel@tonic-gate 					envd_log(LOG_ALERT, msgbuf);
1725*0Sstevel@tonic-gate 				}
1726*0Sstevel@tonic-gate 				if (system_shutdown_started == B_FALSE) {
1727*0Sstevel@tonic-gate 					(void) snprintf(syscmd, sizeof (syscmd),
1728*0Sstevel@tonic-gate 					    "%s \"%s\"", SHUTDOWN_CMD, msgbuf);
1729*0Sstevel@tonic-gate 					envd_log(LOG_ALERT, syscmd);
1730*0Sstevel@tonic-gate 					system_shutdown_started = B_TRUE;
1731*0Sstevel@tonic-gate 					(void) system(syscmd);
1732*0Sstevel@tonic-gate 				}
1733*0Sstevel@tonic-gate 			} else if (sensorp->shutdown_tstamp != 0)
1734*0Sstevel@tonic-gate 				sensorp->shutdown_tstamp = 0;
1735*0Sstevel@tonic-gate 		}
1736*0Sstevel@tonic-gate 
1737*0Sstevel@tonic-gate 		/*
1738*0Sstevel@tonic-gate 		 * Sweep thorugh Sensor Map and if warnings OR shutdown
1739*0Sstevel@tonic-gate 		 * are not logged then return to caller.
1740*0Sstevel@tonic-gate 		 */
1741*0Sstevel@tonic-gate 		return_flag = B_TRUE;
1742*0Sstevel@tonic-gate 		for (i = 0; i < N_ENVD_SENSORS; i++)
1743*0Sstevel@tonic-gate 			if (smap[i] == SENSOR_WARN)
1744*0Sstevel@tonic-gate 				return_flag = B_FALSE;
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 		if ((return_flag == B_TRUE) &&
1747*0Sstevel@tonic-gate 		    (system_shutdown_started == B_FALSE)) {
1748*0Sstevel@tonic-gate 			return (1);
1749*0Sstevel@tonic-gate 		}
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate wait_till_timeout:
1752*0Sstevel@tonic-gate 		/*
1753*0Sstevel@tonic-gate 		 * We use pthread_cond_reltimedwait_np to sleep for
1754*0Sstevel@tonic-gate 		 * fixed interval of time.
1755*0Sstevel@tonic-gate 		 * earlier implementation used alarm() call which
1756*0Sstevel@tonic-gate 		 * fails in Multi threaded environment. If multiple
1757*0Sstevel@tonic-gate 		 * threads call alarm() only one of the threads is
1758*0Sstevel@tonic-gate 		 * sent the SIGALRM signal.
1759*0Sstevel@tonic-gate 		 */
1760*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
1761*0Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1762*0Sstevel@tonic-gate 			&env_monitor_mutex, &to);
1763*0Sstevel@tonic-gate 		to.tv_sec = SENSORPOLL_INTERVAL;
1764*0Sstevel@tonic-gate 		to.tv_nsec = 0;
1765*0Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
1766*0Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&env_monitor_mutex);
1767*0Sstevel@tonic-gate 			goto wait_till_timeout;
1768*0Sstevel@tonic-gate 		}
1769*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1770*0Sstevel@tonic-gate 	}
1771*0Sstevel@tonic-gate }
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate /*
1774*0Sstevel@tonic-gate  * This is env thread which monitors the current temperature when
1775*0Sstevel@tonic-gate  * warning threshold is exceeded. The job is to make sure it does
1776*0Sstevel@tonic-gate  * not execced/decrease shutdown threshold. If it does it will start
1777*0Sstevel@tonic-gate  * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
1778*0Sstevel@tonic-gate  * For Enchilada there will be two threads, one for each ADM chip.
1779*0Sstevel@tonic-gate  */
1780*0Sstevel@tonic-gate static void *
ovtemp_thr(void * args)1781*0Sstevel@tonic-gate ovtemp_thr(void *args)
1782*0Sstevel@tonic-gate {
1783*0Sstevel@tonic-gate 	int	fd;
1784*0Sstevel@tonic-gate 	uint8_t stat[2];
1785*0Sstevel@tonic-gate 	int	hwm_id = (int)args;
1786*0Sstevel@tonic-gate 	int    err;
1787*0Sstevel@tonic-gate 	env_fan_t *fanp;
1788*0Sstevel@tonic-gate 	timespec_t	to;
1789*0Sstevel@tonic-gate 	int	ret;
1790*0Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1791*0Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	fd = open(hwm_devs[hwm_id], O_RDWR);
1794*0Sstevel@tonic-gate 	if (fd == -1) {
1795*0Sstevel@tonic-gate 		envd_log(LOG_ERR, ENV_ADM_OPEN_FAIL, hwm_devs[hwm_id],
1796*0Sstevel@tonic-gate 		    errno, strerror(errno));
1797*0Sstevel@tonic-gate 		return (NULL);
1798*0Sstevel@tonic-gate 	}
1799*0Sstevel@tonic-gate 	if (env_debug)
1800*0Sstevel@tonic-gate 		envd_log(LOG_ERR, "ovtemp thread for %s running...\n",
1801*0Sstevel@tonic-gate 			hwm_devs[hwm_id]);
1802*0Sstevel@tonic-gate 
1803*0Sstevel@tonic-gate 	for (;;) {
1804*0Sstevel@tonic-gate 		/*
1805*0Sstevel@tonic-gate 		 * Sleep for specified seconds before issuing IOCTL
1806*0Sstevel@tonic-gate 		 * again.
1807*0Sstevel@tonic-gate 		 */
1808*0Sstevel@tonic-gate 
1809*0Sstevel@tonic-gate 		/*
1810*0Sstevel@tonic-gate 		 * We use pthread_cond_reltimedwait_np to sleep for
1811*0Sstevel@tonic-gate 		 * fixed interval of time.
1812*0Sstevel@tonic-gate 		 * earlier implementation used alarm() call which
1813*0Sstevel@tonic-gate 		 * fails in Multi threaded environment. If multiple
1814*0Sstevel@tonic-gate 		 * threads call alarm() only one of the threads is
1815*0Sstevel@tonic-gate 		 * sent the SIGALRM signal.
1816*0Sstevel@tonic-gate 		 */
1817*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
1818*0Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1819*0Sstevel@tonic-gate 			&env_monitor_mutex, &to);
1820*0Sstevel@tonic-gate 		to.tv_sec = INTERRUPTPOLL_INTERVAL;
1821*0Sstevel@tonic-gate 		to.tv_nsec = 0;
1822*0Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
1823*0Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&env_monitor_mutex);
1824*0Sstevel@tonic-gate 			continue;
1825*0Sstevel@tonic-gate 		}
1826*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1827*0Sstevel@tonic-gate 		/*
1828*0Sstevel@tonic-gate 		 * Monitor the sensors to update fan status
1829*0Sstevel@tonic-gate 		 */
1830*0Sstevel@tonic-gate 		if (mon_fanstat)
1831*0Sstevel@tonic-gate 			monitor_fanstat();
1832*0Sstevel@tonic-gate 
1833*0Sstevel@tonic-gate 		/*
1834*0Sstevel@tonic-gate 		 * Read ADM1031 two Status Registers to determine source
1835*0Sstevel@tonic-gate 		 * of Interrupts.
1836*0Sstevel@tonic-gate 		 */
1837*0Sstevel@tonic-gate 
1838*0Sstevel@tonic-gate 		if ((err = ioctl(fd, ADM1031_GET_STATUS_1, &stat[0])) != -1)
1839*0Sstevel@tonic-gate 			err = ioctl(fd, ADM1031_GET_STATUS_2, &stat[1]);
1840*0Sstevel@tonic-gate 
1841*0Sstevel@tonic-gate 		if (err == -1) {
1842*0Sstevel@tonic-gate 			if (env_debug)
1843*0Sstevel@tonic-gate 				envd_log(LOG_ERR,
1844*0Sstevel@tonic-gate 					"OverTemp: Status Error");
1845*0Sstevel@tonic-gate 			continue;
1846*0Sstevel@tonic-gate 		}
1847*0Sstevel@tonic-gate 
1848*0Sstevel@tonic-gate 		if (env_debug)
1849*0Sstevel@tonic-gate 			envd_log(LOG_ERR, "INTR %s, Stat1 %x, Stat2 %x",
1850*0Sstevel@tonic-gate 				hwm_devs[hwm_id], stat[0], stat[1]);
1851*0Sstevel@tonic-gate 
1852*0Sstevel@tonic-gate 		if (stat[0] & FANFAULT) {
1853*0Sstevel@tonic-gate 			fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN1]);
1854*0Sstevel@tonic-gate 			if (fanp && fanp->present)
1855*0Sstevel@tonic-gate 				envd_log(LOG_ERR, ENV_FAN_FAULT,
1856*0Sstevel@tonic-gate 					hwm_devs[hwm_id],
1857*0Sstevel@tonic-gate 					hwm_fans[hwm_id][HWM_FAN1]);
1858*0Sstevel@tonic-gate 		}
1859*0Sstevel@tonic-gate 		if (stat[1] & FANFAULT) {
1860*0Sstevel@tonic-gate 			fanp = fan_lookup(hwm_fans[hwm_id][HWM_FAN2]);
1861*0Sstevel@tonic-gate 			if (fanp && fanp->present)
1862*0Sstevel@tonic-gate 				envd_log(LOG_ERR, ENV_FAN_FAULT,
1863*0Sstevel@tonic-gate 					hwm_devs[hwm_id],
1864*0Sstevel@tonic-gate 					hwm_fans[hwm_id][HWM_FAN2]);
1865*0Sstevel@tonic-gate 		}
1866*0Sstevel@tonic-gate 		/*
1867*0Sstevel@tonic-gate 		 * Check respective Remote/Local High, Low before start
1868*0Sstevel@tonic-gate 		 * manual monitoring
1869*0Sstevel@tonic-gate 		 */
1870*0Sstevel@tonic-gate 		if ((stat[0] & STAT1MASK) || (stat[1] & STAT2MASK))
1871*0Sstevel@tonic-gate 			(void) handle_overtemp_interrupt(hwm_id);
1872*0Sstevel@tonic-gate 
1873*0Sstevel@tonic-gate 	}	/* end of for ever loop */
1874*0Sstevel@tonic-gate 	/*NOTREACHED*/
1875*0Sstevel@tonic-gate 	return (NULL);
1876*0Sstevel@tonic-gate }
1877*0Sstevel@tonic-gate 
1878*0Sstevel@tonic-gate static void *
dimm_fan_thr(void * args)1879*0Sstevel@tonic-gate dimm_fan_thr(void *args)
1880*0Sstevel@tonic-gate {
1881*0Sstevel@tonic-gate 	char syscmd[BUFSIZ];
1882*0Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
1883*0Sstevel@tonic-gate 	i2c_reg_t	i2c_reg;
1884*0Sstevel@tonic-gate 	timespec_t	to;
1885*0Sstevel@tonic-gate 	int	ret;
1886*0Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
1887*0Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate #ifdef	__lint
1890*0Sstevel@tonic-gate 	args = args;
1891*0Sstevel@tonic-gate #endif
1892*0Sstevel@tonic-gate 
1893*0Sstevel@tonic-gate 	for (;;) {
1894*0Sstevel@tonic-gate 		/*
1895*0Sstevel@tonic-gate 		 * Sleep for specified seconds before issuing IOCTL
1896*0Sstevel@tonic-gate 		 * again.
1897*0Sstevel@tonic-gate 		 */
1898*0Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
1899*0Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
1900*0Sstevel@tonic-gate 			&env_monitor_mutex, &to);
1901*0Sstevel@tonic-gate 		to.tv_sec = INTERRUPTPOLL_INTERVAL;
1902*0Sstevel@tonic-gate 		to.tv_nsec = 0;
1903*0Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
1904*0Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&env_monitor_mutex);
1905*0Sstevel@tonic-gate 			continue;
1906*0Sstevel@tonic-gate 		}
1907*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
1908*0Sstevel@tonic-gate 		/*
1909*0Sstevel@tonic-gate 		 * We write to the comand register periodically
1910*0Sstevel@tonic-gate 		 * to inform the PIC firmware that Solaris is
1911*0Sstevel@tonic-gate 		 * Monitoring the dimm fan periodically.
1912*0Sstevel@tonic-gate 		 */
1913*0Sstevel@tonic-gate 		i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
1914*0Sstevel@tonic-gate 		i2c_reg.reg_value = PIC16F819_SW_AWARE_MODE;
1915*0Sstevel@tonic-gate 		if (ioctl(envd_dimm_fan.fd,
1916*0Sstevel@tonic-gate 			I2C_SET_REG, &i2c_reg) == -1) {
1917*0Sstevel@tonic-gate 			if (env_debug)
1918*0Sstevel@tonic-gate 				envd_log(LOG_ERR,
1919*0Sstevel@tonic-gate 		"Error in writing to COMMAND reg. of DIMM FAN controller\n");
1920*0Sstevel@tonic-gate 		}
1921*0Sstevel@tonic-gate 		/*
1922*0Sstevel@tonic-gate 		 * We initiate shutdown if fan status indicates
1923*0Sstevel@tonic-gate 		 * failure.
1924*0Sstevel@tonic-gate 		 */
1925*0Sstevel@tonic-gate 		if (is_dimm_fan_failed() != 0) {
1926*0Sstevel@tonic-gate 			/*
1927*0Sstevel@tonic-gate 			 * Mark Dimm fan present as False so that we
1928*0Sstevel@tonic-gate 			 * do not WARN the user of the Fan failure
1929*0Sstevel@tonic-gate 			 * repeatedly.
1930*0Sstevel@tonic-gate 			 */
1931*0Sstevel@tonic-gate 			envd_dimm_fan.present = B_FALSE;
1932*0Sstevel@tonic-gate 			(void) snprintf(msgbuf, sizeof (msgbuf),
1933*0Sstevel@tonic-gate 				ENV_DIMM_FAN_FAILURE_SHUTDOWN_MSG,
1934*0Sstevel@tonic-gate 				ENV_DIMM_FAN,
1935*0Sstevel@tonic-gate 				dimm_fan_rpm_string, dimm_fan_status_string,
1936*0Sstevel@tonic-gate 				dimm_fan_command_string,
1937*0Sstevel@tonic-gate 				dimm_fan_debug_string);
1938*0Sstevel@tonic-gate 			envd_log(LOG_ALERT, msgbuf);
1939*0Sstevel@tonic-gate 
1940*0Sstevel@tonic-gate 			if (system_shutdown_started == B_FALSE) {
1941*0Sstevel@tonic-gate 				system_shutdown_started = B_TRUE;
1942*0Sstevel@tonic-gate 				(void) snprintf(syscmd, sizeof (syscmd),
1943*0Sstevel@tonic-gate 					"%s \"%s\"",
1944*0Sstevel@tonic-gate 					SHUTDOWN_CMD,
1945*0Sstevel@tonic-gate 					msgbuf);
1946*0Sstevel@tonic-gate 				envd_log(LOG_ALERT, syscmd);
1947*0Sstevel@tonic-gate 				(void) system(syscmd);
1948*0Sstevel@tonic-gate 			}
1949*0Sstevel@tonic-gate 		}
1950*0Sstevel@tonic-gate 	}
1951*0Sstevel@tonic-gate 	/*NOTREACHED*/
1952*0Sstevel@tonic-gate 	return (NULL);
1953*0Sstevel@tonic-gate }
1954*0Sstevel@tonic-gate static int
scsi_log_sense(int fd,uchar_t page_code,uchar_t * pagebuf,uint16_t pagelen)1955*0Sstevel@tonic-gate scsi_log_sense(int fd, uchar_t page_code, uchar_t *pagebuf, uint16_t pagelen)
1956*0Sstevel@tonic-gate {
1957*0Sstevel@tonic-gate 	struct uscsi_cmd	ucmd_buf;
1958*0Sstevel@tonic-gate 	uchar_t		cdb_buf[CDB_GROUP1];
1959*0Sstevel@tonic-gate 	struct	scsi_extended_sense	sense_buf;
1960*0Sstevel@tonic-gate 	int	ret_val;
1961*0Sstevel@tonic-gate 
1962*0Sstevel@tonic-gate 	bzero((void *)&cdb_buf, sizeof (cdb_buf));
1963*0Sstevel@tonic-gate 	bzero((void *)&ucmd_buf, sizeof (ucmd_buf));
1964*0Sstevel@tonic-gate 	bzero((void *)&sense_buf, sizeof (sense_buf));
1965*0Sstevel@tonic-gate 
1966*0Sstevel@tonic-gate 	cdb_buf[0] = SCMD_LOG_SENSE_G1;
1967*0Sstevel@tonic-gate 	cdb_buf[2] = (0x01 << 6) | page_code;
1968*0Sstevel@tonic-gate 	cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
1969*0Sstevel@tonic-gate 	cdb_buf[8] = (uchar_t)(pagelen  & 0x00FF);
1970*0Sstevel@tonic-gate 
1971*0Sstevel@tonic-gate 	ucmd_buf.uscsi_cdb = (char *)cdb_buf;
1972*0Sstevel@tonic-gate 	ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
1973*0Sstevel@tonic-gate 	ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
1974*0Sstevel@tonic-gate 	ucmd_buf.uscsi_buflen = pagelen;
1975*0Sstevel@tonic-gate 	ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
1976*0Sstevel@tonic-gate 	ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
1977*0Sstevel@tonic-gate 	ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
1978*0Sstevel@tonic-gate 	ucmd_buf.uscsi_timeout = 60;
1979*0Sstevel@tonic-gate 
1980*0Sstevel@tonic-gate 	ret_val = ioctl(fd, USCSICMD, ucmd_buf);
1981*0Sstevel@tonic-gate 	if (ret_val == 0 && ucmd_buf.uscsi_status == 0) {
1982*0Sstevel@tonic-gate 		if (env_debug)
1983*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
1984*0Sstevel@tonic-gate 		"log sense command for page_code 0x%x succeeded\n", page_code);
1985*0Sstevel@tonic-gate 		return (ret_val);
1986*0Sstevel@tonic-gate 	}
1987*0Sstevel@tonic-gate 	if (env_debug)
1988*0Sstevel@tonic-gate 		envd_log(LOG_ERR,
1989*0Sstevel@tonic-gate 	"log sense command failed.ret_val = 0x%x status = 0x%x errno = 0x%x\n",
1990*0Sstevel@tonic-gate 		ret_val, ucmd_buf.uscsi_status, errno);
1991*0Sstevel@tonic-gate 	return (1);
1992*0Sstevel@tonic-gate }
1993*0Sstevel@tonic-gate 
1994*0Sstevel@tonic-gate static int
get_disk_temp(env_disk_t * diskp)1995*0Sstevel@tonic-gate get_disk_temp(env_disk_t *diskp)
1996*0Sstevel@tonic-gate {
1997*0Sstevel@tonic-gate 	int	ret;
1998*0Sstevel@tonic-gate 	uchar_t	tpage[256];
1999*0Sstevel@tonic-gate 
2000*0Sstevel@tonic-gate 	ret = scsi_log_sense(diskp->fd,
2001*0Sstevel@tonic-gate 			TEMPERATURE_PAGE,
2002*0Sstevel@tonic-gate 			tpage, sizeof (tpage));
2003*0Sstevel@tonic-gate 	if (ret != 0) {
2004*0Sstevel@tonic-gate 		diskp->current_temp = DISK_INVALID_TEMP;
2005*0Sstevel@tonic-gate 		diskp->ref_temp = DISK_INVALID_TEMP;
2006*0Sstevel@tonic-gate 		return (-1);
2007*0Sstevel@tonic-gate 	}
2008*0Sstevel@tonic-gate 	/*
2009*0Sstevel@tonic-gate 	 * For the current temperature verify that the parameter
2010*0Sstevel@tonic-gate 	 * length is 0x02 and the parameter code is 0x00
2011*0Sstevel@tonic-gate 	 * Temperature value of 255(0xFF) is considered INVALID.
2012*0Sstevel@tonic-gate 	 */
2013*0Sstevel@tonic-gate 	if ((tpage[7] == 0x02) && (tpage[4] == 0x00) &&
2014*0Sstevel@tonic-gate 		(tpage[5] == 0x00)) {
2015*0Sstevel@tonic-gate 		if (tpage[9] == 0xFF) {
2016*0Sstevel@tonic-gate 			diskp->current_temp = DISK_INVALID_TEMP;
2017*0Sstevel@tonic-gate 			return (-1);
2018*0Sstevel@tonic-gate 		} else {
2019*0Sstevel@tonic-gate 			diskp->current_temp = tpage[9];
2020*0Sstevel@tonic-gate 		}
2021*0Sstevel@tonic-gate 	}
2022*0Sstevel@tonic-gate 
2023*0Sstevel@tonic-gate 	/*
2024*0Sstevel@tonic-gate 	 * For the reference temperature verify that the parameter
2025*0Sstevel@tonic-gate 	 * length is 0x02 and the parameter code is 0x01
2026*0Sstevel@tonic-gate 	 * Temperature value of 255(0xFF) is considered INVALID.
2027*0Sstevel@tonic-gate 	 */
2028*0Sstevel@tonic-gate 	if ((tpage[13] == 0x02) && (tpage[10] == 0x00) &&
2029*0Sstevel@tonic-gate 		(tpage[11] == 0x01)) {
2030*0Sstevel@tonic-gate 		if (tpage[15] == 0xFF) {
2031*0Sstevel@tonic-gate 			diskp->ref_temp = DISK_INVALID_TEMP;
2032*0Sstevel@tonic-gate 		} else {
2033*0Sstevel@tonic-gate 			diskp->ref_temp = tpage[15];
2034*0Sstevel@tonic-gate 		}
2035*0Sstevel@tonic-gate 	}
2036*0Sstevel@tonic-gate 	return (0);
2037*0Sstevel@tonic-gate }
2038*0Sstevel@tonic-gate 
2039*0Sstevel@tonic-gate /* ARGSUSED */
2040*0Sstevel@tonic-gate static void *
disk_temp_thr(void * args)2041*0Sstevel@tonic-gate disk_temp_thr(void *args)
2042*0Sstevel@tonic-gate {
2043*0Sstevel@tonic-gate 	char syscmd[BUFSIZ];
2044*0Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
2045*0Sstevel@tonic-gate 	timespec_t	to;
2046*0Sstevel@tonic-gate 	int	ret, i;
2047*0Sstevel@tonic-gate 	env_disk_t	*diskp;
2048*0Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
2049*0Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
2050*0Sstevel@tonic-gate 	pm_state_change_t	pmstate;
2051*0Sstevel@tonic-gate 	int	idle_time;
2052*0Sstevel@tonic-gate 	int	disk_pm_fd;
2053*0Sstevel@tonic-gate 	time_t	ct;
2054*0Sstevel@tonic-gate 
2055*0Sstevel@tonic-gate 	disk_pm_fd = open(PM_DEVICE, O_RDWR);
2056*0Sstevel@tonic-gate 	if (disk_pm_fd == -1) {
2057*0Sstevel@tonic-gate 		envd_log(LOG_ERR,
2058*0Sstevel@tonic-gate 			DISK_TEMP_THREAD_EXITING,
2059*0Sstevel@tonic-gate 			errno, strerror(errno));
2060*0Sstevel@tonic-gate 		return (NULL);
2061*0Sstevel@tonic-gate 	}
2062*0Sstevel@tonic-gate 	for (;;) {
2063*0Sstevel@tonic-gate 	/*
2064*0Sstevel@tonic-gate 	 * Sleep for specified seconds before issuing IOCTL
2065*0Sstevel@tonic-gate 	 * again.
2066*0Sstevel@tonic-gate 	 */
2067*0Sstevel@tonic-gate 	    (void) pthread_mutex_lock(&env_monitor_mutex);
2068*0Sstevel@tonic-gate 	    ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
2069*0Sstevel@tonic-gate 	    &env_monitor_mutex, &to);
2070*0Sstevel@tonic-gate 	    to.tv_sec = disk_scan_interval;
2071*0Sstevel@tonic-gate 	    to.tv_nsec = 0;
2072*0Sstevel@tonic-gate 	    if (ret != ETIMEDOUT) {
2073*0Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
2074*0Sstevel@tonic-gate 		continue;
2075*0Sstevel@tonic-gate 	    }
2076*0Sstevel@tonic-gate 	    (void) pthread_mutex_unlock(&env_monitor_mutex);
2077*0Sstevel@tonic-gate 	    for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
2078*0Sstevel@tonic-gate 		if (diskp->present == B_FALSE)
2079*0Sstevel@tonic-gate 			continue;
2080*0Sstevel@tonic-gate 		if (diskp->tpage_supported == B_FALSE)
2081*0Sstevel@tonic-gate 			continue;
2082*0Sstevel@tonic-gate 		/*
2083*0Sstevel@tonic-gate 		 * If the disk temperature is above the warning threshold
2084*0Sstevel@tonic-gate 		 * continue monitoring until the temperature drops below
2085*0Sstevel@tonic-gate 		 * warning threshold.
2086*0Sstevel@tonic-gate 		 * if the temperature is in the NORMAL range monitor only
2087*0Sstevel@tonic-gate 		 * when the disk is BUSY.
2088*0Sstevel@tonic-gate 		 * We do not want to read the disk temperature if the disk is
2089*0Sstevel@tonic-gate 		 * is idling. The reason for this is disk will never get into
2090*0Sstevel@tonic-gate 		 * lowest power mode if we scan the disk temperature
2091*0Sstevel@tonic-gate 		 * peridoically. To avoid this situation we first determine
2092*0Sstevel@tonic-gate 		 * the idle_time of the disk. If the disk has been IDLE since
2093*0Sstevel@tonic-gate 		 * we scanned the temperature last time we will not read the
2094*0Sstevel@tonic-gate 		 * temperature.
2095*0Sstevel@tonic-gate 		 */
2096*0Sstevel@tonic-gate 		if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
2097*0Sstevel@tonic-gate 			pmstate.physpath = diskp->physpath;
2098*0Sstevel@tonic-gate 			pmstate.size = strlen(diskp->physpath);
2099*0Sstevel@tonic-gate 			pmstate.component = 0;
2100*0Sstevel@tonic-gate 			if ((idle_time =
2101*0Sstevel@tonic-gate 				ioctl(disk_pm_fd,
2102*0Sstevel@tonic-gate 					PM_GET_TIME_IDLE, &pmstate)) == -1) {
2103*0Sstevel@tonic-gate 				if (errno != EINTR) {
2104*0Sstevel@tonic-gate 					if (env_debug)
2105*0Sstevel@tonic-gate 						envd_log(LOG_ERR,
2106*0Sstevel@tonic-gate 			"ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n",
2107*0Sstevel@tonic-gate 							errno);
2108*0Sstevel@tonic-gate 					continue;
2109*0Sstevel@tonic-gate 				}
2110*0Sstevel@tonic-gate 				continue;
2111*0Sstevel@tonic-gate 			}
2112*0Sstevel@tonic-gate 			if (idle_time >= (disk_scan_interval/2)) {
2113*0Sstevel@tonic-gate 				if (env_debug) {
2114*0Sstevel@tonic-gate 					envd_log(LOG_ERR,
2115*0Sstevel@tonic-gate 					"%s idle time = %d\n",
2116*0Sstevel@tonic-gate 					diskp->name, idle_time);
2117*0Sstevel@tonic-gate 				}
2118*0Sstevel@tonic-gate 			continue;
2119*0Sstevel@tonic-gate 			}
2120*0Sstevel@tonic-gate 		}
2121*0Sstevel@tonic-gate 		ret = get_disk_temp(diskp);
2122*0Sstevel@tonic-gate 		if (ret != 0)
2123*0Sstevel@tonic-gate 			continue;
2124*0Sstevel@tonic-gate 		if (env_debug) {
2125*0Sstevel@tonic-gate 		    envd_log(LOG_ERR,
2126*0Sstevel@tonic-gate 			"%s temp = %d ref. temp = %d\n",
2127*0Sstevel@tonic-gate 			    diskp->name, diskp->current_temp, diskp->ref_temp);
2128*0Sstevel@tonic-gate 		}
2129*0Sstevel@tonic-gate 		/*
2130*0Sstevel@tonic-gate 		 * If this disk already triggered system shutdown, don't
2131*0Sstevel@tonic-gate 		 * log any more shutdown/warning messages for it.
2132*0Sstevel@tonic-gate 		 */
2133*0Sstevel@tonic-gate 		if (diskp->shutdown_initiated)
2134*0Sstevel@tonic-gate 			continue;
2135*0Sstevel@tonic-gate 
2136*0Sstevel@tonic-gate 		/*
2137*0Sstevel@tonic-gate 		 * Check for the temperature in warning and shutdown range
2138*0Sstevel@tonic-gate 		 * and take appropriate action.
2139*0Sstevel@tonic-gate 		 */
2140*0Sstevel@tonic-gate 		if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
2141*0Sstevel@tonic-gate 			/*
2142*0Sstevel@tonic-gate 			 * Check if the temperature has been in warning
2143*0Sstevel@tonic-gate 			 * range during last disk_warning_duration interval.
2144*0Sstevel@tonic-gate 			 * If so, the temperature is truly in warning
2145*0Sstevel@tonic-gate 			 * range and we need to log a warning message,
2146*0Sstevel@tonic-gate 			 * but no more than once every disk_warning_interval
2147*0Sstevel@tonic-gate 			 * seconds.
2148*0Sstevel@tonic-gate 			 */
2149*0Sstevel@tonic-gate 			time_t	wtstamp = diskp->warning_tstamp;
2150*0Sstevel@tonic-gate 
2151*0Sstevel@tonic-gate 			ct = (time_t)(gethrtime() / NANOSEC);
2152*0Sstevel@tonic-gate 			if (diskp->warning_start == 0)
2153*0Sstevel@tonic-gate 				diskp->warning_start = ct;
2154*0Sstevel@tonic-gate 			if (((ct - diskp->warning_start) >=
2155*0Sstevel@tonic-gate 			    disk_warning_duration) && (wtstamp == 0 ||
2156*0Sstevel@tonic-gate 			    (ct - wtstamp) >= disk_warning_interval)) {
2157*0Sstevel@tonic-gate 				envd_log(LOG_CRIT, ENV_WARNING_MSG,
2158*0Sstevel@tonic-gate 				    diskp->name, diskp->current_temp,
2159*0Sstevel@tonic-gate 				    diskp->low_warning,
2160*0Sstevel@tonic-gate 				    diskp->high_warning);
2161*0Sstevel@tonic-gate 				diskp->warning_tstamp = ct;
2162*0Sstevel@tonic-gate 			}
2163*0Sstevel@tonic-gate 		} else if (diskp->warning_start != 0)
2164*0Sstevel@tonic-gate 			diskp->warning_start = 0;
2165*0Sstevel@tonic-gate 
2166*0Sstevel@tonic-gate 		if (!shutdown_override &&
2167*0Sstevel@tonic-gate 		    DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) {
2168*0Sstevel@tonic-gate 			ct = (time_t)(gethrtime() / NANOSEC);
2169*0Sstevel@tonic-gate 			if (diskp->shutdown_tstamp == 0)
2170*0Sstevel@tonic-gate 				diskp->shutdown_tstamp = ct;
2171*0Sstevel@tonic-gate 
2172*0Sstevel@tonic-gate 			/*
2173*0Sstevel@tonic-gate 			 * Shutdown the system if the temperature remains
2174*0Sstevel@tonic-gate 			 * in the shutdown range for over disk_shutdown_interval
2175*0Sstevel@tonic-gate 			 * seconds.
2176*0Sstevel@tonic-gate 			 */
2177*0Sstevel@tonic-gate 			if ((ct - diskp->shutdown_tstamp) >=
2178*0Sstevel@tonic-gate 			    disk_shutdown_interval) {
2179*0Sstevel@tonic-gate 				/* log error */
2180*0Sstevel@tonic-gate 				diskp->shutdown_initiated = B_TRUE;
2181*0Sstevel@tonic-gate 				(void) snprintf(msgbuf, sizeof (msgbuf),
2182*0Sstevel@tonic-gate 				    ENV_SHUTDOWN_MSG, diskp->name,
2183*0Sstevel@tonic-gate 				    diskp->current_temp, diskp->low_shutdown,
2184*0Sstevel@tonic-gate 				    diskp->high_shutdown);
2185*0Sstevel@tonic-gate 				envd_log(LOG_ALERT, msgbuf);
2186*0Sstevel@tonic-gate 
2187*0Sstevel@tonic-gate 				/* shutdown the system (only once) */
2188*0Sstevel@tonic-gate 				if (system_shutdown_started == B_FALSE) {
2189*0Sstevel@tonic-gate 					(void) snprintf(syscmd, sizeof (syscmd),
2190*0Sstevel@tonic-gate 					    "%s \"%s\"", shutdown_cmd, msgbuf);
2191*0Sstevel@tonic-gate 					envd_log(LOG_ALERT, syscmd);
2192*0Sstevel@tonic-gate 					system_shutdown_started = B_TRUE;
2193*0Sstevel@tonic-gate 					(void) system(syscmd);
2194*0Sstevel@tonic-gate 				}
2195*0Sstevel@tonic-gate 			}
2196*0Sstevel@tonic-gate 		} else if (diskp->shutdown_tstamp != 0)
2197*0Sstevel@tonic-gate 			diskp->shutdown_tstamp = 0;
2198*0Sstevel@tonic-gate 
2199*0Sstevel@tonic-gate 	    }
2200*0Sstevel@tonic-gate 	}	/* end of forever loop */
2201*0Sstevel@tonic-gate }
2202*0Sstevel@tonic-gate 
2203*0Sstevel@tonic-gate /*
2204*0Sstevel@tonic-gate  * Setup envrionmental monitor state and start threads to monitor
2205*0Sstevel@tonic-gate  * temperature and power management state.
2206*0Sstevel@tonic-gate  * Returns -1 on error, 0 if successful.
2207*0Sstevel@tonic-gate  */
2208*0Sstevel@tonic-gate static int
envd_setup(void)2209*0Sstevel@tonic-gate envd_setup(void)
2210*0Sstevel@tonic-gate {
2211*0Sstevel@tonic-gate 	int 	ret;
2212*0Sstevel@tonic-gate 
2213*0Sstevel@tonic-gate 	if (getenv("SUNW_piclenvd_debug") != NULL)
2214*0Sstevel@tonic-gate 			env_debug = 1;
2215*0Sstevel@tonic-gate 
2216*0Sstevel@tonic-gate 	if (pthread_attr_init(&thr_attr) != 0 ||
2217*0Sstevel@tonic-gate 	    pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
2218*0Sstevel@tonic-gate 		return (-1);
2219*0Sstevel@tonic-gate 	}
2220*0Sstevel@tonic-gate 
2221*0Sstevel@tonic-gate 	ret = envd_es_setup();
2222*0Sstevel@tonic-gate 	if (ret < 0) {
2223*0Sstevel@tonic-gate 		ovtemp_monitor = 0;
2224*0Sstevel@tonic-gate 		pm_monitor = 0;
2225*0Sstevel@tonic-gate 	}
2226*0Sstevel@tonic-gate 
2227*0Sstevel@tonic-gate 	/*
2228*0Sstevel@tonic-gate 	 * Setup temperature sensors and fail if we can't open
2229*0Sstevel@tonic-gate 	 * at least one sensor.
2230*0Sstevel@tonic-gate 	 */
2231*0Sstevel@tonic-gate 	if (envd_setup_sensors() <= 0) {
2232*0Sstevel@tonic-gate 		return (NULL);
2233*0Sstevel@tonic-gate 	}
2234*0Sstevel@tonic-gate 
2235*0Sstevel@tonic-gate 	/*
2236*0Sstevel@tonic-gate 	 * Setup fan device (don't fail even if we can't access
2237*0Sstevel@tonic-gate 	 * the fan as we can still monitor temeperature.
2238*0Sstevel@tonic-gate 	 */
2239*0Sstevel@tonic-gate 	(void) envd_setup_fans();
2240*0Sstevel@tonic-gate 
2241*0Sstevel@tonic-gate 	(void) envd_setup_disks();
2242*0Sstevel@tonic-gate 
2243*0Sstevel@tonic-gate 	/* If ES Segment setup failed,don't create  thread */
2244*0Sstevel@tonic-gate 
2245*0Sstevel@tonic-gate 	if (ovtemp_monitor && ovtemp_thr1_created == B_FALSE) {
2246*0Sstevel@tonic-gate 		if (pthread_create(&ovtemp_thr1_id, &thr_attr, ovtemp_thr,
2247*0Sstevel@tonic-gate 		    (void *)CPU_HWM_ID) != 0)
2248*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2249*0Sstevel@tonic-gate 		else
2250*0Sstevel@tonic-gate 			ovtemp_thr1_created = B_TRUE;
2251*0Sstevel@tonic-gate 	}
2252*0Sstevel@tonic-gate 
2253*0Sstevel@tonic-gate 	if (ovtemp_monitor && ovtemp_thr2_created == B_FALSE) {
2254*0Sstevel@tonic-gate 		if (pthread_create(&ovtemp_thr2_id, &thr_attr, ovtemp_thr,
2255*0Sstevel@tonic-gate 		    (void *)SYS_HWM_ID) != 0)
2256*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2257*0Sstevel@tonic-gate 		else
2258*0Sstevel@tonic-gate 			ovtemp_thr2_created = B_TRUE;
2259*0Sstevel@tonic-gate 	}
2260*0Sstevel@tonic-gate 
2261*0Sstevel@tonic-gate 	if (envd_dimm_fan.present) {
2262*0Sstevel@tonic-gate 	    if (dimm_fan_thr_created == B_FALSE) {
2263*0Sstevel@tonic-gate 		if (pthread_create(&dimm_fan_thr_id, &thr_attr, dimm_fan_thr,
2264*0Sstevel@tonic-gate 		    NULL) != 0)
2265*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2266*0Sstevel@tonic-gate 		else
2267*0Sstevel@tonic-gate 			dimm_fan_thr_created = B_TRUE;
2268*0Sstevel@tonic-gate 	    }
2269*0Sstevel@tonic-gate 	}
2270*0Sstevel@tonic-gate 
2271*0Sstevel@tonic-gate 	/*
2272*0Sstevel@tonic-gate 	 * Create a thread to monitor PM state
2273*0Sstevel@tonic-gate 	 */
2274*0Sstevel@tonic-gate 	if (pm_monitor && pmthr_created == B_FALSE) {
2275*0Sstevel@tonic-gate 		if (pthread_create(&pmthr_tid, &thr_attr, pmthr,
2276*0Sstevel@tonic-gate 		    NULL) != 0)
2277*0Sstevel@tonic-gate 			envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
2278*0Sstevel@tonic-gate 		else
2279*0Sstevel@tonic-gate 			pmthr_created = B_TRUE;
2280*0Sstevel@tonic-gate 	}
2281*0Sstevel@tonic-gate 	if (monitor_disk_temp) {
2282*0Sstevel@tonic-gate 	    if (disk_temp_thr_created == B_FALSE) {
2283*0Sstevel@tonic-gate 		if (pthread_create(&disk_temp_thr_id, &thr_attr, disk_temp_thr,
2284*0Sstevel@tonic-gate 		    NULL) != 0)
2285*0Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
2286*0Sstevel@tonic-gate 		else
2287*0Sstevel@tonic-gate 			disk_temp_thr_created = B_TRUE;
2288*0Sstevel@tonic-gate 	    }
2289*0Sstevel@tonic-gate 	}
2290*0Sstevel@tonic-gate 	return (0);
2291*0Sstevel@tonic-gate }
2292*0Sstevel@tonic-gate 
2293*0Sstevel@tonic-gate static void
piclenvd_register(void)2294*0Sstevel@tonic-gate piclenvd_register(void)
2295*0Sstevel@tonic-gate {
2296*0Sstevel@tonic-gate 	picld_plugin_register(&my_reg_info);
2297*0Sstevel@tonic-gate }
2298*0Sstevel@tonic-gate 
2299*0Sstevel@tonic-gate static void
piclenvd_init(void)2300*0Sstevel@tonic-gate piclenvd_init(void)
2301*0Sstevel@tonic-gate {
2302*0Sstevel@tonic-gate 
2303*0Sstevel@tonic-gate 	(void) env_picl_setup_tuneables();
2304*0Sstevel@tonic-gate 
2305*0Sstevel@tonic-gate 	/*
2306*0Sstevel@tonic-gate 	 * Setup the environmental data structures
2307*0Sstevel@tonic-gate 	 */
2308*0Sstevel@tonic-gate 	if (envd_setup() != 0) {
2309*0Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
2310*0Sstevel@tonic-gate 		return;
2311*0Sstevel@tonic-gate 	}
2312*0Sstevel@tonic-gate 
2313*0Sstevel@tonic-gate 	/*
2314*0Sstevel@tonic-gate 	 * Now setup/populate PICL tree
2315*0Sstevel@tonic-gate 	 */
2316*0Sstevel@tonic-gate 	env_picl_setup();
2317*0Sstevel@tonic-gate }
2318*0Sstevel@tonic-gate 
2319*0Sstevel@tonic-gate static void
piclenvd_fini(void)2320*0Sstevel@tonic-gate piclenvd_fini(void)
2321*0Sstevel@tonic-gate {
2322*0Sstevel@tonic-gate 
2323*0Sstevel@tonic-gate 	/*
2324*0Sstevel@tonic-gate 	 * Invoke env_picl_destroy() to remove any PICL nodes/properties
2325*0Sstevel@tonic-gate 	 * (including volatile properties) we created. Once this call
2326*0Sstevel@tonic-gate 	 * returns, there can't be any more calls from the PICL framework
2327*0Sstevel@tonic-gate 	 * to get current temperature or fan speed.
2328*0Sstevel@tonic-gate 	 */
2329*0Sstevel@tonic-gate 	env_picl_destroy();
2330*0Sstevel@tonic-gate 	envd_close_sensors();
2331*0Sstevel@tonic-gate 	envd_close_fans();
2332*0Sstevel@tonic-gate 	envd_es_destroy();
2333*0Sstevel@tonic-gate }
2334*0Sstevel@tonic-gate 
2335*0Sstevel@tonic-gate /*VARARGS2*/
2336*0Sstevel@tonic-gate void
envd_log(int pri,const char * fmt,...)2337*0Sstevel@tonic-gate envd_log(int pri, const char *fmt, ...)
2338*0Sstevel@tonic-gate {
2339*0Sstevel@tonic-gate 	va_list	ap;
2340*0Sstevel@tonic-gate 
2341*0Sstevel@tonic-gate 	va_start(ap, fmt);
2342*0Sstevel@tonic-gate 	vsyslog(pri, fmt, ap);
2343*0Sstevel@tonic-gate 	va_end(ap);
2344*0Sstevel@tonic-gate }
2345*0Sstevel@tonic-gate 
2346*0Sstevel@tonic-gate /*
2347*0Sstevel@tonic-gate  * Tunables support functions
2348*0Sstevel@tonic-gate  */
2349*0Sstevel@tonic-gate static env_tuneable_t *
tuneable_lookup(picl_prophdl_t proph)2350*0Sstevel@tonic-gate tuneable_lookup(picl_prophdl_t proph)
2351*0Sstevel@tonic-gate {
2352*0Sstevel@tonic-gate 	int i;
2353*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep = NULL;
2354*0Sstevel@tonic-gate 
2355*0Sstevel@tonic-gate 	for (i = 0; i < ntuneables; i++) {
2356*0Sstevel@tonic-gate 		tuneablep = &tuneables[i];
2357*0Sstevel@tonic-gate 		if (tuneablep->proph == proph)
2358*0Sstevel@tonic-gate 			return (tuneablep);
2359*0Sstevel@tonic-gate 	}
2360*0Sstevel@tonic-gate 
2361*0Sstevel@tonic-gate 	return (NULL);
2362*0Sstevel@tonic-gate }
2363*0Sstevel@tonic-gate 
2364*0Sstevel@tonic-gate static int
get_cpu_tach(ptree_rarg_t * parg,void * buf)2365*0Sstevel@tonic-gate get_cpu_tach(ptree_rarg_t *parg, void *buf)
2366*0Sstevel@tonic-gate {
2367*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2368*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2369*0Sstevel@tonic-gate 	int		fd;
2370*0Sstevel@tonic-gate 	int8_t		cfg;
2371*0Sstevel@tonic-gate 
2372*0Sstevel@tonic-gate 	proph = parg->proph;
2373*0Sstevel@tonic-gate 
2374*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2375*0Sstevel@tonic-gate 
2376*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2377*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2378*0Sstevel@tonic-gate 
2379*0Sstevel@tonic-gate 	fd = open(CPU_HWM_DEVFS, O_RDWR);
2380*0Sstevel@tonic-gate 
2381*0Sstevel@tonic-gate 	if (fd == -1) {
2382*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2383*0Sstevel@tonic-gate 	}
2384*0Sstevel@tonic-gate 
2385*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2386*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2387*0Sstevel@tonic-gate 	}
2388*0Sstevel@tonic-gate 
2389*0Sstevel@tonic-gate 	if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
2390*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = ENABLE;
2391*0Sstevel@tonic-gate 	} else {
2392*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = DISABLE;
2393*0Sstevel@tonic-gate 	}
2394*0Sstevel@tonic-gate 
2395*0Sstevel@tonic-gate 	(void) memcpy(buf, tuneablep->value,
2396*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2397*0Sstevel@tonic-gate 
2398*0Sstevel@tonic-gate 	(void) close(fd);
2399*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2400*0Sstevel@tonic-gate }
2401*0Sstevel@tonic-gate 
2402*0Sstevel@tonic-gate static int
set_cpu_tach(ptree_warg_t * parg,const void * buf)2403*0Sstevel@tonic-gate set_cpu_tach(ptree_warg_t *parg, const void *buf)
2404*0Sstevel@tonic-gate {
2405*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2406*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2407*0Sstevel@tonic-gate 	int		 fd, val;
2408*0Sstevel@tonic-gate 	int8_t		 cfg;
2409*0Sstevel@tonic-gate 
2410*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2411*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2412*0Sstevel@tonic-gate 
2413*0Sstevel@tonic-gate 	proph = parg->proph;
2414*0Sstevel@tonic-gate 
2415*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2416*0Sstevel@tonic-gate 
2417*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2418*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2419*0Sstevel@tonic-gate 
2420*0Sstevel@tonic-gate 
2421*0Sstevel@tonic-gate 	fd = open(CPU_HWM_DEVFS, O_RDWR);
2422*0Sstevel@tonic-gate 
2423*0Sstevel@tonic-gate 	if (fd == -1) {
2424*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2425*0Sstevel@tonic-gate 	}
2426*0Sstevel@tonic-gate 
2427*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2428*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2429*0Sstevel@tonic-gate 	}
2430*0Sstevel@tonic-gate 
2431*0Sstevel@tonic-gate 	(void) memcpy(&val, (caddr_t)buf, sizeof (val));
2432*0Sstevel@tonic-gate 
2433*0Sstevel@tonic-gate 	if (val == ENABLE) {
2434*0Sstevel@tonic-gate 		cfg |= TACH_ENABLE_MASK;
2435*0Sstevel@tonic-gate 	} else if (val == DISABLE) {
2436*0Sstevel@tonic-gate 		cfg &= ~TACH_ENABLE_MASK;
2437*0Sstevel@tonic-gate 	}
2438*0Sstevel@tonic-gate 
2439*0Sstevel@tonic-gate 
2440*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
2441*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2442*0Sstevel@tonic-gate 	}
2443*0Sstevel@tonic-gate 
2444*0Sstevel@tonic-gate 	(void) close(fd);
2445*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2446*0Sstevel@tonic-gate }
2447*0Sstevel@tonic-gate 
2448*0Sstevel@tonic-gate static int
get_sys_tach(ptree_rarg_t * parg,void * buf)2449*0Sstevel@tonic-gate get_sys_tach(ptree_rarg_t *parg, void *buf)
2450*0Sstevel@tonic-gate {
2451*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2452*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2453*0Sstevel@tonic-gate 	int		fd;
2454*0Sstevel@tonic-gate 	int8_t		cfg;
2455*0Sstevel@tonic-gate 
2456*0Sstevel@tonic-gate 	proph = parg->proph;
2457*0Sstevel@tonic-gate 
2458*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2459*0Sstevel@tonic-gate 
2460*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2461*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2462*0Sstevel@tonic-gate 
2463*0Sstevel@tonic-gate 	fd = open(SYS_HWM_DEVFS, O_RDWR);
2464*0Sstevel@tonic-gate 
2465*0Sstevel@tonic-gate 	if (fd == -1) {
2466*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2467*0Sstevel@tonic-gate 	}
2468*0Sstevel@tonic-gate 
2469*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2470*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2471*0Sstevel@tonic-gate 	}
2472*0Sstevel@tonic-gate 
2473*0Sstevel@tonic-gate 	if ((cfg & TACH_ENABLE_MASK) == TACH_ENABLE_MASK) {
2474*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = ENABLE;
2475*0Sstevel@tonic-gate 	} else {
2476*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = DISABLE;
2477*0Sstevel@tonic-gate 	}
2478*0Sstevel@tonic-gate 
2479*0Sstevel@tonic-gate 	(void) memcpy(buf, tuneablep->value,
2480*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2481*0Sstevel@tonic-gate 
2482*0Sstevel@tonic-gate 	(void) close(fd);
2483*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2484*0Sstevel@tonic-gate }
2485*0Sstevel@tonic-gate 
2486*0Sstevel@tonic-gate static int
set_sys_tach(ptree_warg_t * parg,const void * buf)2487*0Sstevel@tonic-gate set_sys_tach(ptree_warg_t *parg, const void *buf)
2488*0Sstevel@tonic-gate {
2489*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2490*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2491*0Sstevel@tonic-gate 	int		fd, val;
2492*0Sstevel@tonic-gate 	int8_t		cfg;
2493*0Sstevel@tonic-gate 
2494*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2495*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2496*0Sstevel@tonic-gate 
2497*0Sstevel@tonic-gate 	proph = parg->proph;
2498*0Sstevel@tonic-gate 
2499*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2500*0Sstevel@tonic-gate 
2501*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2502*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2503*0Sstevel@tonic-gate 
2504*0Sstevel@tonic-gate 
2505*0Sstevel@tonic-gate 	fd = open(SYS_HWM_DEVFS, O_RDWR);
2506*0Sstevel@tonic-gate 
2507*0Sstevel@tonic-gate 	if (fd == -1) {
2508*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2509*0Sstevel@tonic-gate 	}
2510*0Sstevel@tonic-gate 
2511*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_CONFIG_2, &cfg) == -1) {
2512*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2513*0Sstevel@tonic-gate 	}
2514*0Sstevel@tonic-gate 
2515*0Sstevel@tonic-gate 	(void) memcpy(&val, buf, sizeof (val));
2516*0Sstevel@tonic-gate 
2517*0Sstevel@tonic-gate 	if (val == ENABLE) {
2518*0Sstevel@tonic-gate 		cfg |= TACH_ENABLE_MASK;
2519*0Sstevel@tonic-gate 	} else if (val == DISABLE) {
2520*0Sstevel@tonic-gate 		cfg &= ~TACH_ENABLE_MASK;
2521*0Sstevel@tonic-gate 	}
2522*0Sstevel@tonic-gate 
2523*0Sstevel@tonic-gate 
2524*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_SET_CONFIG_2, &cfg) == -1) {
2525*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2526*0Sstevel@tonic-gate 	}
2527*0Sstevel@tonic-gate 
2528*0Sstevel@tonic-gate 	(void) close(fd);
2529*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2530*0Sstevel@tonic-gate }
2531*0Sstevel@tonic-gate 
2532*0Sstevel@tonic-gate static int
get_monitor_cpu_mode(ptree_rarg_t * parg,void * buf)2533*0Sstevel@tonic-gate get_monitor_cpu_mode(ptree_rarg_t *parg, void *buf)
2534*0Sstevel@tonic-gate {
2535*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2536*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2537*0Sstevel@tonic-gate 	int		fd;
2538*0Sstevel@tonic-gate 	int8_t		mmode;
2539*0Sstevel@tonic-gate 
2540*0Sstevel@tonic-gate 	proph = parg->proph;
2541*0Sstevel@tonic-gate 
2542*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2543*0Sstevel@tonic-gate 
2544*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2545*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2546*0Sstevel@tonic-gate 
2547*0Sstevel@tonic-gate 	fd = open(CPU_HWM_DEVFS, O_RDWR);
2548*0Sstevel@tonic-gate 
2549*0Sstevel@tonic-gate 	if (fd == -1) {
2550*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2551*0Sstevel@tonic-gate 	}
2552*0Sstevel@tonic-gate 
2553*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
2554*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2555*0Sstevel@tonic-gate 	}
2556*0Sstevel@tonic-gate 
2557*0Sstevel@tonic-gate 	if (mmode == ADM1031_AUTO_MODE) {
2558*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = ENABLE;
2559*0Sstevel@tonic-gate 	} else {
2560*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = DISABLE;
2561*0Sstevel@tonic-gate 	}
2562*0Sstevel@tonic-gate 
2563*0Sstevel@tonic-gate 	(void) memcpy(buf, tuneablep->value,
2564*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2565*0Sstevel@tonic-gate 
2566*0Sstevel@tonic-gate 	(void) close(fd);
2567*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2568*0Sstevel@tonic-gate }
2569*0Sstevel@tonic-gate 
2570*0Sstevel@tonic-gate static int
set_monitor_cpu_mode(ptree_warg_t * parg,const void * buf)2571*0Sstevel@tonic-gate set_monitor_cpu_mode(ptree_warg_t *parg, const void *buf)
2572*0Sstevel@tonic-gate {
2573*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2574*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2575*0Sstevel@tonic-gate 	int		fd, val;
2576*0Sstevel@tonic-gate 	int8_t		mmode;
2577*0Sstevel@tonic-gate 
2578*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2579*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2580*0Sstevel@tonic-gate 
2581*0Sstevel@tonic-gate 	proph = parg->proph;
2582*0Sstevel@tonic-gate 
2583*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2584*0Sstevel@tonic-gate 
2585*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2586*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2587*0Sstevel@tonic-gate 
2588*0Sstevel@tonic-gate 	fd = open(CPU_HWM_DEVFS, O_RDWR);
2589*0Sstevel@tonic-gate 
2590*0Sstevel@tonic-gate 	if (fd == -1) {
2591*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2592*0Sstevel@tonic-gate 	}
2593*0Sstevel@tonic-gate 
2594*0Sstevel@tonic-gate 	(void) memcpy(&val, buf, sizeof (val));
2595*0Sstevel@tonic-gate 
2596*0Sstevel@tonic-gate 	if (val == ENABLE) {
2597*0Sstevel@tonic-gate 		mmode = ADM1031_AUTO_MODE;
2598*0Sstevel@tonic-gate 	} else if (val == DISABLE) {
2599*0Sstevel@tonic-gate 		mmode = ADM1031_MANUAL_MODE;
2600*0Sstevel@tonic-gate 	}
2601*0Sstevel@tonic-gate 
2602*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
2603*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2604*0Sstevel@tonic-gate 	}
2605*0Sstevel@tonic-gate 
2606*0Sstevel@tonic-gate 	(void) close(fd);
2607*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2608*0Sstevel@tonic-gate }
2609*0Sstevel@tonic-gate 
2610*0Sstevel@tonic-gate static int
get_monitor_sys_mode(ptree_rarg_t * parg,void * buf)2611*0Sstevel@tonic-gate get_monitor_sys_mode(ptree_rarg_t *parg, void *buf)
2612*0Sstevel@tonic-gate {
2613*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2614*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2615*0Sstevel@tonic-gate 	int		fd;
2616*0Sstevel@tonic-gate 	int8_t		mmode;
2617*0Sstevel@tonic-gate 
2618*0Sstevel@tonic-gate 	proph = parg->proph;
2619*0Sstevel@tonic-gate 
2620*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2621*0Sstevel@tonic-gate 
2622*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2623*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2624*0Sstevel@tonic-gate 
2625*0Sstevel@tonic-gate 	fd = open(SYS_HWM_DEVFS, O_RDWR);
2626*0Sstevel@tonic-gate 
2627*0Sstevel@tonic-gate 	if (fd == -1) {
2628*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2629*0Sstevel@tonic-gate 	}
2630*0Sstevel@tonic-gate 
2631*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_GET_MONITOR_MODE, &mmode) == -1) {
2632*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2633*0Sstevel@tonic-gate 	}
2634*0Sstevel@tonic-gate 
2635*0Sstevel@tonic-gate 	if (mmode == ADM1031_AUTO_MODE) {
2636*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = ENABLE;
2637*0Sstevel@tonic-gate 	} else {
2638*0Sstevel@tonic-gate 		*((int *)tuneablep->value) = DISABLE;
2639*0Sstevel@tonic-gate 	}
2640*0Sstevel@tonic-gate 
2641*0Sstevel@tonic-gate 	(void) memcpy(buf, tuneablep->value,
2642*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2643*0Sstevel@tonic-gate 
2644*0Sstevel@tonic-gate 	(void) close(fd);
2645*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2646*0Sstevel@tonic-gate }
2647*0Sstevel@tonic-gate 
2648*0Sstevel@tonic-gate static int
set_monitor_sys_mode(ptree_warg_t * parg,const void * buf)2649*0Sstevel@tonic-gate set_monitor_sys_mode(ptree_warg_t *parg, const void *buf)
2650*0Sstevel@tonic-gate {
2651*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2652*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2653*0Sstevel@tonic-gate 	int		fd, val;
2654*0Sstevel@tonic-gate 	int8_t		mmode;
2655*0Sstevel@tonic-gate 
2656*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2657*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2658*0Sstevel@tonic-gate 
2659*0Sstevel@tonic-gate 	proph = parg->proph;
2660*0Sstevel@tonic-gate 
2661*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2662*0Sstevel@tonic-gate 
2663*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2664*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2665*0Sstevel@tonic-gate 
2666*0Sstevel@tonic-gate 	fd = open(SYS_HWM_DEVFS, O_RDWR);
2667*0Sstevel@tonic-gate 
2668*0Sstevel@tonic-gate 	if (fd == -1) {
2669*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2670*0Sstevel@tonic-gate 	}
2671*0Sstevel@tonic-gate 
2672*0Sstevel@tonic-gate 	(void) memcpy(&val, buf, sizeof (val));
2673*0Sstevel@tonic-gate 
2674*0Sstevel@tonic-gate 	if (val == ENABLE) {
2675*0Sstevel@tonic-gate 		mmode = ADM1031_AUTO_MODE;
2676*0Sstevel@tonic-gate 	} else if (val == DISABLE) {
2677*0Sstevel@tonic-gate 		mmode = ADM1031_MANUAL_MODE;
2678*0Sstevel@tonic-gate 	}
2679*0Sstevel@tonic-gate 
2680*0Sstevel@tonic-gate 	if (ioctl(fd, ADM1031_SET_MONITOR_MODE, &mmode) == -1) {
2681*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2682*0Sstevel@tonic-gate 	}
2683*0Sstevel@tonic-gate 
2684*0Sstevel@tonic-gate 	(void) close(fd);
2685*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2686*0Sstevel@tonic-gate }
2687*0Sstevel@tonic-gate 
2688*0Sstevel@tonic-gate static int
get_string_val(ptree_rarg_t * parg,void * buf)2689*0Sstevel@tonic-gate get_string_val(ptree_rarg_t *parg, void *buf)
2690*0Sstevel@tonic-gate {
2691*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2692*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2693*0Sstevel@tonic-gate 
2694*0Sstevel@tonic-gate 	proph = parg->proph;
2695*0Sstevel@tonic-gate 
2696*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2697*0Sstevel@tonic-gate 
2698*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2699*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2700*0Sstevel@tonic-gate 
2701*0Sstevel@tonic-gate 	(void) memcpy(buf, (caddr_t)tuneablep->value,
2702*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2703*0Sstevel@tonic-gate 
2704*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2705*0Sstevel@tonic-gate }
2706*0Sstevel@tonic-gate 
2707*0Sstevel@tonic-gate static int
set_string_val(ptree_warg_t * parg,const void * buf)2708*0Sstevel@tonic-gate set_string_val(ptree_warg_t *parg, const void *buf)
2709*0Sstevel@tonic-gate {
2710*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2711*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2712*0Sstevel@tonic-gate 
2713*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2714*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2715*0Sstevel@tonic-gate 
2716*0Sstevel@tonic-gate 	proph = parg->proph;
2717*0Sstevel@tonic-gate 
2718*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2719*0Sstevel@tonic-gate 
2720*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2721*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2722*0Sstevel@tonic-gate 
2723*0Sstevel@tonic-gate 	(void) memcpy((caddr_t)tuneables->value, (caddr_t)buf,
2724*0Sstevel@tonic-gate 	    tuneables->nbytes);
2725*0Sstevel@tonic-gate 
2726*0Sstevel@tonic-gate 
2727*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2728*0Sstevel@tonic-gate }
2729*0Sstevel@tonic-gate 
2730*0Sstevel@tonic-gate static int
get_int_val(ptree_rarg_t * parg,void * buf)2731*0Sstevel@tonic-gate get_int_val(ptree_rarg_t *parg, void *buf)
2732*0Sstevel@tonic-gate {
2733*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2734*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2735*0Sstevel@tonic-gate 
2736*0Sstevel@tonic-gate 	proph = parg->proph;
2737*0Sstevel@tonic-gate 
2738*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2739*0Sstevel@tonic-gate 
2740*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2741*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2742*0Sstevel@tonic-gate 
2743*0Sstevel@tonic-gate 	(void) memcpy((int *)buf, (int *)tuneablep->value,
2744*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2745*0Sstevel@tonic-gate 
2746*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2747*0Sstevel@tonic-gate }
2748*0Sstevel@tonic-gate 
2749*0Sstevel@tonic-gate static int
set_int_val(ptree_warg_t * parg,const void * buf)2750*0Sstevel@tonic-gate set_int_val(ptree_warg_t *parg, const void *buf)
2751*0Sstevel@tonic-gate {
2752*0Sstevel@tonic-gate 	picl_prophdl_t	proph;
2753*0Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
2754*0Sstevel@tonic-gate 
2755*0Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
2756*0Sstevel@tonic-gate 		return (PICL_PERMDENIED);
2757*0Sstevel@tonic-gate 
2758*0Sstevel@tonic-gate 	proph = parg->proph;
2759*0Sstevel@tonic-gate 
2760*0Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
2761*0Sstevel@tonic-gate 
2762*0Sstevel@tonic-gate 	if (tuneablep == NULL)
2763*0Sstevel@tonic-gate 		return (PICL_FAILURE);
2764*0Sstevel@tonic-gate 
2765*0Sstevel@tonic-gate 	(void) memcpy((int *)tuneablep->value, (int *)buf,
2766*0Sstevel@tonic-gate 	    tuneablep->nbytes);
2767*0Sstevel@tonic-gate 
2768*0Sstevel@tonic-gate 	return (PICL_SUCCESS);
2769*0Sstevel@tonic-gate }
2770*0Sstevel@tonic-gate 
2771*0Sstevel@tonic-gate int
get_dimm_fan_speed(int fan_fd,fanspeed_t * fanspeedp)2772*0Sstevel@tonic-gate get_dimm_fan_speed(int fan_fd, fanspeed_t *fanspeedp)
2773*0Sstevel@tonic-gate {
2774*0Sstevel@tonic-gate 	int16_t	dimm_fan_period;
2775*0Sstevel@tonic-gate 	i2c_reg_t	i2c_reg;
2776*0Sstevel@tonic-gate 
2777*0Sstevel@tonic-gate 	/*
2778*0Sstevel@tonic-gate 	 * The dimm fan period is 16 bit value and we need to read
2779*0Sstevel@tonic-gate 	 * registers 2 and 3 to get the LSB and MSB values.
2780*0Sstevel@tonic-gate 	 */
2781*0Sstevel@tonic-gate 	i2c_reg.reg_num = PIC16F819_FAN_PERIOD_MSB_REGISTER;
2782*0Sstevel@tonic-gate 	if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) {
2783*0Sstevel@tonic-gate 		if (env_debug)
2784*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
2785*0Sstevel@tonic-gate 			"Error in reading FAN_PERIOD MSB REGISTER\n");
2786*0Sstevel@tonic-gate 		return (-1);
2787*0Sstevel@tonic-gate 	}
2788*0Sstevel@tonic-gate 	dimm_fan_period = (i2c_reg.reg_value << 8);
2789*0Sstevel@tonic-gate 	i2c_reg.reg_num = PIC16F819_FAN_PERIOD_LSB_REGISTER;
2790*0Sstevel@tonic-gate 	if (ioctl(fan_fd, I2C_GET_REG, &i2c_reg) == -1) {
2791*0Sstevel@tonic-gate 		if (env_debug)
2792*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
2793*0Sstevel@tonic-gate 			"Error in reading FAN_PERIOD LSB REGISTER\n");
2794*0Sstevel@tonic-gate 		return (-1);
2795*0Sstevel@tonic-gate 	}
2796*0Sstevel@tonic-gate 	dimm_fan_period |= i2c_reg.reg_value;
2797*0Sstevel@tonic-gate 	if (env_debug)
2798*0Sstevel@tonic-gate 		envd_log(LOG_ERR,
2799*0Sstevel@tonic-gate 		" dimm fan tach period is 0x%x\n", dimm_fan_period);
2800*0Sstevel@tonic-gate 	if (dimm_fan_period == 0) {
2801*0Sstevel@tonic-gate 		if (env_debug)
2802*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
2803*0Sstevel@tonic-gate 			"dimm fan tach period read as zero. Illegal value.\n");
2804*0Sstevel@tonic-gate 		return (-1);
2805*0Sstevel@tonic-gate 	}
2806*0Sstevel@tonic-gate 	*fanspeedp = PIC16F819_FAN_TACH_TO_RPM(dimm_fan_period);
2807*0Sstevel@tonic-gate 	return (0);
2808*0Sstevel@tonic-gate }
2809*0Sstevel@tonic-gate 
2810*0Sstevel@tonic-gate int
is_dimm_fan_failed(void)2811*0Sstevel@tonic-gate is_dimm_fan_failed(void)
2812*0Sstevel@tonic-gate {
2813*0Sstevel@tonic-gate 	i2c_reg_t	i2c_reg;
2814*0Sstevel@tonic-gate 	fanspeed_t	fan_speed;
2815*0Sstevel@tonic-gate 	int		retry_count;
2816*0Sstevel@tonic-gate 
2817*0Sstevel@tonic-gate 	if (envd_dimm_fan.fd == -1)
2818*0Sstevel@tonic-gate 		return (-1);
2819*0Sstevel@tonic-gate 	/*
2820*0Sstevel@tonic-gate 	 * read register 1 to look at Fan fault bit.
2821*0Sstevel@tonic-gate 	 */
2822*0Sstevel@tonic-gate 	i2c_reg.reg_num = PIC16F819_STATUS_REGISTER;
2823*0Sstevel@tonic-gate 	retry_count = MAX_RETRIES_FOR_PIC16F819_REG_READ;
2824*0Sstevel@tonic-gate 	while (retry_count > 0) {
2825*0Sstevel@tonic-gate 		if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2826*0Sstevel@tonic-gate 			retry_count--;
2827*0Sstevel@tonic-gate 			continue;
2828*0Sstevel@tonic-gate 		} else break;
2829*0Sstevel@tonic-gate 	}
2830*0Sstevel@tonic-gate 	if (retry_count != MAX_RETRIES_FOR_PIC16F819_REG_READ) {
2831*0Sstevel@tonic-gate 		if (env_debug)
2832*0Sstevel@tonic-gate 			envd_log(LOG_ERR,
2833*0Sstevel@tonic-gate 			"%d retries attempted in reading STATUS register.\n",
2834*0Sstevel@tonic-gate 			    (MAX_RETRIES_FOR_PIC16F819_REG_READ - retry_count));
2835*0Sstevel@tonic-gate 	}
2836*0Sstevel@tonic-gate 	if (retry_count == 0) {
2837*0Sstevel@tonic-gate 		(void) strncpy(dimm_fan_status_string, NOT_AVAILABLE,
2838*0Sstevel@tonic-gate 			sizeof (dimm_fan_status_string));
2839*0Sstevel@tonic-gate 		(void) strncpy(dimm_fan_command_string, NOT_AVAILABLE,
2840*0Sstevel@tonic-gate 			sizeof (dimm_fan_command_string));
2841*0Sstevel@tonic-gate 		(void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE,
2842*0Sstevel@tonic-gate 			sizeof (dimm_fan_debug_string));
2843*0Sstevel@tonic-gate 		(void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE,
2844*0Sstevel@tonic-gate 			sizeof (dimm_fan_rpm_string));
2845*0Sstevel@tonic-gate 		return (-1);
2846*0Sstevel@tonic-gate 	}
2847*0Sstevel@tonic-gate 	if (env_debug)
2848*0Sstevel@tonic-gate 		envd_log(LOG_ERR,
2849*0Sstevel@tonic-gate 		"DIMM FAN STATUS reg = 0x%x\n", i2c_reg.reg_value);
2850*0Sstevel@tonic-gate 	if (i2c_reg.reg_value & PIC16F819_FAN_FAILED) {
2851*0Sstevel@tonic-gate 		(void) snprintf(dimm_fan_status_string,
2852*0Sstevel@tonic-gate 			sizeof (dimm_fan_status_string), "0x%x",
2853*0Sstevel@tonic-gate 			i2c_reg.reg_value);
2854*0Sstevel@tonic-gate 		i2c_reg.reg_num = PIC16F819_DEBUG_REGISTER;
2855*0Sstevel@tonic-gate 		if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2856*0Sstevel@tonic-gate 			(void) strncpy(dimm_fan_debug_string, NOT_AVAILABLE,
2857*0Sstevel@tonic-gate 				sizeof (dimm_fan_debug_string));
2858*0Sstevel@tonic-gate 		} else {
2859*0Sstevel@tonic-gate 			(void) snprintf(dimm_fan_debug_string,
2860*0Sstevel@tonic-gate 				sizeof (dimm_fan_debug_string),
2861*0Sstevel@tonic-gate 				"0x%x", i2c_reg.reg_value);
2862*0Sstevel@tonic-gate 		}
2863*0Sstevel@tonic-gate 		i2c_reg.reg_num = PIC16F819_COMMAND_REGISTER;
2864*0Sstevel@tonic-gate 		if (ioctl(envd_dimm_fan.fd, I2C_GET_REG, &i2c_reg) == -1) {
2865*0Sstevel@tonic-gate 			(void) strncpy(dimm_fan_command_string, NOT_AVAILABLE,
2866*0Sstevel@tonic-gate 				sizeof (dimm_fan_command_string));
2867*0Sstevel@tonic-gate 		} else {
2868*0Sstevel@tonic-gate 			(void) snprintf(dimm_fan_command_string,
2869*0Sstevel@tonic-gate 				sizeof (dimm_fan_command_string),
2870*0Sstevel@tonic-gate 				"0x%x", i2c_reg.reg_value);
2871*0Sstevel@tonic-gate 		}
2872*0Sstevel@tonic-gate 		if (get_dimm_fan_speed(envd_dimm_fan.fd, &fan_speed) == -1) {
2873*0Sstevel@tonic-gate 			(void) strncpy(dimm_fan_rpm_string, NOT_AVAILABLE,
2874*0Sstevel@tonic-gate 				sizeof (dimm_fan_rpm_string));
2875*0Sstevel@tonic-gate 		} else {
2876*0Sstevel@tonic-gate 			(void) snprintf(dimm_fan_rpm_string,
2877*0Sstevel@tonic-gate 				sizeof (dimm_fan_rpm_string),
2878*0Sstevel@tonic-gate 				"%d", fan_speed);
2879*0Sstevel@tonic-gate 		}
2880*0Sstevel@tonic-gate 		return (1);
2881*0Sstevel@tonic-gate 	} else return (0);
2882*0Sstevel@tonic-gate }
2883