9455 Expose drive speed and temperature on disk topo node
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Approved by: Dan McDonald <danmcd@joyent.com>
diff --git a/usr/src/lib/fm/topo/modules/common/disk/Makefile b/usr/src/lib/fm/topo/modules/common/disk/Makefile
index 4b4c965..8e8935b 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/disk/Makefile
@@ -22,6 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright (c) 2018, Joyent, Inc.
+#
MODULE = disk
CLASS = common
@@ -32,5 +34,5 @@
CPPFLAGS += -I$(SRC)/uts/common
-LDLIBS += -ldevinfo -ldevid -lcfgadm -ldiskstatus
+LDLIBS += -ldevinfo -ldevid -lcfgadm -ldiskstatus -ldiskmgt
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk.h b/usr/src/lib/fm/topo/modules/common/disk/disk.h
index d597df2..02aa7ef 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk.h
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk.h
@@ -23,7 +23,7 @@
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
#ifndef _DISK_H
@@ -50,6 +50,7 @@
#define TOPO_STORAGE_SERIAL_NUM "serial-number"
#define TOPO_STORAGE_FIRMWARE_REV "firmware-revision"
#define TOPO_STORAGE_CAPACITY "capacity-in-bytes"
+#define TOPO_STORAGE_RPM "speed-in-rpm"
/*
* Properties for binding group: The binding group required in platform
diff --git a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
index 123e86f..3eebb3e 100644
--- a/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
+++ b/usr/src/lib/fm/topo/modules/common/disk/disk_common.c
@@ -21,7 +21,7 @@
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2017, Joyent, Inc.
+ * Copyright (c) 2018, Joyent, Inc.
*/
/*
@@ -38,6 +38,7 @@
#include <ctype.h>
#include <strings.h>
#include <libdevinfo.h>
+#include <libdiskmgt.h>
#include <devid.h>
#include <sys/libdevid.h>
#include <pthread.h>
@@ -86,6 +87,20 @@
{ NULL }
};
+static int disk_temp_reading(topo_mod_t *, tnode_t *, topo_version_t,
+ nvlist_t *, nvlist_t **);
+
+#define TOPO_METH_DISK_TEMP "disk_temp_reading"
+#define TOPO_METH_DISK_TEMP_DESC "Disk Temperature Reading"
+#define TOPO_METH_DISK_TEMP_VERSION 0
+
+static const topo_method_t disk_fac_methods[] = {
+ { TOPO_METH_DISK_TEMP, TOPO_METH_DISK_TEMP_DESC,
+ TOPO_METH_DISK_TEMP_VERSION, TOPO_STABILITY_INTERNAL,
+ disk_temp_reading },
+ { NULL }
+};
+
static const topo_pgroup_info_t io_pgroup = {
TOPO_PGROUP_IO,
TOPO_STABILITY_PRIVATE,
@@ -125,9 +140,11 @@
disk_set_props(topo_mod_t *mod, tnode_t *parent,
tnode_t *dtn, dev_di_node_t *dnode)
{
- nvlist_t *asru = NULL;
+ nvlist_t *asru = NULL, *drive_attrs;
char *label = NULL;
nvlist_t *fmri = NULL;
+ dm_descriptor_t drive_descr = NULL;
+ uint32_t rpm;
int err;
/* pull the label property down from our parent 'bay' node */
@@ -265,9 +282,29 @@
"set cap error %s\n", topo_strerror(err));
goto error;
}
+
+ if (dnode->ddn_devid == NULL ||
+ (drive_descr = dm_get_descriptor_by_name(DM_DRIVE,
+ dnode->ddn_devid, &err)) == NULL ||
+ (drive_attrs = dm_get_attributes(drive_descr, &err)) == NULL)
+ goto out;
+
+ if (nvlist_lookup_boolean(drive_attrs, DM_SOLIDSTATE) == 0 ||
+ nvlist_lookup_uint32(drive_attrs, DM_RPM, &rpm) != 0)
+ goto out;
+
+ if (topo_prop_set_uint32(dtn, TOPO_PGROUP_STORAGE, TOPO_STORAGE_RPM,
+ TOPO_PROP_IMMUTABLE, rpm, &err) != 0) {
+ topo_mod_dprintf(mod, "disk_set_props: "
+ "set rpm error %s\n", topo_strerror(err));
+ dm_free_descriptor(drive_descr);
+ goto error;
+ }
err = 0;
out:
+ if (drive_descr != NULL)
+ dm_free_descriptor(drive_descr);
nvlist_free(fmri);
if (label)
topo_mod_strfree(mod, label);
@@ -307,26 +344,134 @@
return (buf);
}
-/*
- * Manufacturing strings can contain characters that are invalid for use in hc
- * authority names. This trims leading and trailing whitespace, and
- * substitutes any characters known to be bad.
- */
-char *
-disk_auth_clean(topo_mod_t *mod, const char *str)
+/*ARGSUSED*/
+static int
+disk_temp_reading(topo_mod_t *mod, tnode_t *node, topo_version_t vers,
+ nvlist_t *in, nvlist_t **out)
{
- char *buf, *p;
+ char *devid;
+ uint32_t temp;
+ dm_descriptor_t drive_descr = NULL;
+ nvlist_t *drive_stats, *pargs, *nvl;
+ int err;
- if (str == NULL)
- return (NULL);
+ if (vers > TOPO_METH_DISK_TEMP_VERSION)
+ return (topo_mod_seterrno(mod, ETOPO_METHOD_VERNEW));
- if ((buf = topo_mod_strdup(mod, str)) == NULL)
- return (NULL);
+ if (nvlist_lookup_nvlist(in, TOPO_PROP_ARGS, &pargs) != 0 ||
+ nvlist_lookup_string(pargs, TOPO_IO_DEVID, &devid) != 0) {
+ topo_mod_dprintf(mod, "Failed to lookup %s arg",
+ TOPO_IO_DEVID);
+ return (topo_mod_seterrno(mod, EMOD_NVL_INVAL));
+ }
- while ((p = strpbrk(buf, " :=")) != NULL)
- *p = '-';
+ if ((drive_descr = dm_get_descriptor_by_name(DM_DRIVE, devid,
+ &err)) == NULL) {
+ topo_mod_dprintf(mod, "failed to get drive decriptor for %s",
+ devid);
+ return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+ }
- return (buf);
+ if ((drive_stats = dm_get_stats(drive_descr, DM_DRV_STAT_TEMPERATURE,
+ &err)) == NULL ||
+ nvlist_lookup_uint32(drive_stats, DM_TEMPERATURE, &temp) != 0) {
+ topo_mod_dprintf(mod, "failed to read disk temp for %s",
+ devid);
+ dm_free_descriptor(drive_descr);
+ return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
+ }
+ dm_free_descriptor(drive_descr);
+
+ if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0 ||
+ nvlist_add_string(nvl, TOPO_PROP_VAL_NAME,
+ TOPO_SENSOR_READING) != 0 ||
+ nvlist_add_uint32(nvl, TOPO_PROP_VAL_TYPE, TOPO_TYPE_DOUBLE) !=
+ 0 || nvlist_add_double(nvl, TOPO_PROP_VAL_VAL, (double)temp) != 0) {
+ topo_mod_dprintf(mod, "Failed to allocate 'out' nvlist\n");
+ nvlist_free(nvl);
+ return (topo_mod_seterrno(mod, EMOD_NOMEM));
+ }
+ *out = nvl;
+
+ return (0);
+}
+
+static int
+disk_add_temp_sensor(topo_mod_t *mod, tnode_t *pnode, const char *devid)
+{
+ tnode_t *fnode;
+ topo_pgroup_info_t pgi;
+ nvlist_t *arg_nvl = NULL;
+ int err;
+
+ if ((fnode = topo_node_facbind(mod, pnode, "temp",
+ TOPO_FAC_TYPE_SENSOR)) == NULL) {
+ topo_mod_dprintf(mod, "failed to bind facility node");
+ /* errno set */
+ return (-1);
+ }
+
+ /*
+ * Set props:
+ * - facility/sensor-class
+ * - facility/sensor-type
+ * - facility/units
+ */
+ pgi.tpi_name = TOPO_PGROUP_FACILITY;
+ pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
+ pgi.tpi_version = 1;
+ if (topo_pgroup_create(fnode, &pgi, &err) != 0) {
+ if (err != ETOPO_PROP_DEFD) {
+ topo_mod_dprintf(mod, "pgroups create failure (%s)\n",
+ topo_strerror(err));
+ /* errno set */
+ goto err;
+ }
+ }
+ if (topo_prop_set_string(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_SENSOR_CLASS, TOPO_PROP_IMMUTABLE,
+ TOPO_SENSOR_CLASS_THRESHOLD, &err) != 0 ||
+ topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_FACILITY_TYPE, TOPO_PROP_IMMUTABLE, TOPO_SENSOR_TYPE_TEMP,
+ &err) != 0 ||
+ topo_prop_set_uint32(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_SENSOR_UNITS, TOPO_PROP_IMMUTABLE,
+ TOPO_SENSOR_UNITS_DEGREES_C, &err) != 0) {
+ topo_mod_dprintf(mod, "Failed to set props on facnode (%s)",
+ topo_strerror(err));
+ /* errno set */
+ goto err;
+ }
+
+ /*
+ * Register a property method for facility/reading
+ */
+ if (topo_method_register(mod, fnode, disk_fac_methods) < 0) {
+ topo_mod_dprintf(mod, "failed to register facility methods");
+ goto err;
+ }
+ if (topo_mod_nvalloc(mod, &arg_nvl, NV_UNIQUE_NAME) < 0 ||
+ nvlist_add_string(arg_nvl, TOPO_IO_DEVID, devid) != 0) {
+ topo_mod_dprintf(mod, "Failed build arg nvlist\n");
+ (void) topo_mod_seterrno(mod, EMOD_NOMEM);
+ goto err;
+ }
+ if (topo_prop_method_register(fnode, TOPO_PGROUP_FACILITY,
+ TOPO_SENSOR_READING, TOPO_TYPE_DOUBLE, "disk_temp_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));
+ /* errno set */
+ goto err;
+ }
+ nvlist_free(arg_nvl);
+ return (0);
+err:
+ topo_node_unbind(fnode);
+ nvlist_free(arg_nvl);
+ return (-1);
}
/* create the disk topo node */
@@ -343,10 +488,10 @@
*rval = NULL;
if (dnode != NULL) {
- mfg = disk_auth_clean(mod, dnode->ddn_mfg);
- model = disk_auth_clean(mod, dnode->ddn_model);
- firm = disk_auth_clean(mod, dnode->ddn_firm);
- serial = disk_auth_clean(mod, dnode->ddn_serial);
+ mfg = topo_mod_clean_str(mod, dnode->ddn_mfg);
+ model = topo_mod_clean_str(mod, dnode->ddn_model);
+ firm = topo_mod_clean_str(mod, dnode->ddn_firm);
+ serial = topo_mod_clean_str(mod, dnode->ddn_serial);
} else {
mfg = model = firm = serial = NULL;
}
@@ -404,6 +549,13 @@
topo_node_unbind(dtn);
return (-1);
}
+
+ if (dnode->ddn_devid != NULL &&
+ disk_add_temp_sensor(mod, dtn, dnode->ddn_devid) != 0) {
+ topo_mod_dprintf(mod, "disk_tnode_create: failed to create "
+ "temperature sensor node on bay=%d/disk=0",
+ topo_node_instance(parent));
+ }
*rval = dtn;
return (0);
}
@@ -624,7 +776,7 @@
char lentry[MAXPATHLEN];
int pathcount;
int *inq_dtype, itype;
- int i;
+ int i;
if (devid) {
/*
diff --git a/usr/src/lib/fm/topo/modules/common/ses/Makefile b/usr/src/lib/fm/topo/modules/common/ses/Makefile
index 578b5bf..acd772c 100644
--- a/usr/src/lib/fm/topo/modules/common/ses/Makefile
+++ b/usr/src/lib/fm/topo/modules/common/ses/Makefile
@@ -20,6 +20,7 @@
#
#
# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2018, Joyent, Inc.
#
MODULE = ses
@@ -34,6 +35,6 @@
CPPFLAGS += -I../disk
LDLIBS += -L$(ROOTLIBDIR)/scsi -R/usr/lib/scsi -lses
-LDLIBS += -ldevinfo -ldevid -ldiskstatus -lcontract -lsysevent
+LDLIBS += -ldevinfo -ldevid -ldiskstatus -lcontract -lsysevent -ldiskmgt
CLOBBERFILES += disk_common.ln
diff --git a/usr/src/lib/fm/topo/modules/common/ses/ses_facility.c b/usr/src/lib/fm/topo/modules/common/ses/ses_facility.c
index 08a4a56..2c4a131 100644
--- a/usr/src/lib/fm/topo/modules/common/ses/ses_facility.c
+++ b/usr/src/lib/fm/topo/modules/common/ses/ses_facility.c
@@ -29,37 +29,41 @@
*/
/*
+ * Copyright (c) 2018, Joyent, Inc.
+ */
+
+/*
* 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
+ * bay
+ * indicator=ident
+ * indicator=fail
+ * indicator=ok2rm
+ * sensor=fault
*
- * controller
- * indicator=ident
- * indicator=fail
+ * controller
+ * indicator=ident
+ * indicator=fail
*
- * fan
- * indicator=ident
- * indicator=fail
- * sensor=speed
- * sensor=fault
+ * fan
+ * indicator=ident
+ * indicator=fail
+ * sensor=speed
+ * sensor=fault
*
- * psu
- * indicator=ident
- * indicator=fail
- * sensor=status
+ * psu
+ * indicator=ident
+ * indicator=fail
+ * sensor=status
*
- * ses-enclosure
- * indicator=ident
- * indicator=fail
- * sensor=fault
- * sensor=<name> (temperature)
- * sensor=<name> (voltage)
- * sensor=<name> (current)
+ * 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
@@ -930,7 +934,7 @@
"%.*s %llu", len, desc, index);
}
- if ((name = disk_auth_clean(mod, rawname)) == NULL)
+ if ((name = topo_mod_clean_str(mod, rawname)) == NULL)
return (-1);
if (ses_add_sensor(mod, tn, nodeid, name, &sd) != 0) {