summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Johnston <rob.johnston@joyent.com>2018-03-05 21:47:01 +0000
committerRob Johnston <rob.johnston@joyent.com>2018-04-04 22:02:15 +0000
commit414afefe58a0a3292d2689bd10360ebb4b505ca6 (patch)
treea3eb66dcb0c3d160b5ea1acd62ce0faee53dc6b0
parent84636c8082b9aee9413dca55149c8d17a373523e (diff)
downloadillumos-joyent-414afefe58a0a3292d2689bd10360ebb4b505ca6.tar.gz
OS-6732 expose thresholds as properties on sensor facility nodes
Reviewed by: Robert Mustacchi <rm@joyent.com> Approved by: Jason King <jason.king@joyent.com>
-rw-r--r--usr/src/lib/fm/topo/libtopo/common/libtopo.h8
-rw-r--r--usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c161
-rw-r--r--usr/src/lib/libipmi/common/ipmi_sensor.c29
-rw-r--r--usr/src/lib/libipmi/common/libipmi.h18
-rw-r--r--usr/src/lib/libipmi/common/mapfile-vers3
5 files changed, 184 insertions, 35 deletions
diff --git a/usr/src/lib/fm/topo/libtopo/common/libtopo.h b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
index da6083a5be..822922294c 100644
--- a/usr/src/lib/fm/topo/libtopo/common/libtopo.h
+++ b/usr/src/lib/fm/topo/libtopo/common/libtopo.h
@@ -418,6 +418,14 @@ void topo_sensor_state_name(uint32_t sensor_type, uint8_t state, char *buf,
#define TOPO_SENSOR_UNITS "units"
#define TOPO_LED_MODE "mode"
+#define TOPO_PROP_THRESHOLD_LNC "threshold-lower-non-critical"
+#define TOPO_PROP_THRESHOLD_LCR "threshold-lower-critical"
+#define TOPO_PROP_THRESHOLD_LNR "threshold-lower-non-recoverable"
+
+#define TOPO_PROP_THRESHOLD_UNC "threshold-upper-non-critical"
+#define TOPO_PROP_THRESHOLD_UCR "threshold-upper-critical"
+#define TOPO_PROP_THRESHOLD_UNR "threshold-upper-non-recoverable"
+
/*
* Sensor Classes
*
diff --git a/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c b/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
index 5592f25cdd..b394923833 100644
--- a/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
+++ b/usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c
@@ -23,7 +23,7 @@
* Use is subject to license terms.
*/
/*
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#include <unistd.h>
#include <stdio.h>
@@ -171,6 +171,7 @@ struct sensor_data {
uint32_t sd_stype;
uint32_t sd_rtype;
char *sd_class;
+ ipmi_sdr_full_sensor_t *sd_fs_sdr;
};
/*ARGSUSED*/
@@ -1349,14 +1350,66 @@ chassis_ident_mode(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
return (0);
}
+#define ISBITSET(MASK, BIT) ((MASK & BIT) == BIT)
+
+struct sensor_thresh {
+ uint8_t sthr_threshbit;
+ const char *sthr_propname;
+ uint8_t sthr_threshoff;
+};
+
+static const struct sensor_thresh threshset[] = {
+ { IPMI_SENSOR_THRESHOLD_LOWER_NONCRIT, TOPO_PROP_THRESHOLD_LNC,
+ offsetof(ipmi_sensor_thresholds_t, ithr_lower_noncrit) },
+ { IPMI_SENSOR_THRESHOLD_LOWER_CRIT, TOPO_PROP_THRESHOLD_LCR,
+ offsetof(ipmi_sensor_thresholds_t, ithr_lower_crit) },
+ { IPMI_SENSOR_THRESHOLD_LOWER_NONRECOV, TOPO_PROP_THRESHOLD_LNR,
+ offsetof(ipmi_sensor_thresholds_t, ithr_lower_nonrec) },
+ { IPMI_SENSOR_THRESHOLD_UPPER_NONCRIT, TOPO_PROP_THRESHOLD_UNC,
+ offsetof(ipmi_sensor_thresholds_t, ithr_upper_noncrit) },
+ { IPMI_SENSOR_THRESHOLD_UPPER_CRIT, TOPO_PROP_THRESHOLD_UCR,
+ offsetof(ipmi_sensor_thresholds_t, ithr_upper_crit) },
+ { IPMI_SENSOR_THRESHOLD_UPPER_NONRECOV, TOPO_PROP_THRESHOLD_UNR,
+ offsetof(ipmi_sensor_thresholds_t, ithr_upper_nonrec) }
+};
+
+static uint_t num_thresholds =
+ sizeof (threshset) / sizeof (struct sensor_thresh);
+
+static int
+set_thresh_prop(topo_mod_t *mod, tnode_t *fnode, ipmi_sdr_full_sensor_t *fs,
+ uint8_t raw_thresh, const struct sensor_thresh *thresh)
+{
+ int err;
+ double conv_thresh;
+
+ if (ipmi_sdr_conv_reading(fs, raw_thresh, &conv_thresh) != 0) {
+ topo_mod_dprintf(mod, "Failed to convert threshold %s on node "
+ "%s", thresh->sthr_propname, topo_node_name(fnode));
+ return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
+ }
+ if (topo_prop_set_double(fnode, TOPO_PGROUP_FACILITY,
+ thresh->sthr_propname, TOPO_PROP_IMMUTABLE, conv_thresh, &err) !=
+ 0) {
+ topo_mod_dprintf(mod, "Failed to set property %s on node %s "
+ "(%s)", thresh->sthr_propname, topo_node_name(fnode),
+ topo_strerror(err));
+ return (topo_mod_seterrno(mod, err));
+ }
+ return (0);
+}
+
static int
-make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
+make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd,
+ ipmi_handle_t *hdl)
{
int err, ret, i;
tnode_t *fnode;
char *ftype = "sensor", facname[MAX_ID_LEN], **entity_refs;
topo_pgroup_info_t pgi;
nvlist_t *arg_nvl = NULL;
+ ipmi_sensor_thresholds_t thresh = { 0 };
+ uint8_t mask;
/*
* Some platforms have '/' characters in the IPMI entity name, but '/'
@@ -1371,7 +1424,7 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
if ((fnode = topo_node_facbind(mod, pnode, facname, ftype)) == NULL) {
topo_mod_dprintf(mod, "Failed to bind facility node: %s\n",
facname);
- /* topo errno set */
+ /* errno set */
return (-1);
}
@@ -1384,23 +1437,20 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
topo_mod_dprintf(mod, "pgroups create failure: %s\n",
topo_strerror(err));
topo_node_unbind(fnode);
- return (-1);
+ return (topo_mod_seterrno(mod, err));
}
}
if (topo_method_register(mod, fnode, ipmi_fac_methods) < 0) {
topo_mod_dprintf(mod, "make_fac_node: "
"failed to register facility methods");
topo_node_unbind(fnode);
+ /* errno set */
return (-1);
}
/*
* For both threshold and discrete sensors we set up a propmethod for
* getting the sensor state and properties to hold the entity ref,
* sensor class and sensor type.
- *
- * Additionally, for analog sensors we set up a property method for
- * getting the converted sensor reading and property for the base
- * unit type
*/
if ((entity_refs = topo_mod_alloc(mod, sizeof (char *))) == NULL)
return (topo_mod_seterrno(mod, EMOD_NOMEM));
@@ -1414,7 +1464,7 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
"on node: %s=%d (%s)\n", __func__, topo_node_name(fnode),
topo_node_instance(fnode), topo_strerror(err));
strarr_free(mod, entity_refs, 1);
- return (-1);
+ return (topo_mod_seterrno(mod, err));
}
strarr_free(mod, entity_refs, 1);
@@ -1423,14 +1473,14 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
topo_mod_dprintf(mod, "Failed to set %s property on node: "
"%s=%d (%s)\n", TOPO_SENSOR_CLASS, topo_node_name(fnode),
topo_node_instance(fnode), topo_strerror(err));
- return (-1);
+ return (topo_mod_seterrno(mod, err));
}
if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, sd->sd_stype, &err) != 0) {
topo_mod_dprintf(mod, "Failed to set %s property on node: "
"%s=%d (%s)\n", TOPO_FACILITY_TYPE, topo_node_name(fnode),
topo_node_instance(fnode), topo_strerror(err));
- return (-1);
+ return (topo_mod_seterrno(mod, err));
}
if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0) {
topo_node_unbind(fnode);
@@ -1442,7 +1492,7 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
topo_mod_dprintf(mod, "Failed build arg nvlist (%s)\n",
strerror(ret));
nvlist_free(arg_nvl);
- return (-1);
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
}
if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
@@ -1452,30 +1502,75 @@ make_sensor_node(topo_mod_t *mod, tnode_t *pnode, struct sensor_data *sd)
"node %s (%s)\n", TOPO_SENSOR_STATE, topo_node_name(fnode),
topo_strerror(err));
nvlist_free(arg_nvl);
- return (-1);
+ return (topo_mod_seterrno(mod, err));
}
- if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) == 0) {
- if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
- TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE,
- "ipmi_sensor_reading", arg_nvl, &err) != 0) {
- topo_mod_dprintf(mod, "Failed to register %s propmeth "
- "on fac node %s (%s)\n", TOPO_SENSOR_READING,
- topo_node_name(fnode), topo_strerror(err));
- nvlist_free(arg_nvl);
- return (-1);
- }
- if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
- TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err)
- != 0) {
- topo_mod_dprintf(mod, "Failed to set units property on "
- "node: %s (%s)\n", topo_node_name(fnode),
- topo_strerror(err));
- nvlist_free(arg_nvl);
+ /*
+ * If it's a discrete sensor then we're done. For threshold sensors,
+ * there are additional properties to set up.
+ */
+ if (strcmp(sd->sd_class, TOPO_SENSOR_CLASS_THRESHOLD) != 0) {
+ nvlist_free(arg_nvl);
+ return (0);
+ }
+
+ /*
+ * Create properties to expose the analog sensor reading, the unit
+ * type and the upper and lower thresholds, if available.
+ */
+ if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, "ipmi_sensor_reading",
+ arg_nvl, &err) != 0) {
+ topo_mod_dprintf(mod, "Failed to register %s propmeth on fac "
+ "node %s (%s)\n", TOPO_SENSOR_READING,
+ topo_node_name(fnode), topo_strerror(err));
+ nvlist_free(arg_nvl);
+ return (topo_mod_seterrno(mod, err));
+ }
+ if (topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE, sd->sd_units, &err) != 0) {
+ topo_mod_dprintf(mod, "Failed to set units property on node "
+ "%s (%s)\n", topo_node_name(fnode), topo_strerror(err));
+ nvlist_free(arg_nvl);
+ return (topo_mod_seterrno(mod, err));
+ }
+ nvlist_free(arg_nvl);
+
+ /*
+ * It is possible (though unusual) for a compact sensor record to
+ * represent a threshold sensor. However, due to how
+ * ipmi_sdr_conv_reading() is currently implemented, we only support
+ * gathering threshold readings on sensors enumerated from Full Sensor
+ * Records.
+ */
+ if (sd->sd_fs_sdr == NULL)
+ return (0);
+
+ if (ipmi_get_sensor_thresholds(hdl, &thresh,
+ sd->sd_fs_sdr->is_fs_number) != 0) {
+ topo_mod_dprintf(mod, "Failed to get sensor thresholds for "
+ "node %s (%s)\n", topo_node_name(fnode), ipmi_errmsg(hdl));
+ return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
+ }
+
+ /*
+ * The IPMI Get Sensor Thresholds command returns a bitmask describing
+ * which of the 3 upper and lower thresholds are readable. Iterate
+ * through those and create a topo property for each threshold that is
+ * readable.
+ */
+ mask = thresh.ithr_readable_mask;
+ for (i = 0; i < num_thresholds; i++) {
+ if (!ISBITSET(mask, threshset[i].sthr_threshbit))
+ continue;
+
+ if (set_thresh_prop(mod, fnode, sd->sd_fs_sdr,
+ *(uint8_t *)((char *)&thresh +
+ threshset[i].sthr_threshoff), &threshset[i]) != 0) {
+ /* errno set */
return (-1);
}
}
- nvlist_free(arg_nvl);
return (0);
}
@@ -1513,6 +1608,7 @@ sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
sd.sd_units = f_sensor->is_fs_unit2;
sd.sd_stype = f_sensor->is_fs_type;
sd.sd_rtype = f_sensor->is_fs_reading_type;
+ sd.sd_fs_sdr = f_sensor;
break;
case IPMI_SDR_TYPE_COMPACT_SENSOR:
c_sensor =
@@ -1527,6 +1623,7 @@ sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
sd.sd_units = c_sensor->is_cs_unit2;
sd.sd_stype = c_sensor->is_cs_type;
sd.sd_rtype = c_sensor->is_cs_reading_type;
+ sd.sd_fs_sdr = NULL;
break;
default:
return (0);
@@ -1546,7 +1643,7 @@ sdr_callback(ipmi_handle_t *hdl, const char *id, ipmi_sdr_t *sdr, void *data)
ei->ei_list, ei->ei_listsz) == B_TRUE) ||
(sensor_entity == ei->ei_id && sensor_inst == ei->ei_inst)) {
- if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd) != 0) {
+ if (make_sensor_node(ei->ei_mod, ei->ei_node, &sd, hdl) != 0) {
topo_mod_dprintf(ei->ei_mod, "Failed to create sensor "
"node for %s\n", sd.sd_entity_ref);
if (topo_mod_errno(ei->ei_mod) != EMOD_NODE_DUP)
diff --git a/usr/src/lib/libipmi/common/ipmi_sensor.c b/usr/src/lib/libipmi/common/ipmi_sensor.c
index 0b035709a3..63a7999d56 100644
--- a/usr/src/lib/libipmi/common/ipmi_sensor.c
+++ b/usr/src/lib/libipmi/common/ipmi_sensor.c
@@ -22,8 +22,9 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
#include <libipmi.h>
#include <string.h>
@@ -95,3 +96,27 @@ ipmi_set_sensor_reading(ipmi_handle_t *ihp, ipmi_set_sensor_reading_t *req)
return (0);
}
+
+int
+ipmi_get_sensor_thresholds(ipmi_handle_t *ihp, ipmi_sensor_thresholds_t *thresh,
+ uint8_t id)
+{
+ ipmi_cmd_t cmd, *resp;
+
+ cmd.ic_netfn = IPMI_NETFN_SE;
+ cmd.ic_cmd = IPMI_CMD_GET_SENSOR_THRESHOLDS;
+ cmd.ic_lun = 0;
+ cmd.ic_data = &id;
+ cmd.ic_dlen = sizeof (id);
+
+ if ((resp = ipmi_send(ihp, &cmd)) == NULL)
+ return (-1);
+
+ if (resp->ic_dlen < sizeof (ipmi_sensor_thresholds_t)) {
+ return (ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL));
+ }
+
+ (void) memcpy(thresh, resp->ic_data, sizeof (ipmi_sensor_thresholds_t));
+
+ return (0);
+}
diff --git a/usr/src/lib/libipmi/common/libipmi.h b/usr/src/lib/libipmi/common/libipmi.h
index 01bf3cb546..84573d2711 100644
--- a/usr/src/lib/libipmi/common/libipmi.h
+++ b/usr/src/lib/libipmi/common/libipmi.h
@@ -1606,6 +1606,24 @@ extern ipmi_sdr_full_sensor_t *ipmi_sdr_lookup_full_sensor(
#define IPMI_ET_RTC 0x35
/*
+ * Get Sensor Threshold. See section 35.9
+ */
+#define IPMI_CMD_GET_SENSOR_THRESHOLDS 0x27
+
+typedef struct ipmi_sensor_thresholds {
+ uint8_t ithr_readable_mask;
+ uint8_t ithr_lower_noncrit;
+ uint8_t ithr_lower_crit;
+ uint8_t ithr_lower_nonrec;
+ uint8_t ithr_upper_noncrit;
+ uint8_t ithr_upper_crit;
+ uint8_t ithr_upper_nonrec;
+} ipmi_sensor_thresholds_t;
+
+extern int ipmi_get_sensor_thresholds(ipmi_handle_t *,
+ ipmi_sensor_thresholds_t *, uint8_t);
+
+/*
* Get Sensor Reading. See section 35.14.
*/
diff --git a/usr/src/lib/libipmi/common/mapfile-vers b/usr/src/lib/libipmi/common/mapfile-vers
index 85526ddd84..3852cf83f4 100644
--- a/usr/src/lib/libipmi/common/mapfile-vers
+++ b/usr/src/lib/libipmi/common/mapfile-vers
@@ -23,7 +23,7 @@
#
#
-# Copyright (c) 2017, Joyent, Inc.
+# Copyright (c) 2018, Joyent, Inc.
#
#
@@ -66,6 +66,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
ipmi_get_channel_info;
ipmi_get_deviceid;
ipmi_get_sensor_reading;
+ ipmi_get_sensor_thresholds;
ipmi_is_sun_ilom;
ipmi_lan_get_config;
ipmi_lan_set_config;