Linux-NVME Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: hare@suse.de (Hannes Reinecke)
Subject: [PATCH 5/6] nvme-cli: Implement ana log page support
Date: Fri, 27 Jul 2018 12:26:31 +0200	[thread overview]
Message-ID: <20180727102632.32455-6-hare@suse.de> (raw)
In-Reply-To: <20180727102632.32455-1-hare@suse.de>

Signed-off-by: Hannes Reinecke <hare at suse.com>
---
 Documentation/nvme-ana-log.txt | 62 ++++++++++++++++++++++++++++++
 linux/nvme.h                   | 19 ++++++++++
 nvme-builtin.h                 |  1 +
 nvme-ioctl.c                   |  9 +++++
 nvme-ioctl.h                   |  2 +
 nvme-print.c                   | 86 ++++++++++++++++++++++++++++++++++++++++++
 nvme-print.h                   |  2 +
 nvme.c                         | 70 ++++++++++++++++++++++++++++++++++
 8 files changed, 251 insertions(+)
 create mode 100644 Documentation/nvme-ana-log.txt

diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt
new file mode 100644
index 0000000..6ef33e7
--- /dev/null
+++ b/Documentation/nvme-ana-log.txt
@@ -0,0 +1,62 @@
+nvme-ana-log(1)
+===============
+
+NAME
+----
+nvme-ana-log - Send NVME ANA log page request, return result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme ana-log' <device> [--log-size=<size> | -l <size> ]
+			[--raw-binary | -b ]
+			[--output-format=<fmt> | -o <fmt> ]
+
+DESCRIPTION
+-----------
+Retrieves NVMe Asymmetric Namespace Access (ANA) log page from and
+NVMe device and prints the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned ANA log struct may be returned in one of several
+ways depending on the option flags; the structure may be parsed by the
+program and printed in readable format or the raw buffer may be printed to
+stdout for another program to parse.
+
+OPTIONS
+-------
+-l <size>::
+--log-size=<size>::
+	Specify the size of the ANA log buffer.
+
+-b::
+--raw-binary::
+	Print the raw error log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+	Set the reporting format to 'normal', 'json', or 'binary'.
+	Only one output formath can be used at a time.
+
+EXAMPLES
+--------
+* Get the ANA log and print it in a humen readable format:
+*
+------------
+# nvme ana-log /dev/nvme0
+------------
++
+
+* Print the raw output to a file:
++
+------------
+# nvme ana-log /dev/nvme0 --raw-binary > ana_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/linux/nvme.h b/linux/nvme.h
index 55a197b..645e171 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -889,6 +889,7 @@ enum {
 	NVME_LOG_TELEMETRY_HOST = 0x07,
 	NVME_LOG_TELEMETRY_CTRL = 0x08,
 	NVME_LOG_ENDURANCE_GROUP = 0x09,
+	NVME_LOG_ANA		= 0x0c,
 	NVME_LOG_DISC		= 0x70,
 	NVME_LOG_RESERVATION	= 0x80,
 	NVME_LOG_SANITIZE	= 0x81,
@@ -901,6 +902,7 @@ enum {
 	NVME_NO_LOG_LSP       = 0x0,
 	NVME_NO_LOG_LPO       = 0x0,
 	NVME_TELEM_LSP_CREATE = 0x1,
+	NVME_ANA_LSP_RGO      = 0x1,
 };
 
 /* Sanitize and Sanitize Monitor/Log */
@@ -1085,6 +1087,23 @@ struct nvme_sanitize_log_page {
 	__le32			est_crypto_erase_time;
 };
 
+/* Asymmetric Namespace Access Log Page */
+struct nvme_ana_group_descriptor {
+	__le32			groupid;
+	__le32			nsid_num;
+	__le64			change_count;
+	__u8			ana_state;
+	__u8			resv1[7];
+	__le32			nsid[0];
+};
+
+struct nvme_ana_log_page {
+	__le64			change_count;
+	__le16			grpid_num;
+	__le16			resv[3];
+	struct nvme_ana_group_descriptor desc[0];
+};
+
 /*
  * Fabrics subcommands.
  */
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 2c26d57..df3eb4f 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -28,6 +28,7 @@ COMMAND_LIST(
 	ENTRY("error-log", "Retrieve Error Log, show it", get_error_log)
 	ENTRY("effects-log", "Retrieve Command Effects Log, show it", get_effects_log)
 	ENTRY("endurance-log", "Retrieve Endurance Group Log, show it", get_endurance_log)
+	ENTRY("ana-log", "Retrieve ANA Log, show it", ana_log)
 	ENTRY("get-feature", "Get feature and show the resulting value", get_feature)
 	ENTRY("device-self-test", "Perform the necessary tests to observe the performance", device_self_test)
 	ENTRY("self-test-log", "Retrieve the SELF-TEST Log, show it", self_test_log)
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 9cf2a33..f88909d 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -488,6 +488,15 @@ int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
 	return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, sizeof(*sanitize_log), sanitize_log);
 }
 
