All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] nvme-cli: Implemented primary and secondary controller
@ 2018-06-18 21:28 Revanth Rajashekar
  2018-06-18 21:57 ` Keith Busch
  0 siblings, 1 reply; 8+ messages in thread
From: Revanth Rajashekar @ 2018-06-18 21:28 UTC (permalink / raw)


Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 linux/nvme.h   |   3 ++
 nvme-builtin.h |   2 +
 nvme-ioctl.c   |  24 +++++++++
 nvme-ioctl.h   |   3 ++
 nvme-print.c   | 118 ++++++++++++++++++++++++++++++++++++++++++++
 nvme-print.h   |   7 +++
 nvme.c         | 129 +++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 286 insertions(+)

diff --git a/linux/nvme.h b/linux/nvme.h
index 97204f3..3db25ad 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -377,6 +377,8 @@ enum {
 	NVME_ID_CNS_NS_PRESENT		= 0x11,
 	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
 	NVME_ID_CNS_CTRL_LIST		= 0x13,
+	NVME_ID_CNS_PIMARY_CNTRLR_CAP 		= 0x14,
+	NVME_ID_CNS_SECONDARY_CNTRLR_LIST 	= 0x15,
 };
 
 enum {
@@ -974,6 +976,7 @@ struct nvme_identify {
 };
 
 #define NVME_IDENTIFY_DATA_SIZE 4096
+#define NVME_VIRTUAL_CNTRLR_DATA_SIZE 4096
 
 struct nvme_features {
 	__u8			opcode;
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 86b0fff..ccb3d16 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -63,6 +63,8 @@ COMMAND_LIST(
 	ENTRY("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd)
 	ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive)
 	ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send)
+	ENTRY("primary-cntrlr", "Obtain the primary controller capabilities structure", primary_cntrlr)
+	ENTRY("secondary-cntrlr", "Obtain a Secondary Controller list associated with the primary controller", secondary_cntrlr)
 );
 
 #endif
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 63ff8fb..4bc6154 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -393,6 +393,30 @@ int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
 	return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
 }
 
+int nvme_cntrlr13(int fd, __u32 cdw10, __u32 cdw11, void *data)
+{
+	struct nvme_admin_cmd cmd = {
+		.opcode 	= nvme_admin_virtual_mgmt,
+		.nsid		= 0,
+		.addr 		= (__u64)(uintptr_t) data,
+		.data_len	= NVME_VIRTUAL_CNTRLR_DATA_SIZE,
+		.cdw10 		= cdw10,
+		.cdw11 		= cdw11,
+	};
+
+	return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_primary_cntrlr(int fd, void *data)
+{
+	return nvme_cntrlr13(fd, NVME_ID_CNS_PIMARY_CNTRLR_CAP, 0, data);
+}
+
+int nvme_secondary_cntrlr(int fd, void *data)
+{
+	return nvme_cntrlr13(fd, NVME_ID_CNS_SECONDARY_CNTRLR_LIST, 0, data);
+}
+
 int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
                  __u16 lsi, __u32 data_len, void *data)
 {
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index 6d4ac95..e6385eb 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -138,4 +138,7 @@ int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
 		  __u8 no_dealloc, __u32 ovrpat);
 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log);
+int nvme_cntrlr13(int fd, __u32 cdw10, __u32 cdw11, void *data);
+int nvme_primary_cntrlr(int fd, void *data);
+int nvme_secondary_cntrlr(int fd, void *data);
 #endif				/* _NVME_LIB_H */
diff --git a/nvme-print.c b/nvme-print.c
index 8699d6c..732be8d 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -951,6 +951,72 @@ void show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
 	__show_nvme_id_ctrl(ctrl, mode, NULL);
 }
 
+void show_nvme_primary_cntrlr_crt(__u8 crt)
+{
+	__u8 rsvd = (crt & 0xFC) >> 2;
+	__u8 vir  = (crt & 0x2) >> 1;
+	__u8 vqr  = crt & 0x1;
+	if (rsvd)
+		printf("  [7:2] : %#x\tReserved\n", rsvd);
+	printf("  [1:1] : %#x\t VI Resources are %s\n",
+		vir, vir ? "Supported" : "NOT Supported");
+	printf("  [0:0] : %#x\t VQ Resources are %s\n", vqr,
+		vqr ? "Supported" : "NOT Supported");
+	printf("\n");
+}
+
+void show_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl)
+{
+	printf("cntlid     : %#x\n", le16_to_cpu(ctrl->cntlid));
+	printf("portid     : %#x\n", le16_to_cpu(ctrl->portid));
+	printf("crt        : %#x\n", ctrl->crt);
+	show_nvme_primary_cntrlr_crt(ctrl->crt);
+	printf("vqfrt      : %d\n", ctrl->vqfrt);
+	printf("vqrfa      : %d\n", ctrl->vqrfa);
+	printf("vqrfap     : %d\n", le16_to_cpu(ctrl->vqrfap));
+	printf("vqprt      : %d\n", le16_to_cpu(ctrl->vqprt));
+	printf("vqfrsm     : %d\n", le16_to_cpu(ctrl->vqfrsm));
+	printf("vqgran     : %d\n", le16_to_cpu(ctrl->vqgran));
+	printf("vifrt      : %u\n", le32_to_cpu(ctrl->vifrt));
+	printf("virfa      : %u\n", le32_to_cpu(ctrl->virfa));
+	printf("virfap     : %d\n", le16_to_cpu(ctrl->virfap));
+	printf("viprt      : %d\n", le16_to_cpu(ctrl->viprt));
+	printf("vifrsm     : %d\n", le16_to_cpu(ctrl->vifrsm));
+	printf("vigran     : %d\n", le16_to_cpu(ctrl->vigran));
+}
+
+void show_nvme_secondary_cntrlr_entry_scs(__u8 scs)
+{
+	__u8 rsvd = (scs & 0xFE) >> 1;
+	__u8 os  = scs & 0x1;
+
+	if (rsvd)
+		printf("  [7:1] : %#x\tReserved\n", rsvd);
+	printf("  [0:0] : %#x\t Controller is in %s state\n", os,
+		os ? "Online" : "Offline");
+
+}
+
+void show_nvme_secondary_cntrlr_entry(struct nvme_secondary_cntrlr_entry *ctrl)
+{
+	printf("scid     : %#x\n", le16_to_cpu(ctrl->scid));
+	printf("pcid     : %#x\n", le16_to_cpu(ctrl->pcid));
+	printf("scs 	 : %#x\n",ctrl->scs);
+	show_nvme_secondary_cntrlr_entry_scs(ctrl->scs);
+	printf("vfn	     : %d\n", le16_to_cpu(ctrl->vfn));
+	printf("nvq	     : %d\n", le16_to_cpu(ctrl->nvq));
+	printf("nvi	     : %d\n", le16_to_cpu(ctrl->nvi));
+}
+
+void show_nvme_secondary_cntrlr_list(struct nvme_secondary_cntrlr_list *ctrl)
+{
+	int i;
+
+	printf("num_of_identifiers  : %d\n", ctrl->num_of_identifiers);
+	for(i = 0; i < ctrl->num_of_identifiers; i++)
+		show_nvme_secondary_cntrlr_entry(&ctrl->sc[i]);
+}
+
 void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
 {
 	int i;
@@ -2141,6 +2207,58 @@ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*vs)(
 	json_free_object(root);
 }
 
+void json_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl)
+{
+	struct json_object *root;
+	root = json_create_object();
+
+	json_object_add_value_int(root, "cntlid", le16_to_cpu(ctrl->cntlid));
+	json_object_add_value_int(root, "portid", le16_to_cpu(ctrl->portid));
+	json_object_add_value_int(root, "crt", ctrl->crt);
+	json_object_add_value_int(root, "vqfrt", ctrl->vqfrt);
+	json_object_add_value_int(root, "vqrfa", ctrl->vqrfa);
+	json_object_add_value_int(root, "vqrfap", le16_to_cpu(ctrl->vqrfap));
+	json_object_add_value_int(root, "vqprt", le16_to_cpu(ctrl->vqprt));
+	json_object_add_value_int(root, "vqfrsm", le16_to_cpu(ctrl->vqfrsm));
+	json_object_add_value_int(root, "vqgran", le16_to_cpu(ctrl->vqgran));
+	json_object_add_value_uint(root, "vifrt", le32_to_cpu(ctrl->vifrt));
+	json_object_add_value_uint(root, "virfa", le32_to_cpu(ctrl->virfa));
+	json_object_add_value_int(root, "virfap", le16_to_cpu(ctrl->virfap));
+	json_object_add_value_int(root, "viprt", le16_to_cpu(ctrl->viprt));
+	json_object_add_value_int(root, "vifrsm", le16_to_cpu(ctrl->vifrsm));
+	json_object_add_value_int(root, "vigran", le16_to_cpu(ctrl->vigran));
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
+void json_nvme_secondary_cntrlr(struct nvme_secondary_cntrlr_list *ctrl)
+{
+	struct json_object *root;
+	struct json_array *valid;
+	struct json_object *valid_attrs;
+	int i;
+
+	root = json_create_object();
+	json_object_add_value_int(root, "num_of_identifiers", ctrl->num_of_identifiers);
+	valid = json_create_array();
+
+	for (i=0; i < ctrl->num_of_identifiers; i++) {
+		valid_attrs = json_create_object();
+		json_object_add_value_int(valid_attrs, "scid", le16_to_cpu(ctrl->sc[i].scid));
+		json_object_add_value_int(valid_attrs, "pcid", le16_to_cpu(ctrl->sc[i].pcid));
+		json_object_add_value_int(valid_attrs, "scs", ctrl->sc[i].scs );
+		json_object_add_value_int(valid_attrs, "vfn", le16_to_cpu(ctrl->sc[i].vfn));
+		json_object_add_value_int(valid_attrs, "nvq", le16_to_cpu(ctrl->sc[i].nvq));
+		json_object_add_value_int(valid_attrs, "nvi", le16_to_cpu(ctrl->sc[i].nvi));
+		json_array_add_value_object(valid, valid_attrs);
+	}
+	json_object_add_value_array(root, "Secondary Controller Entries", valid);
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
 void json_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname)
 {
 	struct json_object *root;
diff --git a/nvme-print.h b/nvme-print.h
index 7dd5f34..bdef9b2 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -58,6 +58,13 @@ void json_nvme_id_ns_descs(void *data);
 void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
 void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname);
 void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname);
+void show_nvme_primary_cntrlr_crt(__u8 crt);
+void show_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl);
+void show_nvme_secondary_cntrlr_entry_scs(__u8 scs);
+void show_nvme_secondary_cntrlr_entry(struct nvme_secondary_cntrlr_entry *ctrl);
+void show_nvme_secondary_cntrlr_list(struct nvme_secondary_cntrlr_list *ctrl);
+void json_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl);
+void json_nvme_secondary_cntrlr(struct nvme_secondary_cntrlr_list *ctrl);
 
 
 #endif
diff --git a/nvme.c b/nvme.c
index 2dd74d2..3de55f3 100644
--- a/nvme.c
+++ b/nvme.c
@@ -1633,6 +1633,135 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
 	return __id_ctrl(argc, argv, cmd, plugin, NULL);
 }
 
+int primary_cntrlr(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Primary Controller command to "\
+		"the given device and report information about the specified "\
+		"primary controller in human-readable or binary format.";
+	const char *raw_binary = "show infos in binary format";
+	const char *human_readable = "show infos in readable format";
+	int err, fmt, fd;
+	struct nvme_id_primary_cntrlr ctrl;
+
+	struct config {
+		int raw_binary;
+		int human_readable;
+		char *output_format;
+	};
+
+	struct config cfg = {
+		.output_format = "normal",
+	};
+
+	const struct argconfig_commandline_options command_line_options[] = {
+		{"raw-binary",      'b', "",    CFG_NONE,   &cfg.raw_binary,      no_argument,       raw_binary},
+		{"human-readable",  'H', "",    CFG_NONE,   &cfg.human_readable,  no_argument,       human_readable},
+		{"output-format",   'o', "FMT", CFG_STRING, &cfg.output_format,   required_argument, output_format },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+	if (cfg.raw_binary) {
+		fprintf(stderr, "binary output\n");
+		fmt = BINARY;
+	}
+
+	err = nvme_primary_cntrlr(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_primary_cntrlr(&ctrl);
+		else {
+			printf("NVME Primary Controller:\n");
+			show_nvme_primary_cntrlr(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Primary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
+int secondary_cntrlr(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Secondary Controller command to "\
+		"the given device and report information about the "\
+		"secondary controllers associated with the primary controller in "\
+		"human-readable or binary format.";
+	const char *raw_binary = "show infos in binary format";
+	const char *human_readable = "show infos in readable format";
+	int err, fmt, fd;
+	struct nvme_secondary_cntrlr_list ctrl;
+
+	struct config {
+		int raw_binary;
+		int human_readable;
+		char *output_format;
+	};
+
+	struct config cfg = {
+		.output_format = "normal",
+	};
+
+	const struct argconfig_commandline_options command_line_options[] = {
+		{"raw-binary",      'b', "",    CFG_NONE,   &cfg.raw_binary,      no_argument,       raw_binary},
+		{"human-readable",  'H', "",    CFG_NONE,   &cfg.human_readable,  no_argument,       human_readable},
+		{"output-format",   'o', "FMT", CFG_STRING, &cfg.output_format,   required_argument, output_format },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+	if (cfg.raw_binary) {
+		fprintf(stderr, "binary output\n");
+		fmt = BINARY;
+	}
+
+	err = nvme_secondary_cntrlr(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_secondary_cntrlr(&ctrl);
+		else {
+			printf("NVME Secondary Controller:\n");
+			show_nvme_secondary_cntrlr_list(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Secondary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
 static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
 	const char *desc = "Send Namespace Identification Descriptors command to the "\
-- 
2.17.1

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
  2018-06-18 21:28 Revanth Rajashekar
@ 2018-06-18 21:57 ` Keith Busch
  0 siblings, 0 replies; 8+ messages in thread
