Linux-NVME Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: hch@lst.de (Christoph Hellwig)
Subject: [PATCH 5/6] nvme-cli: Implement ana log page support
Date: Fri, 27 Jul 2018 17:15:30 +0200	[thread overview]
Message-ID: <20180727151530.GA30341@lst.de> (raw)
In-Reply-To: <20180727102632.32455-6-hare@suse.de>

Chaitanya already sent a patch for this two days ago..

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

  reply	other threads:[~2018-07-27 15:15 UTC|newest]

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

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20180727151530.GA30341@lst.de \
    --to=hch@lst.de \
    /path/to/YOUR_REPLY

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

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