From 9131dc9866a85aa71bcaab5ae15c993537499f51 Mon Sep 17 00:00:00 2001 From: Steven Seungcheol Lee Date: Thu, 6 Jan 2022 21:53:08 +0900 Subject: [PATCH] nvme: Add NVM Command Set specific identify namespace command Signed-off-by: Steven Seungcheol Lee --- Documentation/nvme-nvm-id-ns.1 | 162 +++++ Documentation/nvme-nvm-id-ns.html | 881 ++++++++++++++++++++++++++++ Documentation/nvme-nvm-id-ns.txt | 83 +++ completions/_nvme | 21 +- completions/bash-nvme-completion.sh | 6 +- nvme-builtin.h | 1 + nvme-print.c | 80 +++ nvme-print.h | 2 + nvme.c | 75 +++ 9 files changed, 1308 insertions(+), 3 deletions(-) create mode 100644 Documentation/nvme-nvm-id-ns.1 create mode 100644 Documentation/nvme-nvm-id-ns.html create mode 100644 Documentation/nvme-nvm-id-ns.txt diff --git a/Documentation/nvme-nvm-id-ns.1 b/Documentation/nvme-nvm-id-ns.1 new file mode 100644 index 00000000..fde30b7b --- /dev/null +++ b/Documentation/nvme-nvm-id-ns.1 @@ -0,0 +1,162 @@ +'\" t +.\" Title: nvme-nvm-id-ns +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.78.1 +.\" Date: 01/07/2022 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-NVM\-ID\-NS" "1" "01/07/2022" "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-nvm-id-ns \- Send NVMe Identify NVM Command Set specific Namespace data structure, display structure +.SH "SYNOPSIS" +.sp +.nf +\fInvme nvm\-id\-ns\fR [\-\-uuid\-index= | \-U ] + [\-\-namespace\-id= | \-n ] + [\-v | \-\-verbose] + [\-\-output\-format= | \-o ] +.fi +.SH "DESCRIPTION" +.sp +Identify NVM Command Set specific Namespace data structure for the specified NSID for the NVM Command Set specified in the CSI field\&. +.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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&. +.SH "OPTIONS" +.PP +\-n , \-\-namespace\-id= +.RS 4 +Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&. +.RE +.PP +\-U , \-\-uuid\-index= +.RS 4 +UUID Index of the feature +.RE +.PP +\-v, \-\-verbose +.RS 4 +Increase the information detail in the output\&. +.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 +.\} +Has the program interpret the returned buffer and display the known fields in a human readable format: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme nvm\-id\-ns /dev/nvme0n1 +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +If using the character device or overriding namespace id: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme nvm\-id\-ns /dev/nvme0 \-n 1 +# nvme nvm\-id\-ns /dev/nvme0n1 \-n 1 +# nvme nvm\-id\-ns /dev/nvme0 \-\-namespace\-id=1 +.fi +.if n \{\ +.RE +.\} +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Have the program return the raw structure in binary: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme nvm\-id\-ns /dev/nvme0n1 \-o binary > id_ns\&.raw +# nvme nvm\-id\-ns /dev/nvme0n1 \-\-output\-format=binary > id_ns\&.raw +.fi +.if n \{\ +.RE +.\} +.sp +It is probably a bad idea to not redirect stdout when using this mode\&. +.RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Alternatively you may want to send the data to another program that can parse the raw buffer\&. +.sp +.if n \{\ +.RS 4 +.\} +.nf +NVME +.fi +.if n \{\ +.RE +.\} +.RE +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-nvm-id-ns.html b/Documentation/nvme-nvm-id-ns.html new file mode 100644 index 00000000..82645dcf --- /dev/null +++ b/Documentation/nvme-nvm-id-ns.html @@ -0,0 +1,881 @@ + + + + + +nvme-nvm-id-ns(1) + + + + + +
+
+

SYNOPSIS

+
+
+
nvme nvm-id-ns <device> [--uuid-index=<uuid-index> | -U <uuid_index>]
+                        [--namespace-id=<NUM> | -n <NUM>]
+                        [-v | --verbose]
+                        [--output-format=<fmt> | -o <fmt>]
+
+
+
+
+
+

DESCRIPTION

+
+

Identify NVM Command Set specific Namespace data structure for the specified +NSID for the NVM Command Set specified in the CSI field.