From: Keith Busch @ 2018-06-18 21:57 UTC (permalink / raw)


On Mon, Jun 18, 2018@03:28:14PM -0600, Revanth Rajashekar wrote:
>  	NVME_ID_CNS_NS_PRESENT		= 0x11,
>  	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
>  	NVME_ID_CNS_CTRL_LIST		= 0x13,
> +	NVME_ID_CNS_PIMARY_CNTRLR_CAP 		= 0x14,
> +	NVME_ID_CNS_SECONDARY_CNTRLR_LIST 	= 0x15,

Let's stick with the existing convention of "CTRL" as the abbreviation
for controller.

> +	ENTRY("primary-cntrlr", "Obtain the primary controller capabilities structure", primary_cntrlr)
> +	ENTRY("secondary-cntrlr", "Obtain a Secondary Controller list associated with the primary controller", secondary_cntrlr)


Similarly, controller is abbreviated as "ctrl" by existing convention,
and different types of identify commands are prefixed with "id-".

> +int nvme_cntrlr13(int fd, __u32 cdw10, __u32 cdw11, void *data)
> +{
> +	struct nvme_admin_cmd cmd = {
> +		.opcode 	= nvme_admin_virtual_mgmt,
> +		.nsid		= 0,
> +		.addr 		= (__u64)(uintptr_t) data,
> +		.data_len	= NVME_VIRTUAL_CNTRLR_DATA_SIZE,
> +		.cdw10 		= cdw10,
> +		.cdw11 		= cdw11,
> +	};
> +
> +	return nvme_submit_admin_passthru(fd, &cmd);
> +}

