From: Gollu Appalanaidu Date: Tue, 23 Feb 2021 18:58:45 +0000 (+0530) Subject: nvme: add support for lba status log page X-Git-Tag: v1.14~70 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=b7477b20f37cc991c02681c46a76d1d891ace62a;p=users%2Fsagi%2Fnvme-cli.git nvme: add support for lba status log page This log page is used to provide information about subsequent actions the host may take to discover which logical blocks, in namespaces that are attached to the controller, may no longer be recoverable when read. For more details see NVM Express 1.4 Spec. Section 5.14.1.14("LBA Status Information (Log Identifier 0Eh)") Signed-off-by: Gollu Appalanaidu Co-Authored-By: Karthik Balan --- diff --git a/Documentation/nvme-lba-status-log.1 b/Documentation/nvme-lba-status-log.1 new file mode 100644 index 00000000..6903a3ea --- /dev/null +++ b/Documentation/nvme-lba-status-log.1 @@ -0,0 +1,105 @@ +'\" t +.\" Title: nvme-lba-status-log +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 02/24/2021 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-LBA\-STATUS\-L" "1" "02/24/2021" "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-lba-status-log \- Send LBA Status Log Page request returns result and log +.SH "SYNOPSIS" +.sp +.nf +\fInvme lba\-status\-log\fR [\-\-rae | \-r] [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +Retrieves the NVMe LBA Status Log Page from an NVMe device and provides the returned structure\&. +.sp +The parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&. +.sp +On success, the returned LBA Status Log Page 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 +\-r, \-\-rae +.RS 4 +Retain an Asynchronous Event\&. +.RE +.PP +\-o , \-\-output\-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 LBA Status Log page in a normal readable format: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme lba\-status\-log /dev/nvme0 +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Show the output in json format +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme lba\-status\-log /dev/nvme0 \-o json ++ + +NVME +.fi +.if n \{\ +.RE +.\} +.RE +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-lba-status-log.html b/Documentation/nvme-lba-status-log.html new file mode 100644 index 00000000..64cb9383 --- /dev/null +++ b/Documentation/nvme-lba-status-log.html @@ -0,0 +1,838 @@ + + + + + + +nvme-lba-status-log(1) + + + + + +
+
+

SYNOPSIS

+
+
+
nvme lba-status-log <device> [--rae | -r] [--output-format=<fmt> | -o <fmt>]
+
+
+
+
+
+

DESCRIPTION

+
+

Retrieves the NVMe LBA Status Log Page from an NVMe device and provides +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 LBA Status Log Page 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

+
+
+
+-r +
+
+--rae +
+
+

+ Retain an Asynchronous Event. +

