ses_facility.c revision 7793aa8b1cb26c7fc1397aa9db2364098fc25543
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Facility node support for SES enclosures. We support the following facility
* nodes, based on the node type:
*
* bay
* indicator=ident
* indicator=fail
* indicator=ok2rm
* sensor=fault
*
* controller
* indicator=ident
* indicator=fail
*
* fan
* indicator=ident
* indicator=fail
* sensor=speed
* sensor=fault
*
* psu
* indicator=ident
* indicator=fail
* sensor=status
*
* ses-enclosure
* indicator=ident
* indicator=fail
* sensor=fault
* sensor=<name> (temperature)
* sensor=<name> (voltage)
* sensor=<name> (current)
*
* Most of these are handled by a single method that supports getting and
* setting boolean properties on the node. The fan speed sensor requires a
* special handler, while the analog enclosure sensors all have similar
* behavior and can be grouped together using a common method.
*/
#include "ses.h"
#include "disk.h"
#include <string.h>
#define SES_SUPP_WARN_UNDER 0x01
#define SES_SUPP_WARN_OVER 0x02
#define SES_SUPP_CRIT_UNDER 0x04
#define SES_SUPP_CRIT_OVER 0x08
typedef struct ses_sensor_desc {
int sd_type;
int sd_units;
const char *sd_propname;
double sd_multiplier;
#define TOPO_METH_SES_MODE_VERSION 0
#define TOPO_METH_SES_READING_VERSION 0
#define TOPO_METH_SES_STATE_VERSION 0
#define TOPO_METH_SES_PSU_VERSION 0
#define TOPO_METH_SES_READING_PROP "propname"
#define TOPO_METH_SES_READING_MULT "multiplier"
#define TOPO_METH_SES_STATE_PROP "propname"
#define TOPO_METH_SES_MODE_PROP "property-name"
#define TOPO_METH_SES_MODE_ALTPROP "alternate-property"
static const topo_method_t ses_indicator_methods[] = {
{ "ses_indicator_mode", TOPO_PROP_METH_DESC,
};
static const topo_method_t ses_sensor_methods[] = {
{ "ses_sensor_reading", TOPO_PROP_METH_DESC,
{ "ses_sensor_state", TOPO_PROP_METH_DESC,
{ "ses_psu_state", TOPO_PROP_METH_DESC,
};
/*
* Get or set an indicator. This method is invoked with arguments indicating
* the property to query to retrieve the value. Some elements (enclosures and
* devices) support a request property that is distinct from an array-detected
* property. Either of these conditions will result in the indicator being
* lit, so we have to check both properties.
*/
static int
{
ses_node_t *np;
if (vers > TOPO_METH_SES_MODE_VERSION)
&propname) != 0) {
}
&altprop) != 0)
"method\n");
return (-1);
}
/* set operation */
&mode) != 0) {
"mode property");
}
mode);
}
}
ses_errmsg());
return (-1);
}
} else {
/* get operation */
"properties\n", propname);
}
altprop, &altcurrent) == 0)
current |= altcurrent;
}
TOPO_LED_MODE) != 0 ||
}
return (0);
}
/*
* Read the given sensor value. This just looks up the value in the node
* properties, and multiplies by a fixed value (determined when the method is
* instantiated).
*/
static int
{
ses_node_t *np;
char *prop;
double raw, multiplier;
if (vers > TOPO_METH_SES_MODE_VERSION)
&prop) != 0) {
"invalid arguments to 'reading' method\n");
}
&multiplier) != 0)
multiplier = 1;
"method\n");
return (-1);
}
} else {
"properties\n", prop);
}
TOPO_SENSOR_READING) != 0 ||
}
return (0);
}
/*
* Returns the current sensor state. This can be invoked for one of two
* different types of sensors: threshold or discrete sensors. For discrete
* sensors, we expect a name of a boolean property and indicate
* asserted/deasserted based on that. For threshold sensors, we check for the
* topo state.
*/
/*ARGSUSED*/
static int
{
ses_node_t *np;
char *prop;
"method\n");
return (-1);
}
"invalid arguments to 'state' method\n");
}
state = 0;
&prop) == 0) {
/* discrete (fault) sensor */
if (status == SES_ESC_UNRECOVERABLE ||
if (asserted)
else
} else {
/* threshold sensor */
}
TOPO_SENSOR_STATE) != 0 ||
}
return (0);
}
/*
* Read the status of a PSU. This is such a specialized operation that it has
* its own method instead of trying to piggyback on ses_sensor_state(). We
* use the following mapping to get to the standard topo power supply states:
*
* acfail -> INPUT_LOST
* dcfail -> INPUT_LOST
* undervoltage -> INPUT_RANGE
* overvoltage -> INPUT_RANGE_PRES
* overcurrent -> INPUT_RANGE_PRES
* overtemp -> (none)
*
* If we ever have a need for reading overtemp, we can expand the topo
* representation for power supplies, but at the moment this seems unnecessary.
*/
/*ARGSUSED*/
static int
{
ses_node_t *np;
"method\n");
return (-1);
}
state = 0;
TOPO_SENSOR_STATE) != 0 ||
}
return (0);
}
/*
* Create a facility node, either a sensor or an indicator.
*/
static tnode_t *
{
int err;
name);
return (NULL);
}
stp->set_refcount++;
return (NULL);
}
/*
* We need the node-id property for each facility node.
*/
return (NULL);
}
"failed to create property %s: %s\n",
return (NULL);
}
return (tn);
}
/*
* Add an indicator. This can be represented by a single property, or by the
* union of two elements when SES is capable of distinguishing between
* requested failure and detected failure.
*/
static int
{
int err;
/* create facility node and add methods */
return (-1);
return (-1);
}
/* set standard properties */
"failed to set facility node properties: %s\n",
topo_strerror(err));
return (-1);
}
/* 'mode' property */
propname) != 0 ||
TOPO_METH_SES_MODE_ALTPROP, altprop) != 0)) {
}
topo_strerror(err));
return (-1);
}
TOPO_LED_MODE, &err) != 0) {
topo_strerror(err));
return (-1);
}
return (0);
}
static tnode_t *
{
int err;
/* create facility node and add methods */
return (NULL);
return (NULL);
}
/* set standard properties */
"failed to set facility node properties: %s\n",
topo_strerror(err));
return (NULL);
}
return (tn);
}
/*
* Add an analog (threshold) sensor to the enclosure. This is used for fan
* speed, voltage, current, and temperature sensors.
*/
static int
{
int err;
return (-1);
"failed to set facility node properties: %s\n",
topo_strerror(err));
return (-1);
}
/* 'reading' property */
sdp->sd_propname) != 0 ||
(sdp->sd_multiplier != 0 &&
sdp->sd_multiplier) != 0)) {
return (-1);
}
topo_strerror(err));
return (-1);
}
return (-1);
}
/* 'state' property */
topo_strerror(err));
return (-1);
}
return (0);
}
/*
* Add a discrete sensor for simple boolean values. This is used to indicate
* externally-detected failures for fans, bays, and enclosures.
*/
static int
{
int err;
return (-1);
return (-1);
}
/* 'state' property */
topo_strerror(err));
return (-1);
}
return (0);
}
/*ARGSUSED*/
static int
{
int err;
/* create facility node and add methods */
return (-1);
return (-1);
}
/* 'state' property */
topo_strerror(err));
return (-1);
}
return (0);
}
/*ARGSUSED*/
int
{
ses_node_t *np;
ses_sensor_desc_t sd = { 0 };
return (-1);
return (0);
/*
* Every element supports an 'ident' indicator. All elements also
* support a 'fail' indicator, but the properties used to represent
* this condition differs between elements.
*/
SES_PROP_IDENT, NULL) != 0)
return (-1);
switch (type) {
case SES_ET_DEVICE:
case SES_ET_ARRAY_DEVICE:
/*
* Disks support an additional 'ok2rm' indicator, as well as
* externally detected 'fail' sensor.
*/
"fail", SES_DEV_PROP_FAULT_RQSTD,
SES_DEV_PROP_FAULT_SENSED) != 0 ||
SES_DEV_PROP_FAULT_SENSED) != 0)
return (-1);
break;
case SES_ET_COOLING:
/*
* Add the fan speed sensor, and a discrete sensor for
* detecting failure.
*/
SES_PROP_OFF) != 0)
return (-1);
break;
case SES_ET_POWER_SUPPLY:
/*
* For power supplies, we have a number of different sensors:
* acfail, dcfail, overtemp, undervoltate, overvoltage,
* and overcurrent. Rather than expose these all as individual
* sensors, we lump them together into a 'status' sensor of
* type TOPO_SENSOR_TYPE_POWER_SUPPLY and export the
* appropriate status flags as defined by the libtopo standard.
*/
return (-1);
return (-1);
break;
default:
return (0);
}
return (0);
}
/*
* Add enclosure-wide sensors (temperature, voltage, and current) beneath the
* given aggregate.
*/
static int
{
const char *defaultname;
char rawname[64];
ses_sensor_desc_t sd = { 0 };
switch (type) {
defaultname = "temperature";
break;
case SES_ET_VOLTAGE_SENSOR:
defaultname = "voltage";
break;
case SES_ET_CURRENT_SENSOR:
defaultname = "current";
break;
default:
return (0);
}
/*
* The only tricky part here is getting the name for the
* sensor, where we follow the algorithm of the standard
* elements.
*/
&index) != 0)
continue;
} else {
SES_PROP_CLASS_DESCRIPTION, &desc) != 0 ||
desc[0] == '\0')
desc = (char *)defaultname;
len--;
}
return (-1);
return (-1);
}
}
return (0);
}
/*ARGSUSED*/
int
{
return (-1);
/*
* 'ident' and 'fail' LEDs, and 'fault' sensor.
*/
SES_PROP_IDENT, NULL) != 0 ||
SES_PROP_FAIL_REQ, SES_PROP_FAIL) != 0 ||
return (-1);
/*
* Environmental sensors (temperature, voltage, current). We have no
* way of knowing if any of these sensors correspond to a particular
* element, so we just attach them to the enclosure as a whole. In the
* future, some vendor-specific libses plugin knowledge could let us
* make this correlation clearer.
*/
continue;
&type) != 0)
continue;
return (-1);
}
return (0);
}