All of 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.