diff mbox

[ndctl,4/5] ndctl, list: add a '--health' option

Message ID 20160407010720.30641.60021.stgit@dwillia2-desk3.jf.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dan Williams April 7, 2016, 1:07 a.m. UTC
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(-)

Comments

Johannes Thumshirn April 7, 2016, 8:41 a.m. UTC | #1
On Mittwoch, 6. April 2016 18:07:20 CEST Dan Williams wrote:
> Dump dimm smart data in the dimm listing when '--health' is specified.
> 
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---

[...]

> @@ -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);

Maybe some sort of error message for the else path? Either here or in 
util_dimm_health_to_json()?
Dan Williams April 7, 2016, 1:16 p.m. UTC | #2
On Thu, Apr 7, 2016 at 1:41 AM, Johannes Thumshirn <jthumshirn@suse.de> wrote:
> On Mittwoch, 6. April 2016 18:07:20 CEST Dan Williams wrote:
>> Dump dimm smart data in the dimm listing when '--health' is specified.
>>
>> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
>> ---
>
> [...]
>
>> @@ -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);
>
> Maybe some sort of error message for the else path? Either here or in
> util_dimm_health_to_json()?

Yeah, I wasn't sure how to differentiate "dimm does not support smart"
vs "dimm smart data retrieval failed" in this routine.  However,
you're right a debug message at a minimum is needed.
diff mbox

Patch

diff --git a/Documentation/ndctl-list.txt b/Documentation/ndctl-list.txt
index 806548196118..36398aa34b42 100644
--- a/Documentation/ndctl-list.txt
+++ b/Documentation/ndctl-list.txt
@@ -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
diff --git a/builtin-list.c b/builtin-list.c
index df0871ab544a..8b65767c37be 100644
--- a/builtin-list.c
+++ b/builtin-list.c
@@ -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.
diff --git a/util/json.c b/util/json.c
index 288efee723ff..6e61372e4f69 100644
--- a/util/json.c
+++ b/util/json.c
@@ -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);
diff --git a/util/json.h b/util/json.h
index 653bbd9beef1..79962cacc35c 100644
--- a/util/json.h
+++ b/util/json.h
@@ -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__ */