+

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 structure may be returned in one of several ways depending +on the option flags; the structure may be parsed by the program or the +raw buffer may be printed to stdout.

+
+
+
+

OPTIONS

+
+
+
+-n <NUM> +
+
+--namespace-id=<NUM> +
+
+

+ Use the provided namespace id for the command. If not provided, the + namespace id of the block device will be used. If the command is issued + to a non-block device, the parameter is required. +

+
+
+-U <uuid-index> +
+
+--uuid-index=<uuid-index> +
+
+

+ UUID Index of the feature +

+
+
+-v +
+
+--verbose +
+
+

+ Increase the information detail in the output. +

+
+
+-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

+
+
    +
  • +

    +Has the program interpret the returned buffer and display the known +fields in a human readable format: +

    +
    +
    +
    # nvme nvm-id-ns /dev/nvme0n1
    +
    +
  • +
  • +

    +If using the character device or overriding namespace id: +

    +
    +
    +
    # nvme nvm-id-ns /dev/nvme0 -n 1
    +# nvme nvm-id-ns /dev/nvme0n1 -n 1
    +# nvme nvm-id-ns /dev/nvme0 --namespace-id=1
    +
    +
  • +
  • +

    +Have the program return the raw structure in binary: +

    +
    +
    +
    # nvme nvm-id-ns /dev/nvme0n1 -o binary > id_ns.raw
    +# nvme nvm-id-ns /dev/nvme0n1 --output-format=binary > id_ns.raw
    +
    +

    It is probably a bad idea to not redirect stdout when using this mode.

    +
  • +
  • +

    +Alternatively you may want to send the data to another program that +can parse the raw buffer. +

    +
    +
    +
    NVME
    +
    +
  • +
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-nvm-id-ns.txt b/Documentation/nvme-nvm-id-ns.txt new file mode 100644 index 00000000..dfbbfaa2 --- /dev/null +++ b/Documentation/nvme-nvm-id-ns.txt @@ -0,0 +1,83 @@ +nvme-nvm-id-ns(1) +================= + +NAME +---- +nvme-nvm-id-ns - Send NVMe Identify NVM Command Set specific Namespace data structure, display structure + +SYNOPSIS +-------- +[verse] +'nvme nvm-id-ns' [--uuid-index= | -U ] + [--namespace-id= | -n ] + [-v | --verbose] + [--output-format= | -o ] + +DESCRIPTION +----------- +Identify NVM Command Set specific Namespace data structure for the specified +NSID for the NVM Command Set specified in the CSI field. + +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 structure may be returned in one of several ways depending +on the option flags; the structure may be parsed by the program or the +raw buffer may be printed to stdout. + +OPTIONS +------- +-n :: +--namespace-id=:: + Use the provided namespace id for the command. If not provided, the + namespace id of the block device will be used. If the command is issued + to a non-block device, the parameter is required. + +-U :: +--uuid-index=:: + UUID Index of the feature + +-v:: +--verbose:: + Increase the information detail in the output. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. + +EXAMPLES +-------- +* Has the program interpret the returned buffer and display the known +fields in a human readable format: ++ +------------ +# nvme nvm-id-ns /dev/nvme0n1 +------------ ++ + +* If using the character device or overriding namespace id: ++ +------------ +# nvme nvm-id-ns /dev/nvme0 -n 1 +# nvme nvm-id-ns /dev/nvme0n1 -n 1 +# nvme nvm-id-ns /dev/nvme0 --namespace-id=1 +------------ ++ +* Have the program return the raw structure in binary: ++ +------------ +# nvme nvm-id-ns /dev/nvme0n1 -o binary > id_ns.raw +# nvme nvm-id-ns /dev/nvme0n1 --output-format=binary > id_ns.raw +------------ ++ +It is probably a bad idea to not redirect stdout when using this mode. + +* Alternatively you may want to send the data to another program that +can parse the raw buffer. ++ +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/completions/_nvme b/completions/_nvme index 03398f3a..980dbc9e 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -20,6 +20,7 @@ _nvme () { 'detach-ns:detach namespace from controller' 'list-ctrl:identify all controller(s) attached' 'nvm-id-ctrl:display information about the nvm command set' + 'nvm-id-ns:display information about the namespace of nvm command set' 'list-endgrp:display information about nvme endurance group list' 'get-ns-id:get namespace id of opened block device' 'get-log:retrieve any log in raw format' @@ -163,7 +164,7 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme id-domain options" _iddomain ;; - nvm-id-ctrl) + (nvm-id-ctrl) local _nvmidctrl _nvmidctrl=( /dev/nvme':supply a device to use (required)' @@ -171,6 +172,22 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme nvm-id-ctrl options" _nvmidctrl ;; + (nvm-id-ns) + local _nvmidns + _nvmidns=( + /dev/nvme':supply a device to use (required)' + --namespace-id=':show infos for namespace ' + -n':alias of --namespace-id' + --uuid-index=':uuid index' + -U':alias for --uuid-index' + --output-format=':Output format: normal|json|binary' + -o':alias for --output-format' + --verbose':show infos verbosely' + -v':alias of --verbose' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme nvm-id-ns options" _nvmidns + ;; (list-endgrp) local _listendgrp _listendgrp=( @@ -931,7 +948,7 @@ _nvme () { resv-report flush compare read write copy show-regs persistent-event-log pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log lba-status-log resv-notif-log capacity-mgmt id-domain boot-part-log fid-support-effects-log - supported-log-pages lockdown media-unit-stat-log id-ns-lba-format + supported-log-pages lockdown media-unit-stat-log id-ns-lba-format nvm-id-ns ) _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 facffb87..da9ed9bf 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -78,7 +78,7 @@ readonly _plugin_funcs=( # Top level commands _cmds="list list-subsys id-ctrl id-ns \ id-ns-granularity list-ns list-ctrl \ - id-ns-lba-format \ + id-ns-lba-format nvm-id-ns \ nvm-id-ctrl primary-ctrl-caps list-secondary \ ns-descs id-nvmset id-uuid id-iocs create-ns \ delete-ns get-ns-id get-log telemetry-log \ @@ -164,6 +164,10 @@ nvme_list_opts () { "nvm-id-ctrl") opts+=" --output-format= -o" ;; + "nvm-id-ns") + opts+=" --namespace-id= -n --uuid-index= -U\ + --verbose -v --output-format= -o" + ;; "primary-ctrl-caps") opts+=" --output-format= -o --human-readable -H" ;; diff --git a/nvme-builtin.h b/nvme-builtin.h index 89c3c14f..bac94cba 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -16,6 +16,7 @@ COMMAND_LIST( ENTRY("list-ns", "Send NVMe Identify List, display structure", list_ns) ENTRY("list-ctrl", "Send NVMe Identify Controller List, display structure", list_ctrl) ENTRY("nvm-id-ctrl", "Send NVMe Identify Controller NVM Command Set, display structure", nvm_id_ctrl) + ENTRY("nvm-id-ns", "Send NVMe Identify Namespace NVM Command Set, display structure", nvm_id_ns) ENTRY("primary-ctrl-caps", "Send NVMe Identify Primary Controller Capabilities", primary_ctrl_caps) ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl) ENTRY("cmdset-ind-id-ns", "I/O Command Set Independent Identify Namespace", cmd_set_independent_id_ns) diff --git a/nvme-print.c b/nvme-print.c index 0da0ba56..2fb6197e 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -4424,6 +4424,86 @@ void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, printf("dmsl : %"PRIu64"\n", le64_to_cpu(ctrl_nvm->dmsl)); } +static void json_nvme_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, + struct nvme_id_ns *ns) +{ + struct json_object *root; + struct json_object *elbafs; + int i; + + root = json_create_object(); + + json_object_add_value_uint64(root, "lbstm", le64_to_cpu(nvm_ns->lbstm)); + json_object_add_value_int(root, "pic", nvm_ns->pic); + + elbafs = json_create_array(); + json_object_add_value_array(root, "elbafs", elbafs); + + for (i = 0; i <= ns->nlbaf; i++) { + struct json_object *elbaf = json_create_object(); + unsigned int elbaf_val = le32_to_cpu(nvm_ns->elbaf[i]); + + json_object_add_value_int(elbaf, "sts", elbaf_val & 0x7F); + json_object_add_value_int(elbaf, "pif", (elbaf_val >> 7) & 0x3); + + json_array_add_value_object(elbafs, elbaf); + } + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +static void nvme_show_nvm_id_ns_pic(__u8 pic) +{ + __u8 rsvd = (pic & 0xFC) >> 2; + __u8 pic_16bpistm = (pic & 0x2) >> 1; + __u8 pic_16bpists = pic & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\t16b Guard Protection Information Storage Tag Mask\n", + pic_16bpistm); + printf(" [0:0] : %#x\t16b Guard Protection Information Storage Tag Support\n", + pic_16bpists); + printf("\n"); +} + +void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, + struct nvme_id_ns *ns, enum nvme_print_flags flags) +{ + int i, verbose = flags & VERBOSE; + __u32 elbaf; + int pif, sts; + + if (flags & BINARY) + return d_raw((unsigned char *)nvm_ns, sizeof(*nvm_ns)); + else if (flags & JSON) + return json_nvme_nvm_id_ns(nvm_ns, ns); + + printf("NVMe NVM Identify Namespace %d:\n", nsid); + printf("lbstm : %#"PRIx64"\n", le64_to_cpu(nvm_ns->lbstm)); + printf("pic : %#x\n", nvm_ns->pic); + if (verbose) + nvme_show_nvm_id_ns_pic(nvm_ns->pic); + + for (i = 0; i <= ns->nlbaf; i++) { + elbaf = le32_to_cpu(nvm_ns->elbaf[i]); + pif = (elbaf >> 7) & 0x3; + sts = elbaf & 0x7f; + if (verbose) + printf("Extended LBA Format %2d : Protection Information Format: " + "%s(%d) - Storage Tag Size (MSB): %-2d %s\n", + i, pif == 3 ? "Reserved" : + pif == 2 ? "64b Guard" : + pif == 1 ? "32b Guard" : "16b Guard", + pif, sts, i == (ns->flbas & 0xf) ? "(in use)" : ""); + else + printf("elbaf %2d : pif:%d lbads:%-2d %s\n", i, + pif, sts, i == (ns->flbas & 0xf) ? "(in use)" : ""); + } +} + static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl) { struct json_object *root; diff --git a/nvme-print.h b/nvme-print.h index 073e171e..f9ba54d4 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -112,6 +112,8 @@ void nvme_show_select_result(__u32 result); void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode); void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, enum nvme_print_flags flags); +void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, + struct nvme_id_ns *ns, enum nvme_print_flags flags); void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns, struct nvme_id_ns *id_ns, unsigned long flags); void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log, diff --git a/nvme.c b/nvme.c index dbf557b7..1c7069cf 100644 --- a/nvme.c +++ b/nvme.c @@ -2655,6 +2655,81 @@ ret: return err; } +static int nvm_id_ns(int argc, char **argv, struct command *cmd, + struct plugin *plugin) +{ + const char *desc = "Send an Identify Namespace NVM Command Set "\ + "command to the given device and report information about "\ + "the specified namespace in various formats."; + const char *namespace_id = "identifier of desired namespace"; + const char *uuid_index = "UUID index"; + const char *verbose = "Increase output verbosity"; + enum nvme_print_flags flags; + struct nvme_nvm_id_ns id_ns; + struct nvme_id_ns ns; + int fd, err = -1; + + struct config { + __u32 namespace_id; + __u8 uuid_index; + char *output_format; + int verbose; + }; + + struct config cfg = { + .namespace_id = 0, + .uuid_index = NVME_UUID_NONE, + .output_format = "normal", + .verbose = 0, + }; + + OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), + OPT_END() + }; + + 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; + + if (cfg.verbose) + flags |= VERBOSE; + + if (!cfg.namespace_id) { + err = nvme_get_nsid(fd, &cfg.namespace_id); + if (err < 0) { + perror("get-namespace-id"); + goto close_fd; + } + } + + err = nvme_identify_ns(fd, cfg.namespace_id, &ns); + if (err) { + nvme_show_status(err); + goto close_fd; + } + + err = nvme_identify_ns_csi(fd, cfg.namespace_id, cfg.uuid_index, + NVME_CSI_NVM, &id_ns); + if (!err) + nvme_show_nvm_id_ns(&id_ns, cfg.namespace_id, &ns, flags); + else if (err > 0) + nvme_show_status(err); + else + perror("nvm identify namespace"); +close_fd: + close(fd); +ret: + return nvme_status_to_errno(err, false); +} + 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.50.1