@@ -3,7 +3,7 @@ ndctl-list(1)
NAME
----
-ndctl-list - dump the platform nvdimm device topology in json
+ndctl-list - dump the platform nvdimm device topology and attributes in json
SYNOPSIS
--------
@@ -72,6 +72,23 @@ include::xable-region-options.txt[]
--dimms::
Include dimm info in the listing
+-H::
+--health::
+ Include dimm health info in the listing. For example:
+[verse]
+{
+ "dev":"nmem0",
+ "health":{
+ "health_state":"non-critical",
+ "temperature_celsius":23,
+ "spares_percentage":75,
+ "alarm_temperature":true,
+ "alarm_spares":true,
+ "life_used_percentage":5,
+ "shutdown_state":"clean"
+ }
+}
+
-R::
--regions::
Include region info in the listing
@@ -22,6 +22,7 @@ static struct {
bool regions;
bool namespaces;
bool idle;
+ bool health;
} list;
static struct {
@@ -200,6 +201,7 @@ int cmd_list(int argc, const char **argv)
"filter by region-type"),
OPT_BOOLEAN('B', "buses", &list.buses, "include bus info"),
OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
+ OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
OPT_BOOLEAN('R', "regions", &list.regions,
"include region info"),
OPT_BOOLEAN('N', "namespaces", &list.namespaces,
@@ -299,6 +301,15 @@ int cmd_list(int argc, const char **argv)
continue;
}
+ if (list.health) {
+ struct json_object *jhealth;
+
+ jhealth = util_dimm_health_to_json(dimm);
+ if (jhealth)
+ json_object_object_add(jdimm, "health",
+ jhealth);
+ }
+
/*
* Without a bus we are collecting dimms anonymously
* across the platform.
@@ -61,6 +61,103 @@ struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm)
return NULL;
}
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
+{
+ struct json_object *jhealth = json_object_new_object();
+ struct json_object *jobj;
+ struct ndctl_cmd *cmd;
+ unsigned int flags;
+ int rc;
+
+ if (!jhealth)
+ return NULL;
+
+ cmd = ndctl_dimm_cmd_new_smart(dimm);
+ if (!cmd)
+ goto err;
+
+ rc = ndctl_cmd_submit(cmd);
+ if (rc || ndctl_cmd_get_firmware_status(cmd))
+ goto err;
+
+ flags = ndctl_cmd_smart_get_flags(cmd);
+ if (flags & ND_SMART_HEALTH_VALID) {
+ unsigned int health = ndctl_cmd_smart_get_health(cmd);
+
+ if (health & ND_SMART_FATAL_HEALTH)
+ jobj = json_object_new_string("fatal");
+ else if (health & ND_SMART_CRITICAL_HEALTH)
+ jobj = json_object_new_string("critical");
+ else if (health & ND_SMART_NON_CRITICAL_HEALTH)
+ jobj = json_object_new_string("non-critical");
+ else
+ jobj = json_object_new_string("ok");
+ if (jobj)
+ json_object_object_add(jhealth, "health_state", jobj);
+ }
+
+ if (flags & ND_SMART_TEMP_VALID) {
+ unsigned int temp = ndctl_cmd_smart_get_temperature(cmd);
+ bool negative = !!(temp & (1 << 15));
+ double t;
+
+ temp &= ~(1 << 15);
+ t = (double) temp / 16;
+ if (negative)
+ t *= -1;
+ jobj = json_object_new_double(t);
+ if (jobj)
+ json_object_object_add(jhealth, "temperature_celsius", jobj);
+ }
+
+ if (flags & ND_SMART_SPARES_VALID) {
+ unsigned int spares = ndctl_cmd_smart_get_spares(cmd);
+
+ jobj = json_object_new_int(spares);
+ if (jobj)
+ json_object_object_add(jhealth, "spares_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_ALARM_VALID) {
+ unsigned int alarm_flags = ndctl_cmd_smart_get_spares(cmd);
+ bool temp_flag = !!(alarm_flags & ND_SMART_TEMP_TRIP);
+ bool spares_flag = !!(alarm_flags & ND_SMART_SPARE_TRIP);
+
+ jobj = json_object_new_boolean(temp_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_temperature", jobj);
+
+ jobj = json_object_new_boolean(spares_flag);
+ if (jobj)
+ json_object_object_add(jhealth, "alarm_spares", jobj);
+ }
+
+ if (flags & ND_SMART_USED_VALID) {
+ unsigned int life_used = ndctl_cmd_smart_get_life_used(cmd);
+
+ jobj = json_object_new_int(life_used);
+ if (jobj)
+ json_object_object_add(jhealth, "life_used_percentage", jobj);
+ }
+
+ if (flags & ND_SMART_SHUTDOWN_VALID) {
+ unsigned int shutdown = ndctl_cmd_smart_get_shutdown_state(cmd);
+
+ jobj = json_object_new_string(shutdown ? "dirty" : "clean");
+ if (jobj)
+ json_object_object_add(jhealth, "shutdown_state", jobj);
+ }
+
+ ndctl_cmd_unref(cmd);
+ return jhealth;
+ err:
+ json_object_put(jhealth);
+ if (cmd)
+ ndctl_cmd_unref(cmd);
+ return NULL;
+}
+
+
bool util_namespace_active(struct ndctl_namespace *ndns)
{
struct ndctl_btt *btt = ndctl_namespace_get_btt(ndns);
@@ -6,6 +6,7 @@
bool util_namespace_active(struct ndctl_namespace *ndns);
struct json_object *util_bus_to_json(struct ndctl_bus *bus);
struct json_object *util_dimm_to_json(struct ndctl_dimm *dimm);
+struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
struct json_object *util_mapping_to_json(struct ndctl_mapping *mapping);
struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns);
#endif /* __NDCTL_JSON_H__ */
Dump dimm smart data in the dimm listing when '--health' is specified. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- Documentation/ndctl-list.txt | 19 ++++++++ builtin-list.c | 11 +++++ util/json.c | 97 ++++++++++++++++++++++++++++++++++++++++++ util/json.h | 1 4 files changed, 127 insertions(+), 1 deletion(-)