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
next prev 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