/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This file contains the environmental PICL plug-in module.
*/
/*
* This plugin sets up the PICLTREE for Enchilada WS.
* fan speeds.
*
* The environmental policy defaults to the auto mode
* as programmed by OBP at boot time.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysmacros.h>
#include <limits.h>
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <alloca.h>
#include <unistd.h>
#include <sys/processor.h>
#include <syslog.h>
#include <errno.h>
#include <fcntl.h>
#include <picl.h>
#include <picltree.h>
#include <picldefs.h>
#include <pthread.h>
#include <signal.h>
#include <libdevinfo.h>
#include <sys/systeminfo.h>
#include <note.h>
#include "envd.h"
/*
* PICL plugin entry points
*/
static void piclenvd_register(void);
static void piclenvd_init(void);
static void piclenvd_fini(void);
/*
* Env setup routines
*/
extern void env_picl_setup(void);
extern void env_picl_destroy(void);
extern int env_picl_setup_tuneables(void);
/*
* Sleep routine used for polling
*/
static int get_dimm_fan_speed(int, fanspeed_t *);
static int is_dimm_fan_failed(void);
#pragma init(piclenvd_register)
/*
* Plugin registration information
*/
"SUNW_piclenvd",
};
static int get_disk_temp(env_disk_t *);
/*
* ES Segment data structures
*/
/*
* Env thread variables
*/
/*
* PM thread related variables
*/
/*
* Envd plug-in verbose flag set by SUNW_PICLENVD_DEBUG environment var
* Setting the verbose tuneable also enables debugging for better
* control
*/
int env_debug = 0;
/*
* Fan devices
*/
-1, -1,
};
};
};
};
};
};
};
/*
* The vendor-id and device-id are the properties associated with
* the SCSI controller. This is used to identify a particular controller
* like LSI1030.
*/
/*
* The implementation for SCSI disk drives to supply info. about
* temperature is not mandatory. Hence we first determine if the
* temperature page is supported. To do this we need to scan the list
* of pages supported.
*/
#define SUPPORTED_LPAGES 0
/*
* NULL terminated array of fans
*/
};
};
/*
* ADM1031 speedrange map is indexed by a 2-bit value
*/
/*
* ADM1031 devices
*/
static char *hwm_devs[] = {
CPU_HWM_DEVFS, /* CPU_HWM_ID */
SYS_HWM_DEVFS /* SYS_HWM_ID */
};
/*
* Fan names associated with each ADM1031 hwms - used to
* print fault messages.
*/
};
/*
* Temperature sensors
*/
};
/*
* ADM1031 macros
*/
(trange & TRANGE_MASK))
/*
* Tuneables
*/
#define DISABLE 0
static int disk_high_shutdown_temperature =
static int shutdown_override = 0;
static int cpu_mode;
static int sys_mode;
static int cpu_tach;
static int sys_tach;
&get_int_val, &set_int_val, sizeof (int)},
&get_int_val, &set_int_val, sizeof (int)},
&get_int_val, &set_int_val, sizeof (int)},
sizeof (int)},
sizeof (int)},
{"sensor-poll-interval", PICL_PTYPE_INT,
sizeof (int)},
{"disk-scan-interval", PICL_PTYPE_INT,
sizeof (int)},
sizeof (int)},
sizeof (int)},
sizeof (int)},
sizeof (int)},
sizeof (int)},
sizeof (shutdown_cmd)},
sizeof (int)},
sizeof (int)},
&get_int_val, &set_int_val, sizeof (int)},
&get_int_val, &set_int_val, sizeof (int)},
{"disk-high-warn-temperature", PICL_PTYPE_INT,
&set_int_val, sizeof (int)},
{"disk-low-warn-temperature", PICL_PTYPE_INT,
&set_int_val, sizeof (int)},
{"disk-high-shutdown-temperature", PICL_PTYPE_INT,
&set_int_val, sizeof (int)},
{"disk-low-shutdown-temperature", PICL_PTYPE_INT,
&set_int_val, sizeof (int)},
&get_int_val, &set_int_val, sizeof (int)},
};
/*
* We use this to figure out how many tuneables there are
* This is variable because the publishing routine needs this info
* in piclenvsetup.c
*/
/*
* Table Handling Code
*/
static void
{
return;
}
static table_t *
{
if (npoints == 0)
return (NULL);
return (NULL);
return (NULL);
}
return (tblp);
}
/*
* function: calculates y for a given x based on a table of points
* for monotonically increasing x values.
* 'tbl' specifies the table to use, 'val' specifies the 'x', returns 'y'
*/
static int
{
int i;
int entries;
float newval;
/*
* If the temperature is outside the correction table
* then simply return the original value.
*/
return (xval);
return (xymap[0].y);
return (xymap[i].y);
break;
}
/*
* Use linear interpolation
*/
}
/*
* Get environmental segment from the specified FRU SEEPROM
*/
static int
{
return (EINVAL);
}
/*
* Verify we have the correct section and contents are valid
* For now, we don't verify the CRC.
*/
if (env_debug)
"Invalid section header tag:%x version:%x\n",
return (EINVAL);
}
/*
* Locate our environmental segment
*/
for (i = 0; i < segcnt; i++) {
return (EINVAL);
}
if (env_debug)
"Seg name: %x desc:%x off:%x len:%x\n",
break;
}
if (i >= segcnt) {
return (ENOENT);
}
/*
* Allocate memory to hold the environmental segment data.
*/
return (ENOMEM);
}
return (EIO);
}
*envseglenp = envseglen;
return (0);
}
/*
* Get all environmental segments
* Return NULL on error
*/
static fruenvseg_t *
get_fru_envsegs(void)
{
void *envsegbufp;
fruenvsegs = NULL;
if (fruenvsegs == NULL) {
return (NULL);
}
/*
* Now get the environmental segment from this FRU
*/
if (fd == -1) {
return (NULL);
}
/*
* Read environmental segment from this FRU SEEPROM
*/
return (NULL);
}
/*
* Validate envseg version number and header length
*/
hdrlen = sizeof (envseg_layout_t) -
sizeof (envseg_sensor_t) +
/*
* version mismatch or header not big enough
*/
if (envsegbufp != NULL)
(void) free(envsegbufp);
return (NULL);
}
return (fruenvsegs);
}
static int
{
int i;
int id_offset = 0;
int nsensors;
int nfans;
if (nsensors != MAX_SENSORS) {
return (-1);
}
return (-1);
}
while (nsensors > 0) {
if (env_debug)
return (-1);
}
/*
* Copy into the sensor control block array according to the
* sensor ID
*/
sizeof (sensor_ctrl_blk_t));
nsensors--;
id_offset += ID_OFF_SIZE;
}
/*
* Skip past no of Fan entry(single byte)
*/
id_offset++;
while (nfans > 0) {
if (env_debug)
return (-1);
}
nfans--;
id_offset += ID_OFF_SIZE;
}
/*
* based on IDs
*/
for (i = 0; i < N_ENVD_SENSORS; i++) {
snodep = &envd_sensors[i];
}
/*
* based on IDs
*/
return (0);
}
static int
envd_es_setup(void)
{
envfru = get_fru_envsegs();
return (-1);
}
}
static void
envd_es_destroy(void)
{
}
/*
* Lookup fan and return a pointer to env_fan_t data structure.
*/
{
int i;
return (fanp);
}
return (NULL);
}
/*
* Lookup sensor and return a pointer to env_sensor_t data structure.
*/
{
int i;
for (i = 0; i < N_ENVD_SENSORS; ++i) {
sensorp = &envd_sensors[i];
return (sensorp);
}
return (NULL);
}
/*
* Lookup disk and return a pointer to env_disk_t data structure.
*/
{
int i;
return (diskp);
}
return (NULL);
}
/*
* Get current temperature
* Returns -1 on error, 0 if successful
*/
int
{
int retval = 0;
if (fd == -1)
retval = -1;
retval = -1;
}
}
}
return (retval);
}
/*
* Get current disk temperature
* Returns -1 on error, 0 if successful
*/
int
{
int retval = 0;
retval = -1;
else {
}
return (retval);
}
/*
* Get uncorrected current temperature
* Returns -1 on error, 0 if successful
*/
static int
{
int retval = 0;
if (fd == -1)
retval = -1;
retval = -1;
}
return (retval);
}
/*
* Return Fan RPM given N & tach
* count and N are retrived from the
* ADM1031 chip.
*/
static int
{
if (n * tach == 0)
return (0);
}
static int
{
int fan_fd;
int retval = 0;
if (fan_fd == -1)
retval = -1;
retval = -1;
}
return (retval);
}
/*
* Get current fan speed
* This function returns a RPM value for fanspeed
* in fanspeedp.
* Returns -1 on error, 0 if successful
*/
int
{
int fan_fd;
if (fan_fd == -1)
return (-1);
}
return (-1);
}
/*
* Fanspeeds are reported as 0
* if the tach is out of range or fan status is off
* and if monitoring fan status is enabled.
*/
*fanspeedp = 0;
} else {
*fanspeedp =
}
return (0);
}
/*
* Set fan speed
* This function accepts a percentage of fan speed
* from 0-100 and programs the HW monitor fans to the corresponding
* fanspeed value.
* Returns -1 on error, -2 on invalid args passed, 0 if successful
*/
int
{
int fan_fd;
int retval = 0;
if (fan_fd == -1)
return (-1);
return (-2);
retval = -1;
}
return (retval);
}
/*
* close all fan devices
*/
static void
envd_close_fans(void)
{
int i;
}
}
}
/*
* Close sensor devices and freeup resources
*/
static void
envd_close_sensors(void)
{
int i;
for (i = 0; i < N_ENVD_SENSORS; ++i) {
sensorp = &envd_sensors[i];
}
}
}
/*
* Open fan devices and initialize per fan data structure.
* Returns #fans found.
*/
static int
envd_setup_fans(void)
{
int i, fd;
int fancnt = 0;
uint8_t n = 0;
/* make sure cpu0/1 present for validating cpu fans */
PICL_SUCCESS) {
continue;
}
}
PICL_SUCCESS) {
continue;
}
}
&tnodeh) != PICL_SUCCESS) {
if (env_debug)
"dimm Fan not found in the system.\n");
continue;
}
}
if (fd == -1) {
continue;
}
/*
* set the SW aware bit in command register.
* Clear the Fan fault latch bit.
*/
if (env_debug)
"Error in writing to COMMAND reg. of DIMM FAN controller\n");
}
} else {
/* Get speed range value */
fanp->speedrange =
} else {
}
}
fancnt++;
}
return (fancnt);
}
static int
envd_setup_disks(void)
{
/*
* Check if the SCSi controller on the system is 1010 or 1030
*/
&tnodeh) != PICL_SUCCESS) {
if (env_debug)
"On-Board SCSI controller not found in the system.\n");
monitor_disk_temp = 0;
return (-1);
}
sizeof (vendor_id))) != 0) {
if (env_debug)
"Error in getting vendor-id for SCSI controller. ret = %d errno = 0x%d\n",
monitor_disk_temp = 0;
return (-1);
}
sizeof (device_id))) != 0) {
if (env_debug)
"Error in getting device-id for SCSI controller. ret = %d errno = 0x%d\n",
monitor_disk_temp = 0;
return (-1);
}
if (env_debug)
if ((vendor_id != LSI1030_VENDOR_ID) ||
(device_id != LSI1030_DEVICE_ID)) {
monitor_disk_temp = 0;
return (-1);
}
/*
* We have found LSI1030 SCSi controller onboard.
*/
&tnodeh) != PICL_SUCCESS) {
if (env_debug)
"DISK %d not found in the system.\n",
continue;
}
"Error in opening %s errno = 0x%x\n",
continue;
}
/*
* Find out if the Temperature page is supported by the disk.
*/
if (ret != 0) {
continue;
}
for (page_index = LOGPAGEHDRSIZE;
switch (log_page[page_index]) {
case TEMPERATURE_PAGE:
if (env_debug)
"tpage supported for %s\n",
default:
break;
}
}
diskp->warning_tstamp = 0;
diskp->shutdown_tstamp = 0;
}
return (0);
}
/*
* Open temperature sensor devices and initialize per sensor data structure.
* Returns #sensors found.
*/
static int
envd_setup_sensors(void)
{
int sensorcnt = 0;
int i, j, nentries;
for (i = 0; i < N_ENVD_SENSORS; ++i) {
sensorp = &envd_sensors[i];
/* Initialize sensor's initial state */
sensorp->warning_tstamp = 0;
sensorp->shutdown_tstamp = 0;
/* make sure cpu0/1 sensors are present */
PICL_SUCCESS) {
continue;
}
}
PICL_SUCCESS) {
continue;
}
}
sizeof (path));
continue;
}
sensorcnt++;
/*
* Get Tmin
*/
&tmin) != -1) {
} else {
}
if (env_debug)
/*
* Create a correction table
* if correction pairs are present in es
* segment.
*/
continue;
}
if (nentries <= 2) {
if (env_debug)
continue;
}
continue;
for (j = 1; j < nentries; ++j) {
break;
}
}
if (env_debug) {
for (j = 0; j < nentries; j++)
}
}
return (sensorcnt);
}
/*
* we are from.
*/
static void
{
int sysfd;
return;
/*
* If there is only one Control pairs then return
*/
return;
/*
* if fan control specifies that ranges are same then
* we skip re-programming adm chip.
*/
return;
if (sysfd == -1) {
if (env_debug)
return;
}
/* Read ADM default value only for the first time */
if (env_debug)
"read tminrange ioctl failed");
return;
}
}
/*
* Need to reinit ADM to manual mode for Tmin range to be
* effective.
*/
if (env_debug)
return;
}
if (cur_lpstate == 1) {
/*
*/
<< TMIN_SHIFT);
/* Need to pack tRange in ADM bits 2:0 */
case 5:
break;
case 10:
tdata |= 1;
break;
case 20:
tdata |= 2;
break;
case 40:
tdata |= 3;
break;
case 80:
tdata |= 4;
break;
}
} else
&tdata) != -1)
if (env_debug)
}
}
/* ARGSUSED */
static void *
{
int pre_lpstate;
cur_lpstate = 0;
pre_lpstate = 1;
if (pm_fd == -1) {
return (NULL);
}
for (;;) {
/*
* Get PM state change events to check if the system
* is in lowest power state and adjust ADM hardware
* monitor's fan speed settings.
*
* To minimize polling, we use the blocking interface
* to get the power state change event here.
*/
break;
continue;
}
do {
if (env_debug) {
"pmstate event:0x%x flags:%x"
"comp:%d oldval:%d newval:%d path:%s\n",
}
/*
* Change ADM ranges as per E* Requirements. Update
* happens only for valid state changes.
*/
if (pre_lpstate != cur_lpstate) {
}
}
/* Not reached */
return (NULL);
}
/*
* This function is used to reasonably predict the
*
* We know the fan is on if temp >= tmin and fan is off if
* temp < (Tmin - Hysterisis).
*
* because the temperature could be decreasing and not have crossed
* Tmin - hysterisis and vice a versa.
*
* FAN ON
* Tmin
* -------------------------------------------
*
*
* --------------------------------------------
* Tmin - Hysterisis
* FAN OFF
*
* we keep track of the last read tach and the current read tach. From
* experimentation and from discussions with analog devices it is unlikely that
* if the fans are on we will get a constant tach reading more than 5 times in
* a row. This is not but the most fool proof approach but the best we can do.
*
* This routine implements the above logic for a sensor with an
* associated fan. The caller garauntees sensorp and fanp are not null.
*/
static void
{
return;
} else {
return;
/*
* First time in the gray area
* set last read speed to current speed
*/
} else {
} else {
}
}
}
}
/*
* There is an issue with the ADM1031 chip that causes the chip
* to not update the tach register in case the fan stops. The
* fans stop when the temperature measured (temp) drops below
* Tmin - Hysterisis and turn on when the temp >= Tmin.
*
* Since the tach registers don't update and remain stuck at the
* last read tach value our get_fan_speed function always returns
* a non-zero RPM reading.
*
* depending on the current temperature. Currently we poll for
* interrupts, we can use that loop to determine what the current
*
* We get current temperature and check the fans.
*/
static void
monitor_fanstat(void)
{
int i;
for (i = 0; i < N_ENVD_SENSORS; i++) {
sensorp = &envd_sensors[i];
if (!sensorp)
continue;
continue;
} else {
}
}
}
static int
{
uchar_t i;
int ret;
/* Clear Map of Sensor Entries */
for (;;) {
for (i = 0; i < N_ENVD_SENSORS; i++) {
sensorp = &envd_sensors[i];
/*
* Check whether the sensor belongs to the
* interrupting ADM hardware monitor
*/
continue;
continue;
/*
* if shutdown is initiated then we simply loop
* through the sensors until shutdown
*/
continue;
/* get current temp for this sensor */
continue;
if (env_debug)
"sensor name %s, cur temp %d, "
"HW %d LW %d SD %d LS %d\n",
/*
* Log on warning atmost one second
*/
temp,
}
smap[i] = SENSOR_WARN;
} else {
/*
* We will fall in this caterory only if
* threshold. If so we set sensor map to
* OK so that we can exit the loop if
* shutdown not initiated.
*/
}
if (sensorp->shutdown_tstamp == 0)
temp,
}
if (system_shutdown_started == B_FALSE) {
}
} else if (sensorp->shutdown_tstamp != 0)
sensorp->shutdown_tstamp = 0;
}
/*
* Sweep thorugh Sensor Map and if warnings OR shutdown
* are not logged then return to caller.
*/
for (i = 0; i < N_ENVD_SENSORS; i++)
if (smap[i] == SENSOR_WARN)
if ((return_flag == B_TRUE) &&
(system_shutdown_started == B_FALSE)) {
return (1);
}
/*
* We use pthread_cond_reltimedwait_np to sleep for
* fixed interval of time.
* earlier implementation used alarm() call which
* fails in Multi threaded environment. If multiple
* threads call alarm() only one of the threads is
* sent the SIGALRM signal.
*/
(void) pthread_mutex_lock(&env_monitor_mutex);
&env_monitor_mutex, &to);
(void) pthread_mutex_unlock(&env_monitor_mutex);
goto wait_till_timeout;
}
(void) pthread_mutex_unlock(&env_monitor_mutex);
}
}
/*
* This is env thread which monitors the current temperature when
* warning threshold is exceeded. The job is to make sure it does
* forced shutdown to avoid reaching hardware poweroff via THERM interrupt.
* For Enchilada there will be two threads, one for each ADM chip.
*/
static void *
{
int fd;
int err;
int ret;
if (fd == -1) {
return (NULL);
}
if (env_debug)
for (;;) {
/*
* Sleep for specified seconds before issuing IOCTL
* again.
*/
/*
* We use pthread_cond_reltimedwait_np to sleep for
* fixed interval of time.
* earlier implementation used alarm() call which
* fails in Multi threaded environment. If multiple
* threads call alarm() only one of the threads is
* sent the SIGALRM signal.
*/
(void) pthread_mutex_lock(&env_monitor_mutex);
&env_monitor_mutex, &to);
(void) pthread_mutex_unlock(&env_monitor_mutex);
continue;
}
(void) pthread_mutex_unlock(&env_monitor_mutex);
/*
* Monitor the sensors to update fan status
*/
if (mon_fanstat)
/*
* Read ADM1031 two Status Registers to determine source
* of Interrupts.
*/
if (err == -1) {
if (env_debug)
"OverTemp: Status Error");
continue;
}
if (env_debug)
}
}
/*
* manual monitoring
*/
(void) handle_overtemp_interrupt(hwm_id);
} /* end of for ever loop */
/*NOTREACHED*/
return (NULL);
}
static void *
{
int ret;
#ifdef __lint
#endif
for (;;) {
/*
* Sleep for specified seconds before issuing IOCTL
* again.
*/
(void) pthread_mutex_lock(&env_monitor_mutex);
&env_monitor_mutex, &to);
(void) pthread_mutex_unlock(&env_monitor_mutex);
continue;
}
(void) pthread_mutex_unlock(&env_monitor_mutex);
/*
* We write to the comand register periodically
* to inform the PIC firmware that Solaris is
* Monitoring the dimm fan periodically.
*/
if (env_debug)
"Error in writing to COMMAND reg. of DIMM FAN controller\n");
}
/*
* We initiate shutdown if fan status indicates
* failure.
*/
if (is_dimm_fan_failed() != 0) {
/*
* Mark Dimm fan present as False so that we
* do not WARN the user of the Fan failure
* repeatedly.
*/
if (system_shutdown_started == B_FALSE) {
"%s \"%s\"",
msgbuf);
}
}
}
/*NOTREACHED*/
return (NULL);
}
static int
{
int ret_val;
cdb_buf[0] = SCMD_LOG_SENSE_G1;
if (env_debug)
"log sense command for page_code 0x%x succeeded\n", page_code);
return (ret_val);
}
if (env_debug)
"log sense command failed.ret_val = 0x%x status = 0x%x errno = 0x%x\n",
return (1);
}
static int
{
int ret;
if (ret != 0) {
return (-1);
}
/*
* For the current temperature verify that the parameter
* length is 0x02 and the parameter code is 0x00
* Temperature value of 255(0xFF) is considered INVALID.
*/
return (-1);
} else {
}
}
/*
* For the reference temperature verify that the parameter
* length is 0x02 and the parameter code is 0x01
* Temperature value of 255(0xFF) is considered INVALID.
*/
} else {
}
}
return (0);
}
/* ARGSUSED */
static void *
{
int ret, i;
int idle_time;
int disk_pm_fd;
if (disk_pm_fd == -1) {
return (NULL);
}
for (;;) {
/*
* Sleep for specified seconds before issuing IOCTL
* again.
*/
(void) pthread_mutex_lock(&env_monitor_mutex);
&env_monitor_mutex, &to);
(void) pthread_mutex_unlock(&env_monitor_mutex);
continue;
}
(void) pthread_mutex_unlock(&env_monitor_mutex);
continue;
continue;
/*
* If the disk temperature is above the warning threshold
* continue monitoring until the temperature drops below
* warning threshold.
* if the temperature is in the NORMAL range monitor only
* when the disk is BUSY.
* We do not want to read the disk temperature if the disk is
* is idling. The reason for this is disk will never get into
* lowest power mode if we scan the disk temperature
* peridoically. To avoid this situation we first determine
* the idle_time of the disk. If the disk has been IDLE since
* we scanned the temperature last time we will not read the
* temperature.
*/
if ((idle_time =
if (env_debug)
"ioctl PM_GET_TIME_IDLE failed for DISK0. errno=0x%x\n",
errno);
continue;
}
continue;
}
if (env_debug) {
"%s idle time = %d\n",
}
continue;
}
}
if (ret != 0)
continue;
if (env_debug) {
"%s temp = %d ref. temp = %d\n",
}
/*
* If this disk already triggered system shutdown, don't
*/
if (diskp->shutdown_initiated)
continue;
/*
* Check for the temperature in warning and shutdown range
* and take appropriate action.
*/
/*
* Check if the temperature has been in warning
* range during last disk_warning_duration interval.
* If so, the temperature is truly in warning
* range and we need to log a warning message,
* but no more than once every disk_warning_interval
* seconds.
*/
if (diskp->warning_start == 0)
disk_warning_duration) && (wtstamp == 0 ||
}
} else if (diskp->warning_start != 0)
diskp->warning_start = 0;
if (!shutdown_override &&
if (diskp->shutdown_tstamp == 0)
/*
* Shutdown the system if the temperature remains
* in the shutdown range for over disk_shutdown_interval
* seconds.
*/
/* log error */
/* shutdown the system (only once) */
if (system_shutdown_started == B_FALSE) {
}
}
} else if (diskp->shutdown_tstamp != 0)
diskp->shutdown_tstamp = 0;
}
} /* end of forever loop */
}
/*
* Setup envrionmental monitor state and start threads to monitor
* temperature and power management state.
* Returns -1 on error, 0 if successful.
*/
static int
envd_setup(void)
{
int ret;
env_debug = 1;
if (pthread_attr_init(&thr_attr) != 0 ||
return (-1);
}
ret = envd_es_setup();
if (ret < 0) {
ovtemp_monitor = 0;
pm_monitor = 0;
}
/*
* Setup temperature sensors and fail if we can't open
* at least one sensor.
*/
if (envd_setup_sensors() <= 0) {
return (NULL);
}
/*
* Setup fan device (don't fail even if we can't access
* the fan as we can still monitor temeperature.
*/
(void) envd_setup_fans();
(void) envd_setup_disks();
/* If ES Segment setup failed,don't create thread */
(void *)CPU_HWM_ID) != 0)
else
}
(void *)SYS_HWM_ID) != 0)
else
}
if (envd_dimm_fan.present) {
if (dimm_fan_thr_created == B_FALSE) {
NULL) != 0)
else
}
}
/*
* Create a thread to monitor PM state
*/
NULL) != 0)
else
}
if (monitor_disk_temp) {
if (disk_temp_thr_created == B_FALSE) {
NULL) != 0)
else
}
}
return (0);
}
static void
piclenvd_register(void)
{
}
static void
piclenvd_init(void)
{
(void) env_picl_setup_tuneables();
/*
* Setup the environmental data structures
*/
if (envd_setup() != 0) {
return;
}
/*
*/
}
static void
piclenvd_fini(void)
{
/*
* Invoke env_picl_destroy() to remove any PICL nodes/properties
* (including volatile properties) we created. Once this call
* returns, there can't be any more calls from the PICL framework
* to get current temperature or fan speed.
*/
}
/*VARARGS2*/
void
{
}
/*
* Tunables support functions
*/
static env_tuneable_t *
{
int i;
for (i = 0; i < ntuneables; i++) {
return (tuneablep);
}
return (NULL);
}
static int
{
int fd;
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
} else {
}
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
cfg |= TACH_ENABLE_MASK;
cfg &= ~TACH_ENABLE_MASK;
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static int
{
int fd;
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
} else {
}
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
cfg |= TACH_ENABLE_MASK;
cfg &= ~TACH_ENABLE_MASK;
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static int
{
int fd;
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (mmode == ADM1031_AUTO_MODE) {
} else {
}
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static int
{
int fd;
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
return (PICL_FAILURE);
}
if (mmode == ADM1031_AUTO_MODE) {
} else {
}
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
if (fd == -1) {
return (PICL_FAILURE);
}
}
return (PICL_FAILURE);
}
return (PICL_SUCCESS);
}
static int
{
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
static int
{
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
static int
{
return (PICL_PERMDENIED);
return (PICL_FAILURE);
return (PICL_SUCCESS);
}
int
{
/*
* The dimm fan period is 16 bit value and we need to read
* registers 2 and 3 to get the LSB and MSB values.
*/
if (env_debug)
"Error in reading FAN_PERIOD MSB REGISTER\n");
return (-1);
}
if (env_debug)
"Error in reading FAN_PERIOD LSB REGISTER\n");
return (-1);
}
if (env_debug)
" dimm fan tach period is 0x%x\n", dimm_fan_period);
if (dimm_fan_period == 0) {
if (env_debug)
"dimm fan tach period read as zero. Illegal value.\n");
return (-1);
}
return (0);
}
int
is_dimm_fan_failed(void)
{
int retry_count;
return (-1);
/*
* read register 1 to look at Fan fault bit.
*/
while (retry_count > 0) {
retry_count--;
continue;
} else break;
}
if (env_debug)
"%d retries attempted in reading STATUS register.\n",
}
if (retry_count == 0) {
sizeof (dimm_fan_status_string));
sizeof (dimm_fan_command_string));
sizeof (dimm_fan_debug_string));
sizeof (dimm_fan_rpm_string));
return (-1);
}
if (env_debug)
(void) snprintf(dimm_fan_status_string,
sizeof (dimm_fan_status_string), "0x%x",
sizeof (dimm_fan_debug_string));
} else {
(void) snprintf(dimm_fan_debug_string,
sizeof (dimm_fan_debug_string),
}
sizeof (dimm_fan_command_string));
} else {
(void) snprintf(dimm_fan_command_string,
sizeof (dimm_fan_command_string),
}
sizeof (dimm_fan_rpm_string));
} else {
(void) snprintf(dimm_fan_rpm_string,
sizeof (dimm_fan_rpm_string),
"%d", fan_speed);
}
return (1);
} else return (0);
}