From: Wen Xiong <wenxiong@linux.vnet.ibm.com>
Date: Wed, 8 Jan 2020 12:24:41 -0800
Subject: [PATCH] Add additional smart log critical warn decoding
Git-commit: 4bad11866a349b7ae5d10869474f7c0fee740845

Provide a user option to request additional smart log page decoding,
and print out detailed critical warning when requested.

Signed-off-by: Wendy Xiong<wenxiong@linux.vnet.ibm.com>
[merge up, rename json keys]
Signed-off-by: Keith Busch <kbusch@kernel.org>
---
 nvme-print.c | 37 +++++++++++++++++++++++++++++++------
 nvme.c       | 11 ++++++++---
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/nvme-print.c b/nvme-print.c
index 2ba1de1..46d5228 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -585,10 +585,11 @@ static void json_endurance_log(struct nvme_endurance_group_log *endurance_group,
 	json_free_object(root);
 }
 
-static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid)
+static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+	enum nvme_print_flags flags)
 {
+	int c, human = flags & VERBOSE;
 	struct json_object *root;
-	int c;
 	char key[21];
 
 	unsigned int temperature = ((smart->temperature[1] << 8) |
@@ -607,8 +608,22 @@ static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid)
 
 	root = json_create_object();
 
-	json_object_add_value_int(root, "critical_warning",
-		smart->critical_warning);
+	if (human) {
+		struct json_object *crt = json_create_object();
+
+		json_object_add_value_int(crt, "value", smart->critical_warning);
+		json_object_add_value_int(crt, "available_spare", smart->critical_warning & 0x01);
+		json_object_add_value_int(crt, "temp_threshold", (smart->critical_warning & 0x02) >> 1);
+		json_object_add_value_int(crt, "reliability_degraded", (smart->critical_warning & 0x04) >> 2);
+		json_object_add_value_int(crt, "ro", (smart->critical_warning & 0x08) >> 3);
+		json_object_add_value_int(crt, "vmbu_failed", (smart->critical_warning & 0x10) >> 4);
+		json_object_add_value_int(crt, "pmr_ro", (smart->critical_warning & 0x20) >> 5);
+
+		json_object_add_value_object(root, "critical_warning", crt);
+	} else
+		json_object_add_value_int(root, "critical_warning",
+			smart->critical_warning);
+
 	json_object_add_value_int(root, "temperature", temperature);
 	json_object_add_value_int(root, "avail_spare", smart->avail_spare);
 	json_object_add_value_int(root, "spare_thresh", smart->spare_thresh);
@@ -3400,16 +3415,26 @@ void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
 	/* convert temperature from Kelvin to Celsius */
 	int temperature = ((smart->temperature[1] << 8) |
 			    smart->temperature[0]) - 273;
-	int i;
+	int i, human = flags & VERBOSE;
 
 	if (flags & BINARY)
 		return d_raw((unsigned char *)smart, sizeof(*smart));
 	else if (flags & JSON)
-		return json_smart_log(smart, nsid);
+		return json_smart_log(smart, nsid, flags);
 
 	printf("Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
 	printf("critical_warning			: %#x\n",
 		smart->critical_warning);
+
+	if (human) {
+		printf("      Available Spare[0]             : %d\n", smart->critical_warning & 0x01);
+		printf("      Temp. Threshold[1]             : %d\n", (smart->critical_warning & 0x02) >> 1);
+		printf("      NVM subsystem Reliability[2]   : %d\n", (smart->critical_warning & 0x04) >> 2);
+		printf("      Read-only[3]                   : %d\n", (smart->critical_warning & 0x08) >> 3);
+		printf("      Volatile mem. backup failed[4] : %d\n", (smart->critical_warning & 0x10) >> 4);
+		printf("      Persistent Mem. RO[5]          : %d\n", (smart->critical_warning & 0x20) >> 5);
+	}
+
 	printf("temperature				: %d C\n",
 		temperature);
 	printf("available_spare				: %u%%\n",
diff --git a/nvme.c b/nvme.c
index 3b386bc..dd3ab58 100644
--- a/nvme.c
+++ b/nvme.c
@@ -218,6 +218,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
 			"(default) or binary.";
 	const char *namespace = "(optional) desired namespace";
 	const char *raw = "output in binary format";
+	const char *human_readable = "show info in readable format";
 	enum nvme_print_flags flags;
 	int err, fd;
 
@@ -225,6 +226,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
 		__u32 namespace_id;
 		int   raw_binary;
 		char *output_format;
+		int   human_readable;
 	};
 
 	struct config cfg = {
@@ -234,9 +236,10 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
 
 
 	OPT_ARGS(opts) = {
-		OPT_UINT("namespace-id", 'n', &cfg.namespace_id,  namespace),
-		OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
-		OPT_FLAG("raw-binary",   'b', &cfg.raw_binary,    raw),
+		OPT_UINT("namespace-id",   'n', &cfg.namespace_id,   namespace),
+		OPT_FMT("output-format",   'o', &cfg.output_format,  output_format),
+		OPT_FLAG("raw-binary",     'b', &cfg.raw_binary,     raw),
+		OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
 		OPT_END()
 	};
 
@@ -249,6 +252,8 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
 		goto close_fd;
 	if (cfg.raw_binary)
 		flags = BINARY;
+	if (cfg.human_readable)
+		flags |= VERBOSE;
 
 	err = nvme_smart_log(fd, cfg.namespace_id, &smart_log);
 	if (!err)
-- 
2.13.7

