diff options
author | Rob Johnston <rob.johnston@joyent.com> | 2018-03-05 21:47:01 +0000 |
---|---|---|
committer | Rob Johnston <rob.johnston@joyent.com> | 2018-04-04 22:02:15 +0000 |
commit | 414afefe58a0a3292d2689bd10360ebb4b505ca6 (patch) | |
tree | a3eb66dcb0c3d160b5ea1acd62ce0faee53dc6b0 | |
parent | 84636c8082b9aee9413dca55149c8d17a373523e (diff) | |
download | illumos-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.h | 8 | ||||
-rw-r--r-- | usr/src/lib/fm/topo/modules/common/fac_prov_ipmi/fac_prov_ipmi.c | 161 | ||||
-rw-r--r-- | usr/src/lib/libipmi/common/ipmi_sensor.c | 29 | ||||
-rw-r--r-- | usr/src/lib/libipmi/common/libipmi.h | 18 | ||||
-rw-r--r-- | usr/src/lib/libipmi/common/mapfile-vers | 3 |
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; |