+int nvme_ana_log(int fd, bool rgo, struct nvme_ana_log_page *ana_log,
+		 ssize_t ana_log_size)
+{
+	return nvme_get_log13(fd, 0, NVME_LOG_ANA,
+			      rgo ? NVME_ANA_LSP_RGO : NVME_NO_LOG_LSP,
+			      NVME_NO_LOG_LPO, 0, 1,
+			      ana_log_size, ana_log);
+}
+
 int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
 		 __u32 cdw12, __u32 data_len, void *data, __u32 *result)
 {
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index b34f5de..9527cc3 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -97,6 +97,8 @@ int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
 int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
 int nvme_endurance_log(int fd, __u16 group_id,
 		       struct nvme_endurance_group_log *endurance_log);
+int nvme_ana_log(int fd, bool rgo, struct nvme_ana_log_page *ana_log,
+		 ssize_t ana_log_size);
 
 int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10,
 		 __u32 cdw11, __u32 cdw12, __u32 data_len, void *data,
diff --git a/nvme-print.c b/nvme-print.c
index e4c90bf..487ea44 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -1508,6 +1508,45 @@ void show_sanitize_log(struct nvme_sanitize_log_page *sanitize, unsigned int mod
 	printf("Estimated Time For Crypto Erase               :  %u\n", le32_to_cpu(sanitize->est_crypto_erase_time));
 }
 
+static char *nvme_ana_state_to_string(uint8_t ana_state)
+{
+	switch (ana_state & 0x0f) {
+	case 0x1: return "optimized";
+	case 0x2: return "non-optimized";
+	case 0x3: return "inaccessible";
+	case 0x4: return "persistent-loss";
+	case 0xf: return "change-state";
+	default: return "reserved";
+	}
+}
+
+void show_ana_log(struct nvme_ana_log_page *ana, const char *devname)
+{
+	int grpid_num = le16_to_cpu(ana->grpid_num), i, j;
+	unsigned char *p;
+
+	printf("ANA Log page for device:%s\n", devname);
+	printf("desc_num : %d\n", grpid_num);
+	printf("chgcnt   : %"PRIu64"\n",
+	       (uint64_t)le64_to_cpu(ana->change_count));
+	p = (unsigned char *)&ana->desc[0];
+	for (i = 0; i < grpid_num; i++) {
+		struct nvme_ana_group_descriptor *desc =
+			(struct nvme_ana_group_descriptor *)p;
+		int nsid_num = le32_to_cpu(desc->nsid_num);
+		printf(" desc[%d] :\n", i);
+		printf("  groupid  : %x\n", le32_to_cpu(desc->groupid));
+		printf("  nsid_num : %d\n", nsid_num);
+		printf("  chgcnt   : %"PRId64"\n",
+		       (uint64_t)le64_to_cpu(desc->change_count));
+		printf("  state    : %s\n",
+		       nvme_ana_state_to_string(desc->ana_state));
+		for (j = 0; j < nsid_num; j++)
+			printf("    nsid[%d] : %x\n", j, le32_to_cpu(desc->nsid[j]));
+		p += sizeof(*desc) + nsid_num * 4;
+	}
+}
+
 char *nvme_feature_to_string(int feature)
 {
 	switch (feature) {
@@ -2571,6 +2610,53 @@ void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log, const char *
 	json_free_object(root);
 }
 
+void json_ana_log(struct nvme_ana_log_page *ana_log)
+{
+	struct json_object *root;
+	struct json_array *ags;
+	unsigned char *p;
+	int grpid_num = le32_to_cpu(ana_log->grpid_num);
+	int i, j;
+
+	root = json_create_object();
+
+	json_object_add_value_int(root, "chgcnt", le64_to_cpu(ana_log->change_count));
+	json_object_add_value_int(root, "desc_num", grpid_num);
+	ags = json_create_array();
+	p = (unsigned char *)&ana_log->desc[0];
+	for (i = 0; i < grpid_num; i++) {
+		struct nvme_ana_group_descriptor *desc =
+			(struct nvme_ana_group_descriptor *)p;
+		struct json_object *ag = json_create_object();
+		struct json_array *nsids;
+		int nsid_num = le32_to_cpu(desc->nsid_num);
+
+		json_object_add_value_int(ag, "groupid", le32_to_cpu(desc->groupid));
+		json_object_add_value_int(ag, "nsid_num", nsid_num);
+		json_object_add_value_int(ag, "chgcnt", le64_to_cpu(desc->change_count));
+		json_object_add_value_string(ag, "state",
+			nvme_ana_state_to_string(desc->ana_state));
+
+		nsids = json_create_array();
+		for (j = 0; j < nsid_num; j++) {
+			struct json_object *nsid = json_create_object();
+
+			json_object_add_value_int(nsid, "nsid", desc->nsid[j]);
+			json_array_add_value_object(nsids, nsid);
+		}
+		if (j)
+			json_object_add_value_array(ag, "nsids", nsids);
+		json_array_add_value_object(ags, ag);
+
+		p += sizeof(*desc) + nsid_num * 4;
+	}
+	if (i)
+		json_object_add_value_array(root, "group_descriptors", ags);
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
 static void show_nvme_subsystem(struct subsys_list_item *item)
 {
 	int i;
diff --git a/nvme-print.h b/nvme-print.h
index da287c2..b3d16dc 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -31,6 +31,7 @@ void show_changed_ns_list_log(struct nvme_changed_ns_list_log *log, const char *
 void show_endurance_log(struct nvme_endurance_group_log *endurance_group,
 			__u16 group_id, const char *devname);
 void show_sanitize_log(struct nvme_sanitize_log_page *sanitize, unsigned int mode, const char *devname);
+void show_ana_log(struct nvme_ana_log_page *ana, const char *devname);
 void show_ctrl_registers(void *bar, unsigned int mode, bool fabrics);
 void show_single_property(int offset, uint64_t prop, int human);
 void show_nvme_id_ns_descs(void *data);
@@ -56,6 +57,7 @@ void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
 void json_changed_ns_list_log(struct nvme_changed_ns_list_log *log, const char *devname);
 void json_endurance_log(struct nvme_endurance_group_log *endurance_group,
 			__u16 group_id, const char *devname);
+void json_ana_log(struct nvme_ana_log_page *ana_log);
 void json_print_list_items(struct list_item *items, unsigned amnt);
 void json_nvme_id_ns_descs(void *data);
 void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
diff --git a/nvme.c b/nvme.c
index 74dfb61..e463efc 100644
--- a/nvme.c
+++ b/nvme.c
@@ -824,6 +824,76 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
 	return ret;
 }
 
+static int ana_log(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+	const char *desc = "Retrieve ANA log and show it.";
+	const char *raw_binary = "show infos in binary format";
+	const char *log_size = "Size of the ANA log page";
+	const char *rgo = "Retrieve ANA Group Descriptors only";
+	int fd;
+	int ret;
+	int fmt;
+	struct nvme_ana_log_page *ana_log;
+
+	struct config {
+		int   raw_binary;
+		char *output_format;
+		size_t log_size;
+		int rgo;
+	};
+
+	struct config cfg = {
+		.output_format = "normal",
+		.log_size = 4096,
+	};
+
+	const struct argconfig_commandline_options command_line_options[] = {
+		{"output-format", 'o', "FMT", CFG_STRING,   &cfg.output_format, required_argument, output_format},
+		{"raw-binary",    'b', "",    CFG_NONE,     &cfg.raw_binary,    no_argument,       raw_binary},
+		{"log-size",      'l', "NUM", CFG_POSITIVE, &cfg.log_size,    required_argument,  log_size},
+		{"groups-only",   'r', "",    CFG_NONE,     &cfg.rgo,         no_argument,        rgo},
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+	ana_log = calloc(cfg.log_size, sizeof(char));
+	if (!ana_log) {
+		fprintf(stderr, "could not allocate buffer for ANA log\n");
+		ret = ENOMEM;
+		goto close_fd;
+	}
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		ret = fmt;
+		goto close_fd_and_free;
+	}
+	if (cfg.raw_binary)
+		fmt = BINARY;
+
+	ret = nvme_ana_log(fd, cfg.rgo, ana_log, cfg.log_size);
+	if (!ret) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)ana_log, cfg.log_size);
+		else if (fmt == JSON)
+			json_ana_log(ana_log);
+		else
+			show_ana_log(ana_log, devicename);
+	}
+	else if (ret > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+	else
+		perror("ana status log");
+
+close_fd_and_free:
+	free(ana_log);
+ close_fd:
+	close(fd);
+
+	return ret;
+}
+
 static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
 	const char *desc = "Show controller list information for the subsystem the "\
-- 
2.13.7

  parent reply	other threads:[~2018-07-27 10:26 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-27 10:26 [PATCH 0/6] nvme-cli ANA update Hannes Reinecke
2018-07-27 10:26 ` [PATCH 1/6] nvme-discover: sanitize options Hannes Reinecke
2018-07-27 10:26 ` [PATCH 2/6] nvme-discover: Retry discovery log if the generation counter changes Hannes Reinecke
2018-07-27 10:26 ` [PATCH 3/6] nvme-cli: Add ANA support Hannes Reinecke
2018-07-27 10:26 ` [PATCH 4/6] nvme-list-subsys: Add device name argument and print out ANA state Hannes Reinecke
2018-07-27 10:26 ` Hannes Reinecke [this message]
2018-07-27 15:15   ` [PATCH 5/6] nvme-cli: Implement ana log page support Christoph Hellwig
2018-07-28 14:14     ` Hannes Reinecke
2018-07-28 14:46       ` Chaitanya Kulkarni
2018-07-29  8:56         ` Hannes Reinecke
2018-07-27 10:26 ` [PATCH 6/6] fabrics: display controller ID in discovery log output Hannes Reinecke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180727102632.32455-6-hare@suse.de \
    --to=hare@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox