linux-nvme.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V3 0/2] nvme-cli: add ana-log page support
@ 2018-08-02  3:28 Chaitanya Kulkarni
  2018-08-02  3:28 ` [PATCH V3 1/2] nvme-cli: add minimal " Chaitanya Kulkarni
  2018-08-02  3:28 ` [PATCH V3 2/2] nvme-cli: add ana-log documentation Chaitanya Kulkarni
  0 siblings, 2 replies; 6+ messages in thread
From: Chaitanya Kulkarni @ 2018-08-02  3:28 UTC (permalink / raw)


This patch series implements ANA-LOG-PAGE support for nvme-cli.

Regards,
Chaitanya

Changes since V2:-
1. Add CMIC and ANACAP decoding.
2. Incorporate comments from Hannes.

Changes since V1:-
1. Add JSON support.
2. Incorporate comments from Christoph.

Chaitanya Kulkarni (2):
  nvme-cli: add minimal ana-log page support
  nvme-cli: add ana-log documentation

 Documentation/nvme-ana-log.1    |  82 ++++
 Documentation/nvme-ana-log.html | 826 ++++++++++++++++++++++++++++++++
 Documentation/nvme-ana-log.txt  |  45 ++
 linux/nvme.h                    |  52 +-
 nvme-builtin.h                  |   1 +
 nvme-ioctl.c                    |   8 +
 nvme-ioctl.h                    |   1 +
 nvme-print.c                    | 170 ++++++-
 nvme-print.h                    |   2 +
 nvme.c                          |  77 +++
 10 files changed, 1257 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/nvme-ana-log.1
 create mode 100644 Documentation/nvme-ana-log.html
 create mode 100644 Documentation/nvme-ana-log.txt

-- 
2.17.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V3 1/2] nvme-cli: add minimal ana-log page support
  2018-08-02  3:28 [PATCH V3 0/2] nvme-cli: add ana-log page support Chaitanya Kulkarni
@ 2018-08-02  3:28 ` Chaitanya Kulkarni
  2018-08-03 10:18   ` Minwoo Im
  2018-08-03 11:59   ` Minwoo Im
  2018-08-02  3:28 ` [PATCH V3 2/2] nvme-cli: add ana-log documentation Chaitanya Kulkarni
  1 sibling, 2 replies; 6+ messages in thread
From: Chaitanya Kulkarni @ 2018-08-02  3:28 UTC (permalink / raw)


This patch adds a new command to retrieve the ANA Log page.
We update identify ctrl/ns data structure to support this command.
We also add ana based error codes and different identifiers to the
linux/nvme.h header file in order to support this command.

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
Signed-off-by: Hannes Reinecke <hare at suse.com>
---
 linux/nvme.h   |  52 +++++++++++++--
 nvme-builtin.h |   1 +
 nvme-ioctl.c   |   8 +++
 nvme-ioctl.h   |   1 +
 nvme-print.c   | 170 ++++++++++++++++++++++++++++++++++++++++++++++++-
 nvme-print.h   |   2 +
 nvme.c         |  77 ++++++++++++++++++++++
 7 files changed, 304 insertions(+), 7 deletions(-)

diff --git a/linux/nvme.h b/linux/nvme.h
index dc8ea89..ee6bcc6 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -241,7 +241,12 @@ struct nvme_id_ctrl {
 	__le32			hmminds;
 	__le16			hmmaxd;
 	__le16			nsetidmax;
-	__u8			rsvd340[172];
+	__u8			rsvd340[2];
+	__u8			anatt;
+	__u8			anacap;
+	__le32			anagrpmax;
+	__le32			nanagrpid;
+	__u8			rsvd352[160];
 	__u8			sqes;
 	__u8			cqes;
 	__le16			maxcmd;
@@ -257,7 +262,8 @@ struct nvme_id_ctrl {
 	__le16			acwu;
 	__u8			rsvd534[2];
 	__le32			sgls;
-	__u8			rsvd540[228];
+	__le32			mnan;
+	__u8			rsvd544[224];
 	char			subnqn[256];
 	__u8			rsvd1024[768];
 	__le32			ioccsz;
@@ -317,7 +323,9 @@ struct nvme_id_ns {
 	__le16			nabspf;
 	__le16			noiob;
 	__u8			nvmcap[16];
-	__u8			rsvd64[36];
+	__u8			rsvd64[28];
+	__le32			anagrpid;
+	__u8			rsvd96[4];
 	__le16			nvmsetid;
 	__le16			endgid;
 	__u8			nguid[16];
@@ -516,6 +524,32 @@ struct nvme_effects_log {
 	__u8   resv[2048];
 };
 
+enum nvme_ana_state {
+	NVME_ANA_OPTIMIZED		= 0x01,
+	NVME_ANA_NONOPTIMIZED		= 0x02,
+	NVME_ANA_INACCESSIBLE		= 0x03,
+	NVME_ANA_PERSISTENT_LOSS	= 0x04,
+	NVME_ANA_CHANGE			= 0x0f,
+};
+
+struct nvme_ana_group_desc {
+	__le32  grpid;
+	__le32  nnsids;
+	__le64  chgcnt;
+	__u8    state;
+	__u8    rsvd17[7];
+	__le32  nsids[];
+};
+
+/* flag for the log specific field of the ANA log */
+#define NVME_ANA_LOG_RGO   (1 << 0)
+
+struct nvme_ana_rsp_hdr {
+	__le64  chgcnt;
+	__le16  ngrps;
+	__le16  rsvd10[3];
+};
+
 enum {
 	NVME_SMART_CRIT_SPARE		= 1 << 0,
 	NVME_SMART_CRIT_TEMPERATURE	= 1 << 1,
@@ -531,6 +565,7 @@ enum {
 	NVME_AER_VS			= 7,
 	NVME_AER_NOTICE_NS_CHANGED	= 0x0002,
 	NVME_AER_NOTICE_FW_ACT_STARTING = 0x0102,
+	NVME_AER_NOTICE_ANA		= 0x03,
 };
 
 struct nvme_lba_range_type {
@@ -881,6 +916,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,
@@ -892,6 +928,7 @@ enum {
 enum {
 	NVME_NO_LOG_LSP       = 0x0,
 	NVME_NO_LOG_LPO       = 0x0,
+	NVME_LOG_ANA_LSP_RGO  = 0x1,
 	NVME_TELEM_LSP_CREATE = 0x1,
 };
 
@@ -1040,7 +1077,7 @@ struct nvme_get_log_page_command {
 	__u64			rsvd2[2];
 	union nvme_data_ptr	dptr;
 	__u8			lid;
-	__u8			rsvd10;
+	__u8			lsp;
 	__le16			numdl;
 	__le16			numdu;
 	__u16			rsvd11;
@@ -1354,6 +1391,13 @@ enum {
 	NVME_SC_ACCESS_DENIED		= 0x286,
 	NVME_SC_UNWRITTEN_BLOCK		= 0x287,
 
+	/*
+	 * Path-related Errors:
+	 */
+	NVME_SC_ANA_PERSISTENT_LOSS	= 0x301,
+	NVME_SC_ANA_INACCESSIBLE	= 0x302,
+	NVME_SC_ANA_TRANSITION		= 0x303,
+
 	NVME_SC_DNR			= 0x4000,
 };
 
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 2c26d57..f9e47b3 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -25,6 +25,7 @@ COMMAND_LIST(
 	ENTRY("fw-log", "Retrieve FW Log, show it", get_fw_log)
 	ENTRY("changed-ns-list-log", "Retrieve Changed Namespace List, show it", get_changed_ns_list_log)
 	ENTRY("smart-log", "Retrieve SMART Log, show it", get_smart_log)
+	ENTRY("ana-log", "Retrieve ANA Log, show it", get_ana_log)
 	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)
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 9cf2a33..d63c863 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -467,6 +467,14 @@ int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
 	return nvme_get_log(fd, nsid, NVME_LOG_SMART, sizeof(*smart_log), smart_log);
 }
 
+int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
+{
+	__u64 lpo = 0;
+
+	return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_ANA, rgo, lpo, 0,
+			true, ana_log_len, ana_log);
+}
+
 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log)
 {
 	return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_DEVICE_SELF_TEST,
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index b34f5de..d3823a4 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -92,6 +92,7 @@ int nvme_changed_ns_list_log(int fd,
 		struct nvme_changed_ns_list_log *changed_ns_list_log);
 int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log);
 int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
+int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
 int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
 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);
diff --git a/nvme-print.c b/nvme-print.c
index daf2929..cc9a567 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -8,6 +8,23 @@
 #include "nvme-models.h"
 #include "suffix.h"
 
+static const char *nvme_ana_state_to_string(enum nvme_ana_state state)
+{
+	switch (state) {
+	case NVME_ANA_OPTIMIZED:
+		return "optimized";
+	case NVME_ANA_NONOPTIMIZED:
+		return "non-optimized";
+	case NVME_ANA_INACCESSIBLE:
+		return "inaccessible";
+	case NVME_ANA_PERSISTENT_LOSS:
+		return "persistent-loss";
+	case NVME_ANA_CHANGE:
+		return "change";
+	}
+	return "invalid state";
+}
+
 static long double int128_to_double(__u8 *data)
 {
 	int i;
@@ -78,12 +95,15 @@ static void format(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
 
 static void show_nvme_id_ctrl_cmic(__u8 cmic)
 {
-	__u8 rsvd = (cmic & 0xF8) >> 3;
+	__u8 rsvd = (cmic & 0xF0) >> 4;
+	__u8 ana = (cmic & 0x8) >> 3;
 	__u8 sriov = (cmic & 0x4) >> 2;
 	__u8 mctl = (cmic & 0x2) >> 1;
 	__u8 mp = cmic & 0x1;
+
 	if (rsvd)
-		printf("  [7:3] : %#x\tReserved\n", rsvd);
+		printf("  [7:4] : %#x\tReserved\n", rsvd);
+	printf("  [3:3] : %#x\tANA %ssupported\n", ana, ana ? "" : "not ");
 	printf("  [2:2] : %#x\t%s\n", sriov, sriov ? "SR-IOV" : "PCI");
 	printf("  [1:1] : %#x\t%s Controller\n",
 		mctl, mctl ? "Multi" : "Single");
@@ -283,6 +303,37 @@ static void show_nvme_id_ctrl_sanicap(__le32 ctrl_sanicap)
 	printf("\n");
 }
 
+
+static void show_nvme_id_ctrl_anacap(__u8 anacap)
+{
+	__u8 nz = (anacap & 0x80) >> 7;
+	__u8 grpid_change = (anacap & 0x40) >> 6;
+	__u8 rsvd = (anacap & 0x20) >> 5;
+	__u8 ana_change = (anacap & 0x10) >> 4;
+	__u8 ana_persist_loss = (anacap & 0x08) >> 3;
+	__u8 ana_inaccessible = (anacap & 0x04) >> 2;
+	__u8 ana_nonopt = (anacap & 0x02) >> 1;
+	__u8 ana_opt = (anacap & 0x01);
+
+	printf("  [7:7] : %#x\tNon-zero group ID %sSupported\n",
+	       nz, nz ? "" : "Not ");
+	printf("  [6:6] : %#x\tGroup ID does %schange\n",
+	       grpid_change, grpid_change ? "" : "not ");
+	if (rsvd)
+		printf(" [5:5] : %#x\tReserved\n", rsvd);
+	printf("  [4:4] : %#x\tANA Change state %sSupported\n",
+		ana_change, ana_change ? "" : "Not ");
+	printf("  [3:3] : %#x\tANA Persistent Loss state %sSupported\n",
+		ana_persist_loss, ana_persist_loss ? "" : "Not ");
+	printf("  [2:2] : %#x\tANA Inaccessible state %sSupported\n",
+		ana_inaccessible, ana_inaccessible ? "" : "Not ");
+	printf("  [1:1] : %#x\tANA Non-optimized state %sSupported\n",
+		ana_nonopt, ana_nonopt ? "" : "Not ");
+	printf("  [0:0] : %#x\tANA Optimized state %sSupported\n",
+		ana_opt, ana_opt ? "" : "Not ");
+	printf("\n");
+}
+
 static void show_nvme_id_ctrl_sqes(__u8 sqes)
 {
 	__u8 msqes = (sqes & 0xF0) >> 4;
@@ -645,6 +696,7 @@ void show_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
 	printf("noiob   : %d\n", le16_to_cpu(ns->noiob));
 	printf("nvmcap  : %.0Lf\n", int128_to_double(ns->nvmcap));
 	printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid));
+	printf("anagrpid: %d\n", le32_to_cpu(ns->anagrpid));
 	printf("endgid  : %d\n", le16_to_cpu(ns->endgid));
 
 	printf("nguid   : ");
@@ -924,6 +976,12 @@ void __show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*ve
 	printf("hmminds   : %d\n", le32_to_cpu(ctrl->hmminds));
 	printf("hmmaxd    : %d\n", le16_to_cpu(ctrl->hmmaxd));
 	printf("nsetidmax : %d\n", le16_to_cpu(ctrl->nsetidmax));
+	printf("anatt     : %d\n", ctrl->anatt);
+	printf("anacap    : %d\n", ctrl->anacap);
+	if (human)
+		show_nvme_id_ctrl_anacap(ctrl->anacap);
+	printf("anagrpmax : %d\n", ctrl->anagrpmax);
+	printf("nanagrpid : %d\n", le32_to_cpu(ctrl->nanagrpid));
 	printf("sqes      : %#x\n", ctrl->sqes);
 	if (human)
 		show_nvme_id_ctrl_sqes(ctrl->sqes);
@@ -951,6 +1009,7 @@ void __show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*ve
 		show_nvme_id_ctrl_nvscc(ctrl->nvscc);
 	printf("acwu      : %d\n", le16_to_cpu(ctrl->acwu));
 	printf("sgls      : %x\n", le32_to_cpu(ctrl->sgls));
+	printf("mnan      : %d\n", le32_to_cpu(ctrl->mnan));
 	if (human)
 		show_nvme_id_ctrl_sgls(ctrl->sgls);
 	printf("subnqn    : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn);
@@ -1325,6 +1384,44 @@ void show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char
 	printf("Thermal Management T2 Total Time    : %u\n", le32_to_cpu(smart->thm_temp2_total_time));
 }
 
+void show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
+{
+	int offset = sizeof(struct nvme_ana_rsp_hdr);
+	struct nvme_ana_rsp_hdr *hdr = ana_log;
+	struct nvme_ana_group_desc *desc;
+	size_t nsid_buf_size;
+	void *base = ana_log;
+	__u32 nr_nsids;
+	int i;
+	int j;
+
+	printf("Asynchronous Namespace Access Log for NVMe device: %s\n",
+			devname);
+	printf("ANA LOG HEADER :-\n");
+	printf("chgcnt	:	%"PRIu64"\n",
+			(uint64_t)le64_to_cpu(hdr->chgcnt));
+	printf("ngrps	:	%u\n", le16_to_cpu(hdr->ngrps));
+	printf("ANA Log Desc :-\n");
+
+	for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) {
+		desc = base + offset;
+		nr_nsids = le32_to_cpu(desc->nnsids);
+		nsid_buf_size = nr_nsids * sizeof(__le32);
+
+		offset += sizeof(*desc);
+		printf("grpid	:	%u\n", le32_to_cpu(desc->grpid));
+		printf("nnsids	:	%u\n", le32_to_cpu(desc->nnsids));
+		printf("chgcnt	:	%llu\n", le64_to_cpu(desc->chgcnt));
+		printf("state	:	%s\n",
+				nvme_ana_state_to_string(desc->state));
+		for (j = 0; j < le32_to_cpu(desc->nnsids); j++)
+			printf("	nsid	:	%u\n",
+					le32_to_cpu(desc->nsids[j]));
+		printf("\n");
+		offset += nsid_buf_size;
+	}
+}
+
 void show_self_test_log(struct nvme_self_test_log *self_test, const char *devname)
 {
 	int i, temp;
@@ -1550,7 +1647,7 @@ char *nvme_status_to_string(__u32 status)
 	case NVME_SC_SANITIZE_IN_PROGRESS:	return "SANITIZE_IN_PROGRESS: The requested function is prohibited while a sanitize operation is in progress";
 	case NVME_SC_LBA_RANGE:			return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace";
 	case NVME_SC_CAP_EXCEEDED:		return "CAP_EXCEEDED: The execution of the command has caused the capacity of the namespace to be exceeded";
-	case NVME_SC_NS_NOT_READY:		return "NS_NOT_READY: The namespace is not ready to be accessed";
+	case NVME_SC_NS_NOT_READY:		return "NS_NOT_READY: The namespace is not ready to be accessed as a result of a condition other than a condition that is reported as an Asymmetric Namespace Access condition";
 	case NVME_SC_RESERVATION_CONFLICT:	return "RESERVATION_CONFLICT: The command was aborted due to a conflict with a reservation held on the accessed namespace";
 	case NVME_SC_CQ_INVALID:		return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist";
 	case NVME_SC_QID_INVALID:		return "QID_INVALID: The creation of the I/O Completion Queue failed due to an invalid queue identifier specified as part of the command. An invalid queue identifier is one that is currently in use or one that is outside the range supported by the controller";
@@ -1590,6 +1687,9 @@ char *nvme_status_to_string(__u32 status)
 	case NVME_SC_COMPARE_FAILED:		return "COMPARE_FAILED: The command failed due to a miscompare during a Compare command";
 	case NVME_SC_ACCESS_DENIED:		return "ACCESS_DENIED: Access to the namespace and/or LBA range is denied due to lack of access rights";
 	case NVME_SC_UNWRITTEN_BLOCK:		return "UNWRITTEN_BLOCK: The command failed due to an attempt to read from an LBA range containing a deallocated or unwritten logical block";
+	case NVME_SC_ANA_PERSISTENT_LOSS:	return "Asymmetric Namespace Access Persistent Loss";
+	case NVME_SC_ANA_INACCESSIBLE:		return "Asymmetric Namespace Access Inaccessible";
+	case NVME_SC_ANA_TRANSITION:		return "Asymmetric Namespace Access Transition";
 	default:				return "Unknown";
 	}
 }
@@ -2030,6 +2130,7 @@ void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
 	json_object_add_value_int(root, "noiob", le16_to_cpu(ns->noiob));
 	json_object_add_value_float(root, "nvmcap", nvmcap);
 	json_object_add_value_int(root, "nvmsetid", le16_to_cpu(ns->nvmsetid));
+	json_object_add_value_int(root, "anagrpid", le32_to_cpu(ns->anagrpid));
 	json_object_add_value_int(root, "endgid", le16_to_cpu(ns->endgid));
 
 	memset(eui64, 0, sizeof(eui64_buf));
@@ -2126,6 +2227,10 @@ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*vs)(
 	json_object_add_value_int(root, "hmminds", le32_to_cpu(ctrl->hmminds));
 	json_object_add_value_int(root, "hmmaxd", le16_to_cpu(ctrl->hmmaxd));
 	json_object_add_value_int(root, "nsetidmax", le16_to_cpu(ctrl->nsetidmax));
+	json_object_add_value_int(root, "anatt",ctrl->anatt);
+	json_object_add_value_int(root, "anacap", ctrl->anacap);
+	json_object_add_value_int(root, "anagrpmax", le32_to_cpu(ctrl->anagrpmax));
+	json_object_add_value_int(root, "nanagrpid", le32_to_cpu(ctrl->nanagrpid));
 	json_object_add_value_int(root, "sqes", ctrl->sqes);
 	json_object_add_value_int(root, "cqes", ctrl->cqes);
 	json_object_add_value_int(root, "maxcmd", le16_to_cpu(ctrl->maxcmd));
@@ -2432,6 +2537,65 @@ void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char
 	json_free_object(root);
 }
 
+void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
+{
+	int offset = sizeof(struct nvme_ana_rsp_hdr);
+	struct nvme_ana_rsp_hdr *hdr = ana_log;
+	struct nvme_ana_group_desc *ana_desc;
+	struct json_array *desc_list;
+	struct json_array *ns_list;
+	struct json_object *desc;
+	struct json_object *nsid;
+	struct json_object *root;
+	size_t nsid_buf_size;
+	void *base = ana_log;
+	__u32 nr_nsids;
+	int i;
+	int j;
+
+	root = json_create_object();
+	json_object_add_value_string(root,
+			"Asynchronous Namespace Access Log for NVMe device:",
+			devname);
+	json_object_add_value_uint(root, "chgcnt",
+			(uint64_t)le64_to_cpu(hdr->chgcnt));
+	json_object_add_value_uint(root, "ngrps", le16_to_cpu(hdr->ngrps));
+
+	desc_list = json_create_array();
+	for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) {
+		desc = json_create_object();
+		ana_desc = base + offset;
+		nr_nsids = le32_to_cpu(ana_desc->nnsids);
+		nsid_buf_size = nr_nsids * sizeof(__le32);
+
+		offset += sizeof(*ana_desc);
+		json_object_add_value_uint(desc, "grpid",
+				le32_to_cpu(ana_desc->grpid));
+		json_object_add_value_uint(desc, "nnsids",
+				le32_to_cpu(ana_desc->nnsids));
+		json_object_add_value_uint(desc, "chgcnt",
+				le64_to_cpu(ana_desc->chgcnt));
+		json_object_add_value_string(desc, "state",
+				nvme_ana_state_to_string(ana_desc->state));
+
+		ns_list = json_create_array();
+		for (j = 0; j < le32_to_cpu(ana_desc->nnsids); j++) {
+			nsid = json_create_object();
+			json_object_add_value_uint(nsid, "nsid",
+					le32_to_cpu(ana_desc->nsids[j]));
+			json_array_add_value_object(ns_list, nsid);
+		}
+		json_object_add_value_array(desc, "NSIDS", ns_list);
+		offset += nsid_buf_size;
+		json_array_add_value_object(desc_list, desc);
+	}
+
+	json_object_add_value_array(root, "ANA DESC LIST ", desc_list);
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
 void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname)
 {
 	struct json_object *root;
diff --git a/nvme-print.h b/nvme-print.h
index da287c2..367347c 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -24,6 +24,7 @@ void show_nvme_resv_report(struct nvme_reservation_status *status, int bytes, __
 void show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges);
 void show_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname);
 void show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname);
+void show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname);
 void show_self_test_log(struct nvme_self_test_log *self_test, const char *devname);
 void show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
 void show_effects_log(struct nvme_effects_log_page *effects, unsigned int flags);
@@ -50,6 +51,7 @@ void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int flags);
 void json_nvme_resv_report(struct nvme_reservation_status *status, int bytes, __u32 cdw11);
 void json_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname);
 void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname);
+void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname);
 void json_effects_log(struct nvme_effects_log_page *effects_log, const char *devname);
 void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log, const char *devname);
 void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
diff --git a/nvme.c b/nvme.c
index 4815caa..2c4b1aa 100644
--- a/nvme.c
+++ b/nvme.c
@@ -224,7 +224,84 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug
 
  close_fd:
 	close(fd);
+	return err;
+}
+
+static int get_ana_log(int argc, char **argv, struct command *cmd,
+		struct plugin *plugin)
+{
+	const char *desc = "Retrieve ANA log for the given device" \
+			"in either decoded format "\
+			"(default) or binary.";
+	const char *raw = "output in binary format";
+	void *ana_log;
+	int err, fmt, fd;
+	int groups = 0; /* Right now get all the per ANA group NSIDS */
+	size_t ana_log_len;
+	struct nvme_id_ctrl ctrl;
+
+	struct config {
+		int   raw_binary;
+		char *output_format;
+	};
+
+	struct config cfg = {
+		.output_format = "normal",
+	};
+
+	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},
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, NULL, 0);
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
 
+	if (cfg.raw_binary)
+		fmt = BINARY;
+
+	memset(&ctrl, 0, sizeof (struct nvme_id_ctrl));
+	err = nvme_identify_ctrl(fd, &ctrl);
+	if (err) {
+		fprintf(stderr, "ERROR : nvme_identify_ctrl() failed 0x%x\n",
+				err);
+		goto close_fd;
+	}
+	ana_log_len = sizeof(struct nvme_ana_rsp_hdr) +
+		le32_to_cpu(ctrl.nanagrpid) * sizeof(struct nvme_ana_group_desc);
+	if (!(ctrl.anacap & (1 << 6)))
+		ana_log_len += ctrl.mnan * sizeof(__le32);
+
+	ana_log = malloc(ana_log_len);
+	if (!ana_log) {
+		perror("malloc : ");
+		err = -ENOMEM;
+		goto close_fd;
+	}
+
+	err = nvme_ana_log(fd, ana_log, ana_log_len, groups ? NVME_ANA_LOG_RGO : 0);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)ana_log, ana_log_len);
+		else if (fmt == JSON)
+			json_ana_log(ana_log, devicename);
+		else
+			show_ana_log(ana_log, devicename);
+	} else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+	else
+		perror("ana-log");
+	free(ana_log);
+close_fd:
+	close(fd);
 	return err;
 }
 
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH V3 2/2] nvme-cli: add ana-log documentation
  2018-08-02  3:28 [PATCH V3 0/2] nvme-cli: add ana-log page support Chaitanya Kulkarni
  2018-08-02  3:28 ` [PATCH V3 1/2] nvme-cli: add minimal " Chaitanya Kulkarni
@ 2018-08-02  3:28 ` Chaitanya Kulkarni
  2018-08-03 11:59   ` Minwoo Im
  1 sibling, 1 reply; 6+ messages in thread
From: Chaitanya Kulkarni @ 2018-08-02  3:28 UTC (permalink / raw)


Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
Reviewed-by: Hannes Reinecke <hare at suse.com>
---
 Documentation/nvme-ana-log.1    |  82 ++++
 Documentation/nvme-ana-log.html | 826 ++++++++++++++++++++++++++++++++
 Documentation/nvme-ana-log.txt  |  45 ++
 3 files changed, 953 insertions(+)
 create mode 100644 Documentation/nvme-ana-log.1
 create mode 100644 Documentation/nvme-ana-log.html
 create mode 100644 Documentation/nvme-ana-log.txt

diff --git a/Documentation/nvme-ana-log.1 b/Documentation/nvme-ana-log.1
new file mode 100644
index 0000000..6baea09
--- /dev/null
+++ b/Documentation/nvme-ana-log.1
@@ -0,0 +1,82 @@
+'\" t
+.\"     Title: nvme-ana-log
+.\"    Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\"      Date: 07/25/2018
+.\"    Manual: NVMe Manual
+.\"    Source: NVMe
+.\"  Language: English
+.\"
+.TH "NVME\-ANA\-LOG" "1" "07/25/2018" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-ana-log \- Send NVMe ANA log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ana\-log\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned ANA log structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw ANA log buffer to stdout\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the ANA log page in a human readable format:
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ana\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-ana-log.html b/Documentation/nvme-ana-log.html
new file mode 100644
index 0000000..f24e13f
--- /dev/null
+++ b/Documentation/nvme-ana-log.html
@@ -0,0 +1,826 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-ana-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+  font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+  font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+  margin: 1em 5% 1em 5%;
+}
+
+a {
+  color: blue;
+  text-decoration: underline;
+}
+a:visited {
+  color: fuchsia;
+}
+
+em {
+  font-style: italic;
+  color: navy;
+}
+
+strong {
+  font-weight: bold;
+  color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+  color: #527bbd;
+  margin-top: 1.2em;
+  margin-bottom: 0.5em;
+  line-height: 1.3;
+}
+
+h1, h2, h3 {
+  border-bottom: 2px solid silver;
+}
+h2 {
+  padding-top: 0.5em;
+}
+h3 {
+  float: left;
+}
+h3 + * {
+  clear: left;
+}
+h5 {
+  font-size: 1.0em;
+}
+
+div.sectionbody {
+  margin-left: 0;
+}
+
+hr {
+  border: 1px solid silver;
+}
+
+p {
+  margin-top: 0.5em;
+  margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+  margin-top: 0;
+}
+ul > li     { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+  font-family: "Courier New", Courier, monospace;
+  font-size: inherit;
+  color: navy;
+  padding: 0;
+  margin: 0;
+}
+
+
+#author {
+  color: #527bbd;
+  font-weight: bold;
+  font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+  font-size: small;
+  border-top: 2px solid silver;
+  padding-top: 0.5em;
+  margin-top: 4.0em;
+}
+#footer-text {
+  float: left;
+  padding-bottom: 0.5em;
+}
+#footer-badges {
+  float: right;
+  padding-bottom: 0.5em;
+}
+
+#preamble {
+  margin-top: 1.5em;
+  margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.admonitionblock {
+  margin-top: 2.0em;
+  margin-bottom: 2.0em;
+  margin-right: 10%;
+  color: #606060;
+}
+
+div.content { /* Block element content. */
+  padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+  color: #527bbd;
+  font-weight: bold;
+  text-align: left;
+  margin-top: 1.0em;
+  margin-bottom: 0.5em;
+}
+div.title + * {
+  margin-top: 0;
+}
+
+td div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content div.title:first-child {
+  margin-top: 0.0em;
+}
+div.content + div.title {
+  margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+  background: #ffffee;
+  border: 1px solid #dddddd;
+  border-left: 4px solid #f0f0f0;
+  padding: 0.5em;
+}
+
+div.listingblock > div.content {
+  border: 1px solid #dddddd;
+  border-left: 5px solid #f0f0f0;
+  background: #f8f8f8;
+  padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+  padding-left: 1.0em;
+  margin-left: 1.0em;
+  margin-right: 10%;
+  border-left: 5px solid #f0f0f0;
+  color: #888;
+}
+
+div.quoteblock > div.attribution {
+  padding-top: 0.5em;
+  text-align: right;
+}
+
+div.verseblock > pre.content {
+  font-family: inherit;
+  font-size: inherit;
+}
+div.verseblock > div.attribution {
+  padding-top: 0.75em;
+  text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+  text-align: left;
+}
+
+div.admonitionblock .icon {
+  vertical-align: top;
+  font-size: 1.1em;
+  font-weight: bold;
+  text-decoration: underline;
+  color: #527bbd;
+  padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+  padding-left: 0.5em;
+  border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+  border-left: 3px solid #dddddd;
+  padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+dt {
+  margin-top: 0.5em;
+  margin-bottom: 0;
+  font-style: normal;
+  color: navy;
+}
+dd > *:first-child {
+  margin-top: 0.1em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+ol.arabic {
+  list-style-type: decimal;
+}
+ol.loweralpha {
+  list-style-type: lower-alpha;
+}
+ol.upperalpha {
+  list-style-type: upper-alpha;
+}
+ol.lowerroman {
+  list-style-type: lower-roman;
+}
+ol.upperroman {
+  list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+  margin-top: 0.1em;
+  margin-bottom: 0.1em;
+}
+
+tfoot {
+  font-weight: bold;
+}
+td > div.verse {
+  white-space: pre;
+}
+
+div.hdlist {
+  margin-top: 0.8em;
+  margin-bottom: 0.8em;
+}
+div.hdlist tr {
+  padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+  font-weight: bold;
+}
+td.hdlist1 {
+  vertical-align: top;
+  font-style: normal;
+  padding-right: 0.8em;
+  color: navy;
+}
+td.hdlist2 {
+  vertical-align: top;
+}
+div.hdlist.compact tr {
+  margin: 0;
+  padding-bottom: 0;
+}
+
+.comment {
+  background: yellow;
+}
+
+.footnote, .footnoteref {
+  font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+  vertical-align: super;
+}
+
+#footnotes {
+  margin: 20px 0 20px 0;
+  padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+  margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+  border: none;
+  border-top: 1px solid silver;
+  height: 1px;
+  text-align: left;
+  margin-left: 0;
+  width: 20%;
+  min-width: 100px;
+}
+
+div.colist td {
+  padding-right: 0.5em;
+  padding-bottom: 0.3em;
+  vertical-align: top;
+}
+div.colist td img {
+  margin-top: 0.3em;
+}
+
+ at media print {
+  #footer-badges { display: none; }
+}
+
+#toc {
+  margin-bottom: 2.5em;
+}
+
+#toctitle {
+  color: #527bbd;
+  font-size: 1.1em;
+  font-weight: bold;
+  margin-top: 1.0em;
+  margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+div.toclevel2 {
+  margin-left: 2em;
+  font-size: 0.9em;
+}
+div.toclevel3 {
+  margin-left: 4em;
+  font-size: 0.9em;
+}
+div.toclevel4 {
+  margin-left: 6em;
+  font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+div.tableblock > table {
+  border: 3px solid #527bbd;
+}
+thead, p.table.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.table {
+  margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+  border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+  border-left-style: none;
+  border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+  border-top-style: none;
+  border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+  margin-top: 1.0em;
+  margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+  font-weight: bold;
+  color: #527bbd;
+}
+p.tableblock {
+  margin-top: 0;
+}
+table.tableblock {
+  border-width: 3px;
+  border-spacing: 0px;
+  border-style: solid;
+  border-color: #527bbd;
+  border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+  border-width: 1px;
+  padding: 4px;
+  border-style: solid;
+  border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+  border-left-style: hidden;
+  border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+  border-top-style: hidden;
+  border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+  border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+  text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+  text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+  text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+  vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+  vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+  vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+  padding-top: 0.5em;
+  padding-bottom: 0.5em;
+  border-top: 2px solid silver;
+  border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+  border-style: none;
+}
+body.manpage div.sectionbody {
+  margin-left: 3em;
+}
+
+ at media print {
+  body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = {  // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+  function getText(el) {
+    var text = "";
+    for (var i = el.firstChild; i != null; i = i.nextSibling) {
+      if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+        text += i.data;
+      else if (i.firstChild != null)
+        text += getText(i);
+    }
+    return text;
+  }
+
+  function TocEntry(el, text, toclevel) {
+    this.element = el;
+    this.text = text;
+    this.toclevel = toclevel;
+  }
+
+  function tocEntries(el, toclevels) {
+    var result = new Array;
+    var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+    // Function that scans the DOM tree for header elements (the DOM2
+    // nodeIterator API would be a better technique but not supported by all
+    // browsers).
+    var iterate = function (el) {
+      for (var i = el.firstChild; i != null; i = i.nextSibling) {
+        if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+          var mo = re.exec(i.tagName);
+          if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+            result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+          }
+          iterate(i);
+        }
+      }
+    }
+    iterate(el);
+    return result;
+  }
+
+  var toc = document.getElementById("toc");
+  if (!toc) {
+    return;
+  }
+
+  // Delete existing TOC entries in case we're reloading the TOC.
+  var tocEntriesToRemove = [];
+  var i;
+  for (i = 0; i < toc.childNodes.length; i++) {
+    var entry = toc.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div'
+     && entry.getAttribute("class")
+     && entry.getAttribute("class").match(/^toclevel/))
+      tocEntriesToRemove.push(entry);
+  }
+  for (i = 0; i < tocEntriesToRemove.length; i++) {
+    toc.removeChild(tocEntriesToRemove[i]);
+  }
+
+  // Rebuild TOC entries.
+  var entries = tocEntries(document.getElementById("content"), toclevels);
+  for (var i = 0; i < entries.length; ++i) {
+    var entry = entries[i];
+    if (entry.element.id == "")
+      entry.element.id = "_toc_" + i;
+    var a = document.createElement("a");
+    a.href = "#" + entry.element.id;
+    a.appendChild(document.createTextNode(entry.text));
+    var div = document.createElement("div");
+    div.appendChild(a);
+    div.className = "toclevel" + entry.toclevel;
+    toc.appendChild(div);
+  }
+  if (entries.length == 0)
+    toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+  // Delete existing footnote entries in case we're reloading the footnodes.
+  var i;
+  var noteholder = document.getElementById("footnotes");
+  if (!noteholder) {
+    return;
+  }
+  var entriesToRemove = [];
+  for (i = 0; i < noteholder.childNodes.length; i++) {
+    var entry = noteholder.childNodes[i];
+    if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+      entriesToRemove.push(entry);
+  }
+  for (i = 0; i < entriesToRemove.length; i++) {
+    noteholder.removeChild(entriesToRemove[i]);
+  }
+
+  // Rebuild footnote entries.
+  var cont = document.getElementById("content");
+  var spans = cont.getElementsByTagName("span");
+  var refs = {};
+  var n = 0;
+  for (i=0; i<spans.length; i++) {
+    if (spans[i].className == "footnote") {
+      n++;
+      var note = spans[i].getAttribute("data-note");
+      if (!note) {
+        // Use [\s\S] in place of . so multi-line matches work.
+        // Because JavaScript has no s (dotall) regex flag.
+        note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+        spans[i].innerHTML =
+          "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+        spans[i].setAttribute("data-note", note);
+      }
+      noteholder.innerHTML +=
+        "<div class='footnote' id='_footnote_" + n + "'>" +
+        "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+        n + "</a>. " + note + "</div>";
+      var id =spans[i].getAttribute("id");
+      if (id != null) refs["#"+id] = n;
+    }
+  }
+  if (n == 0)
+    noteholder.parentNode.removeChild(noteholder);
+  else {
+    // Process footnoterefs.
+    for (i=0; i<spans.length; i++) {
+      if (spans[i].className == "footnoteref") {
+        var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+        href = href.match(/#.*/)[0];  // Because IE return full URL.
+        n = refs[href];
+        spans[i].innerHTML =
+          "[<a href='#_footnote_" + n +
+          "' title='View footnote' class='footnote'>" + n + "</a>]";
+      }
+    }
+  }
+},
+
+install: function(toclevels) {
+  var timerId;
+
+  function reinstall() {
+    asciidoc.footnotes();
+    if (toclevels) {
+      asciidoc.toc(toclevels);
+    }
+  }
+
+  function reinstallAndRemoveTimer() {
+    clearInterval(timerId);
+    reinstall();
+  }
+
+  timerId = setInterval(reinstall, 500);
+  if (document.addEventListener)
+    document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+  else
+    window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-ana-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ana-log -
+   Send NVMe ANA log page request, returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme ana-log</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device
+and provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory NVMe character device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success, the returned ANA log structure may be returned in one of
+several ways depending on the option flags; the structure may parsed by
+the program and printed in a readable format or the raw buffer may be
+printed to stdout for another program to parse.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+        Print the raw ANA log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+              Set the reporting format to <em>normal</em>, <em>json</em>, or
+              <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the ANA log page in a human readable format:
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ana-log /dev/nvme0</code></pre>
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2018-07-25 21:10:19 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt
new file mode 100644
index 0000000..3514504
--- /dev/null
+++ b/Documentation/nvme-ana-log.txt
@@ -0,0 +1,45 @@
+nvme-ana-log(1)
+===============
+
+NAME
+----
+nvme-ana-log - Send NVMe ANA log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme ana-log' <device>
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device
+and provides the returned structure.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+On success, the returned ANA log structure may be returned in one of
+several ways depending on the option flags; the structure may parsed by
+the program and printed in a readable format or the raw buffer may be
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+	Print the raw ANA log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+              Set the reporting format to 'normal', 'json', or
+              'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the ANA log page in a human readable format:
+------------
+# nvme ana-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH V3 1/2] nvme-cli: add minimal ana-log page support
  2018-08-02  3:28 ` [PATCH V3 1/2] nvme-cli: add minimal " Chaitanya Kulkarni
@ 2018-08-03 10:18   ` Minwoo Im
  2018-08-03 11:59   ` Minwoo Im
  1 sibling, 0 replies; 6+ messages in thread
From: Minwoo Im @ 2018-08-03 10:18 UTC (permalink / raw)


Hi Chaitanya,

On Wed, 2018-08-01@20:28 -0700, Chaitanya Kulkarni wrote:
> @@ -1550,7 +1647,7 @@ char *nvme_status_to_string(__u32 status)
> ?	case NVME_SC_SANITIZE_IN_PROGRESS:	return "SANITIZE_IN_PROGRESS: The requested function is prohibited while a sanitize operation is in progress";
> ?	case NVME_SC_LBA_RANGE:			return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace";
> ?	case NVME_SC_CAP_EXCEEDED:		return "CAP_EXCEEDED: The execution of the command has caused the capacity of the namespace to be exceeded";
> -	case NVME_SC_NS_NOT_READY:		return "NS_NOT_READY: The namespace is not ready to be accessed";
> +	case NVME_SC_NS_NOT_READY:		return "NS_NOT_READY: The namespace is not ready to be accessed as a result of a condition other than a condition that is
> reported as an Asymmetric Namespace Access condition";
> ?	case NVME_SC_RESERVATION_CONFLICT:	return "RESERVATION_CONFLICT: The command was aborted due to a conflict with a reservation held on the accessed namespace";
> ?	case NVME_SC_CQ_INVALID:		return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist";
> ?	case NVME_SC_QID_INVALID:		return "QID_INVALID: The creation of the I/O Completion Queue failed due to an invalid queue identifier specified as part of the
> command. An invalid queue identifier is one that is currently in use or one that is outside the range supported by the controller";
> @@ -1590,6 +1687,9 @@ char *nvme_status_to_string(__u32 status)
> ?	case NVME_SC_COMPARE_FAILED:		return "COMPARE_FAILED: The command failed due to a miscompare during a Compare command";
> ?	case NVME_SC_ACCESS_DENIED:		return "ACCESS_DENIED: Access to the namespace and/or LBA range is denied due to lack of access rights";
> ?	case NVME_SC_UNWRITTEN_BLOCK:		return "UNWRITTEN_BLOCK: The command failed due to an attempt to read from an LBA range containing a deallocated or
> unwritten logical block";
> +	case NVME_SC_ANA_PERSISTENT_LOSS:	return "Asymmetric Namespace Access Persistent Loss";
> +	case NVME_SC_ANA_INACCESSIBLE:		return "Asymmetric Namespace Access Inaccessible";
> +	case NVME_SC_ANA_TRANSITION:		return "Asymmetric Namespace Access Transition";
> ?	default:				return "Unknown";
> ?	}
> ?}