I can't tell what this function is for or why it's named with a "13"
suffix. Also CDW11 isn't used for identify commands.

> +void show_nvme_primary_cntrlr_crt(__u8 crt)
> +{
> +	__u8 rsvd = (crt & 0xFC) >> 2;
> +	__u8 vir  = (crt & 0x2) >> 1;
> +	__u8 vqr  = crt & 0x1;
> +	if (rsvd)
> +		printf("  [7:2] : %#x\tReserved\n", rsvd);
> +	printf("  [1:1] : %#x\t VI Resources are %s\n",
> +		vir, vir ? "Supported" : "NOT Supported");
> +	printf("  [0:0] : %#x\t VQ Resources are %s\n", vqr,
> +		vqr ? "Supported" : "NOT Supported");
> +	printf("\n");
> +}

I don't think you want to call this without the "human readable"
option, right?

> +void show_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl)
> +{
> +	printf("cntlid     : %#x\n", le16_to_cpu(ctrl->cntlid));
> +	printf("portid     : %#x\n", le16_to_cpu(ctrl->portid));
> +	printf("crt        : %#x\n", ctrl->crt);
> +	show_nvme_primary_cntrlr_crt(ctrl->crt);
> +	printf("vqfrt      : %d\n", ctrl->vqfrt);
> +	printf("vqrfa      : %d\n", ctrl->vqrfa);

le32_to_cpu on the above two prints.

> +void show_nvme_secondary_cntrlr_entry_scs(__u8 scs)
> +{
> +	__u8 rsvd = (scs & 0xFE) >> 1;
> +	__u8 os  = scs & 0x1;
> +
> +	if (rsvd)
> +		printf("  [7:1] : %#x\tReserved\n", rsvd);
> +	printf("  [0:0] : %#x\t Controller is in %s state\n", os,
> +		os ? "Online" : "Offline");
> +
> +}

Another function that looks like it should not be called without the
"human readable" option.

> +void show_nvme_secondary_cntrlr_entry(struct nvme_secondary_cntrlr_entry *ctrl)
> +{
> +	printf("scid     : %#x\n", le16_to_cpu(ctrl->scid));
> +	printf("pcid     : %#x\n", le16_to_cpu(ctrl->pcid));
> +	printf("scs 	 : %#x\n",ctrl->scs);
> +	show_nvme_secondary_cntrlr_entry_scs(ctrl->scs);
> +	printf("vfn	     : %d\n", le16_to_cpu(ctrl->vfn));
> +	printf("nvq	     : %d\n", le16_to_cpu(ctrl->nvq));
> +	printf("nvi	     : %d\n", le16_to_cpu(ctrl->nvi));
> +}
> +
> +void show_nvme_secondary_cntrlr_list(struct nvme_secondary_cntrlr_list *ctrl)
> +{
> +	int i;
> +
> +	printf("num_of_identifiers  : %d\n", ctrl->num_of_identifiers);
> +	for(i = 0; i < ctrl->num_of_identifiers; i++)
> +		show_nvme_secondary_cntrlr_entry(&ctrl->sc[i]);
> +}

We need a print here to break up different controllers in this list.

> +void json_nvme_primary_cntrlr(struct nvme_id_primary_cntrlr *ctrl)
> +{
> +	struct json_object *root;
> +	root = json_create_object();
> +
> +	json_object_add_value_int(root, "cntlid", le16_to_cpu(ctrl->cntlid));
> +	json_object_add_value_int(root, "portid", le16_to_cpu(ctrl->portid));
> +	json_object_add_value_int(root, "crt", ctrl->crt);
> +	json_object_add_value_int(root, "vqfrt", ctrl->vqfrt);
> +	json_object_add_value_int(root, "vqrfa", ctrl->vqrfa);

le32_to_cpu on the above two.

> +int primary_cntrlr(int argc, char **argv, struct command *cmd, struct plugin *plugin)
> +{
> +	const char *desc = "Send an Primary Controller command to "\
> +		"the given device and report information about the specified "\
> +		"primary controller in human-readable or binary format.";
> +	const char *raw_binary = "show infos in binary format";
> +	const char *human_readable = "show infos in readable format";
> +	int err, fmt, fd;
> +	struct nvme_id_primary_cntrlr ctrl;
> +
> +	struct config {
> +		int raw_binary;
> +		int human_readable;
> +		char *output_format;
> +	};
> +
> +	struct config cfg = {
> +		.output_format = "normal",
> +	};
> +
> +	const struct argconfig_commandline_options command_line_options[] = {
> +		{"raw-binary",      'b', "",    CFG_NONE,   &cfg.raw_binary,      no_argument,       raw_binary},
> +		{"human-readable",  'H', "",    CFG_NONE,   &cfg.human_readable,  no_argument,       human_readable},
> +		{"output-format",   'o', "FMT", CFG_STRING, &cfg.output_format,   required_argument, output_format },
> +		{NULL}

Let's not use the binary option when we have the "output-format" option.
That binary option is really a legacy carry-over from when we only had
the two possible options.

Also, I don't think the "human-readable" option is particularly well
named anymore. The "normal" output option already is human readable, but
the additional "human-readable" option really just means to be more
"verbose", so I would favor seeing any new commands that have such
potential for additional verbosity in its decoding use a "--verbose" or
"-v" option instead.

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
@ 2018-06-18 23:12 Revanth Rajashekar
  2018-06-19 14:13 ` Keith Busch
  0 siblings, 1 reply; 8+ messages in thread
From: Revanth Rajashekar @ 2018-06-18 23:12 UTC (permalink / raw)


Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 linux/nvme.h   |  11 +++--
 nvme-builtin.h |   2 +
 nvme-ioctl.c   |  22 +++++++++
 nvme-ioctl.h   |   3 ++
 nvme-print.c   | 120 +++++++++++++++++++++++++++++++++++++++++++++++++
 nvme-print.h   |   7 +++
 nvme.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 270 insertions(+), 4 deletions(-)

diff --git a/linux/nvme.h b/linux/nvme.h
index 97204f3..d6f99d9 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -272,7 +272,7 @@ struct nvme_id_ctrl {
 	__u8			vs[1024];
 };
 
-struct nvme_id_primary_cntrlr {
+struct nvme_id_primary_ctrl {
 	__le16	cntlid;
 	__le16	portid;
 	__u8	crt;
@@ -293,7 +293,7 @@ struct nvme_id_primary_cntrlr {
 	__u8	rsvd80[4016];
 };
 
-struct nvme_secondary_cntrlr_entry {
+struct nvme_secondary_ctrl_entry {
 	__le16	scid;
 	__le16 	pcid;
 	__u8 	scs;
@@ -304,10 +304,10 @@ struct nvme_secondary_cntrlr_entry {
 	__u8 	rsvd14[18];
 };
 
-struct nvme_secondary_cntrlr_list {
+struct nvme_id_secondary_ctrl_list {
 	__u8 	num_of_identifiers;
 	__u8	rsvd1[31];
-	struct  nvme_secondary_cntrlr_entry sc[NVME_SECONDARY_CONTROLLER_MAX];
+	struct  nvme_secondary_ctrl_entry sc[NVME_SECONDARY_CONTROLLER_MAX];
 };
 
 enum {
@@ -377,6 +377,8 @@ enum {
 	NVME_ID_CNS_NS_PRESENT		= 0x11,
 	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
 	NVME_ID_CNS_CTRL_LIST		= 0x13,
+	NVME_ID_CNS_PIMARY_CTRL_CAP 		= 0x14,
+	NVME_ID_CNS_SECONDARY_CTRL_LIST 	= 0x15,
 };
 
 enum {
@@ -974,6 +976,7 @@ struct nvme_identify {
 };
 
 #define NVME_IDENTIFY_DATA_SIZE 4096
+#define NVME_VIRTUAL_CTRL_DATA_SIZE 4096
 
 struct nvme_features {
 	__u8			opcode;
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 86b0fff..0b81193 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -63,6 +63,8 @@ COMMAND_LIST(
 	ENTRY("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd)
 	ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive)
 	ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send)
+	ENTRY("id-primary-ctrl", "Obtain the primary controller capabilities structure", id_primary_ctrl)
+	ENTRY("id-secondary-ctrl", "Obtain a Secondary Controller list associated with the primary controller", id_secondary_ctrl)
 );
 
 #endif
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 63ff8fb..493f643 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -393,6 +393,28 @@ int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
 	return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
 }
 
+int nvme_ctrl(int fd, __u32 cdw10, void *data)
+{
+	struct nvme_admin_cmd cmd = {
+		.opcode 	= nvme_admin_virtual_mgmt,
+		.addr 		= (__u64)(uintptr_t) data,
+		.data_len	= NVME_VIRTUAL_CTRL_DATA_SIZE,
+		.cdw10 		= cdw10,
+	};
+
+	return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_id_primary_ctrl(int fd, void *data)
+{
+	return nvme_ctrl(fd, NVME_ID_CNS_PIMARY_CTRL_CAP, data);
+}
+
+int nvme_id_secondary_ctrl(int fd, void *data)
+{
+	return nvme_ctrl(fd, NVME_ID_CNS_SECONDARY_CTRL_LIST, data);
+}
+
 int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
                  __u16 lsi, __u32 data_len, void *data)
 {
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index 6d4ac95..4919020 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -138,4 +138,7 @@ int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
 		  __u8 no_dealloc, __u32 ovrpat);
 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log);
+int nvme_ctrl(int fd, __u32 cdw10, void *data);
+int nvme_id_primary_ctrl(int fd, void *data);
+int nvme_id_secondary_ctrl(int fd, void *data);
 #endif				/* _NVME_LIB_H */
diff --git a/nvme-print.c b/nvme-print.c
index 8699d6c..509125f 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -951,6 +951,74 @@ void show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
 	__show_nvme_id_ctrl(ctrl, mode, NULL);
 }
 
+void show_nvme_id_primary_ctrl_crt(__u8 crt)
+{
+	__u8 rsvd = (crt & 0xFC) >> 2;
+	__u8 vir  = (crt & 0x2) >> 1;
+	__u8 vqr  = crt & 0x1;
+	if (rsvd)
+		printf("  [7:2] : %#x\tReserved\n", rsvd);
+	printf("  [1:1] : %#x\t VI Resources are %s\n",
+		vir, vir ? "Supported" : "NOT Supported");
+	printf("  [0:0] : %#x\t VQ Resources are %s\n", vqr,
+		vqr ? "Supported" : "NOT Supported");
+	printf("\n");
+}
+
+void show_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl)
+{
+	printf("cntlid     : %#x\n", le16_to_cpu(ctrl->cntlid));
+	printf("portid     : %#x\n", le16_to_cpu(ctrl->portid));
+	printf("crt        : %#x\n", ctrl->crt);
+	show_nvme_id_primary_ctrl_crt(ctrl->crt);
+	printf("vqfrt      : %u\n", le32_to_cpu(ctrl->vqfrt));
+	printf("vqrfa      : %u\n", le32_to_cpu(ctrl->vqrfa));
+	printf("vqrfap     : %d\n", le16_to_cpu(ctrl->vqrfap));
+	printf("vqprt      : %d\n", le16_to_cpu(ctrl->vqprt));
+	printf("vqfrsm     : %d\n", le16_to_cpu(ctrl->vqfrsm));
+	printf("vqgran     : %d\n", le16_to_cpu(ctrl->vqgran));
+	printf("vifrt      : %u\n", le32_to_cpu(ctrl->vifrt));
+	printf("virfa      : %u\n", le32_to_cpu(ctrl->virfa));
+	printf("virfap     : %d\n", le16_to_cpu(ctrl->virfap));
+	printf("viprt      : %d\n", le16_to_cpu(ctrl->viprt));
+	printf("vifrsm     : %d\n", le16_to_cpu(ctrl->vifrsm));
+	printf("vigran     : %d\n", le16_to_cpu(ctrl->vigran));
+}
+
+void show_nvme_id_secondary_ctrl_entry_scs(__u8 scs)
+{
+	__u8 rsvd = (scs & 0xFE) >> 1;
+	__u8 os  = scs & 0x1;
+
+	if (rsvd)
+		printf("  [7:1] : %#x\tReserved\n", rsvd);
+	printf("  [0:0] : %#x\t Controller is in %s state\n", os,
+		os ? "Online" : "Offline");
+
+}
+
+void show_nvme_id_secondary_ctrl_entry(struct nvme_secondary_ctrl_entry *ctrl)
+{
+	printf("scid     : %#x\n", le16_to_cpu(ctrl->scid));
+	printf("pcid     : %#x\n", le16_to_cpu(ctrl->pcid));
+	printf("scs 	 : %#x\n",ctrl->scs);
+	show_nvme_id_secondary_ctrl_entry_scs(ctrl->scs);
+	printf("vfn	     : %d\n", le16_to_cpu(ctrl->vfn));
+	printf("nvq	     : %d\n", le16_to_cpu(ctrl->nvq));
+	printf("nvi	     : %d\n", le16_to_cpu(ctrl->nvi));
+}
+
+void show_nvme_id_secondary_ctrl_list(struct nvme_id_secondary_ctrl_list *ctrl)
+{
+	int i;
+
+	printf("num_of_identifiers  : %d\n", ctrl->num_of_identifiers);
+	for(i = 0; i < ctrl->num_of_identifiers; i++) {
+		printf("\n Secondary Controller - %d  : \n", i+1);
+		show_nvme_id_secondary_ctrl_entry(&ctrl->sc[i]);
+	}
+}
+
 void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
 {
 	int i;
@@ -2141,6 +2209,58 @@ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*vs)(
 	json_free_object(root);
 }
 
+void json_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl)
+{
+	struct json_object *root;
+	root = json_create_object();
+
+	json_object_add_value_int(root, "cntlid", le16_to_cpu(ctrl->cntlid));
+	json_object_add_value_int(root, "portid", le16_to_cpu(ctrl->portid));
+	json_object_add_value_int(root, "crt", ctrl->crt);
+	json_object_add_value_int(root, "vqfrt", le32_to_cpu(ctrl->vqfrt));
+	json_object_add_value_int(root, "vqrfa", le32_to_cpu(ctrl->vqrfa));
+	json_object_add_value_int(root, "vqrfap", le16_to_cpu(ctrl->vqrfap));
+	json_object_add_value_int(root, "vqprt", le16_to_cpu(ctrl->vqprt));
+	json_object_add_value_int(root, "vqfrsm", le16_to_cpu(ctrl->vqfrsm));
+	json_object_add_value_int(root, "vqgran", le16_to_cpu(ctrl->vqgran));
+	json_object_add_value_uint(root, "vifrt", le32_to_cpu(ctrl->vifrt));
+	json_object_add_value_uint(root, "virfa", le32_to_cpu(ctrl->virfa));
+	json_object_add_value_int(root, "virfap", le16_to_cpu(ctrl->virfap));
+	json_object_add_value_int(root, "viprt", le16_to_cpu(ctrl->viprt));
+	json_object_add_value_int(root, "vifrsm", le16_to_cpu(ctrl->vifrsm));
+	json_object_add_value_int(root, "vigran", le16_to_cpu(ctrl->vigran));
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
+void json_nvme_id_secondary_ctrl(struct nvme_id_secondary_ctrl_list *ctrl)
+{
+	struct json_object *root;
+	struct json_array *valid;
+	struct json_object *valid_attrs;
+	int i;
+
+	root = json_create_object();
+	json_object_add_value_int(root, "num_of_identifiers", ctrl->num_of_identifiers);
+	valid = json_create_array();
+
+	for (i=0; i < ctrl->num_of_identifiers; i++) {
+		valid_attrs = json_create_object();
+		json_object_add_value_int(valid_attrs, "scid", le16_to_cpu(ctrl->sc[i].scid));
+		json_object_add_value_int(valid_attrs, "pcid", le16_to_cpu(ctrl->sc[i].pcid));
+		json_object_add_value_int(valid_attrs, "scs", ctrl->sc[i].scs );
+		json_object_add_value_int(valid_attrs, "vfn", le16_to_cpu(ctrl->sc[i].vfn));
+		json_object_add_value_int(valid_attrs, "nvq", le16_to_cpu(ctrl->sc[i].nvq));
+		json_object_add_value_int(valid_attrs, "nvi", le16_to_cpu(ctrl->sc[i].nvi));
+		json_array_add_value_object(valid, valid_attrs);
+	}
+	json_object_add_value_array(root, "Secondary Controller Entries", valid);
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
 void json_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname)
 {
 	struct json_object *root;
diff --git a/nvme-print.h b/nvme-print.h
index 7dd5f34..2d5ab8c 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -58,6 +58,13 @@ void json_nvme_id_ns_descs(void *data);
 void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
 void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname);
 void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname);
+void show_nvme_id_primary_ctrl_crt(__u8 crt);
+void show_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl);
+void show_nvme_id_secondary_ctrl_entry_scs(__u8 scs);
+void show_nvme_id_secondary_ctrl_entry(struct nvme_secondary_ctrl_entry *ctrl);
+void show_nvme_id_secondary_ctrl_list(struct nvme_id_secondary_ctrl_list *ctrl);
+void json_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl);
+void json_nvme_id_secondary_ctrl(struct nvme_id_secondary_ctrl_list *ctrl);
 
 
 #endif
diff --git a/nvme.c b/nvme.c
index 2dd74d2..798cfcd 100644
--- a/nvme.c
+++ b/nvme.c
@@ -1633,6 +1633,115 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
 	return __id_ctrl(argc, argv, cmd, plugin, NULL);
 }
 
+int id_primary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Primary Controller command to "\
+		"the given device and report information about the specified "\
+		"primary controller in human-readable or binary format.";
+	int err, fmt, fd;
+	struct nvme_id_primary_ctrl ctrl;
+
+	struct config {
+		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 },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+
+	err = nvme_id_primary_ctrl(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_id_primary_ctrl(&ctrl);
+		else {
+			printf("NVME Primary Controller:\n");
+			show_nvme_id_primary_ctrl(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Primary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
+int id_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Secondary Controller command to "\
+		"the given device and report information about the "\
+		"secondary controllers associated with the primary controller in "\
+		"human-readable or binary format.";
+	int err, fmt, fd;
+	struct nvme_id_secondary_ctrl_list ctrl;
+
+	struct config {
+		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 },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+
+	err = nvme_id_secondary_ctrl(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_id_secondary_ctrl(&ctrl);
+		else {
+			printf("NVME Secondary Controller:\n");
+			show_nvme_id_secondary_ctrl_list(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Secondary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
 static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
 	const char *desc = "Send Namespace Identification Descriptors command to the "\
-- 
2.17.1

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
  2018-06-18 23:12 Revanth Rajashekar
@ 2018-06-19 14:13 ` Keith Busch
  0 siblings, 0 replies; 8+ messages in thread
From: Keith Busch @ 2018-06-19 14:13 UTC (permalink / raw)


On Mon, Jun 18, 2018@05:12:43PM -0600, Revanth Rajashekar wrote:
> -struct nvme_id_primary_cntrlr {
> +struct nvme_id_primary_ctrl {

Could you rebase your patch so that it doesn't have dependencies on your
previous version?

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
@ 2018-06-19 15:28 Revanth Rajashekar
  2018-06-19 15:45 ` Keith Busch
  0 siblings, 1 reply; 8+ messages in thread
From: Revanth Rajashekar @ 2018-06-19 15:28 UTC (permalink / raw)


Signed-off-by: Revanth Rajashekar <revanth.rajashekar at intel.com>
---
 linux/nvme.h   |  43 ++++++++++++++++++
 nvme-builtin.h |   2 +
 nvme-ioctl.c   |  22 +++++++++
 nvme-ioctl.h   |   3 ++
 nvme-print.c   | 120 +++++++++++++++++++++++++++++++++++++++++++++++++
 nvme-print.h   |   7 +++
 nvme.c         | 109 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 306 insertions(+)

diff --git a/linux/nvme.h b/linux/nvme.h
index 8df7255..d6f99d9 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -34,6 +34,8 @@
 
 #define NVME_NSID_ALL		0xffffffff
 
+#define NVME_SECONDARY_CONTROLLER_MAX	127
+
 enum nvme_subsys_type {
 	NVME_NQN_DISC	= 1,		/* Discovery type target subsystem */
 	NVME_NQN_NVME	= 2,		/* NVME type target subsystem */
@@ -270,6 +272,44 @@ struct nvme_id_ctrl {
 	__u8			vs[1024];
 };
 
+struct nvme_id_primary_ctrl {
+	__le16	cntlid;
+	__le16	portid;
+	__u8	crt;
+	__u8	rsvd5[27];
+	__le32	vqfrt;
+	__le32	vqrfa;
+	__le16	vqrfap;
+	__le16 	vqprt;
+	__le16	vqfrsm;
+	__le16 	vqgran;
+	__u8	rsvd48[16];
+	__le32	vifrt;
+	__le32	virfa;
+	__le16 	virfap;
+	__le16	viprt;
+	__le16	vifrsm;
+	__le16	vigran;
+	__u8	rsvd80[4016];
+};
+
+struct nvme_secondary_ctrl_entry {
+	__le16	scid;
+	__le16 	pcid;
+	__u8 	scs;
+	__u8 	rsvd5[3];
+	__le16 	vfn;
+	__le16 	nvq;
+	__le16 	nvi;
+	__u8 	rsvd14[18];
+};
+
+struct nvme_id_secondary_ctrl_list {
+	__u8 	num_of_identifiers;
+	__u8	rsvd1[31];
+	struct  nvme_secondary_ctrl_entry sc[NVME_SECONDARY_CONTROLLER_MAX];
+};
+
 enum {
 	NVME_CTRL_ONCS_COMPARE			= 1 << 0,
 	NVME_CTRL_ONCS_WRITE_UNCORRECTABLE	= 1 << 1,
@@ -337,6 +377,8 @@ enum {
 	NVME_ID_CNS_NS_PRESENT		= 0x11,
 	NVME_ID_CNS_CTRL_NS_LIST	= 0x12,
 	NVME_ID_CNS_CTRL_LIST		= 0x13,
+	NVME_ID_CNS_PIMARY_CTRL_CAP 		= 0x14,
+	NVME_ID_CNS_SECONDARY_CTRL_LIST 	= 0x15,
 };
 
 enum {
@@ -934,6 +976,7 @@ struct nvme_identify {
 };
 
 #define NVME_IDENTIFY_DATA_SIZE 4096
+#define NVME_VIRTUAL_CTRL_DATA_SIZE 4096
 
 struct nvme_features {
 	__u8			opcode;
diff --git a/nvme-builtin.h b/nvme-builtin.h
index 86b0fff..0b81193 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -63,6 +63,8 @@ COMMAND_LIST(
 	ENTRY("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd)
 	ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive)
 	ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send)
+	ENTRY("id-primary-ctrl", "Obtain the primary controller capabilities structure", id_primary_ctrl)
+	ENTRY("id-secondary-ctrl", "Obtain a Secondary Controller list associated with the primary controller", id_secondary_ctrl)
 );
 
 #endif
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 63ff8fb..493f643 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -393,6 +393,28 @@ int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
 	return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
 }
 
+int nvme_ctrl(int fd, __u32 cdw10, void *data)
+{
+	struct nvme_admin_cmd cmd = {
+		.opcode 	= nvme_admin_virtual_mgmt,
+		.addr 		= (__u64)(uintptr_t) data,
+		.data_len	= NVME_VIRTUAL_CTRL_DATA_SIZE,
+		.cdw10 		= cdw10,
+	};
+
+	return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_id_primary_ctrl(int fd, void *data)
+{
+	return nvme_ctrl(fd, NVME_ID_CNS_PIMARY_CTRL_CAP, data);
+}
+
+int nvme_id_secondary_ctrl(int fd, void *data)
+{
+	return nvme_ctrl(fd, NVME_ID_CNS_SECONDARY_CTRL_LIST, data);
+}
+
 int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
                  __u16 lsi, __u32 data_len, void *data)
 {
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index 6d4ac95..4919020 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -138,4 +138,7 @@ int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
 		  __u8 no_dealloc, __u32 ovrpat);
 int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
 int nvme_self_test_log(int fd, struct nvme_self_test_log *self_test_log);
+int nvme_ctrl(int fd, __u32 cdw10, void *data);
+int nvme_id_primary_ctrl(int fd, void *data);
+int nvme_id_secondary_ctrl(int fd, void *data);
 #endif				/* _NVME_LIB_H */
diff --git a/nvme-print.c b/nvme-print.c
index 8699d6c..509125f 100644
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -951,6 +951,74 @@ void show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
 	__show_nvme_id_ctrl(ctrl, mode, NULL);
 }
 
+void show_nvme_id_primary_ctrl_crt(__u8 crt)
+{
+	__u8 rsvd = (crt & 0xFC) >> 2;
+	__u8 vir  = (crt & 0x2) >> 1;
+	__u8 vqr  = crt & 0x1;
+	if (rsvd)
+		printf("  [7:2] : %#x\tReserved\n", rsvd);
+	printf("  [1:1] : %#x\t VI Resources are %s\n",
+		vir, vir ? "Supported" : "NOT Supported");
+	printf("  [0:0] : %#x\t VQ Resources are %s\n", vqr,
+		vqr ? "Supported" : "NOT Supported");
+	printf("\n");
+}
+
+void show_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl)
+{
+	printf("cntlid     : %#x\n", le16_to_cpu(ctrl->cntlid));
+	printf("portid     : %#x\n", le16_to_cpu(ctrl->portid));
+	printf("crt        : %#x\n", ctrl->crt);
+	show_nvme_id_primary_ctrl_crt(ctrl->crt);
+	printf("vqfrt      : %u\n", le32_to_cpu(ctrl->vqfrt));
+	printf("vqrfa      : %u\n", le32_to_cpu(ctrl->vqrfa));
+	printf("vqrfap     : %d\n", le16_to_cpu(ctrl->vqrfap));
+	printf("vqprt      : %d\n", le16_to_cpu(ctrl->vqprt));
+	printf("vqfrsm     : %d\n", le16_to_cpu(ctrl->vqfrsm));
+	printf("vqgran     : %d\n", le16_to_cpu(ctrl->vqgran));
+	printf("vifrt      : %u\n", le32_to_cpu(ctrl->vifrt));
+	printf("virfa      : %u\n", le32_to_cpu(ctrl->virfa));
+	printf("virfap     : %d\n", le16_to_cpu(ctrl->virfap));
+	printf("viprt      : %d\n", le16_to_cpu(ctrl->viprt));
+	printf("vifrsm     : %d\n", le16_to_cpu(ctrl->vifrsm));
+	printf("vigran     : %d\n", le16_to_cpu(ctrl->vigran));
+}
+
+void show_nvme_id_secondary_ctrl_entry_scs(__u8 scs)
+{
+	__u8 rsvd = (scs & 0xFE) >> 1;
+	__u8 os  = scs & 0x1;
+
+	if (rsvd)
+		printf("  [7:1] : %#x\tReserved\n", rsvd);
+	printf("  [0:0] : %#x\t Controller is in %s state\n", os,
+		os ? "Online" : "Offline");
+
+}
+
+void show_nvme_id_secondary_ctrl_entry(struct nvme_secondary_ctrl_entry *ctrl)
+{
+	printf("scid     : %#x\n", le16_to_cpu(ctrl->scid));
+	printf("pcid     : %#x\n", le16_to_cpu(ctrl->pcid));
+	printf("scs 	 : %#x\n",ctrl->scs);
+	show_nvme_id_secondary_ctrl_entry_scs(ctrl->scs);
+	printf("vfn	     : %d\n", le16_to_cpu(ctrl->vfn));
+	printf("nvq	     : %d\n", le16_to_cpu(ctrl->nvq));
+	printf("nvi	     : %d\n", le16_to_cpu(ctrl->nvi));
+}
+
+void show_nvme_id_secondary_ctrl_list(struct nvme_id_secondary_ctrl_list *ctrl)
+{
+	int i;
+
+	printf("num_of_identifiers  : %d\n", ctrl->num_of_identifiers);
+	for(i = 0; i < ctrl->num_of_identifiers; i++) {
+		printf("\n Secondary Controller - %d  : \n", i+1);
+		show_nvme_id_secondary_ctrl_entry(&ctrl->sc[i]);
+	}
+}
+
 void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
 {
 	int i;
@@ -2141,6 +2209,58 @@ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*vs)(
 	json_free_object(root);
 }
 
+void json_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl)
+{
+	struct json_object *root;
+	root = json_create_object();
+
+	json_object_add_value_int(root, "cntlid", le16_to_cpu(ctrl->cntlid));
+	json_object_add_value_int(root, "portid", le16_to_cpu(ctrl->portid));
+	json_object_add_value_int(root, "crt", ctrl->crt);
+	json_object_add_value_int(root, "vqfrt", le32_to_cpu(ctrl->vqfrt));
+	json_object_add_value_int(root, "vqrfa", le32_to_cpu(ctrl->vqrfa));
+	json_object_add_value_int(root, "vqrfap", le16_to_cpu(ctrl->vqrfap));
+	json_object_add_value_int(root, "vqprt", le16_to_cpu(ctrl->vqprt));
+	json_object_add_value_int(root, "vqfrsm", le16_to_cpu(ctrl->vqfrsm));
+	json_object_add_value_int(root, "vqgran", le16_to_cpu(ctrl->vqgran));
+	json_object_add_value_uint(root, "vifrt", le32_to_cpu(ctrl->vifrt));
+	json_object_add_value_uint(root, "virfa", le32_to_cpu(ctrl->virfa));
+	json_object_add_value_int(root, "virfap", le16_to_cpu(ctrl->virfap));
+	json_object_add_value_int(root, "viprt", le16_to_cpu(ctrl->viprt));
+	json_object_add_value_int(root, "vifrsm", le16_to_cpu(ctrl->vifrsm));
+	json_object_add_value_int(root, "vigran", le16_to_cpu(ctrl->vigran));
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
+void json_nvme_id_secondary_ctrl(struct nvme_id_secondary_ctrl_list *ctrl)
+{
+	struct json_object *root;
+	struct json_array *valid;
+	struct json_object *valid_attrs;
+	int i;
+
+	root = json_create_object();
+	json_object_add_value_int(root, "num_of_identifiers", ctrl->num_of_identifiers);
+	valid = json_create_array();
+
+	for (i=0; i < ctrl->num_of_identifiers; i++) {
+		valid_attrs = json_create_object();
+		json_object_add_value_int(valid_attrs, "scid", le16_to_cpu(ctrl->sc[i].scid));
+		json_object_add_value_int(valid_attrs, "pcid", le16_to_cpu(ctrl->sc[i].pcid));
+		json_object_add_value_int(valid_attrs, "scs", ctrl->sc[i].scs );
+		json_object_add_value_int(valid_attrs, "vfn", le16_to_cpu(ctrl->sc[i].vfn));
+		json_object_add_value_int(valid_attrs, "nvq", le16_to_cpu(ctrl->sc[i].nvq));
+		json_object_add_value_int(valid_attrs, "nvi", le16_to_cpu(ctrl->sc[i].nvi));
+		json_array_add_value_object(valid, valid_attrs);
+	}
+	json_object_add_value_array(root, "Secondary Controller Entries", valid);
+	json_print_object(root, NULL);
+	printf("\n");
+	json_free_object(root);
+}
+
 void json_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname)
 {
 	struct json_object *root;
diff --git a/nvme-print.h b/nvme-print.h
index 7dd5f34..2d5ab8c 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -58,6 +58,13 @@ void json_nvme_id_ns_descs(void *data);
 void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
 void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname);
 void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname);
+void show_nvme_id_primary_ctrl_crt(__u8 crt);
+void show_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl);
+void show_nvme_id_secondary_ctrl_entry_scs(__u8 scs);
+void show_nvme_id_secondary_ctrl_entry(struct nvme_secondary_ctrl_entry *ctrl);
+void show_nvme_id_secondary_ctrl_list(struct nvme_id_secondary_ctrl_list *ctrl);
+void json_nvme_id_primary_ctrl(struct nvme_id_primary_ctrl *ctrl);
+void json_nvme_id_secondary_ctrl(struct nvme_id_secondary_ctrl_list *ctrl);
 
 
 #endif
diff --git a/nvme.c b/nvme.c
index 2dd74d2..798cfcd 100644
--- a/nvme.c
+++ b/nvme.c
@@ -1633,6 +1633,115 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
 	return __id_ctrl(argc, argv, cmd, plugin, NULL);
 }
 
+int id_primary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Primary Controller command to "\
+		"the given device and report information about the specified "\
+		"primary controller in human-readable or binary format.";
+	int err, fmt, fd;
+	struct nvme_id_primary_ctrl ctrl;
+
+	struct config {
+		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 },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+
+	err = nvme_id_primary_ctrl(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_id_primary_ctrl(&ctrl);
+		else {
+			printf("NVME Primary Controller:\n");
+			show_nvme_id_primary_ctrl(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Primary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
+int id_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+	const char *desc = "Send an Secondary Controller command to "\
+		"the given device and report information about the "\
+		"secondary controllers associated with the primary controller in "\
+		"human-readable or binary format.";
+	int err, fmt, fd;
+	struct nvme_id_secondary_ctrl_list ctrl;
+
+	struct config {
+		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 },
+		{NULL}
+	};
+
+	fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+	if (fd < 0)
+		return fd;
+
+	fmt = validate_output_format(cfg.output_format);
+	if (fmt < 0) {
+		err = fmt;
+		goto close_fd;
+	}
+
+	err = nvme_id_secondary_ctrl(fd, &ctrl);
+	if (!err) {
+		if (fmt == BINARY)
+			d_raw((unsigned char *)&ctrl, sizeof(ctrl));
+		else if (fmt == JSON)
+			json_nvme_id_secondary_ctrl(&ctrl);
+		else {
+			printf("NVME Secondary Controller:\n");
+			show_nvme_id_secondary_ctrl_list(&ctrl);
+		}
+	}
+	else if (err > 0)
+		fprintf(stderr, "NVMe Status:%s(%x)\n",
+				nvme_status_to_string(err), err);
+	else
+		perror("Secondary controller");
+
+ close_fd:
+	close(fd);
+
+	return err;
+}
+
 static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
 	const char *desc = "Send Namespace Identification Descriptors command to the "\
-- 
2.17.1

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
  2018-06-19 15:45 ` Keith Busch
@ 2018-06-19 15:43   ` Christoph Hellwig
  2018-06-19 15:54     ` Keith Busch
  0 siblings, 1 reply; 8+ messages in thread
From: Christoph Hellwig @ 2018-06-19 15:43 UTC (permalink / raw)


On Tue, Jun 19, 2018@09:45:31AM -0600, Keith Busch wrote:
> On Tue, Jun 19, 2018@09:28:59AM -0600, Revanth Rajashekar wrote:
> > +int nvme_ctrl(int fd, __u32 cdw10, void *data)
> > +{
> > +	struct nvme_admin_cmd cmd = {
> > +		.opcode 	= nvme_admin_virtual_mgmt,
> 
> A pitfall from not having a capable device to test with: I'm sure you
> don't possibly mean to use the nvme_admin_virtual_mgmt opcode here.
> 
> Just use nvme_identify().

Btw, I'm really unconfortable with having this code around if it
hasn't actually been tested..

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
  2018-06-19 15:28 [PATCH] nvme-cli: Implemented primary and secondary controller Revanth Rajashekar
@ 2018-06-19 15:45 ` Keith Busch
  2018-06-19 15:43   ` Christoph Hellwig
  0 siblings, 1 reply; 8+ messages in thread
From: Keith Busch @ 2018-06-19 15:45 UTC (permalink / raw)


On Tue, Jun 19, 2018@09:28:59AM -0600, Revanth Rajashekar wrote:
> +int nvme_ctrl(int fd, __u32 cdw10, void *data)
> +{
> +	struct nvme_admin_cmd cmd = {
> +		.opcode 	= nvme_admin_virtual_mgmt,

A pitfall from not having a capable device to test with: I'm sure you
don't possibly mean to use the nvme_admin_virtual_mgmt opcode here.

Just use nvme_identify().

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

* [PATCH] nvme-cli: Implemented primary and secondary controller
  2018-06-19 15:43   ` Christoph Hellwig
@ 2018-06-19 15:54     ` Keith Busch
  0 siblings, 0 replies; 8+ messages in thread
From: Keith Busch @ 2018-06-19 15:54 UTC (permalink / raw)


On Tue, Jun 19, 2018@08:43:17AM -0700, Christoph Hellwig wrote:
> Btw, I'm really unconfortable with having this code around if it
> hasn't actually been tested..

Agreed. If you can't test it, it probably doesn't work.

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

end of thread, other threads:[~2018-06-19 15:54 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-19 15:28 [PATCH] nvme-cli: Implemented primary and secondary controller Revanth Rajashekar
2018-06-19 15:45 ` Keith Busch
2018-06-19 15:43   ` Christoph Hellwig
2018-06-19 15:54     ` Keith Busch
  -- strict thread matches above, loose matches on Subject: below --
2018-06-18 23:12 Revanth Rajashekar
2018-06-19 14:13 ` Keith Busch
2018-06-18 21:28 Revanth Rajashekar
2018-06-18 21:57 ` Keith Busch

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.