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