xref: /onnv-gate/usr/src/cmd/picl/plugins/sun4u/chicago/envd/piclenvd.c (revision 8739:be065c2ac4a7)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52137Svenki  * Common Development and Distribution License (the "License").
62137Svenki  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*8739SJustin.Frank@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This file contains the environmental PICL plug-in module.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * This plugin sets up the PICLTREE for Chicago WS.
320Sstevel@tonic-gate  * It provides functionality to get/set temperatures and
330Sstevel@tonic-gate  * fan speeds.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * The environmental policy defaults to the auto mode
360Sstevel@tonic-gate  * as programmed by OBP at boot time.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <stdio.h>
400Sstevel@tonic-gate #include <stdlib.h>
410Sstevel@tonic-gate #include <sys/sysmacros.h>
420Sstevel@tonic-gate #include <limits.h>
430Sstevel@tonic-gate #include <string.h>
440Sstevel@tonic-gate #include <strings.h>
450Sstevel@tonic-gate #include <stdarg.h>
460Sstevel@tonic-gate #include <alloca.h>
470Sstevel@tonic-gate #include <unistd.h>
480Sstevel@tonic-gate #include <sys/processor.h>
490Sstevel@tonic-gate #include <syslog.h>
500Sstevel@tonic-gate #include <errno.h>
510Sstevel@tonic-gate #include <fcntl.h>
520Sstevel@tonic-gate #include <picl.h>
530Sstevel@tonic-gate #include <picltree.h>
540Sstevel@tonic-gate #include <picldefs.h>
550Sstevel@tonic-gate #include <pthread.h>
560Sstevel@tonic-gate #include <signal.h>
570Sstevel@tonic-gate #include <libdevinfo.h>
580Sstevel@tonic-gate #include <sys/pm.h>
590Sstevel@tonic-gate #include <sys/open.h>
600Sstevel@tonic-gate #include <sys/time.h>
610Sstevel@tonic-gate #include <sys/utsname.h>
620Sstevel@tonic-gate #include <sys/systeminfo.h>
630Sstevel@tonic-gate #include <note.h>
640Sstevel@tonic-gate #include <sys/pic16f747.h>
650Sstevel@tonic-gate #include "envd.h"
660Sstevel@tonic-gate #include <sys/scsi/scsi.h>
670Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
680Sstevel@tonic-gate 
690Sstevel@tonic-gate int	debug_fd;
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * PICL plugin entry points
720Sstevel@tonic-gate  */
730Sstevel@tonic-gate static void piclenvd_register(void);
740Sstevel@tonic-gate static void piclenvd_init(void);
750Sstevel@tonic-gate static void piclenvd_fini(void);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate  * Env setup routines
790Sstevel@tonic-gate  */
800Sstevel@tonic-gate extern void env_picl_setup(void);
810Sstevel@tonic-gate extern void env_picl_destroy(void);
820Sstevel@tonic-gate extern int env_picl_setup_tuneables(void);
830Sstevel@tonic-gate 
840Sstevel@tonic-gate static boolean_t has_fan_failed(env_fan_t *fanp);
850Sstevel@tonic-gate 
86707Svenki /*
87707Svenki  * PSU fan fault handling
88707Svenki  */
89707Svenki static boolean_t has_psufan_failed(void);
90707Svenki static int psufan_last_status = FAN_OK;
91707Svenki 
920Sstevel@tonic-gate #pragma init(piclenvd_register)
930Sstevel@tonic-gate 
940Sstevel@tonic-gate /*
950Sstevel@tonic-gate  * Plugin registration information
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate static picld_plugin_reg_t my_reg_info = {
980Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION,
990Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
1000Sstevel@tonic-gate 	"SUNW_piclenvd",
1010Sstevel@tonic-gate 	piclenvd_init,
1020Sstevel@tonic-gate 	piclenvd_fini,
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate #define	REGISTER_INFORMATION_STRING_LENGTH	16
1060Sstevel@tonic-gate static char fan_rpm_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
1070Sstevel@tonic-gate static char fan_status_string[REGISTER_INFORMATION_STRING_LENGTH] = {0};
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate static int	scsi_log_sense(env_disk_t *diskp, uchar_t page_code,
110377Siskreen 			void *pagebuf, uint16_t pagelen, int page_control);
111377Siskreen static int scsi_mode_select(env_disk_t *diskp, uchar_t page_code,
1120Sstevel@tonic-gate 			uchar_t *pagebuf, uint16_t pagelen);
113377Siskreen 
1140Sstevel@tonic-gate static int	get_disk_temp(env_disk_t *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /*
117323Svenki  * ES Segment stuff
118323Svenki  */
119323Svenki static es_sensor_blk_t sensor_ctl[MAX_SENSORS];
120323Svenki 
121323Svenki /*
122323Svenki  * Default limits for sensors, in case ES segment is not present, or has
123323Svenki  * inconsistent information
124323Svenki  */
125323Svenki static es_sensor_blk_t sensor_default_ctl[MAX_SENSORS] = {
126323Svenki 	{
127323Svenki 	    CPU0_HIGH_POWER_OFF, CPU0_HIGH_SHUTDOWN, CPU0_HIGH_WARNING,
128323Svenki 	    CPU0_LOW_WARNING, CPU0_LOW_SHUTDOWN, CPU0_LOW_POWER_OFF
129323Svenki 	},
130323Svenki 	{
131323Svenki 	    CPU1_HIGH_POWER_OFF, CPU1_HIGH_SHUTDOWN, CPU1_HIGH_WARNING,
132323Svenki 	    CPU1_LOW_WARNING, CPU1_LOW_SHUTDOWN, CPU1_LOW_POWER_OFF
133323Svenki 	},
134323Svenki 	{
135323Svenki 	    ADT7462_HIGH_POWER_OFF, ADT7462_HIGH_SHUTDOWN, ADT7462_HIGH_WARNING,
136323Svenki 	    ADT7462_LOW_WARNING, ADT7462_LOW_SHUTDOWN, ADT7462_LOW_POWER_OFF
137323Svenki 	},
138323Svenki 	{
139323Svenki 	    MB_HIGH_POWER_OFF, MB_HIGH_SHUTDOWN, MB_HIGH_WARNING,
140323Svenki 	    MB_LOW_WARNING, MB_LOW_SHUTDOWN, MB_LOW_POWER_OFF
141323Svenki 	},
142323Svenki 	{
143323Svenki 	    LM95221_HIGH_POWER_OFF, LM95221_HIGH_SHUTDOWN, LM95221_HIGH_WARNING,
144323Svenki 	    LM95221_LOW_WARNING, LM95221_LOW_SHUTDOWN, LM95221_LOW_POWER_OFF
145323Svenki 	},
146323Svenki 	{
147323Svenki 	    FIRE_HIGH_POWER_OFF, FIRE_HIGH_SHUTDOWN, FIRE_HIGH_WARNING,
148323Svenki 	    FIRE_LOW_WARNING, FIRE_LOW_SHUTDOWN, FIRE_LOW_POWER_OFF
149323Svenki 	},
150323Svenki 	{
151323Svenki 	    LSI1064_HIGH_POWER_OFF, LSI1064_HIGH_SHUTDOWN, LSI1064_HIGH_WARNING,
152323Svenki 	    LSI1064_LOW_WARNING, LSI1064_LOW_SHUTDOWN, LSI1064_LOW_POWER_OFF
153323Svenki 	},
154323Svenki 	{
155323Svenki 	    FRONT_PANEL_HIGH_POWER_OFF, FRONT_PANEL_HIGH_SHUTDOWN,
156323Svenki 	    FRONT_PANEL_HIGH_WARNING, FRONT_PANEL_LOW_WARNING,
157323Svenki 	    FRONT_PANEL_LOW_SHUTDOWN, FRONT_PANEL_LOW_POWER_OFF
158707Svenki 	},
159707Svenki 	{
160707Svenki 	    PSU_HIGH_POWER_OFF, PSU_HIGH_SHUTDOWN, PSU_HIGH_WARNING,
161707Svenki 	    PSU_LOW_WARNING, PSU_LOW_SHUTDOWN, PSU_LOW_POWER_OFF
162323Svenki 	}
163323Svenki };
164323Svenki 
165323Svenki /*
1660Sstevel@tonic-gate  * Env thread variables
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate static boolean_t  system_shutdown_started = B_FALSE;
169138Svenki static boolean_t  system_temp_thr_created = B_FALSE;
170138Svenki static pthread_t  system_temp_thr_id;
1710Sstevel@tonic-gate static pthread_attr_t thr_attr;
1720Sstevel@tonic-gate static boolean_t  disk_temp_thr_created = B_FALSE;
1730Sstevel@tonic-gate static pthread_t  disk_temp_thr_id;
1740Sstevel@tonic-gate static boolean_t  fan_thr_created = B_FALSE;
1750Sstevel@tonic-gate static pthread_t  fan_thr_id;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * PM thread related variables
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate static pthread_t	pmthr_tid;	/* pmthr thread ID */
1810Sstevel@tonic-gate static int		pm_fd = -1;	/* PM device file descriptor */
1820Sstevel@tonic-gate static boolean_t	pmthr_created = B_FALSE;
1830Sstevel@tonic-gate static int		cur_lpstate;	/* cur low power state */
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate  * Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
1870Sstevel@tonic-gate  * Setting the verbose tuneable also enables debugging for better
1880Sstevel@tonic-gate  * control
1890Sstevel@tonic-gate  */
1900Sstevel@tonic-gate int	env_debug = 0;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate /*
1930Sstevel@tonic-gate  * These are debug variables for keeping track of the total number
1940Sstevel@tonic-gate  * of Fan and Temp sensor retries over the lifetime of the plugin.
1950Sstevel@tonic-gate  */
1960Sstevel@tonic-gate static int total_fan_retries = 0;
1970Sstevel@tonic-gate static int total_temp_retries = 0;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate /*
2000Sstevel@tonic-gate  * Fan devices
2010Sstevel@tonic-gate  */
2020Sstevel@tonic-gate static env_fan_t envd_system_fan0 = {
2030Sstevel@tonic-gate 	ENV_SYSTEM_FAN0, ENV_SYSTEM_FAN0_DEVFS, SYSTEM_FAN0_ID,
2040Sstevel@tonic-gate 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
2050Sstevel@tonic-gate };
2060Sstevel@tonic-gate static env_fan_t envd_system_fan1 = {
2070Sstevel@tonic-gate 	ENV_SYSTEM_FAN1, ENV_SYSTEM_FAN1_DEVFS, SYSTEM_FAN1_ID,
2080Sstevel@tonic-gate 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
2090Sstevel@tonic-gate };
2100Sstevel@tonic-gate static env_fan_t envd_system_fan2 = {
2110Sstevel@tonic-gate 	ENV_SYSTEM_FAN2, ENV_SYSTEM_FAN2_DEVFS, SYSTEM_FAN2_ID,
2120Sstevel@tonic-gate 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
2130Sstevel@tonic-gate };
2140Sstevel@tonic-gate static env_fan_t envd_system_fan3 = {
2150Sstevel@tonic-gate 	ENV_SYSTEM_FAN3, ENV_SYSTEM_FAN3_DEVFS, SYSTEM_FAN3_ID,
2160Sstevel@tonic-gate 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
2170Sstevel@tonic-gate };
2180Sstevel@tonic-gate static env_fan_t envd_system_fan4 = {
2190Sstevel@tonic-gate 	ENV_SYSTEM_FAN4, ENV_SYSTEM_FAN4_DEVFS, SYSTEM_FAN4_ID,
2200Sstevel@tonic-gate 	SYSTEM_FAN_SPEED_MIN, SYSTEM_FAN_SPEED_MAX, -1, -1,
2210Sstevel@tonic-gate };
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate /*
2240Sstevel@tonic-gate  * Disk devices
2250Sstevel@tonic-gate  */
2260Sstevel@tonic-gate static env_disk_t envd_disk0 = {
2270Sstevel@tonic-gate 	ENV_DISK0, ENV_DISK0_DEVFS, DISK0_PHYSPATH, DISK0_NODE_PATH,
2280Sstevel@tonic-gate 	DISK0_ID, -1,
2290Sstevel@tonic-gate };
2300Sstevel@tonic-gate static env_disk_t envd_disk1 = {
2310Sstevel@tonic-gate 	ENV_DISK1, ENV_DISK1_DEVFS, DISK1_PHYSPATH, DISK1_NODE_PATH,
2320Sstevel@tonic-gate 	DISK1_ID, -1,
2330Sstevel@tonic-gate };
2340Sstevel@tonic-gate static env_disk_t envd_disk2 = {
2350Sstevel@tonic-gate 	ENV_DISK2, ENV_DISK2_DEVFS, DISK2_PHYSPATH, DISK2_NODE_PATH,
2360Sstevel@tonic-gate 	DISK2_ID, -1,
2370Sstevel@tonic-gate };
2380Sstevel@tonic-gate static env_disk_t envd_disk3 = {
2390Sstevel@tonic-gate 	ENV_DISK3, ENV_DISK3_DEVFS, DISK3_PHYSPATH, DISK3_NODE_PATH,
2400Sstevel@tonic-gate 	DISK3_ID, -1,
2410Sstevel@tonic-gate };
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * Sensors
2450Sstevel@tonic-gate  */
2460Sstevel@tonic-gate static env_sensor_t envd_sensor_cpu0 = {
247323Svenki 	SENSOR_CPU0, SENSOR_CPU0_DEVFS, CPU0_SENSOR_ID, -1, NULL,
2480Sstevel@tonic-gate };
2490Sstevel@tonic-gate static env_sensor_t envd_sensor_cpu1 = {
250323Svenki 	SENSOR_CPU1, SENSOR_CPU1_DEVFS, CPU1_SENSOR_ID, -1, NULL,
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate static env_sensor_t envd_sensor_adt7462 = {
253323Svenki 	SENSOR_ADT7462, SENSOR_ADT7462_DEVFS, ADT7462_SENSOR_ID, -1, NULL,
2540Sstevel@tonic-gate };
2550Sstevel@tonic-gate static env_sensor_t envd_sensor_mb = {
256323Svenki 	SENSOR_MB, SENSOR_MB_DEVFS, MB_SENSOR_ID, -1, NULL,
2570Sstevel@tonic-gate };
2580Sstevel@tonic-gate static env_sensor_t envd_sensor_lm95221 = {
259323Svenki 	SENSOR_LM95221, SENSOR_LM95221_DEVFS, LM95221_SENSOR_ID, -1, NULL,
2600Sstevel@tonic-gate };
2610Sstevel@tonic-gate static env_sensor_t envd_sensor_fire = {
262323Svenki 	SENSOR_FIRE, SENSOR_FIRE_DEVFS, FIRE_SENSOR_ID, -1, NULL,
2630Sstevel@tonic-gate };
2640Sstevel@tonic-gate static env_sensor_t envd_sensor_lsi1064 = {
265323Svenki 	SENSOR_LSI1064, SENSOR_LSI1064_DEVFS, LSI1064_SENSOR_ID, -1, NULL,
2660Sstevel@tonic-gate };
2670Sstevel@tonic-gate static env_sensor_t envd_sensor_front_panel = {
268323Svenki 	SENSOR_FRONT_PANEL, SENSOR_FRONT_PANEL_DEVFS, FRONT_PANEL_SENSOR_ID,
269323Svenki 	-1, NULL,
2700Sstevel@tonic-gate };
271707Svenki static env_sensor_t envd_sensor_psu = {
272707Svenki 	SENSOR_PSU, SENSOR_PSU_DEVFS, PSU_SENSOR_ID, -1, NULL,
273707Svenki };
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate  * The vendor-id and device-id are the properties associated with
2770Sstevel@tonic-gate  * the SCSI controller. This is used to identify a particular controller
2780Sstevel@tonic-gate  * like LSI1064.
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate #define	VENDOR_ID	"vendor-id"
2810Sstevel@tonic-gate #define	DEVICE_ID	"device-id"
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * The implementation for SCSI disk drives to supply info. about
2850Sstevel@tonic-gate  * temperature is not mandatory. Hence we first determine if the
2860Sstevel@tonic-gate  * temperature page is supported. To do this we need to scan the list
2870Sstevel@tonic-gate  * of pages supported.
2880Sstevel@tonic-gate  */
2890Sstevel@tonic-gate #define	SUPPORTED_LPAGES	0
2900Sstevel@tonic-gate #define	TEMPERATURE_PAGE	0x0D
2910Sstevel@tonic-gate #define	LOGPAGEHDRSIZE	4
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate  * NULL terminated array of fans
2950Sstevel@tonic-gate  */
2960Sstevel@tonic-gate static env_fan_t *envd_fans[] = {
2970Sstevel@tonic-gate 	&envd_system_fan0,
2980Sstevel@tonic-gate 	&envd_system_fan1,
2990Sstevel@tonic-gate 	&envd_system_fan2,
3000Sstevel@tonic-gate 	&envd_system_fan3,
3010Sstevel@tonic-gate 	&envd_system_fan4,
3020Sstevel@tonic-gate 	NULL
3030Sstevel@tonic-gate };
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate /*
3060Sstevel@tonic-gate  * NULL terminated array of disks
3070Sstevel@tonic-gate  */
3080Sstevel@tonic-gate static env_disk_t *envd_disks[] = {
3090Sstevel@tonic-gate 	&envd_disk0,
3100Sstevel@tonic-gate 	&envd_disk1,
3110Sstevel@tonic-gate 	&envd_disk2,
3120Sstevel@tonic-gate 	&envd_disk3,
3130Sstevel@tonic-gate 	NULL
3140Sstevel@tonic-gate };
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate  * NULL terminated array of temperature sensors
3180Sstevel@tonic-gate  */
319707Svenki #define	N_ENVD_SENSORS	9
3200Sstevel@tonic-gate static env_sensor_t *envd_sensors[] = {
3210Sstevel@tonic-gate 	&envd_sensor_cpu0,
3220Sstevel@tonic-gate 	&envd_sensor_cpu1,
3230Sstevel@tonic-gate 	&envd_sensor_adt7462,
3240Sstevel@tonic-gate 	&envd_sensor_mb,
3250Sstevel@tonic-gate 	&envd_sensor_lm95221,
3260Sstevel@tonic-gate 	&envd_sensor_fire,
3270Sstevel@tonic-gate 	&envd_sensor_lsi1064,
3280Sstevel@tonic-gate 	&envd_sensor_front_panel,
329707Svenki 	&envd_sensor_psu,
3300Sstevel@tonic-gate 	NULL
3310Sstevel@tonic-gate };
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate #define	NOT_AVAILABLE	"NA"
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate /*
3360Sstevel@tonic-gate  * Tuneables
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate #define	ENABLE	1
3390Sstevel@tonic-gate #define	DISABLE	0
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate static	int	disk_high_warn_temperature	= DISK_HIGH_WARN_TEMPERATURE;
3420Sstevel@tonic-gate static	int	disk_low_warn_temperature	= DISK_LOW_WARN_TEMPERATURE;
3430Sstevel@tonic-gate static	int	disk_high_shutdown_temperature	=
3440Sstevel@tonic-gate 						DISK_HIGH_SHUTDOWN_TEMPERATURE;
3450Sstevel@tonic-gate static	int	disk_low_shutdown_temperature	= DISK_LOW_SHUTDOWN_TEMPERATURE;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate static	int	disk_scan_interval		= DISK_SCAN_INTERVAL;
3480Sstevel@tonic-gate static	int	sensor_scan_interval		= SENSOR_SCAN_INTERVAL;
3490Sstevel@tonic-gate static	int	fan_scan_interval		= FAN_SCAN_INTERVAL;
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate static int get_int_val(ptree_rarg_t *parg, void *buf);
3520Sstevel@tonic-gate static int set_int_val(ptree_warg_t *parg, const void *buf);
3530Sstevel@tonic-gate static int get_string_val(ptree_rarg_t *parg, void *buf);
3540Sstevel@tonic-gate static int set_string_val(ptree_warg_t *parg, const void *buf);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate static int 	shutdown_override	= 0;
3570Sstevel@tonic-gate static int	sensor_warning_interval	= SENSOR_WARNING_INTERVAL;
3580Sstevel@tonic-gate static int	sensor_warning_duration	= SENSOR_WARNING_DURATION;
3590Sstevel@tonic-gate static int	sensor_shutdown_interval = SENSOR_SHUTDOWN_INTERVAL;
3600Sstevel@tonic-gate static int	disk_warning_interval	= DISK_WARNING_INTERVAL;
3610Sstevel@tonic-gate static int	disk_warning_duration	= DISK_WARNING_DURATION;
3620Sstevel@tonic-gate static int 	disk_shutdown_interval	= DISK_SHUTDOWN_INTERVAL;
363323Svenki 
3640Sstevel@tonic-gate static int	system_temp_monitor	= 1;	/* enabled */
3650Sstevel@tonic-gate static int	fan_monitor		= 1;	/* enabled */
3660Sstevel@tonic-gate static int	pm_monitor		= 1;	/* enabled */
3671245Svenki 
3681245Svenki /* Disable disk temperature monitoring until we have LSI fw support */
3691245Svenki int		disk_temp_monitor	= 0;
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate static char	shutdown_cmd[] = SHUTDOWN_CMD;
372323Svenki const char	*iofru_devname = I2C_DEVFS "/" IOFRU_DEV;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate env_tuneable_t tuneables[] = {
3750Sstevel@tonic-gate 	{"system_temp-monitor", PICL_PTYPE_INT, &system_temp_monitor,
3760Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	{"fan-monitor", PICL_PTYPE_INT, &fan_monitor,
3790Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	{"pm-monitor", PICL_PTYPE_INT, &pm_monitor,
3820Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	{"shutdown-override", PICL_PTYPE_INT, &shutdown_override,
3850Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	{"sensor-warning-duration", PICL_PTYPE_INT,
3880Sstevel@tonic-gate 	    &sensor_warning_duration,
3890Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
3900Sstevel@tonic-gate 	    sizeof (int)},
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	{"disk-scan-interval", PICL_PTYPE_INT,
3930Sstevel@tonic-gate 	    &disk_scan_interval,
3940Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
3950Sstevel@tonic-gate 	    sizeof (int)},
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	{"fan-scan-interval", PICL_PTYPE_INT,
3980Sstevel@tonic-gate 	    &fan_scan_interval,
3990Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4000Sstevel@tonic-gate 	    sizeof (int)},
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	{"sensor-scan-interval", PICL_PTYPE_INT,
4030Sstevel@tonic-gate 	    &sensor_scan_interval,
4040Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4050Sstevel@tonic-gate 	    sizeof (int)},
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	{"sensor_warning-interval", PICL_PTYPE_INT, &sensor_warning_interval,
4080Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4090Sstevel@tonic-gate 	    sizeof (int)},
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	{"sensor_shutdown-interval", PICL_PTYPE_INT, &sensor_shutdown_interval,
4120Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4130Sstevel@tonic-gate 	    sizeof (int)},
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	{"disk_warning-interval", PICL_PTYPE_INT, &disk_warning_interval,
4160Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4170Sstevel@tonic-gate 	    sizeof (int)},
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	{"disk_warning-duration", PICL_PTYPE_INT, &disk_warning_duration,
4200Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4210Sstevel@tonic-gate 	    sizeof (int)},
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	{"disk_shutdown-interval", PICL_PTYPE_INT, &disk_shutdown_interval,
4240Sstevel@tonic-gate 	    &get_int_val, &set_int_val,
4250Sstevel@tonic-gate 	    sizeof (int)},
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	{"shutdown-command", PICL_PTYPE_CHARSTRING, shutdown_cmd,
4280Sstevel@tonic-gate 	    &get_string_val, &set_string_val,
4290Sstevel@tonic-gate 	    sizeof (shutdown_cmd)},
4300Sstevel@tonic-gate 
431138Svenki 	{"monitor-disk-temp", PICL_PTYPE_INT, &disk_temp_monitor,
4320Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)},
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	{"disk-high-warn-temperature", PICL_PTYPE_INT,
4350Sstevel@tonic-gate 	    &disk_high_warn_temperature, &get_int_val,
4360Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	{"disk-low-warn-temperature", PICL_PTYPE_INT,
4390Sstevel@tonic-gate 	    &disk_low_warn_temperature, &get_int_val,
4400Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	{"disk-high-shutdown-temperature", PICL_PTYPE_INT,
4430Sstevel@tonic-gate 	    &disk_high_shutdown_temperature, &get_int_val,
4440Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	{"disk-low-shutdown-temperature", PICL_PTYPE_INT,
4470Sstevel@tonic-gate 	    &disk_low_shutdown_temperature, &get_int_val,
4480Sstevel@tonic-gate 	    &set_int_val, sizeof (int)},
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	{"verbose", PICL_PTYPE_INT, &env_debug,
4510Sstevel@tonic-gate 	    &get_int_val, &set_int_val, sizeof (int)}
4520Sstevel@tonic-gate };
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate /*
4550Sstevel@tonic-gate  * We use this to figure out how many tuneables there are
4560Sstevel@tonic-gate  * This is variable because the publishing routine needs this info
4570Sstevel@tonic-gate  * in piclenvsetup.c
4580Sstevel@tonic-gate  */
4590Sstevel@tonic-gate int	ntuneables = (sizeof (tuneables)/sizeof (tuneables[0]));
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate  * Lookup fan and return a pointer to env_fan_t data structure.
4630Sstevel@tonic-gate  */
4640Sstevel@tonic-gate env_fan_t *
fan_lookup(char * name)4650Sstevel@tonic-gate fan_lookup(char *name)
4660Sstevel@tonic-gate {
4670Sstevel@tonic-gate 	int		i;
4680Sstevel@tonic-gate 	env_fan_t	*fanp;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
4710Sstevel@tonic-gate 		if (strcmp(fanp->name, name) == 0)
4720Sstevel@tonic-gate 			return (fanp);
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 	return (NULL);
4750Sstevel@tonic-gate }
4760Sstevel@tonic-gate 
4770Sstevel@tonic-gate /*
4780Sstevel@tonic-gate  * Lookup sensor and return a pointer to env_sensor_t data structure.
4790Sstevel@tonic-gate  */
4800Sstevel@tonic-gate env_sensor_t *
sensor_lookup(char * name)4810Sstevel@tonic-gate sensor_lookup(char *name)
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	env_sensor_t	*sensorp;
4840Sstevel@tonic-gate 	int		i;
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
4870Sstevel@tonic-gate 		sensorp = envd_sensors[i];
4880Sstevel@tonic-gate 		if (strcmp(sensorp->name, name) == 0)
4890Sstevel@tonic-gate 			return (sensorp);
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	return (NULL);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate /*
4950Sstevel@tonic-gate  * Lookup disk and return a pointer to env_disk_t data structure.
4960Sstevel@tonic-gate  */
4970Sstevel@tonic-gate env_disk_t *
disk_lookup(char * name)4980Sstevel@tonic-gate disk_lookup(char *name)
4990Sstevel@tonic-gate {
5000Sstevel@tonic-gate 	int		i;
5010Sstevel@tonic-gate 	env_disk_t	*diskp;
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
5040Sstevel@tonic-gate 		if (strncmp(diskp->name, name, strlen(name)) == 0)
5050Sstevel@tonic-gate 			return (diskp);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 	return (NULL);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate  * Get current temperature
5120Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
5130Sstevel@tonic-gate  */
5140Sstevel@tonic-gate int
get_temperature(env_sensor_t * sensorp,tempr_t * temp)5150Sstevel@tonic-gate get_temperature(env_sensor_t *sensorp, tempr_t *temp)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	int	fd = sensorp->fd;
5180Sstevel@tonic-gate 	int	retval = 0;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (fd == -1)
5210Sstevel@tonic-gate 		retval = -1;
5220Sstevel@tonic-gate 	else if (ioctl(fd, PIC_GET_TEMPERATURE, temp) != 0) {
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 		retval = -1;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		sensorp->error++;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 		if (sensorp->error == MAX_SENSOR_RETRIES) {
5290Sstevel@tonic-gate 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_FAIL,
5300Sstevel@tonic-gate 			    sensorp->name, errno, strerror(errno));
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		total_temp_retries++;
5340Sstevel@tonic-gate 		(void) sleep(1);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	} else if (sensorp->error != 0) {
5370Sstevel@tonic-gate 		if (sensorp->error >= MAX_SENSOR_RETRIES) {
5380Sstevel@tonic-gate 			envd_log(LOG_WARNING, ENV_SENSOR_ACCESS_OK,
5390Sstevel@tonic-gate 			    sensorp->name);
5400Sstevel@tonic-gate 		}
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 		sensorp->error = 0;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 		if (total_temp_retries && env_debug) {
5450Sstevel@tonic-gate 			envd_log(LOG_WARNING,
5460Sstevel@tonic-gate 			    "Total retries for sensors = %d",
5470Sstevel@tonic-gate 			    total_temp_retries);
5480Sstevel@tonic-gate 		}
5490Sstevel@tonic-gate 	}
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	return (retval);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate  * Get current disk temperature
5560Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
5570Sstevel@tonic-gate  */
5580Sstevel@tonic-gate int
disk_temperature(env_disk_t * diskp,tempr_t * temp)5590Sstevel@tonic-gate disk_temperature(env_disk_t *diskp, tempr_t *temp)
5600Sstevel@tonic-gate {
5610Sstevel@tonic-gate 	int	retval = 0;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	if (diskp == NULL)
5640Sstevel@tonic-gate 		retval = -1;
5650Sstevel@tonic-gate 	else
5660Sstevel@tonic-gate 		*temp = diskp->current_temp;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	return (retval);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate /*
5720Sstevel@tonic-gate  * Get current fan speed
5730Sstevel@tonic-gate  * This function returns a RPM value for fanspeed
5740Sstevel@tonic-gate  * in fanspeedp.
5750Sstevel@tonic-gate  * Returns -1 on error, 0 if successful
5760Sstevel@tonic-gate  */
5770Sstevel@tonic-gate int
get_fan_speed(env_fan_t * fanp,fanspeed_t * fanspeedp)5780Sstevel@tonic-gate get_fan_speed(env_fan_t *fanp, fanspeed_t *fanspeedp)
5790Sstevel@tonic-gate {
5800Sstevel@tonic-gate 	uint8_t tach;
5810Sstevel@tonic-gate 	int	real_tach;
5820Sstevel@tonic-gate 	int	retries;
5830Sstevel@tonic-gate 
584138Svenki 	if (fanp->fd == -1)
585138Svenki 		return (-1);
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	if (has_fan_failed(fanp)) {
5880Sstevel@tonic-gate 		*fanspeedp = 0;
5890Sstevel@tonic-gate 		return (0);
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/* try to read the fan information */
593*8739SJustin.Frank@Sun.COM 	for (retries = 0; retries < MAX_FAN_RETRIES; retries++) {
594138Svenki 		if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) == 0)
595138Svenki 			break;
5960Sstevel@tonic-gate 		(void) sleep(1);
5970Sstevel@tonic-gate 	}
5980Sstevel@tonic-gate 
599138Svenki 	total_fan_retries += retries;
600*8739SJustin.Frank@Sun.COM 	if (retries >= MAX_FAN_RETRIES)
6010Sstevel@tonic-gate 		return (-1);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	if (total_fan_retries && env_debug) {
6040Sstevel@tonic-gate 		envd_log(LOG_WARNING, "total retries for fan = %d",
6050Sstevel@tonic-gate 		    total_fan_retries);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	real_tach = tach << 8;
6090Sstevel@tonic-gate 	*fanspeedp = TACH_TO_RPM(real_tach);
6100Sstevel@tonic-gate 	return (0);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate  * Set fan speed
6150Sstevel@tonic-gate  * This function accepts a percentage of fan speed
6160Sstevel@tonic-gate  * from 0-100 and programs the HW monitor fans to the corresponding
6170Sstevel@tonic-gate  * fanspeed value.
6180Sstevel@tonic-gate  * Returns -1 on error, -2 on invalid args passed, 0 if successful
6190Sstevel@tonic-gate  */
6200Sstevel@tonic-gate int
set_fan_speed(env_fan_t * fanp,fanspeed_t fanspeed)6210Sstevel@tonic-gate set_fan_speed(env_fan_t *fanp, fanspeed_t fanspeed)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate 	uint8_t	speed;
6240Sstevel@tonic-gate 
625138Svenki 	if (fanp->fd == -1)
6260Sstevel@tonic-gate 		return (-1);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	if (fanspeed < 0 || fanspeed > 100)
6290Sstevel@tonic-gate 		return (-2);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	speed = fanspeed;
632138Svenki 	if (ioctl(fanp->fd, PIC_SET_FAN_SPEED, &speed) != 0)
633138Svenki 		return (-1);
6340Sstevel@tonic-gate 
635138Svenki 	return (0);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate  * close all fan devices
6400Sstevel@tonic-gate  */
6410Sstevel@tonic-gate static void
envd_close_fans(void)6420Sstevel@tonic-gate envd_close_fans(void)
6430Sstevel@tonic-gate {
6440Sstevel@tonic-gate 	int		i;
6450Sstevel@tonic-gate 	env_fan_t	*fanp;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
6480Sstevel@tonic-gate 		if (fanp->fd != -1) {
6490Sstevel@tonic-gate 			(void) close(fanp->fd);
6500Sstevel@tonic-gate 			fanp->fd = -1;
6510Sstevel@tonic-gate 		}
6520Sstevel@tonic-gate 	}
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate /*
6560Sstevel@tonic-gate  * Close sensor devices and freeup resources
6570Sstevel@tonic-gate  */
6580Sstevel@tonic-gate static void
envd_close_sensors(void)6590Sstevel@tonic-gate envd_close_sensors(void)
6600Sstevel@tonic-gate {
6610Sstevel@tonic-gate 	env_sensor_t	*sensorp;
6620Sstevel@tonic-gate 	int		i;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	for (i = 0; i < N_ENVD_SENSORS; ++i) {
6650Sstevel@tonic-gate 		sensorp = envd_sensors[i];
6660Sstevel@tonic-gate 		if (sensorp->fd != -1) {
6670Sstevel@tonic-gate 			(void) close(sensorp->fd);
6680Sstevel@tonic-gate 			sensorp->fd = -1;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate /*
6740Sstevel@tonic-gate  * Open fan devices and initialize per fan data structure.
6750Sstevel@tonic-gate  */
6760Sstevel@tonic-gate static int
envd_setup_fans(void)6770Sstevel@tonic-gate envd_setup_fans(void)
6780Sstevel@tonic-gate {
6790Sstevel@tonic-gate 	int		i, fd;
6800Sstevel@tonic-gate 	env_fan_t	*fanp;
6810Sstevel@tonic-gate 	int		fancnt = 0;
6820Sstevel@tonic-gate 	picl_nodehdl_t tnodeh;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
6850Sstevel@tonic-gate 		fanp->last_status = FAN_OK;
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 		/* Make sure cpu0/1 present for validating cpu fans */
6880Sstevel@tonic-gate 		if (fanp->id == CPU0_FAN_ID) {
6890Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
6900Sstevel@tonic-gate 			    PICL_SUCCESS) {
6910Sstevel@tonic-gate 					if (env_debug) {
6920Sstevel@tonic-gate 						envd_log(LOG_ERR,
6930Sstevel@tonic-gate 					"get node by path failed for %s\n",
6940Sstevel@tonic-gate 						    CPU0_PATH);
6950Sstevel@tonic-gate 					}
6960Sstevel@tonic-gate 					fanp->present = B_FALSE;
6970Sstevel@tonic-gate 					continue;
6980Sstevel@tonic-gate 			}
6990Sstevel@tonic-gate 		}
7000Sstevel@tonic-gate 		if (fanp->id == CPU1_FAN_ID) {
7010Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
7020Sstevel@tonic-gate 			    PICL_SUCCESS) {
7030Sstevel@tonic-gate 					if (env_debug) {
7040Sstevel@tonic-gate 						envd_log(LOG_ERR,
7050Sstevel@tonic-gate 				"get node by path failed for %s\n", CPU0_PATH);
7060Sstevel@tonic-gate 					}
7070Sstevel@tonic-gate 					fanp->present = B_FALSE;
7080Sstevel@tonic-gate 					continue;
7090Sstevel@tonic-gate 			}
7100Sstevel@tonic-gate 		}
711138Svenki 		if ((fd = open(fanp->devfs_path, O_RDWR)) == -1) {
7120Sstevel@tonic-gate 			envd_log(LOG_CRIT,
7130Sstevel@tonic-gate 			    ENV_FAN_OPEN_FAIL, fanp->name,
7140Sstevel@tonic-gate 			    fanp->devfs_path, errno, strerror(errno));
7150Sstevel@tonic-gate 			fanp->present = B_FALSE;
7160Sstevel@tonic-gate 			continue;
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 		fanp->fd = fd;
7190Sstevel@tonic-gate 		fanp->present = B_TRUE;
720138Svenki 		fancnt++;
7210Sstevel@tonic-gate 	}
722138Svenki 
723138Svenki 	if (fancnt == 0)
724138Svenki 		return (-1);
725138Svenki 
726138Svenki 	return (0);
7270Sstevel@tonic-gate }
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate static int
envd_setup_disks(void)7300Sstevel@tonic-gate envd_setup_disks(void)
7310Sstevel@tonic-gate {
7320Sstevel@tonic-gate 	int	ret, i, page_index, page_len;
7330Sstevel@tonic-gate 	picl_nodehdl_t tnodeh;
7340Sstevel@tonic-gate 	env_disk_t	*diskp;
7350Sstevel@tonic-gate 	uint_t	vendor_id;
7360Sstevel@tonic-gate 	uint_t	device_id;
7370Sstevel@tonic-gate 	uchar_t	log_page[256];
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	if (ptree_get_node_by_path(SCSI_CONTROLLER_NODE_PATH,
7400Sstevel@tonic-gate 	    &tnodeh) != PICL_SUCCESS) {
741138Svenki 		if (env_debug) {
742323Svenki 			envd_log(LOG_ERR, "On-Board SCSI controller %s "
743323Svenki 			    "not found in the system.\n",
7440Sstevel@tonic-gate 			    SCSI_CONTROLLER_NODE_PATH);
745138Svenki 		}
7460Sstevel@tonic-gate 		return (-1);
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if ((ret = ptree_get_propval_by_name(tnodeh, VENDOR_ID,
750138Svenki 	    &vendor_id, sizeof (vendor_id))) != 0) {
751138Svenki 		if (env_debug) {
752323Svenki 			envd_log(LOG_ERR, "Error in getting vendor-id "
753323Svenki 			    "for SCSI controller. ret = %d errno = 0x%d\n",
7540Sstevel@tonic-gate 			    ret, errno);
755138Svenki 		}
7560Sstevel@tonic-gate 		return (-1);
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 	if ((ret = ptree_get_propval_by_name(tnodeh, DEVICE_ID,
7590Sstevel@tonic-gate 	    &device_id, sizeof (device_id))) != 0) {
760138Svenki 		if (env_debug) {
761323Svenki 			envd_log(LOG_ERR, "Error in getting device-id "
762323Svenki 			    "for SCSI controller. ret = %d errno = 0x%d\n",
7630Sstevel@tonic-gate 			    ret, errno);
764138Svenki 		}
7650Sstevel@tonic-gate 		return (-1);
7660Sstevel@tonic-gate 	}
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	/*
7690Sstevel@tonic-gate 	 * We have found LSI1064 SCSi controller onboard.
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 	for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
7720Sstevel@tonic-gate 		if (ptree_get_node_by_path(diskp->nodepath,
7730Sstevel@tonic-gate 		    &tnodeh) != PICL_SUCCESS) {
7740Sstevel@tonic-gate 			diskp->present = B_FALSE;
775138Svenki 			if (env_debug) {
7760Sstevel@tonic-gate 				envd_log(LOG_ERR,
777138Svenki 				    "DISK %d: %s not found in the system.\n",
7780Sstevel@tonic-gate 				    diskp->id, diskp->nodepath);
779138Svenki 			}
7800Sstevel@tonic-gate 			continue;
7810Sstevel@tonic-gate 		}
782138Svenki 		if ((diskp->fd = open(diskp->devfs_path, O_RDONLY)) == -1) {
7830Sstevel@tonic-gate 			diskp->present = B_FALSE;
784138Svenki 			if (env_debug) {
7850Sstevel@tonic-gate 				envd_log(LOG_ERR,
786138Svenki 				    "Error in opening %s errno = 0x%x\n",
7870Sstevel@tonic-gate 				    diskp->devfs_path, errno);
788138Svenki 			}
7890Sstevel@tonic-gate 			continue;
7900Sstevel@tonic-gate 		}
7910Sstevel@tonic-gate 		diskp->present = B_TRUE;
7920Sstevel@tonic-gate 		diskp->tpage_supported = B_FALSE;
793377Siskreen 		diskp->smart_supported = B_FALSE;
7940Sstevel@tonic-gate 		diskp->warning_tstamp = 0;
7950Sstevel@tonic-gate 		diskp->shutdown_tstamp = 0;
7960Sstevel@tonic-gate 		diskp->high_warning = disk_high_warn_temperature;
7970Sstevel@tonic-gate 		diskp->low_warning = disk_low_warn_temperature;
7980Sstevel@tonic-gate 		diskp->high_shutdown = disk_high_shutdown_temperature;
7990Sstevel@tonic-gate 		diskp->low_shutdown = disk_low_shutdown_temperature;
8000Sstevel@tonic-gate 		/*
8010Sstevel@tonic-gate 		 * Find out if the Temperature page is supported by the disk.
8020Sstevel@tonic-gate 		 */
803138Svenki 		if (scsi_log_sense(diskp, SUPPORTED_LPAGES, log_page,
804377Siskreen 		    sizeof (log_page), 1) == 0) {
805377Siskreen 
806377Siskreen 			page_len = ((log_page[2] << 8) & 0xFF00) | log_page[3];
807377Siskreen 
808377Siskreen 			for (page_index = LOGPAGEHDRSIZE;
809377Siskreen 			    page_index < page_len + LOGPAGEHDRSIZE;
810377Siskreen 			    page_index++) {
811377Siskreen 				if (log_page[page_index] != TEMPERATURE_PAGE)
812377Siskreen 					continue;
813377Siskreen 
814377Siskreen 				diskp->tpage_supported = B_TRUE;
815377Siskreen 				if (env_debug) {
816377Siskreen 					envd_log(LOG_ERR,
817377Siskreen 					    "tpage supported for %s\n",
818377Siskreen 					    diskp->nodepath);
819377Siskreen 				}
820377Siskreen 			}
821138Svenki 		}
822377Siskreen 		/*
823377Siskreen 		 * If the temp log page failed, we can check if this is
824377Siskreen 		 * a SATA drive and attempt to read the temperature
825377Siskreen 		 * using the SMART interface.
826377Siskreen 		 */
827377Siskreen 		if (diskp->tpage_supported != B_TRUE) {
828377Siskreen 			uchar_t iec_page[IEC_PAGE_SIZE];
8290Sstevel@tonic-gate 
830377Siskreen 			if (env_debug)
831377Siskreen 				envd_log(LOG_ERR, "Turning on SMART\n");
832377Siskreen 
833377Siskreen 			(void) memset(iec_page, 0, sizeof (iec_page));
834377Siskreen 			iec_page[0] = IEC_PAGE;	/* SMART PAGE */
835377Siskreen 			iec_page[1] = 0xa;	/* length */
836377Siskreen 			/* Notification, only when requested */
837377Siskreen 			iec_page[3] = REPORT_ON_REQUEST;
838377Siskreen 
839377Siskreen 			ret = scsi_mode_select(diskp, IEC_PAGE,
840377Siskreen 			    iec_page, sizeof (iec_page));
841138Svenki 
842377Siskreen 			/*
843377Siskreen 			 * Since we know this is a SMART capable
844377Siskreen 			 * drive, we will try to set the page and
845377Siskreen 			 * determine if the drive is not capable
846377Siskreen 			 * of reading the TEMP page when we
847377Siskreen 			 * try to read the temperature and disable
848377Siskreen 			 * it then. We do not fail when reading
849377Siskreen 			 * or writing this page because we will
850377Siskreen 			 * determine the SMART capabilities
851377Siskreen 			 * when reading the temperature.
852377Siskreen 			 */
853377Siskreen 			if ((ret != 0) && (env_debug)) {
854377Siskreen 				envd_log(LOG_ERR,
855377Siskreen 				    "Failed to set mode page");
856377Siskreen 			}
857377Siskreen 
858377Siskreen 			diskp->smart_supported = B_TRUE;
859138Svenki 			diskp->tpage_supported = B_TRUE;
8600Sstevel@tonic-gate 		}
861138Svenki 
862138Svenki 		if (get_disk_temp(diskp) < 0) {
863138Svenki 			envd_log(LOG_ERR, " error reading temperature of:%s\n",
864138Svenki 			    diskp->name);
865138Svenki 		} else if (env_debug) {
866138Svenki 			envd_log(LOG_ERR, "%s: temperature = %d\n",
867138Svenki 			    diskp->name, diskp->current_temp);
8680Sstevel@tonic-gate 		}
869377Siskreen 
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	return (0);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
875323Svenki static int
envd_es_setup(void)876323Svenki envd_es_setup(void)
877323Svenki {
878323Svenki 	seeprom_scn_t	scn_hdr;
879323Svenki 	seeprom_seg_t	seg_hdr;
880323Svenki 	es_data_t	*envseg;
881323Svenki 	es_sensor_t	*sensorp;
882323Svenki 	int		i, fd, id;
883323Svenki 	int		envseg_len, esd_len;
884323Svenki 	char		*envsegp;
885323Svenki 
886323Svenki 	/*
887323Svenki 	 * Open the front io fru
888323Svenki 	 */
889323Svenki 	if ((fd = open(iofru_devname, O_RDONLY)) == -1) {
890323Svenki 		envd_log(LOG_ERR, ENV_FRU_OPEN_FAIL, iofru_devname, errno);
891323Svenki 		return (-1);
892323Svenki 	}
893323Svenki 
894323Svenki 	/*
895323Svenki 	 * Read section header from the fru SEEPROM
896323Svenki 	 */
897323Svenki 	if (lseek(fd, SSCN_OFFSET, SEEK_SET) == (off_t)-1 ||
898323Svenki 	    read(fd, &scn_hdr, sizeof (scn_hdr)) != sizeof (scn_hdr)) {
899323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
900323Svenki 		(void) close(fd);
901323Svenki 		return (-1);
902323Svenki 	}
903323Svenki 	if ((scn_hdr.sscn_tag != SSCN_TAG) ||
904323Svenki 	    (GET_UNALIGN16(&scn_hdr.sscn_ver) != SSCN_VER)) {
905323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_SCNHDR, scn_hdr.sscn_tag,
906323Svenki 		    GET_UNALIGN16(&scn_hdr.sscn_ver));
907323Svenki 		(void) close(fd);
908323Svenki 		return (-1);
909323Svenki 	}
910323Svenki 
911323Svenki 	/*
912323Svenki 	 * Locate environmental segment
913323Svenki 	 */
914323Svenki 	for (i = 0; i < scn_hdr.sscn_nsegs; i++) {
915323Svenki 		if (read(fd, &seg_hdr, sizeof (seg_hdr)) != sizeof (seg_hdr)) {
916323Svenki 			envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
917323Svenki 			(void) close(fd);
918323Svenki 			return (-1);
919323Svenki 		}
920323Svenki 
921323Svenki 		if (env_debug) {
922323Svenki 			envd_log(LOG_INFO,
923323Svenki 			    "Seg name: %x off:%x len:%x\n",
924323Svenki 			    GET_UNALIGN16(&seg_hdr.sseg_name),
925323Svenki 			    GET_UNALIGN16(&seg_hdr.sseg_off),
926323Svenki 			    GET_UNALIGN16(&seg_hdr.sseg_len));
927323Svenki 		}
928323Svenki 
929323Svenki 		if (GET_UNALIGN16(&seg_hdr.sseg_name) == ENVSEG_NAME)
930323Svenki 			break;
931323Svenki 	}
932323Svenki 	if (i == scn_hdr.sscn_nsegs) {
933323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
934323Svenki 		(void) close(fd);
935323Svenki 		return (-1);
936323Svenki 	}
937323Svenki 
938323Svenki 	/*
939323Svenki 	 * Read environmental segment
940323Svenki 	 */
941323Svenki 	envseg_len = GET_UNALIGN16(&seg_hdr.sseg_len);
942323Svenki 	if ((envseg = malloc(envseg_len)) == NULL) {
943323Svenki 		envd_log(LOG_ERR, ENV_FRU_NOMEM_FOR_SEG, envseg_len);
944323Svenki 		(void) close(fd);
945323Svenki 		return (-1);
946323Svenki 	}
947323Svenki 
948323Svenki 	if (lseek(fd, (off_t)GET_UNALIGN16(&seg_hdr.sseg_off),
949323Svenki 	    SEEK_SET) == (off_t)-1 ||
950323Svenki 	    read(fd, envseg, envseg_len) != envseg_len) {
951323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
952323Svenki 		free(envseg);
953323Svenki 		(void) close(fd);
954323Svenki 		return (-1);
955323Svenki 	}
956323Svenki 
957323Svenki 	/*
958323Svenki 	 * Check environmental segment data for consistency
959323Svenki 	 */
960323Svenki 	esd_len = sizeof (*envseg) +
961323Svenki 	    (envseg->esd_nsensors - 1) * sizeof (envseg->esd_sensors[0]);
962323Svenki 	if (envseg->esd_ver != ENVSEG_VERSION || envseg_len < esd_len) {
963323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
964323Svenki 		free(envseg);
965323Svenki 		(void) close(fd);
966323Svenki 		return (-1);
967323Svenki 	}
968323Svenki 
969323Svenki 	/*
970323Svenki 	 * Process environmental segment data
971323Svenki 	 */
972323Svenki 	if (envseg->esd_nsensors > MAX_SENSORS) {
973323Svenki 		envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
974323Svenki 		free(envseg);
975323Svenki 		(void) close(fd);
976323Svenki 		return (-1);
977323Svenki 	}
978323Svenki 
979323Svenki 	sensorp = &(envseg->esd_sensors[0]);
980323Svenki 	envsegp = (char *)envseg;
981323Svenki 	for (i = 0; i < envseg->esd_nsensors; i++) {
982323Svenki 		uint32_t ess_id;
983323Svenki 
984323Svenki 		(void) memcpy(&ess_id,
985*8739SJustin.Frank@Sun.COM 		    sensorp->ess_id, sizeof (sensorp->ess_id));
986323Svenki 
987323Svenki 		if (env_debug) {
988323Svenki 			envd_log(LOG_INFO, "\n Sensor Id %x offset %x",
989323Svenki 			    ess_id, sensorp->ess_off);
990323Svenki 		}
991323Svenki 		if (ess_id >= MAX_SENSORS) {
992323Svenki 			envd_log(LOG_ERR, ENV_FRU_BAD_ENVSEG, iofru_devname);
993323Svenki 			free(envseg);
994323Svenki 			(void) close(fd);
995323Svenki 			return (-1);
996323Svenki 		}
997323Svenki 		(void) memcpy(&sensor_ctl[ess_id], &envsegp[sensorp->ess_off],
998323Svenki 		    sizeof (es_sensor_blk_t));
999323Svenki 
1000323Svenki 		sensorp++;
1001323Svenki 	}
1002323Svenki 
1003323Svenki 	/*
1004323Svenki 	 * Match sensor/ES id and point to correct data based on IDs
1005323Svenki 	 */
1006323Svenki 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1007323Svenki 		id = envd_sensors[i]->id;
1008323Svenki 		envd_sensors[i]->es = &sensor_ctl[id];
1009323Svenki 	}
1010323Svenki 
1011323Svenki 	/*
1012323Svenki 	 * Cleanup and return
1013323Svenki 	 */
1014323Svenki 	free(envseg);
1015323Svenki 	(void) close(fd);
1016323Svenki 
1017323Svenki 	return (0);
1018323Svenki }
1019323Svenki 
1020323Svenki static void
envd_es_default_setup(void)1021323Svenki envd_es_default_setup(void)
1022323Svenki {
1023323Svenki 	int	i, id;
1024323Svenki 
1025323Svenki 	for (i = 0; i < N_ENVD_SENSORS; i++) {
1026323Svenki 		id = envd_sensors[i]->id;
1027323Svenki 		envd_sensors[i]->es = &sensor_default_ctl[id];
1028323Svenki 	}
1029323Svenki }
1030323Svenki 
10310Sstevel@tonic-gate /*
10320Sstevel@tonic-gate  * Open temperature sensor devices and initialize per sensor data structure.
10330Sstevel@tonic-gate  */
10340Sstevel@tonic-gate static int
envd_setup_sensors(void)10350Sstevel@tonic-gate envd_setup_sensors(void)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate 	env_sensor_t	*sensorp;
10380Sstevel@tonic-gate 	int		sensorcnt = 0;
10390Sstevel@tonic-gate 	int		i;
10400Sstevel@tonic-gate 	picl_nodehdl_t	tnodeh;
10410Sstevel@tonic-gate 
1042138Svenki 	for (i = 0; i < N_ENVD_SENSORS; i++) {
10430Sstevel@tonic-gate 		if (env_debug)
10440Sstevel@tonic-gate 			envd_log(LOG_ERR, "scanning sensor %d\n", i);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 		sensorp = envd_sensors[i];
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 		/* Initialize sensor's initial state */
10490Sstevel@tonic-gate 		sensorp->shutdown_initiated = B_FALSE;
10500Sstevel@tonic-gate 		sensorp->warning_tstamp = 0;
10510Sstevel@tonic-gate 		sensorp->shutdown_tstamp = 0;
10520Sstevel@tonic-gate 		sensorp->error = 0;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 		/* Make sure cpu0/1 sensors are present */
10550Sstevel@tonic-gate 		if (sensorp->id == CPU0_SENSOR_ID) {
10560Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU0_PATH, &tnodeh) !=
10570Sstevel@tonic-gate 			    PICL_SUCCESS) {
10580Sstevel@tonic-gate 				if (env_debug) {
10590Sstevel@tonic-gate 					envd_log(LOG_ERR,
1060323Svenki 					    "get node by path failed for %s\n",
10610Sstevel@tonic-gate 					    CPU0_PATH);
10620Sstevel@tonic-gate 				}
10630Sstevel@tonic-gate 				sensorp->present = B_FALSE;
10640Sstevel@tonic-gate 				continue;
10650Sstevel@tonic-gate 			}
10660Sstevel@tonic-gate 		}
10670Sstevel@tonic-gate 		if (sensorp->id == CPU1_SENSOR_ID) {
10680Sstevel@tonic-gate 			if (ptree_get_node_by_path(CPU1_PATH, &tnodeh) !=
10690Sstevel@tonic-gate 			    PICL_SUCCESS) {
10700Sstevel@tonic-gate 				if (env_debug) {
10710Sstevel@tonic-gate 					envd_log(LOG_ERR,
1072323Svenki 					    "get node by path failed for %s\n",
10730Sstevel@tonic-gate 					    CPU1_PATH);
10740Sstevel@tonic-gate 				}
10750Sstevel@tonic-gate 				sensorp->present = B_FALSE;
10760Sstevel@tonic-gate 				continue;
10770Sstevel@tonic-gate 			}
10780Sstevel@tonic-gate 		}
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 		sensorp->fd = open(sensorp->devfs_path, O_RDWR);
10810Sstevel@tonic-gate 		if (sensorp->fd == -1) {
10820Sstevel@tonic-gate 			if (env_debug) {
10830Sstevel@tonic-gate 				envd_log(LOG_ERR, ENV_SENSOR_OPEN_FAIL,
10840Sstevel@tonic-gate 				    sensorp->name, sensorp->devfs_path,
10850Sstevel@tonic-gate 				    errno, strerror(errno));
10860Sstevel@tonic-gate 			}
10870Sstevel@tonic-gate 			sensorp->present = B_FALSE;
10880Sstevel@tonic-gate 			continue;
10890Sstevel@tonic-gate 		}
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		/*
10920Sstevel@tonic-gate 		 * Determine if the front panel is attached, we want the
10930Sstevel@tonic-gate 		 * information if it exists, but should not shut down
10940Sstevel@tonic-gate 		 * the system if it is removed.
10950Sstevel@tonic-gate 		 */
10960Sstevel@tonic-gate 		if (sensorp->id == FRONT_PANEL_SENSOR_ID) {
1097138Svenki 			tempr_t temp;
1098138Svenki 			int	tries;
10990Sstevel@tonic-gate 
1100138Svenki 			for (tries = 0; tries < MAX_SENSOR_RETRIES; tries++) {
1101138Svenki 				if (ioctl(sensorp->fd, PIC_GET_TEMPERATURE,
1102138Svenki 				    &temp) == 0) {
1103138Svenki 					break;
11040Sstevel@tonic-gate 				}
1105138Svenki 				(void) sleep(1);
11060Sstevel@tonic-gate 			}
1107138Svenki 			if (tries == MAX_SENSOR_RETRIES)
11080Sstevel@tonic-gate 				sensorp->present = B_FALSE;
11090Sstevel@tonic-gate 		}
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 		sensorp->present = B_TRUE;
11120Sstevel@tonic-gate 		sensorcnt++;
11130Sstevel@tonic-gate 	}
1114138Svenki 
1115138Svenki 	if (sensorcnt == 0)
1116138Svenki 		return (-1);
1117138Svenki 
1118138Svenki 	return (0);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate /* ARGSUSED */
11220Sstevel@tonic-gate static void *
pmthr(void * args)11230Sstevel@tonic-gate pmthr(void *args)
11240Sstevel@tonic-gate {
11250Sstevel@tonic-gate 	pm_state_change_t	pmstate;
11260Sstevel@tonic-gate 	char			physpath[PATH_MAX];
11270Sstevel@tonic-gate 	int			pre_lpstate;
11280Sstevel@tonic-gate 	uint8_t			estar_state;
11290Sstevel@tonic-gate 	int			env_monitor_fd;
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	pmstate.physpath = physpath;
11320Sstevel@tonic-gate 	pmstate.size = sizeof (physpath);
11330Sstevel@tonic-gate 	cur_lpstate = 0;
11340Sstevel@tonic-gate 	pre_lpstate = 1;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	pm_fd = open(PM_DEVICE, O_RDWR);
11370Sstevel@tonic-gate 	if (pm_fd == -1) {
11380Sstevel@tonic-gate 		envd_log(LOG_ERR, PM_THREAD_EXITING, errno, strerror(errno));
11390Sstevel@tonic-gate 		return (NULL);
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 	for (;;) {
11420Sstevel@tonic-gate 		/*
11430Sstevel@tonic-gate 		 * Get PM state change events to check if the system
11440Sstevel@tonic-gate 		 * is in lowest power state and inform PIC which controls
11450Sstevel@tonic-gate 		 * fan speeds.
11460Sstevel@tonic-gate 		 *
11470Sstevel@tonic-gate 		 * To minimize polling, we use the blocking interface
11480Sstevel@tonic-gate 		 * to get the power state change event here.
11490Sstevel@tonic-gate 		 */
11500Sstevel@tonic-gate 		if (ioctl(pm_fd, PM_GET_STATE_CHANGE_WAIT, &pmstate) != 0) {
11510Sstevel@tonic-gate 			if (errno != EINTR)
11520Sstevel@tonic-gate 				break;
11530Sstevel@tonic-gate 			continue;
11540Sstevel@tonic-gate 		}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 		do {
11570Sstevel@tonic-gate 			if (env_debug)  {
11580Sstevel@tonic-gate 				envd_log(LOG_INFO,
11590Sstevel@tonic-gate 				"pmstate event:0x%x flags:%x"
11600Sstevel@tonic-gate 				"comp:%d oldval:%d newval:%d path:%s\n",
11610Sstevel@tonic-gate 				    pmstate.event, pmstate.flags,
11620Sstevel@tonic-gate 				    pmstate.component,
11630Sstevel@tonic-gate 				    pmstate.old_level,
11640Sstevel@tonic-gate 				    pmstate.new_level,
11650Sstevel@tonic-gate 				    pmstate.physpath);
11660Sstevel@tonic-gate 			}
11670Sstevel@tonic-gate 			cur_lpstate =
11680Sstevel@tonic-gate 			    (pmstate.flags & PSC_ALL_LOWEST) ? 1 : 0;
11690Sstevel@tonic-gate 		} while (ioctl(pm_fd, PM_GET_STATE_CHANGE, &pmstate) == 0);
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 		if (pre_lpstate != cur_lpstate) {
11720Sstevel@tonic-gate 			pre_lpstate = cur_lpstate;
11730Sstevel@tonic-gate 			estar_state = (cur_lpstate & 0x1);
11740Sstevel@tonic-gate 			if (env_debug)
11750Sstevel@tonic-gate 				envd_log(LOG_ERR,
11760Sstevel@tonic-gate 				    "setting PIC ESTAR SATE to %x\n",
11770Sstevel@tonic-gate 				    estar_state);
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 			env_monitor_fd = open(ENV_MONITOR_DEVFS, O_RDWR);
11800Sstevel@tonic-gate 			if (env_monitor_fd != -1) {
11810Sstevel@tonic-gate 				if (ioctl(env_monitor_fd, PIC_SET_ESTAR_MODE,
11820Sstevel@tonic-gate 				    &estar_state) < 0) {
11830Sstevel@tonic-gate 					if (env_debug)
11840Sstevel@tonic-gate 						envd_log(LOG_ERR,
11850Sstevel@tonic-gate 					"unable to set ESTAR_MODE in PIC\n");
11860Sstevel@tonic-gate 				}
11870Sstevel@tonic-gate 				(void) close(env_monitor_fd);
11880Sstevel@tonic-gate 			} else {
11890Sstevel@tonic-gate 				if (env_debug)
11900Sstevel@tonic-gate 					envd_log(LOG_ERR,
11910Sstevel@tonic-gate 				"Failed to open %s\n",
11920Sstevel@tonic-gate 					    ENV_MONITOR_DEVFS);
11930Sstevel@tonic-gate 			}
11940Sstevel@tonic-gate 		}
11950Sstevel@tonic-gate 	}
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	/*NOTREACHED*/
11980Sstevel@tonic-gate 	return (NULL);
11990Sstevel@tonic-gate }
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate /*
12020Sstevel@tonic-gate  * This is env thread which monitors the current temperature when
12030Sstevel@tonic-gate  * warning threshold is exceeded. The job is to make sure it does
12040Sstevel@tonic-gate  * not execced/decrease shutdown threshold. If it does it will start
12050Sstevel@tonic-gate  * forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
12060Sstevel@tonic-gate  */
12070Sstevel@tonic-gate /*ARGSUSED*/
12080Sstevel@tonic-gate static void *
system_temp_thr(void * args)12090Sstevel@tonic-gate system_temp_thr(void *args)
12100Sstevel@tonic-gate {
12110Sstevel@tonic-gate 	char syscmd[BUFSIZ];
12120Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
12130Sstevel@tonic-gate 	timespec_t	to;
12140Sstevel@tonic-gate 	int	ret, i;
12150Sstevel@tonic-gate 	env_sensor_t	*sensorp;
12160Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
12170Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
12180Sstevel@tonic-gate 	time_t	ct;
12190Sstevel@tonic-gate 	tempr_t  temp;
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	for (;;) {
1222138Svenki 		/*
1223138Svenki 		 * Sleep for specified seconds before issuing IOCTL
1224138Svenki 		 * again.
1225138Svenki 		 */
12260Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
12270Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
12280Sstevel@tonic-gate 		    &env_monitor_mutex, &to);
12290Sstevel@tonic-gate 		to.tv_sec = sensor_scan_interval;
12300Sstevel@tonic-gate 		to.tv_nsec = 0;
12310Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
12320Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&env_monitor_mutex);
12330Sstevel@tonic-gate 			continue;
12340Sstevel@tonic-gate 		}
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
12370Sstevel@tonic-gate 		for (i = 0; i < N_ENVD_SENSORS; i++) {
12380Sstevel@tonic-gate 			sensorp = envd_sensors[i];
12390Sstevel@tonic-gate 			if (sensorp->present == B_FALSE)
12400Sstevel@tonic-gate 				continue;
12410Sstevel@tonic-gate 			if (get_temperature(sensorp, &temp) == -1)
12420Sstevel@tonic-gate 				continue;
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 			sensorp->cur_temp = temp;
12450Sstevel@tonic-gate 			if (env_debug) {
12460Sstevel@tonic-gate 				envd_log(LOG_ERR,
12470Sstevel@tonic-gate 				"%s temp = %d",
12480Sstevel@tonic-gate 				    sensorp->name, sensorp->cur_temp);
12490Sstevel@tonic-gate 			}
1250138Svenki 
1251138Svenki 			/*
1252138Svenki 			 * If this sensor already triggered system shutdown,
1253138Svenki 			 * don't log any more shutdown/warning messages for it.
1254138Svenki 			 */
12550Sstevel@tonic-gate 			if (sensorp->shutdown_initiated)
12560Sstevel@tonic-gate 				continue;
12570Sstevel@tonic-gate 
1258138Svenki 			/*
1259138Svenki 			 * Check for the temperature in warning and shutdown
1260138Svenki 			 * range and take appropriate action.
1261138Svenki 			 */
12620Sstevel@tonic-gate 			if (SENSOR_TEMP_IN_WARNING_RANGE(sensorp->cur_temp,
12630Sstevel@tonic-gate 			    sensorp)) {
1264138Svenki 				/*
1265138Svenki 				 * Check if the temperature has been in
1266138Svenki 				 * warning range during last
1267138Svenki 				 * sensor_warning_duration interval. If so,
1268138Svenki 				 * the temperature is truly in warning range
1269138Svenki 				 * and we need to log a warning message, but
1270138Svenki 				 * no more than once every
1271138Svenki 				 * sensor_warning_interval seconds.
1272138Svenki 				 */
12730Sstevel@tonic-gate 				time_t	wtstamp = sensorp->warning_tstamp;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 				ct = (time_t)(gethrtime() / NANOSEC);
12760Sstevel@tonic-gate 				if (sensorp->warning_start == 0)
12770Sstevel@tonic-gate 					sensorp->warning_start = ct;
12780Sstevel@tonic-gate 				if (((ct - sensorp->warning_start) >=
12790Sstevel@tonic-gate 				    sensor_warning_duration) &&
12800Sstevel@tonic-gate 				    (wtstamp == 0 || (ct - wtstamp) >=
12810Sstevel@tonic-gate 				    sensor_warning_interval)) {
12820Sstevel@tonic-gate 					envd_log(LOG_CRIT, ENV_WARNING_MSG,
1283*8739SJustin.Frank@Sun.COM 					    sensorp->name, sensorp->cur_temp,
1284*8739SJustin.Frank@Sun.COM 					    (int8_t)
1285*8739SJustin.Frank@Sun.COM 					    sensorp->es->esb_low_warning,
1286*8739SJustin.Frank@Sun.COM 					    (int8_t)
1287*8739SJustin.Frank@Sun.COM 					    sensorp->es->esb_high_warning);
12882137Svenki 
12890Sstevel@tonic-gate 					sensorp->warning_tstamp = ct;
12900Sstevel@tonic-gate 				}
12910Sstevel@tonic-gate 			} else if (sensorp->warning_start != 0)
12920Sstevel@tonic-gate 				sensorp->warning_start = 0;
12930Sstevel@tonic-gate 
12940Sstevel@tonic-gate 			if (!shutdown_override &&
12950Sstevel@tonic-gate 			    SENSOR_TEMP_IN_SHUTDOWN_RANGE(sensorp->cur_temp,
12960Sstevel@tonic-gate 			    sensorp)) {
12970Sstevel@tonic-gate 				ct = (time_t)(gethrtime() / NANOSEC);
12980Sstevel@tonic-gate 				if (sensorp->shutdown_tstamp == 0)
12990Sstevel@tonic-gate 					sensorp->shutdown_tstamp = ct;
13000Sstevel@tonic-gate 
1301138Svenki 				/*
1302138Svenki 				 * Shutdown the system if the temperature
1303138Svenki 				 * remains in the shutdown range for over
1304138Svenki 				 * sensor_shutdown_interval seconds.
1305138Svenki 				 */
13060Sstevel@tonic-gate 				if ((ct - sensorp->shutdown_tstamp) >=
13070Sstevel@tonic-gate 				    sensor_shutdown_interval) {
1308138Svenki 					/*
1309138Svenki 					 * Log error
1310138Svenki 					 */
13110Sstevel@tonic-gate 					sensorp->shutdown_initiated = B_TRUE;
13122137Svenki 
13130Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
1314*8739SJustin.Frank@Sun.COM 					    ENV_SHUTDOWN_MSG, sensorp->name,
1315*8739SJustin.Frank@Sun.COM 					    sensorp->cur_temp,
1316*8739SJustin.Frank@Sun.COM 					    (int8_t)
1317*8739SJustin.Frank@Sun.COM 					    sensorp->es->esb_low_shutdown,
1318*8739SJustin.Frank@Sun.COM 					    (int8_t)
1319*8739SJustin.Frank@Sun.COM 					    sensorp->es->esb_high_shutdown);
13202137Svenki 
13210Sstevel@tonic-gate 					envd_log(LOG_ALERT, msgbuf);
13220Sstevel@tonic-gate 
1323138Svenki 					/*
1324138Svenki 					 * Shutdown the system (only once)
1325138Svenki 					 */
13260Sstevel@tonic-gate 					if (system_shutdown_started ==
13270Sstevel@tonic-gate 					    B_FALSE) {
13280Sstevel@tonic-gate 						(void) snprintf(syscmd,
13290Sstevel@tonic-gate 						    sizeof (syscmd),
13300Sstevel@tonic-gate 						    "%s \"%s\"", shutdown_cmd,
13310Sstevel@tonic-gate 						    msgbuf);
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 						envd_log(LOG_ALERT, syscmd);
13340Sstevel@tonic-gate 						system_shutdown_started =
13350Sstevel@tonic-gate 						    B_TRUE;
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 						(void) system(syscmd);
13380Sstevel@tonic-gate 					}
13390Sstevel@tonic-gate 				}
13400Sstevel@tonic-gate 			} else if (sensorp->shutdown_tstamp != 0)
13410Sstevel@tonic-gate 				sensorp->shutdown_tstamp = 0;
13420Sstevel@tonic-gate 		}
13430Sstevel@tonic-gate 	}	/* end of forever loop */
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	/*NOTREACHED*/
13460Sstevel@tonic-gate 	return (NULL);
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate static int
scsi_log_sense(env_disk_t * diskp,uchar_t page_code,void * pagebuf,uint16_t pagelen,int page_control)1350377Siskreen scsi_log_sense(env_disk_t *diskp, uchar_t page_code, void *pagebuf,
1351377Siskreen 		uint16_t pagelen, int page_control)
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate 	struct uscsi_cmd	ucmd_buf;
13540Sstevel@tonic-gate 	uchar_t		cdb_buf[CDB_GROUP1];
13550Sstevel@tonic-gate 	struct	scsi_extended_sense	sense_buf;
13560Sstevel@tonic-gate 	int	ret_val;
13570Sstevel@tonic-gate 
1358377Siskreen 	bzero(&cdb_buf, sizeof (cdb_buf));
1359377Siskreen 	bzero(&ucmd_buf, sizeof (ucmd_buf));
1360377Siskreen 	bzero(&sense_buf, sizeof (sense_buf));
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	cdb_buf[0] = SCMD_LOG_SENSE_G1;
1363377Siskreen 
1364377Siskreen 	/*
1365377Siskreen 	 * For SATA we need to have the current threshold value set.
1366377Siskreen 	 * For SAS drives we can use the current cumulative value.
1367377Siskreen 	 * This is set for non-SMART drives, by passing a non-zero
1368377Siskreen 	 * page_control.
1369377Siskreen 	 */
1370377Siskreen 	if (page_control)
1371377Siskreen 		cdb_buf[2] = (0x01 << 6) | page_code;
1372377Siskreen 	else
1373377Siskreen 		cdb_buf[2] = page_code;
1374377Siskreen 
13750Sstevel@tonic-gate 	cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
13760Sstevel@tonic-gate 	cdb_buf[8] = (uchar_t)(pagelen  & 0x00FF);
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	ucmd_buf.uscsi_cdb = (char *)cdb_buf;
13790Sstevel@tonic-gate 	ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
13800Sstevel@tonic-gate 	ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
13810Sstevel@tonic-gate 	ucmd_buf.uscsi_buflen = pagelen;
13820Sstevel@tonic-gate 	ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
13830Sstevel@tonic-gate 	ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
13840Sstevel@tonic-gate 	ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_READ | USCSI_SILENT;
1385377Siskreen 	ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf);
1388138Svenki 	if ((ret_val == 0) && (ucmd_buf.uscsi_status == 0)) {
13890Sstevel@tonic-gate 		if (env_debug)
13900Sstevel@tonic-gate 			envd_log(LOG_ERR,
13910Sstevel@tonic-gate 		"log sense command for page_code 0x%x succeeded\n", page_code);
13920Sstevel@tonic-gate 		return (ret_val);
13930Sstevel@tonic-gate 	}
1394377Siskreen 	if (env_debug)
1395138Svenki 		envd_log(LOG_ERR, "log sense command for %s failed. "
1396138Svenki 		    "page_code 0x%x ret_val = 0x%x "
1397138Svenki 		    "status = 0x%x errno = 0x%x\n", diskp->name, page_code,
1398138Svenki 		    ret_val, ucmd_buf.uscsi_status, errno);
1399138Svenki 
14000Sstevel@tonic-gate 	return (1);
14010Sstevel@tonic-gate }
14020Sstevel@tonic-gate 
1403377Siskreen 
14040Sstevel@tonic-gate static int
get_disk_temp(env_disk_t * diskp)14050Sstevel@tonic-gate get_disk_temp(env_disk_t *diskp)
14060Sstevel@tonic-gate {
14070Sstevel@tonic-gate 	int	ret;
14080Sstevel@tonic-gate 	uchar_t	tpage[256];
14090Sstevel@tonic-gate 
1410377Siskreen 	if (diskp->smart_supported == B_TRUE) {
1411377Siskreen 		smart_structure	smartpage;
1412377Siskreen 		smart_attribute	*temp_attrib = NULL;
1413377Siskreen 		uint8_t		checksum;
1414377Siskreen 		uint8_t		*index;
1415377Siskreen 		int		i;
1416377Siskreen 
1417377Siskreen 		bzero(&smartpage, sizeof (smartpage));
1418377Siskreen 
1419377Siskreen 		ret = scsi_log_sense(diskp, GET_SMART_INFO,
1420377Siskreen 		    &smartpage, sizeof (smartpage), 0);
1421377Siskreen 
1422377Siskreen 		if (ret != 0) {
14230Sstevel@tonic-gate 			diskp->current_temp = DISK_INVALID_TEMP;
1424377Siskreen 			diskp->ref_temp = DISK_INVALID_TEMP;
1425377Siskreen 			return (-1);
1426377Siskreen 		}
1427377Siskreen 
1428377Siskreen 		/*
1429377Siskreen 		 * verify the checksum of the data. A 2's compliment
1430377Siskreen 		 * of the result addition of the is stored in the
1431377Siskreen 		 * last byte. The sum of all the checksum should be
1432377Siskreen 		 * 0. If the checksum is bad, return an error for
1433377Siskreen 		 * this iteration.
1434377Siskreen 		 */
1435377Siskreen 		index = (uint8_t *)&smartpage;
1436377Siskreen 
1437377Siskreen 		for (i = checksum = 0; i < 512; i++)
1438377Siskreen 			checksum += index[i];
1439377Siskreen 
1440377Siskreen 		if ((checksum != 0) && env_debug) {
1441377Siskreen 			envd_log(LOG_ERR,
1442377Siskreen 			    "SMART checksum error! 0x%x\n", checksum);
1443377Siskreen 
1444377Siskreen 			/*
1445377Siskreen 			 * We got bad data back from the drive, fail this
1446377Siskreen 			 * time around and picl will retry again. If this
1447377Siskreen 			 * continues to fail picl will give this drive a
1448377Siskreen 			 * failed status.
1449377Siskreen 			 */
1450377Siskreen 			diskp->current_temp = DISK_INVALID_TEMP;
1451377Siskreen 			diskp->ref_temp = DISK_INVALID_TEMP;
1452377Siskreen 
14530Sstevel@tonic-gate 			return (-1);
1454377Siskreen 		}
1455377Siskreen 
1456377Siskreen 		/*
1457377Siskreen 		 * Scan through the various SMART data and look for
1458377Siskreen 		 * the complete drive temp.
1459377Siskreen 		 */
1460377Siskreen 
1461377Siskreen 		for (i = 0; (i < SMART_FIELDS) &&
1462377Siskreen 		    (smartpage.attribute[i].id != 0) &&
1463377Siskreen 		    (temp_attrib == NULL); i++) {
1464377Siskreen 
1465377Siskreen 			if (smartpage.attribute[i].id == HDA_TEMP) {
1466377Siskreen 				temp_attrib = &smartpage.attribute[i];
1467377Siskreen 			}
14680Sstevel@tonic-gate 		}
1469377Siskreen 
1470377Siskreen 		/*
1471377Siskreen 		 * If we dont find any temp SMART attributes, this drive
1472377Siskreen 		 * does not support this page, disable temp checking
1473377Siskreen 		 * for this drive.
1474377Siskreen 		 */
1475377Siskreen 		if (temp_attrib == NULL) {
1476377Siskreen 
1477377Siskreen 			/*
1478377Siskreen 			 * If the checksum is valid, the temp. attributes are
1479377Siskreen 			 * not supported, disable this drive from temp.
1480377Siskreen 			 * checking.
1481377Siskreen 			 */
1482377Siskreen 			if (env_debug)
1483377Siskreen 				envd_log(LOG_ERR,
1484377Siskreen 				    "Temp ATTRIBUTE not supported\n");
1485377Siskreen 			diskp->smart_supported = B_FALSE;
1486377Siskreen 			diskp->tpage_supported = B_FALSE;
1487377Siskreen 			diskp->current_temp = DISK_INVALID_TEMP;
1488377Siskreen 			diskp->ref_temp = DISK_INVALID_TEMP;
1489377Siskreen 
1490377Siskreen 			return (-1);
1491377Siskreen 		}
14920Sstevel@tonic-gate 
1493377Siskreen 		if (env_debug) {
1494377Siskreen 			envd_log(LOG_ERR, "flags = 0x%x%x,curr = 0x%x,"
1495*8739SJustin.Frank@Sun.COM 			    "data = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1496*8739SJustin.Frank@Sun.COM 			    temp_attrib->flags[0], temp_attrib->flags[1],
1497*8739SJustin.Frank@Sun.COM 			    temp_attrib->raw_data[0], temp_attrib->raw_data[1],
1498*8739SJustin.Frank@Sun.COM 			    temp_attrib->raw_data[2], temp_attrib->raw_data[3],
1499*8739SJustin.Frank@Sun.COM 			    temp_attrib->raw_data[4], temp_attrib->raw_data[5],
1500*8739SJustin.Frank@Sun.COM 			    temp_attrib->raw_data[6], temp_attrib->raw_data[7]);
1501377Siskreen 		}
1502377Siskreen 		if (temp_attrib->raw_data[1] != 0xFF) {
1503377Siskreen 			diskp->current_temp = temp_attrib->raw_data[2];
1504377Siskreen 			diskp->ref_temp	= temp_attrib->raw_data[2];
1505377Siskreen 		} else {
1506377Siskreen 			diskp->ref_temp = DISK_INVALID_TEMP;
1507377Siskreen 			diskp->current_temp = DISK_INVALID_TEMP;
1508377Siskreen 
1509377Siskreen 			return (-1);
1510377Siskreen 		}
1511377Siskreen 
1512377Siskreen 	} else {
1513377Siskreen 		ret = scsi_log_sense(diskp, TEMPERATURE_PAGE, tpage,
1514377Siskreen 		    sizeof (tpage), 1);
1515377Siskreen 
1516377Siskreen 		if (ret != 0) {
1517377Siskreen 			diskp->current_temp = DISK_INVALID_TEMP;
15180Sstevel@tonic-gate 			diskp->ref_temp = DISK_INVALID_TEMP;
1519377Siskreen 			return (-1);
1520377Siskreen 		}
1521377Siskreen 		/*
1522377Siskreen 		 * For the current temperature verify that the parameter
1523377Siskreen 		 * length is 0x02 and the parameter code is 0x00
1524377Siskreen 		 * Temperature value of 255(0xFF) is considered INVALID.
1525377Siskreen 		 */
1526377Siskreen 		if ((tpage[7] == 0x02) && (tpage[4] == 0x00) &&
1527377Siskreen 		    (tpage[5] == 0x00)) {
1528377Siskreen 			if (tpage[9] == 0xFF) {
1529377Siskreen 				diskp->current_temp = DISK_INVALID_TEMP;
1530377Siskreen 				return (-1);
1531377Siskreen 			} else {
1532377Siskreen 				diskp->current_temp = tpage[9];
1533377Siskreen 			}
1534377Siskreen 		}
1535377Siskreen 
1536377Siskreen 		/*
1537377Siskreen 		 * For the reference temperature verify that the parameter
1538377Siskreen 		 * length is 0x02 and the parameter code is 0x01
1539377Siskreen 		 * Temperature value of 255(0xFF) is considered INVALID.
1540377Siskreen 		 */
1541377Siskreen 		if ((tpage[13] == 0x02) && (tpage[10] == 0x00) &&
1542377Siskreen 		    (tpage[11] == 0x01)) {
1543377Siskreen 			if (tpage[15] == 0xFF) {
1544377Siskreen 				diskp->ref_temp = DISK_INVALID_TEMP;
1545377Siskreen 			} else {
1546377Siskreen 				diskp->ref_temp = tpage[15];
1547377Siskreen 			}
15480Sstevel@tonic-gate 		}
15490Sstevel@tonic-gate 	}
15500Sstevel@tonic-gate 	return (0);
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate /* ARGSUSED */
15540Sstevel@tonic-gate static void *
disk_temp_thr(void * args)15550Sstevel@tonic-gate disk_temp_thr(void *args)
15560Sstevel@tonic-gate {
15570Sstevel@tonic-gate 	char syscmd[BUFSIZ];
15580Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
15590Sstevel@tonic-gate 	timespec_t	to;
15600Sstevel@tonic-gate 	int	ret, i;
15610Sstevel@tonic-gate 	env_disk_t	*diskp;
15620Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
15630Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
15640Sstevel@tonic-gate 	pm_state_change_t	pmstate;
15650Sstevel@tonic-gate 	int	idle_time;
15660Sstevel@tonic-gate 	int	disk_pm_fd;
15670Sstevel@tonic-gate 	time_t	ct;
15680Sstevel@tonic-gate 
1569138Svenki 	if ((disk_pm_fd = open(PM_DEVICE, O_RDWR)) == -1) {
1570138Svenki 		envd_log(LOG_ERR, DISK_TEMP_THREAD_EXITING,
15710Sstevel@tonic-gate 		    errno, strerror(errno));
15720Sstevel@tonic-gate 		return (NULL);
15730Sstevel@tonic-gate 	}
1574138Svenki 
15750Sstevel@tonic-gate 	for (;;) {
1576138Svenki 		/*
1577138Svenki 		 * Sleep for specified seconds before issuing IOCTL
1578138Svenki 		 * again.
1579138Svenki 		 */
15800Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
15810Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
15820Sstevel@tonic-gate 		    &env_monitor_mutex, &to);
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 		to.tv_sec = disk_scan_interval;
15850Sstevel@tonic-gate 		to.tv_nsec = 0;
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
15880Sstevel@tonic-gate 			(void) pthread_mutex_unlock(
15890Sstevel@tonic-gate 			    &env_monitor_mutex);
15900Sstevel@tonic-gate 			continue;
15910Sstevel@tonic-gate 		}
15920Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 		for (i = 0; (diskp = envd_disks[i]) != NULL; i++) {
15950Sstevel@tonic-gate 			if (diskp->present == B_FALSE)
15960Sstevel@tonic-gate 				continue;
15970Sstevel@tonic-gate 			if (diskp->tpage_supported == B_FALSE)
15980Sstevel@tonic-gate 				continue;
15990Sstevel@tonic-gate 		/*
16000Sstevel@tonic-gate 		 * If the disk temperature is above the warning threshold
16010Sstevel@tonic-gate 		 * continue monitoring until the temperature drops below
16020Sstevel@tonic-gate 		 * warning threshold.
16030Sstevel@tonic-gate 		 * if the temperature is in the NORMAL range monitor only
16040Sstevel@tonic-gate 		 * when the disk is BUSY.
16050Sstevel@tonic-gate 		 * We do not want to read the disk temperature if the disk is
16060Sstevel@tonic-gate 		 * is idling. The reason for this is disk will never get into
16070Sstevel@tonic-gate 		 * lowest power mode if we scan the disk temperature
16080Sstevel@tonic-gate 		 * peridoically. To avoid this situation we first determine
16090Sstevel@tonic-gate 		 * the idle_time of the disk. If the disk has been IDLE since
16100Sstevel@tonic-gate 		 * we scanned the temperature last time we will not read the
16110Sstevel@tonic-gate 		 * temperature.
16120Sstevel@tonic-gate 		 */
16130Sstevel@tonic-gate 		if (!DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
16140Sstevel@tonic-gate 			pmstate.physpath = diskp->physpath;
16150Sstevel@tonic-gate 			pmstate.size = strlen(diskp->physpath);
16160Sstevel@tonic-gate 			pmstate.component = 0;
16170Sstevel@tonic-gate 			if ((idle_time =
16180Sstevel@tonic-gate 			    ioctl(disk_pm_fd, PM_GET_TIME_IDLE,
16190Sstevel@tonic-gate 			    &pmstate)) == -1) {
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 				if (errno != EINTR) {
16220Sstevel@tonic-gate 					if (env_debug)
16230Sstevel@tonic-gate 						envd_log(LOG_ERR,
16240Sstevel@tonic-gate 			"ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n",
16250Sstevel@tonic-gate 						    errno);
16260Sstevel@tonic-gate 					continue;
16270Sstevel@tonic-gate 				}
16280Sstevel@tonic-gate 				continue;
16290Sstevel@tonic-gate 			}
16300Sstevel@tonic-gate 			if (idle_time >= (disk_scan_interval/2)) {
16310Sstevel@tonic-gate 				if (env_debug) {
16320Sstevel@tonic-gate 					envd_log(LOG_ERR, "%s idle time = %d\n",
16330Sstevel@tonic-gate 					    diskp->name, idle_time);
16340Sstevel@tonic-gate 				}
16350Sstevel@tonic-gate 				continue;
16360Sstevel@tonic-gate 			}
16370Sstevel@tonic-gate 		}
16380Sstevel@tonic-gate 		ret = get_disk_temp(diskp);
16390Sstevel@tonic-gate 		if (ret != 0)
16400Sstevel@tonic-gate 			continue;
16410Sstevel@tonic-gate 		if (env_debug) {
16420Sstevel@tonic-gate 			envd_log(LOG_ERR, "%s temp = %d ref. temp = %d\n",
16430Sstevel@tonic-gate 			    diskp->name, diskp->current_temp, diskp->ref_temp);
16440Sstevel@tonic-gate 		}
16450Sstevel@tonic-gate 		/*
16460Sstevel@tonic-gate 		 * If this disk already triggered system shutdown, don't
16470Sstevel@tonic-gate 		 * log any more shutdown/warning messages for it.
16480Sstevel@tonic-gate 		 */
16490Sstevel@tonic-gate 		if (diskp->shutdown_initiated)
16500Sstevel@tonic-gate 			continue;
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 		/*
16530Sstevel@tonic-gate 		 * Check for the temperature in warning and shutdown range
16540Sstevel@tonic-gate 		 * and take appropriate action.
16550Sstevel@tonic-gate 		 */
16560Sstevel@tonic-gate 		if (DISK_TEMP_IN_WARNING_RANGE(diskp->current_temp, diskp)) {
16570Sstevel@tonic-gate 			/*
16580Sstevel@tonic-gate 			 * Check if the temperature has been in warning
16590Sstevel@tonic-gate 			 * range during last disk_warning_duration interval.
16600Sstevel@tonic-gate 			 * If so, the temperature is truly in warning
16610Sstevel@tonic-gate 			 * range and we need to log a warning message,
16620Sstevel@tonic-gate 			 * but no more than once every disk_warning_interval
16630Sstevel@tonic-gate 			 * seconds.
16640Sstevel@tonic-gate 			 */
16650Sstevel@tonic-gate 			time_t	wtstamp = diskp->warning_tstamp;
16660Sstevel@tonic-gate 
16670Sstevel@tonic-gate 			ct = (time_t)(gethrtime() / NANOSEC);
16680Sstevel@tonic-gate 			if (diskp->warning_start == 0)
16690Sstevel@tonic-gate 				diskp->warning_start = ct;
16700Sstevel@tonic-gate 			if (((ct - diskp->warning_start) >=
16710Sstevel@tonic-gate 			    disk_warning_duration) && (wtstamp == 0 ||
16720Sstevel@tonic-gate 			    (ct - wtstamp) >= disk_warning_interval)) {
16730Sstevel@tonic-gate 				envd_log(LOG_CRIT, ENV_WARNING_MSG,
16740Sstevel@tonic-gate 				    diskp->name, diskp->current_temp,
16750Sstevel@tonic-gate 				    diskp->low_warning,
16760Sstevel@tonic-gate 				    diskp->high_warning);
16770Sstevel@tonic-gate 				diskp->warning_tstamp = ct;
16780Sstevel@tonic-gate 			}
16790Sstevel@tonic-gate 		} else if (diskp->warning_start != 0)
16800Sstevel@tonic-gate 			diskp->warning_start = 0;
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 		if (!shutdown_override &&
16830Sstevel@tonic-gate 		    DISK_TEMP_IN_SHUTDOWN_RANGE(diskp->current_temp, diskp)) {
16840Sstevel@tonic-gate 			ct = (time_t)(gethrtime() / NANOSEC);
16850Sstevel@tonic-gate 			if (diskp->shutdown_tstamp == 0)
16860Sstevel@tonic-gate 				diskp->shutdown_tstamp = ct;
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 			/*
16890Sstevel@tonic-gate 			 * Shutdown the system if the temperature remains
16900Sstevel@tonic-gate 			 * in the shutdown range for over disk_shutdown_interval
16910Sstevel@tonic-gate 			 * seconds.
16920Sstevel@tonic-gate 			 */
16930Sstevel@tonic-gate 			if ((ct - diskp->shutdown_tstamp) >=
16940Sstevel@tonic-gate 			    disk_shutdown_interval) {
16950Sstevel@tonic-gate 				/* log error */
16960Sstevel@tonic-gate 				diskp->shutdown_initiated = B_TRUE;
16970Sstevel@tonic-gate 				(void) snprintf(msgbuf, sizeof (msgbuf),
16980Sstevel@tonic-gate 				    ENV_SHUTDOWN_MSG, diskp->name,
16990Sstevel@tonic-gate 				    diskp->current_temp, diskp->low_shutdown,
17000Sstevel@tonic-gate 				    diskp->high_shutdown);
17010Sstevel@tonic-gate 				envd_log(LOG_ALERT, msgbuf);
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 				/* shutdown the system (only once) */
17040Sstevel@tonic-gate 				if (system_shutdown_started == B_FALSE) {
17050Sstevel@tonic-gate 					(void) snprintf(syscmd, sizeof (syscmd),
17060Sstevel@tonic-gate 					    "%s \"%s\"", shutdown_cmd, msgbuf);
17070Sstevel@tonic-gate 					envd_log(LOG_ALERT, syscmd);
17080Sstevel@tonic-gate 					system_shutdown_started = B_TRUE;
17090Sstevel@tonic-gate 					(void) system(syscmd);
17100Sstevel@tonic-gate 				}
17110Sstevel@tonic-gate 			}
17120Sstevel@tonic-gate 		} else if (diskp->shutdown_tstamp != 0)
17130Sstevel@tonic-gate 			diskp->shutdown_tstamp = 0;
17140Sstevel@tonic-gate 		}
1715323Svenki 	} /* end of forever loop */
17160Sstevel@tonic-gate }
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate static void *
fan_thr(void * args)17190Sstevel@tonic-gate fan_thr(void *args)
17200Sstevel@tonic-gate {
17210Sstevel@tonic-gate 	char msgbuf[BUFSIZ];
17220Sstevel@tonic-gate 	timespec_t	to;
17230Sstevel@tonic-gate 	int	ret, i;
17240Sstevel@tonic-gate 	pthread_mutex_t	env_monitor_mutex = PTHREAD_MUTEX_INITIALIZER;
17250Sstevel@tonic-gate 	pthread_cond_t	env_monitor_cv = PTHREAD_COND_INITIALIZER;
17260Sstevel@tonic-gate 	env_fan_t	*fanp;
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate #ifdef	__lint
17290Sstevel@tonic-gate 	args = args;
17300Sstevel@tonic-gate #endif
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	for (;;) {
17330Sstevel@tonic-gate 		/*
17340Sstevel@tonic-gate 		 * Sleep for specified seconds before issuing IOCTL
17350Sstevel@tonic-gate 		 * again.
17360Sstevel@tonic-gate 		 */
17370Sstevel@tonic-gate 		(void) pthread_mutex_lock(&env_monitor_mutex);
17380Sstevel@tonic-gate 		ret = pthread_cond_reltimedwait_np(&env_monitor_cv,
17390Sstevel@tonic-gate 		    &env_monitor_mutex, &to);
17400Sstevel@tonic-gate 		to.tv_sec = fan_scan_interval;
17410Sstevel@tonic-gate 		to.tv_nsec = 0;
17420Sstevel@tonic-gate 		if (ret != ETIMEDOUT) {
17430Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&env_monitor_mutex);
17440Sstevel@tonic-gate 			continue;
17450Sstevel@tonic-gate 		}
17460Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&env_monitor_mutex);
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 		for (i = 0; (fanp = envd_fans[i]) != NULL; i++) {
17490Sstevel@tonic-gate 			if (fanp->present == B_FALSE)
17500Sstevel@tonic-gate 				continue;
1751707Svenki 
17520Sstevel@tonic-gate 			if (has_fan_failed(fanp) == B_TRUE) {
17530Sstevel@tonic-gate 				if (fanp->last_status == FAN_FAILED)
17540Sstevel@tonic-gate 					continue;
17550Sstevel@tonic-gate 				fanp->last_status = FAN_FAILED;
17560Sstevel@tonic-gate 				(void) snprintf(msgbuf, sizeof (msgbuf),
17570Sstevel@tonic-gate 				    ENV_FAN_FAILURE_WARNING_MSG, fanp->name,
17580Sstevel@tonic-gate 				    fan_rpm_string, fan_status_string);
17590Sstevel@tonic-gate 				envd_log(LOG_ALERT, msgbuf);
17600Sstevel@tonic-gate 			} else {
17610Sstevel@tonic-gate 				if (fanp->last_status == FAN_OK)
17620Sstevel@tonic-gate 					continue;
17630Sstevel@tonic-gate 				fanp->last_status = FAN_OK;
17640Sstevel@tonic-gate 				(void) snprintf(msgbuf, sizeof (msgbuf),
17650Sstevel@tonic-gate 				    ENV_FAN_OK_MSG, fanp->name);
17660Sstevel@tonic-gate 				envd_log(LOG_ALERT, msgbuf);
17670Sstevel@tonic-gate 			}
17680Sstevel@tonic-gate 		}
1769707Svenki 
1770707Svenki 		if (has_psufan_failed() == B_TRUE) {
1771707Svenki 			if (psufan_last_status == FAN_FAILED)
1772707Svenki 				continue;
1773707Svenki 			psufan_last_status = FAN_FAILED;
1774707Svenki 			(void) snprintf(msgbuf, sizeof (msgbuf),
1775*8739SJustin.Frank@Sun.COM 			    ENV_FAN_FAILURE_WARNING_MSG, SENSOR_PSU,
1776*8739SJustin.Frank@Sun.COM 			    fan_rpm_string, fan_status_string);
1777707Svenki 			envd_log(LOG_ALERT, msgbuf);
1778707Svenki 		} else {
1779707Svenki 			if (psufan_last_status == FAN_OK)
1780707Svenki 				continue;
1781707Svenki 			psufan_last_status = FAN_OK;
1782707Svenki 			(void) snprintf(msgbuf, sizeof (msgbuf),
1783*8739SJustin.Frank@Sun.COM 			    ENV_FAN_OK_MSG, SENSOR_PSU);
1784707Svenki 			envd_log(LOG_ALERT, msgbuf);
1785707Svenki 		}
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/*NOTREACHED*/
17890Sstevel@tonic-gate 	return (NULL);
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate /*
17930Sstevel@tonic-gate  * Setup envrionmental monitor state and start threads to monitor
17940Sstevel@tonic-gate  * temperature, fan, disk and power management state.
17950Sstevel@tonic-gate  * Returns -1 on error, 0 if successful.
17960Sstevel@tonic-gate  */
17970Sstevel@tonic-gate static int
envd_setup(void)17980Sstevel@tonic-gate envd_setup(void)
17990Sstevel@tonic-gate {
18000Sstevel@tonic-gate 
18010Sstevel@tonic-gate 	if (getenv("SUNW_piclenvd_debug") != NULL)
18020Sstevel@tonic-gate 		env_debug = 1;
18030Sstevel@tonic-gate 
18040Sstevel@tonic-gate 	if (pthread_attr_init(&thr_attr) != 0 ||
18050Sstevel@tonic-gate 	    pthread_attr_setscope(&thr_attr, PTHREAD_SCOPE_SYSTEM) != 0) {
18060Sstevel@tonic-gate 		return (-1);
18070Sstevel@tonic-gate 	}
18080Sstevel@tonic-gate 
1809323Svenki 	/*
1810323Svenki 	 * If ES segment is not present or has inconsistent information, we
1811323Svenki 	 * use default values for sensor limits. For the sake of simplicity,
1812323Svenki 	 * we still store these limits internally in the 'es' member in the
1813323Svenki 	 * structure.
1814323Svenki 	 */
1815323Svenki 	if (envd_es_setup() < 0) {
1816323Svenki 		envd_log(LOG_WARNING, ENV_DEFAULT_LIMITS);
1817323Svenki 		envd_es_default_setup();
1818323Svenki 	}
1819323Svenki 
1820138Svenki 	if (envd_setup_sensors() < 0) {
18210Sstevel@tonic-gate 		if (env_debug)
18220Sstevel@tonic-gate 			envd_log(LOG_ERR, "Failed to setup sensors\n");
18230Sstevel@tonic-gate 		system_temp_monitor = 0;
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 
1826138Svenki 	if (envd_setup_fans() < 0) {
1827138Svenki 		if (env_debug)
1828138Svenki 			envd_log(LOG_ERR, "Failed to setup fans\n");
1829138Svenki 		fan_monitor = 0;
1830138Svenki 		pm_monitor = 0;
1831138Svenki 	}
18320Sstevel@tonic-gate 
18331245Svenki 	/*
18341245Svenki 	 * Disable disk temperature monitoring until we have
18351245Svenki 	 * LSI fw support to read SATA disk temperature
18361245Svenki 	 */
18371245Svenki 	if (disk_temp_monitor) {
18381245Svenki 		if (envd_setup_disks() < 0) {
18391245Svenki 			if (env_debug)
18401245Svenki 				envd_log(LOG_ERR, "Failed to setup disks\n");
18411245Svenki 			disk_temp_monitor = 0;
18421245Svenki 		}
1843138Svenki 	}
18440Sstevel@tonic-gate 
1845323Svenki 	/*
1846323Svenki 	 * Create a thread to monitor system temperatures
1847323Svenki 	 */
1848138Svenki 	if ((system_temp_monitor) && (system_temp_thr_created == B_FALSE)) {
1849138Svenki 		if (pthread_create(&system_temp_thr_id, &thr_attr,
1850138Svenki 		    system_temp_thr, NULL) != 0) {
18510Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1852138Svenki 		} else {
1853138Svenki 			system_temp_thr_created = B_TRUE;
18540Sstevel@tonic-gate 			if (env_debug)
18550Sstevel@tonic-gate 				envd_log(LOG_ERR,
18560Sstevel@tonic-gate 			"Created thread to monitor system temperatures\n");
18570Sstevel@tonic-gate 		}
18580Sstevel@tonic-gate 	}
18590Sstevel@tonic-gate 
1860323Svenki 	/*
1861323Svenki 	 * Create a thread to monitor fans
1862323Svenki 	 */
1863138Svenki 	if ((fan_monitor) && (fan_thr_created == B_FALSE)) {
1864138Svenki 		if (pthread_create(&fan_thr_id, &thr_attr, fan_thr, NULL) != 0)
18650Sstevel@tonic-gate 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
18660Sstevel@tonic-gate 		else {
18670Sstevel@tonic-gate 			fan_thr_created = B_TRUE;
1868138Svenki 			if (env_debug) {
18690Sstevel@tonic-gate 				envd_log(LOG_ERR,
1870138Svenki 				    "Created thread to monitor system fans\n");
1871138Svenki 			}
18720Sstevel@tonic-gate 		}
18730Sstevel@tonic-gate 	}
1874138Svenki 
1875323Svenki 	/*
1876323Svenki 	 * Create a thread to monitor PM state
1877323Svenki 	 */
1878138Svenki 	if ((pm_monitor) && (pmthr_created == B_FALSE)) {
1879138Svenki 		if (pthread_create(&pmthr_tid, &thr_attr, pmthr, NULL) != 0)
18800Sstevel@tonic-gate 			envd_log(LOG_CRIT, PM_THREAD_CREATE_FAILED);
1881138Svenki 		else {
18820Sstevel@tonic-gate 			pmthr_created = B_TRUE;
18830Sstevel@tonic-gate 			if (env_debug)
18840Sstevel@tonic-gate 				envd_log(LOG_ERR,
18850Sstevel@tonic-gate 			"Created thread to monitor system power state\n");
18860Sstevel@tonic-gate 		}
18870Sstevel@tonic-gate 	}
1888138Svenki 
1889323Svenki 	/*
1890323Svenki 	 * Create a thread to monitor disk temperature
1891323Svenki 	 */
1892138Svenki 	if ((disk_temp_monitor) && (disk_temp_thr_created == B_FALSE)) {
1893138Svenki 		if (pthread_create(&disk_temp_thr_id, &thr_attr,
1894138Svenki 		    disk_temp_thr, NULL) != 0) {
1895138Svenki 			envd_log(LOG_ERR, ENVTHR_THREAD_CREATE_FAILED);
1896138Svenki 		} else {
1897138Svenki 			disk_temp_thr_created = B_TRUE;
1898138Svenki 			if (env_debug)
1899138Svenki 				envd_log(LOG_ERR,
1900138Svenki 			"Created thread for disk temperatures\n");
19010Sstevel@tonic-gate 		}
19020Sstevel@tonic-gate 	}
1903138Svenki 
19040Sstevel@tonic-gate 	return (0);
19050Sstevel@tonic-gate }
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate static void
piclenvd_register(void)19080Sstevel@tonic-gate piclenvd_register(void)
19090Sstevel@tonic-gate {
19100Sstevel@tonic-gate 	picld_plugin_register(&my_reg_info);
19110Sstevel@tonic-gate }
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate static void
piclenvd_init(void)19140Sstevel@tonic-gate piclenvd_init(void)
19150Sstevel@tonic-gate {
19160Sstevel@tonic-gate 
19170Sstevel@tonic-gate 	(void) env_picl_setup_tuneables();
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	/*
19201245Svenki 	 * Do not allow disk temperature monitoring to be enabled
19211245Svenki 	 * via tuneables. Disk temperature monitoring is disabled
19221245Svenki 	 * until we have LSI fw support to read the temperature of
19231245Svenki 	 * SATA disks
19241245Svenki 	 */
19251245Svenki 	disk_temp_monitor = 0;
19261245Svenki 
19271245Svenki 	/*
19280Sstevel@tonic-gate 	 * Setup the environmental data structures
19290Sstevel@tonic-gate 	 */
19300Sstevel@tonic-gate 	if (envd_setup() != 0) {
19310Sstevel@tonic-gate 		envd_log(LOG_CRIT, ENVD_PLUGIN_INIT_FAILED);
19320Sstevel@tonic-gate 		return;
19330Sstevel@tonic-gate 	}
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	/*
19360Sstevel@tonic-gate 	 * Now setup/populate PICL tree
19370Sstevel@tonic-gate 	 */
19380Sstevel@tonic-gate 	env_picl_setup();
19390Sstevel@tonic-gate }
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate static void
piclenvd_fini(void)19420Sstevel@tonic-gate piclenvd_fini(void)
19430Sstevel@tonic-gate {
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	/*
19460Sstevel@tonic-gate 	 * Invoke env_picl_destroy() to remove any PICL nodes/properties
19470Sstevel@tonic-gate 	 * (including volatile properties) we created. Once this call
19480Sstevel@tonic-gate 	 * returns, there can't be any more calls from the PICL framework
19490Sstevel@tonic-gate 	 * to get current temperature or fan speed.
19500Sstevel@tonic-gate 	 */
19510Sstevel@tonic-gate 	env_picl_destroy();
19520Sstevel@tonic-gate 	envd_close_sensors();
19530Sstevel@tonic-gate 	envd_close_fans();
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate /*VARARGS2*/
19570Sstevel@tonic-gate void
envd_log(int pri,const char * fmt,...)19580Sstevel@tonic-gate envd_log(int pri, const char *fmt, ...)
19590Sstevel@tonic-gate {
19600Sstevel@tonic-gate 	va_list	ap;
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	va_start(ap, fmt);
19630Sstevel@tonic-gate 	vsyslog(pri, fmt, ap);
19640Sstevel@tonic-gate 	va_end(ap);
19650Sstevel@tonic-gate }
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate /*
19680Sstevel@tonic-gate  * Tunables support functions
19690Sstevel@tonic-gate  */
19700Sstevel@tonic-gate static env_tuneable_t *
tuneable_lookup(picl_prophdl_t proph)19710Sstevel@tonic-gate tuneable_lookup(picl_prophdl_t proph)
19720Sstevel@tonic-gate {
19730Sstevel@tonic-gate 	int i;
19740Sstevel@tonic-gate 	env_tuneable_t	*tuneablep = NULL;
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate 	for (i = 0; i < ntuneables; i++) {
19770Sstevel@tonic-gate 		tuneablep = &tuneables[i];
19780Sstevel@tonic-gate 		if (tuneablep->proph == proph)
19790Sstevel@tonic-gate 			return (tuneablep);
19800Sstevel@tonic-gate 	}
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate 	return (NULL);
19830Sstevel@tonic-gate }
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate static int
get_string_val(ptree_rarg_t * parg,void * buf)19860Sstevel@tonic-gate get_string_val(ptree_rarg_t *parg, void *buf)
19870Sstevel@tonic-gate {
19880Sstevel@tonic-gate 	picl_prophdl_t	proph;
19890Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	proph = parg->proph;
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	if (tuneablep == NULL)
19960Sstevel@tonic-gate 		return (PICL_FAILURE);
19970Sstevel@tonic-gate 
1998323Svenki 	(void) memcpy(buf, tuneablep->value, tuneablep->nbytes);
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	return (PICL_SUCCESS);
20010Sstevel@tonic-gate }
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate static int
set_string_val(ptree_warg_t * parg,const void * buf)20040Sstevel@tonic-gate set_string_val(ptree_warg_t *parg, const void *buf)
20050Sstevel@tonic-gate {
20060Sstevel@tonic-gate 	picl_prophdl_t	proph;
20070Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
20100Sstevel@tonic-gate 		return (PICL_PERMDENIED);
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	proph = parg->proph;
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 	if (tuneablep == NULL)
20170Sstevel@tonic-gate 		return (PICL_FAILURE);
20180Sstevel@tonic-gate 
2019323Svenki 	(void) memcpy(tuneables->value, buf, tuneables->nbytes);
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 
20220Sstevel@tonic-gate 	return (PICL_SUCCESS);
20230Sstevel@tonic-gate }
20240Sstevel@tonic-gate 
20250Sstevel@tonic-gate static int
get_int_val(ptree_rarg_t * parg,void * buf)20260Sstevel@tonic-gate get_int_val(ptree_rarg_t *parg, void *buf)
20270Sstevel@tonic-gate {
20280Sstevel@tonic-gate 	picl_prophdl_t	proph;
20290Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
20300Sstevel@tonic-gate 
20310Sstevel@tonic-gate 	proph = parg->proph;
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	if (tuneablep == NULL)
20360Sstevel@tonic-gate 		return (PICL_FAILURE);
20370Sstevel@tonic-gate 
2038323Svenki 	(void) memcpy(buf, tuneablep->value, tuneablep->nbytes);
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	return (PICL_SUCCESS);
20410Sstevel@tonic-gate }
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate static int
set_int_val(ptree_warg_t * parg,const void * buf)20440Sstevel@tonic-gate set_int_val(ptree_warg_t *parg, const void *buf)
20450Sstevel@tonic-gate {
20460Sstevel@tonic-gate 	picl_prophdl_t	proph;
20470Sstevel@tonic-gate 	env_tuneable_t	*tuneablep;
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	if (parg->cred.dc_euid != 0)
20500Sstevel@tonic-gate 		return (PICL_PERMDENIED);
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	proph = parg->proph;
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 	tuneablep = tuneable_lookup(proph);
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 	if (tuneablep == NULL)
20570Sstevel@tonic-gate 		return (PICL_FAILURE);
20580Sstevel@tonic-gate 
2059323Svenki 	(void) memcpy(tuneablep->value, buf, tuneablep->nbytes);
20600Sstevel@tonic-gate 
20610Sstevel@tonic-gate 	return (PICL_SUCCESS);
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate boolean_t
has_fan_failed(env_fan_t * fanp)20650Sstevel@tonic-gate has_fan_failed(env_fan_t *fanp)
20660Sstevel@tonic-gate {
20670Sstevel@tonic-gate 	fanspeed_t	fan_speed;
20680Sstevel@tonic-gate 	uchar_t		status;
20690Sstevel@tonic-gate 	uint8_t		tach;
20700Sstevel@tonic-gate 	int		real_tach;
2071138Svenki 	int		ret, ntries;
20720Sstevel@tonic-gate 
20730Sstevel@tonic-gate 	if (fanp->fd == -1)
20740Sstevel@tonic-gate 		return (B_TRUE);
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 	/*
20770Sstevel@tonic-gate 	 * Read RF_FAN_STATUS bit of the fan fault register, retry if
20780Sstevel@tonic-gate 	 * the PIC is busy, with a 1 second delay to allow it to update.
20790Sstevel@tonic-gate 	 */
2080138Svenki 	for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) {
2081138Svenki 		ret = ioctl(fanp->fd, PIC_GET_FAN_STATUS, &status);
2082138Svenki 		if ((ret == 0) && ((status & 0x1) == 0))
2083138Svenki 			break;
2084138Svenki 		(void) sleep(1);
2085138Svenki 	}
20860Sstevel@tonic-gate 
2087138Svenki 	if (ntries > 0) {
2088138Svenki 		if (env_debug) {
2089138Svenki 			envd_log(LOG_ERR,
2090138Svenki 			    "%d retries attempted in reading fan status.\n",
2091138Svenki 			    ntries);
20920Sstevel@tonic-gate 		}
20930Sstevel@tonic-gate 	}
20940Sstevel@tonic-gate 
2095138Svenki 	if (ntries == MAX_RETRIES_FOR_FAN_FAULT) {
20960Sstevel@tonic-gate 		(void) strncpy(fan_status_string, NOT_AVAILABLE,
20970Sstevel@tonic-gate 		    sizeof (fan_status_string));
20980Sstevel@tonic-gate 		(void) strncpy(fan_rpm_string, NOT_AVAILABLE,
20990Sstevel@tonic-gate 		    sizeof (fan_rpm_string));
21000Sstevel@tonic-gate 		return (B_TRUE);
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 	if (env_debug)
21040Sstevel@tonic-gate 		envd_log(LOG_ERR, "fan status = 0x%x\n", status);
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	/*
21070Sstevel@tonic-gate 	 * ST_FFAULT bit isn't implemented yet and we're reading only
21080Sstevel@tonic-gate 	 * individual fan status
21090Sstevel@tonic-gate 	 */
21100Sstevel@tonic-gate 	if (status & 0x1) {
21110Sstevel@tonic-gate 		(void) snprintf(fan_status_string, sizeof (fan_status_string),
21120Sstevel@tonic-gate 		    "0x%x", status);
21130Sstevel@tonic-gate 		if (ioctl(fanp->fd, PIC_GET_FAN_SPEED, &tach) != 0) {
21140Sstevel@tonic-gate 			(void) strncpy(fan_rpm_string, NOT_AVAILABLE,
21150Sstevel@tonic-gate 			    sizeof (fan_rpm_string));
21160Sstevel@tonic-gate 		} else {
21170Sstevel@tonic-gate 			real_tach = tach << 8;
21180Sstevel@tonic-gate 			fan_speed = TACH_TO_RPM(real_tach);
21190Sstevel@tonic-gate 			(void) snprintf(fan_rpm_string, sizeof (fan_rpm_string),
21200Sstevel@tonic-gate 			    "%d", fan_speed);
21210Sstevel@tonic-gate 		}
21220Sstevel@tonic-gate 		return (B_TRUE);
21230Sstevel@tonic-gate 	}
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	return (B_FALSE);
21260Sstevel@tonic-gate }
2127377Siskreen 
2128707Svenki boolean_t
has_psufan_failed(void)2129707Svenki has_psufan_failed(void)
2130707Svenki {
2131707Svenki 	uchar_t		status;
2132707Svenki 	int		ret, ntries;
2133707Svenki 
2134707Svenki 	if (envd_sensor_psu.fd == -1)
2135707Svenki 		return (B_FALSE);
2136707Svenki 
2137707Svenki 	/*
2138707Svenki 	 * For psu, only fan fault is visible, no fan speed
2139707Svenki 	 */
2140707Svenki 	(void) strncpy(fan_rpm_string, NOT_AVAILABLE, sizeof (fan_rpm_string));
2141707Svenki 
2142707Svenki 	/*
2143707Svenki 	 * Read RF_FAN_STATUS bit of the fan fault register, retry if
2144707Svenki 	 * the PIC is busy, with a 1 second delay to allow it to update.
2145707Svenki 	 */
2146707Svenki 	for (ntries = 0; ntries < MAX_RETRIES_FOR_FAN_FAULT; ntries++) {
2147707Svenki 		ret = ioctl(envd_sensor_psu.fd, PIC_GET_FAN_STATUS, &status);
2148707Svenki 		if ((ret == 0) && ((status & 0x1) == 0))
2149707Svenki 			break;
2150707Svenki 		(void) sleep(1);
2151707Svenki 	}
2152707Svenki 
2153707Svenki 	if (ntries > 0) {
2154707Svenki 		if (env_debug) {
2155707Svenki 			envd_log(LOG_ERR,
2156707Svenki 			    "%d retries attempted in reading fan status.\n",
2157707Svenki 			    ntries);
2158707Svenki 		}
2159707Svenki 	}
2160707Svenki 
2161707Svenki 	if (ntries == MAX_RETRIES_FOR_FAN_FAULT) {
2162707Svenki 		(void) strncpy(fan_status_string, NOT_AVAILABLE,
2163707Svenki 		    sizeof (fan_status_string));
2164707Svenki 		return (B_TRUE);
2165707Svenki 	}
2166707Svenki 
2167707Svenki 	if (env_debug)
2168707Svenki 		envd_log(LOG_ERR, "fan status = 0x%x\n", status);
2169707Svenki 
2170707Svenki 	if (status & 0x1) {
2171707Svenki 		(void) snprintf(fan_status_string, sizeof (fan_status_string),
2172707Svenki 		    "0x%x", status);
2173707Svenki 		return (B_TRUE);
2174707Svenki 	}
2175707Svenki 
2176707Svenki 	return (B_FALSE);
2177707Svenki }
2178707Svenki 
2179377Siskreen static int
scsi_mode_select(env_disk_t * diskp,uchar_t page_code,uchar_t * pagebuf,uint16_t pagelen)2180377Siskreen scsi_mode_select(env_disk_t *diskp, uchar_t page_code, uchar_t *pagebuf,
2181377Siskreen     uint16_t pagelen)
2182377Siskreen {
2183377Siskreen 	struct uscsi_cmd		ucmd_buf;
2184377Siskreen 	uchar_t				cdb_buf[CDB_GROUP1];
2185377Siskreen 	struct scsi_extended_sense	sense_buf;
2186377Siskreen 	int				ret_val;
2187377Siskreen 
2188377Siskreen 	bzero(&cdb_buf, sizeof (cdb_buf));
2189377Siskreen 	bzero(&ucmd_buf, sizeof (ucmd_buf));
2190377Siskreen 	bzero(&sense_buf, sizeof (sense_buf));
2191377Siskreen 
2192377Siskreen 	cdb_buf[0] = SCMD_MODE_SELECT_G1;
2193377Siskreen 	cdb_buf[1] = 1<<PAGE_FMT;
2194377Siskreen 
2195377Siskreen 	cdb_buf[7] = (uchar_t)((pagelen & 0xFF00) >> 8);
2196377Siskreen 	cdb_buf[8] = (uchar_t)(pagelen  & 0x00FF);
2197377Siskreen 
2198377Siskreen 	ucmd_buf.uscsi_cdb = (char *)cdb_buf;
2199377Siskreen 	ucmd_buf.uscsi_cdblen = sizeof (cdb_buf);
2200377Siskreen 	ucmd_buf.uscsi_bufaddr = (caddr_t)pagebuf;
2201377Siskreen 	ucmd_buf.uscsi_buflen = pagelen;
2202377Siskreen 	ucmd_buf.uscsi_rqbuf = (caddr_t)&sense_buf;
2203377Siskreen 	ucmd_buf.uscsi_rqlen = sizeof (struct scsi_extended_sense);
2204377Siskreen 	ucmd_buf.uscsi_flags = USCSI_RQENABLE | USCSI_WRITE | USCSI_SILENT;
2205377Siskreen 	ucmd_buf.uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
2206377Siskreen 
2207377Siskreen 	ret_val = ioctl(diskp->fd, USCSICMD, ucmd_buf);
2208377Siskreen 
2209377Siskreen 	if (ret_val == 0 && ucmd_buf.uscsi_status == 0) {
2210377Siskreen 		return (ret_val);
2211377Siskreen 	}
2212377Siskreen 	if (env_debug)
2213377Siskreen 		envd_log(LOG_ERR, "mode select command for %s failed. "
2214377Siskreen 		    "page_code 0x%x ret_val = 0x%x "
2215377Siskreen 		    "status = 0x%x errno = 0x%x\n", diskp->name, page_code,
2216377Siskreen 		    ret_val, ucmd_buf.uscsi_status, errno);
2217377Siskreen 
2218377Siskreen 	return (1);
2219377Siskreen 
2220377Siskreen }
2221