+
+
+-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 LBA Status Log page in a normal readable format: +

    +
    +
    +
    # nvme lba-status-log /dev/nvme0
    +
    +
  • +
  • +

    +Show the output in json format +

    +
    +
    +
    # nvme lba-status-log /dev/nvme0 -o json
    ++
    +
    +NVME
    +
    +
  • +
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-lba-status-log.txt b/Documentation/nvme-lba-status-log.txt new file mode 100644 index 00000000..0d888f7f --- /dev/null +++ b/Documentation/nvme-lba-status-log.txt @@ -0,0 +1,54 @@ +nvme-lba-status-log(1) +====================== + +NAME +---- +nvme-lba-status-log - Send LBA Status Log Page request returns result and log + +SYNOPSIS +-------- +[verse] +'nvme lba-status-log' [--rae | -r] [--output-format= | -o ] + +DESCRIPTION +----------- +Retrieves the NVMe LBA Status Log Page from an NVMe device and provides +the returned structure. + +The 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 LBA Status Log Page 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 +------- +-r:: +--rae:: + Retain an Asynchronous Event. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or 'binary'. + Only one output format can be used at a time. + +EXAMPLES +-------- +* Print the LBA Status Log page in a normal readable format: ++ +------------ +# nvme lba-status-log /dev/nvme0 +------------ ++ + +* Show the output in json format ++ +------------ +# nvme lba-status-log /dev/nvme0 -o json ++ + +NVME +---- +Part of the nvme-user suite \ No newline at end of file diff --git a/completions/_nvme b/completions/_nvme index 5faabc7c..71c12975 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -27,6 +27,7 @@ _nvme () { 'smart-log-add:retrieve additional SMART log' 'error-log:retrieve error log' 'endurance-event-agg-log:retrieve endurance group event aggregate log' + 'lba-status-log:retrieve lba status log' 'get-feature:display a controller feature' 'set-feature:set a controller feature and show results' 'format:apply new block format to namespace' @@ -311,6 +312,16 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme endurance-event-agg-log options" _enduranceeventagglog ;; + (lba-status-log) + local _lbastatuslog + _lbastatuslog=( + /dev/nvme':supply a device to use (required)' + --rae': Retain an Asynchronous Event' + -r':alias to --rae + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme lba-status-log options" _lbastatuslog + ;; (get-feature) local _getf _getf=( @@ -767,7 +778,7 @@ _nvme () { set-feature format fw-activate fw-download admin-passthru io-passthru security-send security-recv resv-acquire resv-register resv-release resv-report flush compare read write copy show-regs persistent-event-log - pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log + pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log lba-status-log ) _arguments '*:: :->subcmds' _describe -t commands "help: infos on a specific nvme command, or provide no option to see a synopsis of all nvme commands" _h diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh index 44bb1468..7ab4226a 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -11,7 +11,8 @@ _cmds="list id-ctrl id-ns list-ns id-iocs nvm-id-ctrl create-ns delete-ns \ resv-report dsm flush compare read write write-zeroes \ write-uncor copy reset subsystem-reset show-regs discover \ connect-all connect disconnect version help \ - intel lnvm memblaze list-subsys endurance-event-agg-log" + intel lnvm memblaze list-subsys endurance-event-agg-log \ + lba-status-log" nvme_list_opts () { local opts="" @@ -104,6 +105,9 @@ nvme_list_opts () { opts+=" --log-entries= -e --rae -r \ --raw-binary -b --output-format= -o" ;; + "lba-status-log") + opts+=" --rae -r --output-format= -o" + ;; "get-feature") opts+=" --namespace-id= -n --feature-id= -f --sel= -s \ --data-len= -l --cdw11= --raw-binary -b \ diff --git a/linux/nvme.h b/linux/nvme.h index a5e5f5f4..6ff04abb 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -911,6 +911,27 @@ struct nvme_predlat_per_nvmset_log_page { __u8 rsvd152[360]; }; +struct nvme_lba_status_range_desc { + __le64 rslba; + __le32 rnlb; + __u8 rsvd12[4]; +}; + +struct nvme_lba_status_ns_element { + __le32 neid; + __le32 nlrd; + __u8 ratype; + __u8 rsvd9[7]; +}; + +struct nvme_lba_status_hdr { + __le32 lslplen; + __le32 nlslne; + __le32 estulb; + __u8 rsvd12[2]; + __le16 lsgc; +}; + enum { NVME_SMART_CRIT_SPARE = 1 << 0, NVME_SMART_CRIT_TEMPERATURE = 1 << 1, @@ -1213,6 +1234,7 @@ enum { NVME_LOG_ANA = 0x0c, NVME_LOG_PRELAT_EVENT_AGG = 0x0b, NVME_LOG_PERSISTENT_EVENT = 0x0d, + NVME_LOG_LBA_STATUS = 0x0e, NVME_LOG_ENDURANCE_GROUP_EVENT_AGG = 0x0f, NVME_LOG_DISC = 0x70, NVME_LOG_RESERVATION = 0x80, diff --git a/nvme-builtin.h b/nvme-builtin.h index d84e5f0c..296afd65 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -38,6 +38,7 @@ COMMAND_LIST( ENTRY("pred-lat-event-agg-log", "Retrieve Predictable Latency Event Aggregate Log, show it", get_pred_lat_event_agg_log) ENTRY("persistent-event-log", "Retrieve Presistent Event Log, show it", get_persistent_event_log) ENTRY("endurance-event-agg-log", "Retrieve Endurance Group Event Aggregate Log, show it", get_endurance_event_agg_log) + ENTRY("lba-status-log", "Retrieve LBA Status Information Log, show it", get_lba_status_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 82ac67ab..8aba0bcb 100644 --- a/nvme-ioctl.c +++ b/nvme-ioctl.c @@ -627,6 +627,13 @@ int nvme_endurance_group_event_agg_log(int fd, size, endurance_log); } +int nvme_lba_status_log(int fd, void *lba_status, bool rae, + __u32 size) +{ + return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_LBA_STATUS, + rae, NVME_NO_LOG_LSP, size, lba_status); +} + 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 585d4b27..4f13bdcf 100644 --- a/nvme-ioctl.h +++ b/nvme-ioctl.h @@ -114,7 +114,8 @@ int nvme_endurance_group_event_agg_log(int fd, void *endurance_log, bool rae, __u32 size); int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log); - +int nvme_lba_status_log(int fd, void *lba_status, bool rae, + __u32 size); 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-print.c b/nvme-print.c index c38deacd..85429e11 100755 --- a/nvme-print.c +++ b/nvme-print.c @@ -1614,6 +1614,115 @@ void nvme_show_endurance_group_event_agg_log( } } +void json_lba_status_log(void *lba_status) +{ + struct json_object *root; + struct json_object *desc; + struct json_object *element; + struct json_array *desc_list; + struct json_array *elements_list; + struct nvme_lba_status_hdr *hdr; + struct nvme_lba_status_ns_element *ns_element; + struct nvme_lba_status_range_desc *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc, num_elements; + + root = json_create_object(); + hdr = lba_status; + json_object_add_value_uint(root, "lslplen", le32_to_cpu(hdr->lslplen)); + num_elements = le32_to_cpu(hdr->nlslne); + json_object_add_value_uint(root, "nlslne", num_elements); + json_object_add_value_uint(root, "estulb", le32_to_cpu(hdr->estulb)); + json_object_add_value_uint(root, "lsgc", le16_to_cpu(hdr->lsgc)); + + elements_list = json_create_array(); + for (int ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + element = json_create_object(); + json_object_add_value_uint(element, "neid", + le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + json_object_add_value_uint(element, "nlrd", num_lba_desc); + json_object_add_value_uint(element, "ratype", ns_element->ratype); + + offset += sizeof(*ns_element); + desc_list = json_create_array(); + if (num_lba_desc != 0xffffffff) { + for (int i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + desc = json_create_object(); + json_object_add_value_uint(desc, "rslba", + le64_to_cpu(range_desc->rslba)); + json_object_add_value_uint(desc, "rnlb", + le32_to_cpu(range_desc->rnlb)); + + offset += sizeof(*range_desc); + json_array_add_value_object(desc_list, desc); + } + } else { + printf("Number of LBA Range Descriptors (NLRD) set to %#x for " \ + "NS element %d", num_lba_desc, ele); + } + + json_object_add_value_array(element, "descs", desc_list); + json_array_add_value_object(elements_list, element); + } + + json_object_add_value_array(root, "ns_elements", elements_list); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_lba_status_log(void *lba_status, __u32 size, + const char *devname, enum nvme_print_flags flags) +{ + struct nvme_lba_status_hdr *hdr; + struct nvme_lba_status_ns_element *ns_element; + struct nvme_lba_status_range_desc *range_desc; + int offset = sizeof(*hdr); + __u32 num_lba_desc, num_elements; + + if (flags & BINARY) + return d_raw((unsigned char *)lba_status, size); + if (flags & JSON) + return json_lba_status_log(lba_status); + + hdr = lba_status; + printf("LBA Status Log for device: %s\n", devname); + printf("LBA Status Log Page Length: %"PRIu32"\n", + le32_to_cpu(hdr->lslplen)); + num_elements = le32_to_cpu(hdr->nlslne); + printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n", + num_elements); + printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n", + le32_to_cpu(hdr->estulb)); + printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc)); + for (int ele = 0; ele < num_elements; ele++) { + ns_element = lba_status + offset; + printf("Namespace Element Identifier: %"PRIu32"\n", + le32_to_cpu(ns_element->neid)); + num_lba_desc = le32_to_cpu(ns_element->nlrd); + printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc); + printf("Recommended Action Type: %u\n", ns_element->ratype); + + offset += sizeof(*ns_element); + if (num_lba_desc != 0xffffffff) { + for (int i = 0; i < num_lba_desc; i++) { + range_desc = lba_status + offset; + printf("RSLBA[%d]: %"PRIu64"\n", i, + le64_to_cpu(range_desc->rslba)); + printf("RNLB[%d]: %"PRIu32"\n", i, + le32_to_cpu(range_desc->rnlb)); + offset += sizeof(*range_desc); + } + } else { + printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\ + "NS element %d\n", num_lba_desc, ele); + } + } +} + static void nvme_show_subsystem(struct nvme_subsystem *s) { int i; diff --git a/nvme-print.h b/nvme-print.h index 636c88c9..d6e1e2ab 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -61,6 +61,9 @@ void nvme_show_endurance_group_event_agg_log( struct nvme_event_agg_log_page *endurance_log, __u64 log_entries, __u32 size, const char *devname, enum nvme_print_flags flags); +void json_lba_status_log(void *lba_status); +void nvme_show_lba_status_log(void *lba_status, __u32 size, + const char *devname, enum nvme_print_flags flags); void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags); void nvme_show_single_property(int offset, uint64_t prop, int human); void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags); diff --git a/nvme.c b/nvme.c index 36968839..ea5653c4 100644 --- a/nvme.c +++ b/nvme.c @@ -1097,6 +1097,73 @@ ret: return nvme_status_to_errno(err, false); } +static int get_lba_status_log(int argc, char **argv, + struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Retrieve Get LBA Status Info Log " \ + "and prints it, for the given device in either " \ + "decoded format(default),json or binary."; + const char *rae = "Retain an Asynchronous Event"; + void *lab_status; + enum nvme_print_flags flags; + int err, fd; + __u32 lslplen; + + struct config { + bool rae; + char *output_format; + }; + + struct config cfg = { + .rae = false, + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_FLAG("rae", 'r', &cfg.rae, rae), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_END() + }; + + err = fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + goto ret; + + err = flags = validate_output_format(cfg.output_format); + if (flags < 0) + goto close_fd; + + err = nvme_lba_status_log(fd, &lslplen, true, sizeof(__u32)); + if (err < 0) { + perror("lba status log page"); + goto close_fd; + } else if (err) { + nvme_show_status(err); + goto close_fd; + } + + lab_status = calloc(lslplen, 1); + if (!lab_status) { + perror("could not alloc buffer for lba status log"); + err = -ENOMEM; + goto close_fd; + } + + err = nvme_lba_status_log(fd, lab_status, cfg.rae, lslplen); + if (!err) + nvme_show_lba_status_log(lab_status, lslplen, devicename, flags); + else if (err > 0) + nvme_show_status(err); + else + perror("lba status log page"); + free(lab_status); + +close_fd: + close(fd); +ret: + return nvme_status_to_errno(err, false); +} + static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Retrieve desired number of bytes "\