If possible, can we change the descriptions to something like TP 4004 just
like the others or shorten descriptions? ?All the other state strings are
having statements from the doc.

Thanks,
????????Minwoo Im

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V3 1/2] nvme-cli: add minimal ana-log page support
  2018-08-02  3:28 ` [PATCH V3 1/2] nvme-cli: add minimal " Chaitanya Kulkarni
  2018-08-03 10:18   ` Minwoo Im
@ 2018-08-03 11:59   ` Minwoo Im
  1 sibling, 0 replies; 6+ messages in thread
From: Minwoo Im @ 2018-08-03 11:59 UTC (permalink / raw)


Hi Chaitanya,

One more trivial comment on this patch.

On 18-08-01 20:28:18, Chaitanya Kulkarni wrote:
> This patch adds a new command to retrieve the ANA Log page.
> We update identify ctrl/ns data structure to support this command.
> We also add ana based error codes and different identifiers to the
> linux/nvme.h header file in order to support this command.
>?
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> Signed-off-by: Hannes Reinecke <hare at suse.com>
> ---

> +static int get_ana_log(int argc, char **argv, struct command *cmd,
> +		struct plugin *plugin)
> +{
> +	const char *desc = "Retrieve ANA log for the given device" \
> +			"in either decoded format "\
> +			"(default) or binary.";
> +	const char *raw = "output in binary format";
> +	void *ana_log;
> +	int err, fmt, fd;
> +	int groups = 0; /* Right now get all the per ANA group NSIDS */
> +	size_t ana_log_len;
> +	struct nvme_id_ctrl ctrl;
> +
> +	struct config {
> +		int???raw_binary;
> +		char *output_format;
> +	};
> +
> +	struct config cfg = {
> +		.output_format = "normal",
> +	};
> +
> +	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},
> +		{NULL}
> +	};
> +

There was a discussion about the '--raw-binary' option to deprecate it because
'--output-format=binary' or '-o binary' will make a same result.

You can find the discussion on the Github PR #342 in following link:
????https://github.com/linux-nvme/nvme-cli/pull/342

For the newly added subcommand, it doesn't need to support the '--raw-binary'
option anymore.

Thanks,

	Minwoo Im

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH V3 2/2] nvme-cli: add ana-log documentation
  2018-08-02  3:28 ` [PATCH V3 2/2] nvme-cli: add ana-log documentation Chaitanya Kulkarni
@ 2018-08-03 11:59   ` Minwoo Im
  0 siblings, 0 replies; 6+ messages in thread
From: Minwoo Im @ 2018-08-03 11:59 UTC (permalink / raw)


Hi Chaitanya,

Here's my review on this doc.

On 18-08-01 20:28:19, Chaitanya Kulkarni wrote:
> Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni at wdc.com>
> Reviewed-by: Hannes Reinecke <hare at suse.com>
> ---
> diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt
> new file mode 100644
> index 0000000..3514504
> --- /dev/null
> +++ b/Documentation/nvme-ana-log.txt
> @@ -0,0 +1,45 @@
> +nvme-ana-log(1)
> +===============
> +
> +NAME
> +----
> +nvme-ana-log - Send NVMe ANA log page request, returns result and log
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'nvme ana-log' <device>

This verse can have argument options like all the other docs.
'nvme ana-log' <device> [-o <fmt> | --output-format=<fmt>]

> +
> +DESCRIPTION
> +-----------
> +Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device
> +and provides the returned structure.
> +
> +The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
> +
> +On success, the returned ANA log structure may be returned in one of
> +several ways depending on the option flags; the structure may parsed by
> +the program and printed in a readable format or the raw buffer may be
> +printed to stdout for another program to parse.
> +
> +OPTIONS
> +-------
> +-b::
> +--raw-binary::
> +	Print the raw ANA log buffer to stdout.
> +

It can be deprecated due to a reason mentioned in the first patch comment.

> +-o <format>::
> +--output-format=<format>::
> +??????????????Set the reporting format to 'normal', 'json', or
> +??????????????'binary'. Only one output format can be used at a time.
> +
> +EXAMPLES
> +--------
> +* Print the ANA log page in a human readable format:
> +------------
> +# nvme ana-log /dev/nvme0
> +------------
> +
> +NVME
> +----
> +Part of the nvme-user suite
> --?
> 2.17.0

Thanks,

	Minwoo Im

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-08-03 11:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-02  3:28 [PATCH V3 0/2] nvme-cli: add ana-log page support Chaitanya Kulkarni
2018-08-02  3:28 ` [PATCH V3 1/2] nvme-cli: add minimal " Chaitanya Kulkarni
2018-08-03 10:18   ` Minwoo Im
2018-08-03 11:59   ` Minwoo Im
2018-08-02  3:28 ` [PATCH V3 2/2] nvme-cli: add ana-log documentation Chaitanya Kulkarni
2018-08-03 11:59   ` Minwoo Im

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).