From fb32fdeba1f428a3f6c30c8951e82f2a2eec23a8 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 12 Aug 2021 14:01:09 +0200 Subject: Merging upstream version 1.15. Signed-off-by: Daniel Baumann --- Documentation/nvme-admin-passthru.1 | 14 +- Documentation/nvme-admin-passthru.html | 26 +- Documentation/nvme-admin-passthru.txt | 5 + Documentation/nvme-capacity-mgmt.1 | 71 ++ Documentation/nvme-capacity-mgmt.html | 845 ++++++++++++++ Documentation/nvme-capacity-mgmt.txt | 54 + Documentation/nvme-compare.1 | 14 +- Documentation/nvme-compare.html | 27 +- Documentation/nvme-compare.txt | 6 + Documentation/nvme-connect-all.txt | 10 +- Documentation/nvme-connect.txt | 17 +- Documentation/nvme-discover.txt | 20 +- Documentation/nvme-get-feature.1 | 26 +- Documentation/nvme-get-feature.html | 33 +- Documentation/nvme-get-feature.txt | 9 + Documentation/nvme-get-lba-status.1 | 134 +++ Documentation/nvme-get-lba-status.html | 903 +++++++++++++++ Documentation/nvme-get-lba-status.txt | 82 ++ Documentation/nvme-get-log.1 | 40 +- Documentation/nvme-get-log.html | 53 +- Documentation/nvme-get-log.txt | 30 +- Documentation/nvme-id-domain.1 | 62 + Documentation/nvme-id-domain.html | 819 ++++++++++++++ Documentation/nvme-id-domain.txt | 40 + Documentation/nvme-id-iocs.1 | 43 +- Documentation/nvme-id-iocs.html | 38 +- Documentation/nvme-id-iocs.txt | 17 +- Documentation/nvme-io-passthru.1 | 14 +- Documentation/nvme-io-passthru.html | 21 +- Documentation/nvme-io-passthru.txt | 5 + Documentation/nvme-list-ctrl.1 | 18 +- Documentation/nvme-list-ctrl.html | 28 +- Documentation/nvme-list-ctrl.txt | 7 +- Documentation/nvme-list-ns.1 | 59 +- Documentation/nvme-list-ns.html | 37 +- Documentation/nvme-list-ns.txt | 19 +- Documentation/nvme-micron-smart-add-log.1 | 87 ++ Documentation/nvme-micron-smart-add-log.html | 815 ++++++++++++++ Documentation/nvme-micron-smart-add-log.txt | 54 + Documentation/nvme-primary-ctrl-caps.1 | 104 ++ Documentation/nvme-primary-ctrl-caps.html | 842 ++++++++++++++ Documentation/nvme-primary-ctrl-caps.txt | 53 + Documentation/nvme-read.1 | 14 +- Documentation/nvme-read.html | 17 +- Documentation/nvme-read.txt | 6 + Documentation/nvme-resv-register.1 | 2 +- Documentation/nvme-resv-register.html | 2 +- Documentation/nvme-resv-register.txt | 2 +- Documentation/nvme-set-feature.1 | 16 +- Documentation/nvme-set-feature.html | 27 +- Documentation/nvme-set-feature.txt | 7 + Documentation/nvme-verify.1 | 151 +++ Documentation/nvme-verify.html | 961 ++++++++++++++++ Documentation/nvme-verify.txt | 93 ++ Documentation/nvme-write-zeroes.1 | 34 +- Documentation/nvme-write-zeroes.html | 49 +- Documentation/nvme-write-zeroes.txt | 13 +- Documentation/nvme-write.1 | 14 +- Documentation/nvme-write.html | 17 +- Documentation/nvme-write.txt | 6 + Documentation/nvme-zns-close-zone.1 | 12 +- Documentation/nvme-zns-finish-zone.1 | 12 +- Documentation/nvme-zns-offline-zone.1 | 12 +- Documentation/nvme-zns-open-zone.1 | 12 +- Documentation/nvme-zns-reset-zone.1 | 10 +- Documentation/nvme-zns-set-zone-desc.1 | 10 +- Documentation/nvme-zns-zone-mgmt-send.1 | 16 +- NVME-VERSION-GEN | 2 +- cmd_handler.h | 8 +- completions/_nvme | 46 +- completions/bash-nvme-completion.sh | 1250 +++++++++++++++++++-- etc/discovery.conf.in | 2 +- fabrics.c | 145 ++- fabrics.h | 2 + linux/nvme.h | 133 ++- linux/nvme_ioctl.h | 16 - nvme-builtin.h | 2 + nvme-ioctl.c | 169 +-- nvme-ioctl.h | 30 +- nvme-print.c | 642 +++++++++-- nvme-print.h | 7 +- nvme-rpmb.c | 2 +- nvme-topology.c | 50 +- nvme.c | 1059 +++++++++++------ nvme.h | 9 + nvmf-autoconnect/systemd/nvmf-autoconnect.service | 3 +- plugin.c | 2 +- plugin.h | 1 + plugins/amzn/amzn-nvme.h | 2 +- plugins/dera/dera-nvme.h | 2 +- plugins/huawei/huawei-nvme.h | 2 +- plugins/intel/intel-nvme.c | 10 +- plugins/intel/intel-nvme.h | 2 +- plugins/lnvm/lnvm-nvme.h | 2 +- plugins/memblaze/memblaze-nvme.c | 12 +- plugins/memblaze/memblaze-nvme.h | 2 +- plugins/micron/micron-nvme.c | 473 +++++--- plugins/micron/micron-nvme.h | 5 +- plugins/netapp/netapp-nvme.h | 2 +- plugins/nvidia/nvidia-nvme.h | 2 +- plugins/scaleflux/sfx-nvme.h | 2 +- plugins/seagate/seagate-nvme.c | 2 +- plugins/seagate/seagate-nvme.h | 2 +- plugins/shannon/shannon-nvme.c | 4 +- plugins/shannon/shannon-nvme.h | 2 +- plugins/toshiba/toshiba-nvme.c | 2 +- plugins/toshiba/toshiba-nvme.h | 2 +- plugins/transcend/transcend-nvme.h | 2 +- plugins/virtium/virtium-nvme.h | 2 +- plugins/wdc/wdc-nvme.c | 205 ++-- plugins/wdc/wdc-nvme.h | 3 +- plugins/wdc/wdc-utils.c | 4 + plugins/ymtc/ymtc-nvme.h | 2 +- plugins/zns/zns.c | 66 +- plugins/zns/zns.h | 2 +- scripts/gen-hostnqn.sh | 18 - 116 files changed, 10374 insertions(+), 1158 deletions(-) create mode 100644 Documentation/nvme-capacity-mgmt.1 create mode 100644 Documentation/nvme-capacity-mgmt.html create mode 100644 Documentation/nvme-capacity-mgmt.txt create mode 100644 Documentation/nvme-get-lba-status.1 create mode 100644 Documentation/nvme-get-lba-status.html create mode 100644 Documentation/nvme-get-lba-status.txt create mode 100644 Documentation/nvme-id-domain.1 create mode 100644 Documentation/nvme-id-domain.html create mode 100644 Documentation/nvme-id-domain.txt create mode 100644 Documentation/nvme-micron-smart-add-log.1 create mode 100644 Documentation/nvme-micron-smart-add-log.html create mode 100644 Documentation/nvme-micron-smart-add-log.txt create mode 100644 Documentation/nvme-primary-ctrl-caps.1 create mode 100644 Documentation/nvme-primary-ctrl-caps.html create mode 100644 Documentation/nvme-primary-ctrl-caps.txt create mode 100644 Documentation/nvme-verify.1 create mode 100644 Documentation/nvme-verify.html create mode 100644 Documentation/nvme-verify.txt diff --git a/Documentation/nvme-admin-passthru.1 b/Documentation/nvme-admin-passthru.1 index 286709f..8cf0095 100644 --- a/Documentation/nvme-admin-passthru.1 +++ b/Documentation/nvme-admin-passthru.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-admin-passthru -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 06/04/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ADMIN\-PASSTHR" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-ADMIN\-PASSTHR" "1" "06/04/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -46,6 +46,7 @@ nvme-admin-passthru \- Submit an arbitrary admin command, return results [\-\-dry\-run | \-d] [\-\-raw\-binary | \-b] [\-\-prefill= | \-p ] + [\-\-latency | \-T] .fi .SH "DESCRIPTION" .sp @@ -123,6 +124,11 @@ Print the raw returned buffer to stdout if the command returns a structure\&. .RS 4 Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may be useful if the data you are writing is shorter than the required buffer, and you need to pad it with a known value\&. It may also be useful if you need to confirm if a device is overwriting a buffer for a data\-in command\&. .RE +.PP +\-T, \-\-latency +.RS 4 +Print out the latency the IOCTL took (in us)\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-admin-passthru.html b/Documentation/nvme-admin-passthru.html index 4a113ba..63a7a10 100644 --- a/Documentation/nvme-admin-passthru.html +++ b/Documentation/nvme-admin-passthru.html @@ -1,9 +1,10 @@ + - + nvme-admin-passthru(1) + + + + +
+
+

SYNOPSIS

+
+
+
nvme capacity-mgmt <device> [--operation=<operation> | -o <operation>]
+                        [--element-id=<element-id> | -i <element-id>]
+                        [--cap-lower=<cap-lower> | -l <cap-lower>]
+                        [--cap-upper=<cap-upper> | -u <cap-upper>]
+
+
+
+
+
+

DESCRIPTION

+
+

For the NVMe device given, sends a capacity management command to configure/create/delete +the Endurance Groups or NVM Sets with the requested operation and element_id. On success, +if the Operation is Create Endurance group or NVM Set, CQE CDW0 contains Created element +identifier else CQE CDW0 is reserved.

+

The <device> parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).

+
+
+
+

OPTIONS

+
+
+
+-o <operation> +
+
+--operation=<operation> +
+
+

+ Operation to be performed by the controller +

+
+
+-i <element-id> +
+
+--element-id=<element-id> +
+
+

+ Value specific to the value of the Operation field. +

+
+
+-l <cap-lower> +
+
+--cap-lower=<cap-lower> +
+
+

+ Least significant 32 bits of the capacity in bytes of the Endurance Group or + NVM Set to be created +

+
+
+-u <cap-upper> +
+
+--cap-upper=<cap-upper> +
+
+

+ Most significant 32 bits of the capacity in bytes of the Endurance Group or + NVM Set to be created +

+
+
+
+
+
+

EXAMPLES

+
+

No examples provided yet.

+
+
+
+

NVME

+
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-capacity-mgmt.txt b/Documentation/nvme-capacity-mgmt.txt new file mode 100644 index 0000000..96274cf --- /dev/null +++ b/Documentation/nvme-capacity-mgmt.txt @@ -0,0 +1,54 @@ +nvme-capacity-mgmt(1) +===================== + +NAME +---- +nvme-capacity-mgmt - Send capacity management command to configure/create/delete + Endurance Groups or NVM Sets, returns results. + +SYNOPSIS +-------- +[verse] +'nvme capacity-mgmt' [--operation= | -o ] + [--element-id= | -i ] + [--cap-lower= | -l ] + [--cap-upper= | -u ] + +DESCRIPTION +----------- +For the NVMe device given, sends a capacity management command to +configure/create/delete the Endurance Groups or NVM Sets with the requested +operation and element_id. On success, if the Operation is Create Endurance +group or NVM Set, CQE CDW0 contains Created element identifier else CQE CDW0 is +reserved. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-o :: +--operation=:: + Operation to be performed by the controller + +-i :: +--element-id=:: + Value specific to the value of the Operation field. + +-l :: +--cap-lower=:: + Least significant 32 bits of the capacity in bytes of the Endurance Group or + NVM Set to be created + +-u :: +--cap-upper=:: + Most significant 32 bits of the capacity in bytes of the Endurance Group or + NVM Set to be created + +EXAMPLES +-------- +No examples provided yet. + +NVME +---- +Part of the nvme-user suite \ No newline at end of file diff --git a/Documentation/nvme-compare.1 b/Documentation/nvme-compare.1 index 0638190..ada1790 100644 --- a/Documentation/nvme-compare.1 +++ b/Documentation/nvme-compare.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-compare -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 07/09/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-COMPARE" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-COMPARE" "1" "07/09/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -50,6 +50,7 @@ nvme-compare \- Send an NVMe Compare command, provide results [\-\-show\-command | \-v] [\-\-dry\-run | \-w] [\-\-latency | \-t] + [\-\-storage\-tag\-check | \-C ] .fi .SH "DESCRIPTION" .sp @@ -202,6 +203,11 @@ be set\&. Otherwise \-\-dry\-run option will be .RS 4 Print out the latency the IOCTL took (in us)\&. .RE +.PP +\-\-storage\-tag\-check=, \-C +.RS 4 +This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-compare.html b/Documentation/nvme-compare.html index e3b6857..0c13e32 100644 --- a/Documentation/nvme-compare.html +++ b/Documentation/nvme-compare.html @@ -1,9 +1,10 @@ + - + nvme-compare(1) + + + + +
+
+

SYNOPSIS

+
+
+
nvme get-lba-status <device> [--namespace-id=<nsid> | -n <nsid>]
+                    [--start-lba=<slba> | -s <slba>]
+                    [--max-dw=<max-dw> | -m <max-dw>]
+                    [--action=<action-type> | -a <action-type>]
+                    [--range-len=<range-len> | -l <range-len>]
+                    [--timeout=<timeout> | -t <timeout> ]
+                   [--output-format=<format> | -o <format>]
+
+
+
+
+
+

DESCRIPTION

+
+

For the NVMe device given, send an nvme Get LBA Status admin command +and provides the results.

+

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 get lba data 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

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

+ Send the Get LBA Status command for the specified nsid. This can be + used to override the default value for either character device + (unspecified) or the block device (result from NVME_IOCTL_ID). +

+
+
+-s <slba> +
+
+--start-lba=<slba> +
+
+

+ Starting LBA(SLBA) in 64-bit address of the first logical block addressed +

+
+
+-m <max-dw> +
+
+--max-dw=<max-dw> +
+
+

+ Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return +

+
+
+-a <action-type> +
+
+--action=<action-type> +
+
+

+ Action Type(ATYPE) specifies the mechanism it uses in determining the LBA Status Descriptors. +

+
+
+-l <range-len> +
+
+--range-len=<range-len> +
+
+

+ Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA +

+
+
+-t <timeout> +
+
+--timeout=<timeout> +
+
+

+ Override default timeout value. In milliseconds. +

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

+
+
    +
  • +

    +Get the LBA Status of the device using all defaults: +

    +
    +
    +
    # nvme get-lba-status /dev/nvme0n1
    +
    +
  • +
  • +

    +Get LBA Status of the namespace 1 from SLBA 10 for the max Dwords of 0x1000 +

    +
    +
    +
    # nvme get-lba-status /dev/nvme0 --namespace-id=1 --start-lba=10 --max-dw=0x1000
    +
    +
  • +
+
+
+
+

NVME

+
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-get-lba-status.txt b/Documentation/nvme-get-lba-status.txt new file mode 100644 index 0000000..157dc41 --- /dev/null +++ b/Documentation/nvme-get-lba-status.txt @@ -0,0 +1,82 @@ +nvme-get-lba-status(1) +====================== + +NAME +---- +nvme-get-lba-status - Get LBA Status from NVMe device + +SYNOPSIS +-------- +[verse] +'nvme get-lba-status' [--namespace-id= | -n ] + [--start-lba= | -s ] + [--max-dw= | -m ] + [--action= | -a ] + [--range-len= | -l ] + [--timeout= | -t ] + [--output-format= | -o ] + +DESCRIPTION +----------- +For the NVMe device given, send an nvme Get LBA Status admin command +and provides the results. + +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 get lba data 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 +------- +-n :: +--namespace-id=:: + Send the Get LBA Status command for the specified nsid. This can be + used to override the default value for either character device + (unspecified) or the block device (result from NVME_IOCTL_ID). + +-s :: +--start-lba=:: + Starting LBA(SLBA) in 64-bit address of the first logical block addressed + +-m :: +--max-dw=:: + Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return + +-a :: +--action=:: + Action Type(ATYPE) specifies the mechanism it uses in determining the LBA Status Descriptors. + +-l :: +--range-len=:: + Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA + +-t :: +--timeout=:: + Override default timeout value. In milliseconds. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. + +EXAMPLES +-------- +* Get the LBA Status of the device using all defaults: ++ +------------ +# nvme get-lba-status /dev/nvme0n1 +------------ ++ + +* Get LBA Status of the namespace 1 from SLBA 10 for the max Dwords of 0x1000 ++ +------------ +# nvme get-lba-status /dev/nvme0 --namespace-id=1 --start-lba=10 --max-dw=0x1000 +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-get-log.1 b/Documentation/nvme-get-log.1 index 98f81a8..ccc5ab8 100644 --- a/Documentation/nvme-get-log.1 +++ b/Documentation/nvme-get-log.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-get-log -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 06/12/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-GET\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-GET\-LOG" "1" "06/12/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,13 +33,16 @@ nvme-get-log \- Retrieves a log page from an NVMe device .sp .nf \fInvme get\-log\fR [\-\-log\-id= | \-i ] - [\-\-log\-len= | \-l ] - [\-\-aen= | \-a ] - [\-\-namespace\-id= | \-n ] - [\-\-raw\-binary | \-b] - [\-\-lpo= | \-o ] - [\-\-lsp= | \-s ] - [\-\-rae | \-r] + [\-\-log\-len= | \-l ] + [\-\-aen= | \-a ] + [\-\-namespace\-id= | \-n ] + [\-\-raw\-binary | \-b] + [\-\-lpo= | \-o ] + [\-\-lsp= | \-s ] + [\-\-lsi= | \-S ] + [\-\-rae | \-r] + [\-\-csi= | \-y ] + [\-\-ot | \-O] .fi .SH "DESCRIPTION" .sp @@ -85,10 +88,25 @@ The log page offset specifies the location within a log page to start returning The log specified field of LID\&. .RE .PP +\-S , \-\-lsi= +.RS 4 +The log specified field of Log Specific Identifier\&. +.RE +.PP \-r, \-\-rae .RS 4 Retain an Asynchronous Event\&. .RE +.PP +\-y , \-\-csi= +.RS 4 +This field specifies the identifier of command set\&. if not issued, NVM Command Set will be selected\&. +.RE +.PP +\-O, \-\-ot +.RS 4 +Offset Type +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-get-log.html b/Documentation/nvme-get-log.html index 9aa20e0..53af505 100644 --- a/Documentation/nvme-get-log.html +++ b/Documentation/nvme-get-log.html @@ -750,13 +750,16 @@ nvme-get-log(1) Manual Page
nvme get-log <device> [--log-id=<log-id> | -i <log-id>]
-                      [--log-len=<log-len> | -l <log-len>]
-                      [--aen=<aen> | -a <aen>]
-                      [--namespace-id=<nsid> | -n <nsid>]
-                      [--raw-binary | -b]
-                      [--lpo=<offset> | -o <offset>]
-                      [--lsp=<field> | -s <field>]
-                      [--rae | -r]
+ [--log-len=<log-len> | -l <log-len>] + [--aen=<aen> | -a <aen>] + [--namespace-id=<nsid> | -n <nsid>] + [--raw-binary | -b] + [--lpo=<offset> | -o <offset>] + [--lsp=<field> | -s <field>] + [--lsi=<field> | -S <field>] + [--rae | -r] + [--csi=<command_set_identifier> | -y <command_set_identifier>] + [--ot | -O]
@@ -864,6 +867,17 @@ program to parse.

+-S <field> +
+
+--lsi=<field> +
+
+

+ The log specified field of Log Specific Identifier. +

+
+
-r
@@ -874,6 +888,29 @@ program to parse.

Retain an Asynchronous Event.

+
+-y <command_set_identifier> +
+
+--csi=<command_set_identifier> +
+
+

+ This field specifies the identifier of command set. + if not issued, NVM Command Set will be selected. +

+
+
+-O +
+
+--ot +
+
+

+ Offset Type +

+
@@ -918,7 +955,7 @@ Have the program return the raw log page in binary: diff --git a/Documentation/nvme-get-log.txt b/Documentation/nvme-get-log.txt index 1d49e28..d371f5d 100644 --- a/Documentation/nvme-get-log.txt +++ b/Documentation/nvme-get-log.txt @@ -9,13 +9,16 @@ SYNOPSIS -------- [verse] 'nvme get-log' [--log-id= | -i ] - [--log-len= | -l ] - [--aen= | -a ] - [--namespace-id= | -n ] - [--raw-binary | -b] - [--lpo= | -o ] - [--lsp= | -s ] - [--rae | -r] + [--log-len= | -l ] + [--aen= | -a ] + [--namespace-id= | -n ] + [--raw-binary | -b] + [--lpo= | -o ] + [--lsp= | -s ] + [--lsi= | -S ] + [--rae | -r] + [--csi= | -y ] + [--ot | -O] DESCRIPTION ----------- @@ -68,10 +71,23 @@ OPTIONS --lsp=:: The log specified field of LID. +-S :: +--lsi=:: + The log specified field of Log Specific Identifier. + -r:: --rae:: Retain an Asynchronous Event. +-y :: +--csi=:: + This field specifies the identifier of command set. + if not issued, NVM Command Set will be selected. + +-O:: +--ot:: + Offset Type + EXAMPLES -------- * Get 512 bytes from log page 2 diff --git a/Documentation/nvme-id-domain.1 b/Documentation/nvme-id-domain.1 new file mode 100644 index 0000000..ddd9c3f --- /dev/null +++ b/Documentation/nvme-id-domain.1 @@ -0,0 +1,62 @@ +'\" t +.\" Title: nvme-id-domain +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 07/20/2021 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-ID\-DOMAIN" "1" "07/20/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-id-domain \- Send NVMe Identify Domain List, return result and structure +.SH "SYNOPSIS" +.sp +.nf +\fInvme id\-domain\fR [\-\-dom\-id= | \-d ] + [\-o | \-\-output\-format=] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, send an identify command and return the domian list data 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)\&. +.SH "OPTIONS" +.PP +\-d , \-\-dom\-id= +.RS 4 +Retrieve the identify domain list data structure for the given domain id\&. If this value is not given, domain id will be 0xffff\&. +.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 +No examples yet\&. +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-id-domain.html b/Documentation/nvme-id-domain.html new file mode 100644 index 0000000..067cef0 --- /dev/null +++ b/Documentation/nvme-id-domain.html @@ -0,0 +1,819 @@ + + + + + + +nvme-id-domain(1) + + + + + +
+
+

SYNOPSIS

+
+
+
nvme id-domain <device> [--dom-id=<domian_id> | -d <domian_id>]
+                        [-o <fmt> | --output-format=<fmt>]
+
+
+
+
+
+

DESCRIPTION

+
+

For the NVMe device given, send an identify command and return the domian list +data 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).

+
+
+
+

OPTIONS

+
+
+
+-d <domian_id> +
+
+--dom-id=<domian_id> +
+
+

+ Retrieve the identify domain list data structure for the given + domain id. If this value is not given, domain id will be 0xffff. +

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

+
+

No examples yet.

+
+
+
+

NVME

+
+

Part of the nvme-user suite

+
+
+
+

+ + + diff --git a/Documentation/nvme-id-domain.txt b/Documentation/nvme-id-domain.txt new file mode 100644 index 0000000..be7b81a --- /dev/null +++ b/Documentation/nvme-id-domain.txt @@ -0,0 +1,40 @@ +nvme-id-domain(1) +================= + +NAME +---- +nvme-id-domain - Send NVMe Identify Domain List, return result and structure + +SYNOPSIS +-------- +[verse] +'nvme id-domain' [--dom-id= | -d ] + [-o | --output-format=] + +DESCRIPTION +----------- +For the NVMe device given, send an identify command and return the domian list +data structure. + +The parameter is mandatory and may be either the NVMe character +device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1). + +OPTIONS +------- +-d :: +--dom-id=:: + Retrieve the identify domain list data structure for the given + domain id. If this value is not given, domain id will be 0xffff. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. + +EXAMPLES +-------- +No examples yet. + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-id-iocs.1 b/Documentation/nvme-id-iocs.1 index f79b4de..2320de3 100644 --- a/Documentation/nvme-id-iocs.1 +++ b/Documentation/nvme-id-iocs.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-id-iocs -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 05/28/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ID\-IOCS" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-ID\-IOCS" "1" "05/28/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -33,6 +33,7 @@ nvme-id-iocs \- Send NVMe Identify I/O Command Set, return result and structure .sp .nf \fInvme id\-iocs\fR [\-\-controller\-id= | \-c ] + [\-o | \-\-output\-format=] .fi .SH "DESCRIPTION" .sp @@ -45,6 +46,19 @@ The parameter is mandatory and may be either the NVMe character device .RS 4 Retrieve the identify I/O Command set data structure for the given cntid\&. If this value is not given, cntid will be 0xffff\&. .RE +.PP +\-H, \-\-human\-readable +.RS 4 +This option will parse and format many of the bit fields into human\-readable formats\&. +.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 @@ -67,6 +81,27 @@ Have the program interpret the returned buffer and display the known fields in a .RE .\} .RE +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +show the fields in human readable format +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme id\-iocs /dev/nvme0 \-H +.fi +.if n \{\ +.RE +.\} +.RE .SH "NVME" .sp Part of the nvme\-user suite diff --git a/Documentation/nvme-id-iocs.html b/Documentation/nvme-id-iocs.html index 6bc983f..159f306 100644 --- a/Documentation/nvme-id-iocs.html +++ b/Documentation/nvme-id-iocs.html @@ -749,7 +749,8 @@ nvme-id-iocs(1) Manual Page

SYNOPSIS

-
nvme id-iocs <device> [--controller-id=<cntid> | -c <cntid>]
+
nvme id-iocs <device> [--controller-id=<cntid> | -c <cntid>]
+                        [-o <fmt> | --output-format=<fmt>]
@@ -779,6 +780,30 @@ device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).

+
+-H +
+
+--human-readable +
+
+

+ This option will parse and format many of the bit fields + into human-readable formats. +

+
+
+-o <format> +
+
+--output-format=<format> +
+
+

+ Set the reporting format to normal, json, or + binary. Only one output format can be used at a time. +

+
@@ -796,6 +821,15 @@ fields in a human readable format:
# nvme id-iocs /dev/nvme0
+
  • +

    +show the fields in human readable format +

    +
    +
    +
    # nvme id-iocs /dev/nvme0 -H
    +
    +
  • @@ -810,7 +844,7 @@ fields in a human readable format: diff --git a/Documentation/nvme-id-iocs.txt b/Documentation/nvme-id-iocs.txt index 9e53207..a35217e 100644 --- a/Documentation/nvme-id-iocs.txt +++ b/Documentation/nvme-id-iocs.txt @@ -9,6 +9,7 @@ SYNOPSIS -------- [verse] 'nvme id-iocs' [--controller-id= | -c ] + [-o | --output-format=] DESCRIPTION ----------- @@ -24,6 +25,15 @@ OPTIONS --controller-id=:: Retrieve the identify I/O Command set data structure for the given cntid. If this value is not given, cntid will be 0xffff. +-H:: +--human-readable:: + This option will parse and format many of the bit fields + into human-readable formats. + +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. EXAMPLES -------- @@ -33,7 +43,12 @@ fields in a human readable format: ------------ # nvme id-iocs /dev/nvme0 ------------ - ++ +* show the fields in human readable format ++ +------------ +# nvme id-iocs /dev/nvme0 -H +------------ NVME ---- Part of the nvme-user suite diff --git a/Documentation/nvme-io-passthru.1 b/Documentation/nvme-io-passthru.1 index b5e4322..ad913cc 100644 --- a/Documentation/nvme-io-passthru.1 +++ b/Documentation/nvme-io-passthru.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-io-passthru -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 06/04/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-IO\-PASSTHRU" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-IO\-PASSTHRU" "1" "06/04/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -47,6 +47,7 @@ nvme-io-passthru \- Submit an arbitrary io command, return results [\-\-dry\-run | \-d] [\-\-raw\-binary | \-b] [\-\-prefill= | \-p ] + [\-\-latency | \-T] .fi .SH "DESCRIPTION" .sp @@ -125,6 +126,11 @@ Print the raw returned buffer to stdout if the command returns data or a structu .RS 4 Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may be useful if the data you are writing is shorter than the required buffer, and you need to pad it with a known value\&. It may also be useful if you need to confirm if a device is overwriting a buffer on a data\-in command\&. .RE +.PP +\-T, \-\-latency +.RS 4 +Print out the latency the IOCTL took (in us)\&. +.RE .SH "EXAMPLES" .sp nvme io\-passthru /dev/nvme0n1 \-\-opcode=2 \-\-namespace\-id=1 \-\-data\-len=4096 \-\-read \-\-cdw10=0 \-\-cdw11=0 \-\-cdw12=0x70000 \-\-raw\-binary diff --git a/Documentation/nvme-io-passthru.html b/Documentation/nvme-io-passthru.html index 96b9e1e..8463c5f 100644 --- a/Documentation/nvme-io-passthru.html +++ b/Documentation/nvme-io-passthru.html @@ -1,9 +1,10 @@ + - + nvme-io-passthru(1) + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme micron vs-smart-add-log <device>  -f <json|normal>
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    This command prints NAND information (Total bytes written, Bad block count and +Erase failures etc) for the given micron device if its of 2200 model controller. +For OCP complaint controllers this command print extended SMART health data +along with NAND information (if available)

    +

    The <device> parameter is mandatory and may be either the NVMe +character device (ex: /dev/nvme0), or a namespace block device (ex: +/dev/nvme0n1).

    +

    The -f option controls the displayed output data format based on the option +value. If the option value is json (which is enabled by default), output data +is printed in JSON format. If option value is normal the output is displayed +in non-JSON format.

    +

    This will only work on Micron devices devices of model numbers 54XX and OCP +complaint controllers. Support for new devices may be added subsequently.

    +
    +
    +
    +

    OPTIONS

    +
    +

    -f <json|normal> controls the format of displayed output.

    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Retrieve NAND/extended SMART data and display in json format +

      +
      +
      +
      # nvme micron vs-nand-stats /dev/nvme0
      +
      +* Retrieve NAND/extended SMART data and display in non-json format
      ++
      +
      +
    • +
    +

    # nvme micron vs-nand-stats /dev/nvme0 -f normal

    +
    +
    +
    NVME
    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-micron-smart-add-log.txt b/Documentation/nvme-micron-smart-add-log.txt new file mode 100644 index 0000000..1fd74ba --- /dev/null +++ b/Documentation/nvme-micron-smart-add-log.txt @@ -0,0 +1,54 @@ +nvme-micron-smart-add-log(1) +============================ + +NAME +---- +nvme-micron-smart-add-log - Retrieves NAND statistics (2200 model drives) +or Extended SMART information (OCP complaint models) of given micron device + +SYNOPSIS +-------- +[verse] +'nvme micron vs-smart-add-log' -f + +DESCRIPTION +----------- +This command prints NAND information (Total bytes written, Bad block count and +Erase failures etc) for the given micron device if its of 2200 model controller. +For OCP complaint controllers this command print extended SMART health data +along with NAND information (if available) + +The parameter is mandatory and may be either the NVMe +character device (ex: /dev/nvme0), or a namespace block device (ex: +/dev/nvme0n1). + +The '-f' option controls the displayed output data format based on the option +value. If the option value is 'json' (which is enabled by default), output data +is printed in JSON format. If option value is 'normal' the output is displayed +in non-JSON format. + +This will only work on Micron devices devices of model numbers 54XX and OCP +complaint controllers. Support for new devices may be added subsequently. + +OPTIONS +------- +-f controls the format of displayed output. + + +EXAMPLES +-------- +* Retrieve NAND/extended SMART data and display in json format ++ +------------ +# nvme micron vs-nand-stats /dev/nvme0 + +* Retrieve NAND/extended SMART data and display in non-json format ++ +------------ +# nvme micron vs-nand-stats /dev/nvme0 -f normal + +------------ + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-primary-ctrl-caps.1 b/Documentation/nvme-primary-ctrl-caps.1 new file mode 100644 index 0000000..cdf7529 --- /dev/null +++ b/Documentation/nvme-primary-ctrl-caps.1 @@ -0,0 +1,104 @@ +'\" t +.\" Title: nvme-primary-ctrl-caps +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 05/11/2021 +.\" Manual: NVMe Manual +.\" Source: NVMe +.\" Language: English +.\" +.TH "NVME\-PRIMARY\-CTRL\" "1" "05/11/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-primary-ctrl-caps \- Send identify Primary Controller Caps, return result and structure +.SH "SYNOPSIS" +.sp +.nf +\fInvme primary\-ctrl\-caps\fR [\-o | \-\-output\-format=] +.fi +.SH "DESCRIPTION" +.sp +For the NVMe device given, sends an identify primary Controller caps command and provides the result and 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 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 +\-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 +.PP +\-H, \-\-human\-readable +.RS 4 +This option will parse and format many of the bit fields into human\-readable formats\&. +.RE +.SH "EXAMPLES" +.sp +.RS 4 +.ie n \{\ +\h'-04'\(bu\h'+03'\c +.\} +.el \{\ +.sp -1 +.IP \(bu 2.3 +.\} +Get Primary Ctrl Caps of the device in default format +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme primary\-ctrl\-caps /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 +.\} +Has the program interpret the returned buffer and display the known fields in a human readable format: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# nvme primary\-ctrl\-caps /dev/nvme0 \-\-human\-readbale +# nvme primary\-ctrl\-caps /dev/nvme0 \-H +.fi +.if n \{\ +.RE +.\} +.RE +.SH "NVME" +.sp +Part of the nvme\-user suite diff --git a/Documentation/nvme-primary-ctrl-caps.html b/Documentation/nvme-primary-ctrl-caps.html new file mode 100644 index 0000000..3cae1a2 --- /dev/null +++ b/Documentation/nvme-primary-ctrl-caps.html @@ -0,0 +1,842 @@ + + + + + + +nvme-primary-ctrl-caps(1) + + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme primary-ctrl-caps <device> [-o <format> | --output-format=<format>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    For the NVMe device given, sends an identify primary Controller caps command and +provides the result and 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 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

    +
    +
    +
    +-o <format> +
    +
    +--output-format=<format> +
    +
    +

    + Set the reporting format to normal, json, or + binary. Only one output format can be used at a time. +

    +
    +
    +-H +
    +
    +--human-readable +
    +
    +

    + This option will parse and format many of the bit fields + into human-readable formats. +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +
      +
    • +

      +Get Primary Ctrl Caps of the device in default format +

      +
      +
      +
      # nvme primary-ctrl-caps /dev/nvme0
      +
      +
    • +
    • +

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

      +
      +
      +
      # nvme primary-ctrl-caps /dev/nvme0 --human-readbale
      +# nvme primary-ctrl-caps /dev/nvme0 -H
      +
      +
    • +
    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-primary-ctrl-caps.txt b/Documentation/nvme-primary-ctrl-caps.txt new file mode 100644 index 0000000..e17093f --- /dev/null +++ b/Documentation/nvme-primary-ctrl-caps.txt @@ -0,0 +1,53 @@ +nvme-primary-ctrl-caps(1) +========================= + +NAME +---- +nvme-primary-ctrl-caps - Send identify Primary Controller Caps, return result and structure + +SYNOPSIS +-------- +[verse] +'nvme primary-ctrl-caps' [-o | --output-format=] + +DESCRIPTION +----------- +For the NVMe device given, sends an identify primary Controller caps command and +provides the result and 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 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 +------- +-o :: +--output-format=:: + Set the reporting format to 'normal', 'json', or + 'binary'. Only one output format can be used at a time. + +-H:: +--human-readable:: + This option will parse and format many of the bit fields + into human-readable formats. + +EXAMPLES +-------- +* Get Primary Ctrl Caps of the device in default format ++ +------------ +# nvme primary-ctrl-caps /dev/nvme0 +------------ +* Has the program interpret the returned buffer and display the known +fields in a human readable format: ++ +------------ +# nvme primary-ctrl-caps /dev/nvme0 --human-readbale +# nvme primary-ctrl-caps /dev/nvme0 -H +------------ +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-read.1 b/Documentation/nvme-read.1 index 7ba8d6a..303fc05 100644 --- a/Documentation/nvme-read.1 +++ b/Documentation/nvme-read.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-read -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 07/09/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-READ" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-READ" "1" "07/09/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -50,6 +50,7 @@ nvme-read \- Send an NVMe Read command, provide results [\-\-show\-command | \-v] [\-\-dry\-run | \-w] [\-\-latency | \-t] + [\-\-storage\-tag\-check | \-C ] .fi .SH "DESCRIPTION" .sp @@ -178,6 +179,11 @@ be set\&. Otherwise \-\-dry\-run option will be .RS 4 Print out the latency the IOCTL took (in us)\&. .RE +.PP +\-\-storage\-tag\-check=, \-C +.RS 4 +This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-read.html b/Documentation/nvme-read.html index fdc1606..d61580c 100644 --- a/Documentation/nvme-read.html +++ b/Documentation/nvme-read.html @@ -766,7 +766,8 @@ nvme-read(1) Manual Page [--dsm=<dsm> | -D <dsm>] [--show-command | -v] [--dry-run | -w] - [--latency | -t] + [--latency | -t] + [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>]
    @@ -1013,6 +1014,18 @@ metadata is passes.

    Print out the latency the IOCTL took (in us).

    +
    +--storage-tag-check=<storage-tag-check> +
    +
    +-C <storage-tag-check> +
    +
    +

    + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. +

    +
    @@ -1033,7 +1046,7 @@ metadata is passes.

    diff --git a/Documentation/nvme-read.txt b/Documentation/nvme-read.txt index 55a701c..58902e7 100644 --- a/Documentation/nvme-read.txt +++ b/Documentation/nvme-read.txt @@ -26,6 +26,7 @@ SYNOPSIS [--show-command | -v] [--dry-run | -w] [--latency | -t] + [--storage-tag-check | -C ] DESCRIPTION ----------- @@ -128,6 +129,11 @@ metadata is passes. --latency:: Print out the latency the IOCTL took (in us). +--storage-tag-check=:: +-C :: + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-resv-register.1 b/Documentation/nvme-resv-register.1 index 48b391f..3d9a869 100644 --- a/Documentation/nvme-resv-register.1 +++ b/Documentation/nvme-resv-register.1 @@ -98,7 +98,7 @@ T} .sp 1 .RE .PP -\-a , \-\-rrega= +\-r , \-\-rrega= .RS 4 Reservation Register Action: This field specifies the registration action that is performed by the command\&. .TS diff --git a/Documentation/nvme-resv-register.html b/Documentation/nvme-resv-register.html index a17f869..15bec28 100644 --- a/Documentation/nvme-resv-register.html +++ b/Documentation/nvme-resv-register.html @@ -861,7 +861,7 @@ a power loss.

    --a <rrega> +-r <rrega>
    --rrega=<rrega> diff --git a/Documentation/nvme-resv-register.txt b/Documentation/nvme-resv-register.txt index 076e979..e0553f4 100644 --- a/Documentation/nvme-resv-register.txt +++ b/Documentation/nvme-resv-register.txt @@ -62,7 +62,7 @@ are cleared on a power on. a power loss. |================= --a :: +-r :: --rrega=:: Reservation Register Action: This field specifies the registration action that is performed by the command. diff --git a/Documentation/nvme-set-feature.1 b/Documentation/nvme-set-feature.1 index 913df38..57e8c08 100644 --- a/Documentation/nvme-set-feature.1 +++ b/Documentation/nvme-set-feature.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-set-feature -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 05/16/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-SET\-FEATURE" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-SET\-FEATURE" "1" "05/16/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -34,6 +34,7 @@ nvme-set-feature \- Sets an NVMe feature, returns applicable results .nf \fInvme set\-feature\fR [\-\-namespace\-id= | \-n ] [\-\-feature\-id= | \-f ] [\-\-value= | \-v ] + [\-\-uuid\-index= | \-U ] [\-\-data\-len= | \-l ] [\-\-data= | \-d ] [\-\-save| \-s] @@ -76,6 +77,11 @@ The value for command dword 11, the value you want to set the feature to\&. .RS 4 Save the attribute so that it persists through all power states and resets\&. .RE +.PP +\-U , \-\-uuid\-index= +.RS 4 +UUID Index of the feature +.RE .SH "EXAMPLES" .sp .RS 4 @@ -118,6 +124,8 @@ Sets the host id to the ascii string\&. .if n \{\ .RE .\} +.sp +nvme set\-feature /dev/nvme0 \-f 0x81 \-l 8 \-U 0x1 .RE .SH "NVME" .sp diff --git a/Documentation/nvme-set-feature.html b/Documentation/nvme-set-feature.html index b813b91..b5bf779 100644 --- a/Documentation/nvme-set-feature.html +++ b/Documentation/nvme-set-feature.html @@ -1,9 +1,10 @@ + - + nvme-set-feature(1) + + + + +
    +
    +

    SYNOPSIS

    +
    +
    +
    nvme-verify <device> [--namespace-id=<nsid> | -n <nsid>]
    +            [--start-block=<slba> | -s <slba>]
    +            [--block-count=<nlb> | -c <nlb>]
    +            [--limited-retry | -l]
    +            [--force-unit-access | -f]
    +            [--prinfo=<prinfo> | -p <prinfo>]
    +            [--ref-tag=<reftag> | -r <reftag>]
    +            [--app-tag-mask=<appmask> | -m <appmask>]
    +            [--app-tag=<apptag> | -a <apptag>]
    +            [--storage-tag<storage-tag> | -S <storage-tag>]
    +            [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>]
    +
    +
    +
    +
    +
    +

    DESCRIPTION

    +
    +

    The Verify command verifies the integrity of the stored information by +reading data and metadata.

    +
    +
    +
    +

    OPTIONS

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

    + Namespace ID use in the command. +

    +
    +
    +--start-block=<slba> +
    +
    +-s <slba> +
    +
    +

    + Start block address. +

    +
    +
    +--block-count=<nlb> +
    +
    +-c <nlb> +
    +
    +

    + Number of logical blocks to Verify. +

    +
    +
    +--limited-retry +
    +
    +-l +
    +
    +

    + Sets the limited retry flag. +

    +
    +
    +--force-unit-access +
    +
    +-f +
    +
    +

    + Set the force-unit access flag. +

    +
    +
    +--prinfo=<prinfo> +
    +
    +-p <prinfo> +
    +
    +

    + Protection Information field definition. +

    +
    + +++ + + + + + + + + + + + + + + + + + + + + + + + + + +

    Bit

    Description

    3

    PRACT: Protection Information Action. When set to 1, PI is stripped/inserted +on read/write when the block format’s metadata size is 8. When set to 0, +metadata is passes.

    2:0

    PRCHK: Protection Information Check:

    2

    Set to 1 enables checking the guard tag

    1

    Set to 1 enables checking the application tag

    0

    Set to 1 enables checking the reference tag

    +
    +
    +
    +--ref-tag=<reftag> +
    +
    +-r <reftag> +
    +
    +

    + Optional reftag when used with protection information. +

    +
    +
    +--app-tag-mask=<appmask> +
    +
    +-m <appmask> +
    +
    +

    + Optional application tag mask when used with protection information. +

    +
    +
    +--app-tag=<apptag> +
    +
    +-a <apptag> +
    +
    +

    + Optional application tag when used with protection information. +

    +
    +
    +--storage-tag=<storage-tag> +
    +
    +-S <storage-tag> +
    +
    +

    + Variable Sized Expected Logical Block Storage Tag(ELBST) and Expected Logical + Block Reference Tag (ELBRT), CDW2 and CDW3 (00:47) bits. +

    +
    +
    +--storage-tag-check=<storage-tag-check> +
    +
    +-C <storage-tag-check> +
    +
    +

    + This bit specifies the Storage Tag field shall be checked as part of Verify operation. +

    +
    +
    +
    +
    +
    +

    EXAMPLES

    +
    +

    No examples yet.

    +
    +
    +
    +

    NVME

    +
    +

    Part of the nvme-user suite

    +
    +
    +
    +

    + + + diff --git a/Documentation/nvme-verify.txt b/Documentation/nvme-verify.txt new file mode 100644 index 0000000..3dc2fc7 --- /dev/null +++ b/Documentation/nvme-verify.txt @@ -0,0 +1,93 @@ +nvme-verify(1) +============== + +NAME +---- +nvme-verify - Send an NVMe Verify command, return results + +SYNOPSIS +-------- +[verse] +'nvme-verify' [--namespace-id= | -n ] + [--start-block= | -s ] + [--block-count= | -c ] + [--limited-retry | -l] + [--force-unit-access | -f] + [--prinfo= | -p ] + [--ref-tag= | -r ] + [--app-tag-mask= | -m ] + [--app-tag= | -a ] + [--storage-tag | -S ] + [--storage-tag-check | -C ] + +DESCRIPTION +----------- +The Verify command verifies the integrity of the stored information by +reading data and metadata. + +OPTIONS +------- +--namespace-id=:: +-n :: + Namespace ID use in the command. + +--start-block=:: +-s :: + Start block address. + +--block-count=:: +-c :: + Number of logical blocks to Verify. + +--limited-retry:: +-l:: + Sets the limited retry flag. + +--force-unit-access:: +-f:: + Set the force-unit access flag. + +--prinfo=:: +-p :: + Protection Information field definition. ++ +[] +|================= +|Bit|Description +|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted +on read/write when the block format's metadata size is 8. When set to 0, +metadata is passes. +|2:0|PRCHK: Protection Information Check: +|2|Set to 1 enables checking the guard tag +|1|Set to 1 enables checking the application tag +|0|Set to 1 enables checking the reference tag +|================= + +--ref-tag=:: +-r :: + Optional reftag when used with protection information. + +--app-tag-mask=:: +-m :: + Optional application tag mask when used with protection information. + +--app-tag=:: +-a :: + Optional application tag when used with protection information. + +--storage-tag=:: +-S :: + Variable Sized Expected Logical Block Storage Tag(ELBST) and Expected Logical + Block Reference Tag (ELBRT), CDW2 and CDW3 (00:47) bits. + +--storage-tag-check=:: +-C :: + This bit specifies the Storage Tag field shall be checked as part of Verify operation. + +EXAMPLES +-------- +No examples yet. + +NVME +---- +Part of the nvme-user suite diff --git a/Documentation/nvme-write-zeroes.1 b/Documentation/nvme-write-zeroes.1 index d32e3ca..d7f06bb 100644 --- a/Documentation/nvme-write-zeroes.1 +++ b/Documentation/nvme-write-zeroes.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-zeroes -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 07/09/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-ZEROES" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-ZEROES" "1" "07/09/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -42,6 +42,8 @@ nvme-write-zeroes \- Send an NVMe write zeroes command, return results [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f] [\-\-namespace\-id= | \-n ] + [\-\-storage\-tag | \-S ] + [\-\-storage\-tag\-check | \-C ] .fi .SH "DESCRIPTION" .sp @@ -137,19 +139,19 @@ Set the force\-unit access flag\&. .RS 4 Namespace ID use in the command\&. .RE -.sp -EXAMPLES EXAMPLES -.sp -.if n \{\ +.PP +\-\-storage\-tag=, \-n .RS 4 -.\} -.nf -No examples yet\&. - -NVME -.fi -.if n \{\ +Variable Sized Expected Logical Block Storage Tag(ELBST) and Expected Logical Block Reference Tag (ELBRT), CDW2 and CDW3 (00:47) bits\&. .RE -.\} +.PP +\-\-storage\-tag\-check=, \-C +.RS 4 +This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +.RE +.SH "EXAMPLES" +.sp +No examples yet\&. +.SH "NVME" .sp Part of the nvme\-user suite diff --git a/Documentation/nvme-write-zeroes.html b/Documentation/nvme-write-zeroes.html index f3a3838..0912800 100644 --- a/Documentation/nvme-write-zeroes.html +++ b/Documentation/nvme-write-zeroes.html @@ -758,7 +758,9 @@ nvme-zeroes(1) Manual Page [--deac | -d] [--limited-retry | -l] [--force-unit-access | -f] - [--namespace-id=<nsid> | -n <nsid>] + [--namespace-id=<nsid> | -n <nsid>] + [--storage-tag<storage-tag> | -S <storage-tag>] + [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>]
    @@ -920,15 +922,42 @@ metadata is passes.

    Namespace ID use in the command.

    +
    +--storage-tag=<storage-tag> +
    +
    +-n <storage-tag> +
    +
    +

    + Variable Sized Expected Logical Block Storage Tag(ELBST) and Expected Logical + Block Reference Tag (ELBRT), CDW2 and CDW3 (00:47) bits. +

    +
    +
    +--storage-tag-check=<storage-tag-check> +
    +
    +-C <storage-tag-check> +
    +
    +

    + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. +

    +
    -

    EXAMPLES -EXAMPLES

    -
    -
    -
    No examples yet.
    -
    -NVME
    -
    + + +
    +

    EXAMPLES

    +
    +

    No examples yet.

    +
    +
    +
    +

    NVME

    +

    Part of the nvme-user suite

    @@ -937,7 +966,7 @@ NVME diff --git a/Documentation/nvme-write-zeroes.txt b/Documentation/nvme-write-zeroes.txt index 02adee1..34fec9d 100644 --- a/Documentation/nvme-write-zeroes.txt +++ b/Documentation/nvme-write-zeroes.txt @@ -18,6 +18,8 @@ SYNOPSIS [--limited-retry | -l] [--force-unit-access | -f] [--namespace-id= | -n ] + [--storage-tag | -S ] + [--storage-tag-check | -C ] DESCRIPTION ----------- @@ -77,7 +79,16 @@ metadata is passes. -n :: Namespace ID use in the command. -EXAMPLES +--storage-tag=:: +-n :: + Variable Sized Expected Logical Block Storage Tag(ELBST) and Expected Logical + Block Reference Tag (ELBRT), CDW2 and CDW3 (00:47) bits. + +--storage-tag-check=:: +-C :: + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-write.1 b/Documentation/nvme-write.1 index 727ac03..b8e49e5 100644 --- a/Documentation/nvme-write.1 +++ b/Documentation/nvme-write.1 @@ -1,13 +1,13 @@ '\" t .\" Title: nvme-write -.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author] -.\" Generator: DocBook XSL Stylesheets vsnapshot -.\" Date: 10/20/2020 +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 07/09/2021 .\" Manual: NVMe Manual .\" Source: NVMe .\" Language: English .\" -.TH "NVME\-WRITE" "1" "10/20/2020" "NVMe" "NVMe Manual" +.TH "NVME\-WRITE" "1" "07/09/2021" "NVMe" "NVMe Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -50,6 +50,7 @@ nvme-write \- Send an NVMe write command, provide results [\-\-show\-command | \-v] [\-\-dry\-run | \-w] [\-\-latency | \-t] + [\-\-storage\-tag\-check | \-C ] .fi .SH "DESCRIPTION" .sp @@ -188,6 +189,11 @@ be set\&. Otherwise \-\-dry\-run option will be .RS 4 Print out the latency the IOCTL took (in us)\&. .RE +.PP +\-\-storage\-tag\-check=, \-C +.RS 4 +This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&. +.RE .SH "EXAMPLES" .sp No examples yet\&. diff --git a/Documentation/nvme-write.html b/Documentation/nvme-write.html index b59de9d..57dccc3 100644 --- a/Documentation/nvme-write.html +++ b/Documentation/nvme-write.html @@ -766,7 +766,8 @@ nvme-write(1) Manual Page [--dsm=<dsm> | -D <dsm>] [--show-command | -v] [--dry-run | -w] - [--latency | -t] + [--latency | -t] + [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>]
    @@ -1035,6 +1036,18 @@ metadata is passes.

    Print out the latency the IOCTL took (in us).

    +
    +--storage-tag-check=<storage-tag-check> +
    +
    +-C <storage-tag-check> +
    +
    +

    + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. +

    +
    @@ -1055,7 +1068,7 @@ metadata is passes.

    diff --git a/Documentation/nvme-write.txt b/Documentation/nvme-write.txt index 2074f52..c48e6ae 100644 --- a/Documentation/nvme-write.txt +++ b/Documentation/nvme-write.txt @@ -26,6 +26,7 @@ SYNOPSIS [--show-command | -v] [--dry-run | -w] [--latency | -t] + [--storage-tag-check | -C ] DESCRIPTION ----------- @@ -136,6 +137,11 @@ metadata is passes. --latency:: Print out the latency the IOCTL took (in us). +--storage-tag-check=:: +-C :: + This bit specifies the Storage Tag field shall be checked as part of end-to-end + data protection processing. + EXAMPLES -------- No examples yet. diff --git a/Documentation/nvme-zns-close-zone.1 b/Documentation/nvme-zns-close-zone.1 index d9624c1..5f80a39 100644 --- a/Documentation/nvme-zns-close-zone.1 +++ b/Documentation/nvme-zns-close-zone.1 @@ -32,9 +32,10 @@ nvme-zns-close-zone \- Closes one or all zones .SH "SYNOPSIS" .sp .nf -\fInvme zns close\-zone nvme zns id\-ctrl\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] +\fInvme zns close\-zone\fR [\-\-namespace\-id= | \-n ] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -57,6 +58,11 @@ The starting LBA of the zone to close\&. .RS 4 Select all zones for this action .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-finish-zone.1 b/Documentation/nvme-zns-finish-zone.1 index 764c683..b34801f 100644 --- a/Documentation/nvme-zns-finish-zone.1 +++ b/Documentation/nvme-zns-finish-zone.1 @@ -32,9 +32,10 @@ nvme-zns-finish-zone \- Finishes one or all zones .SH "SYNOPSIS" .sp .nf -\fInvme zns finish\-zone nvme zns id\-ctrl\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] +\fInvme zns finish\-zone\fR [\-\-namespace\-id= | \-n ] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -57,6 +58,11 @@ The starting LBA of the zone to finish\&. .RS 4 Select all zones for this action\&. .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-offline-zone.1 b/Documentation/nvme-zns-offline-zone.1 index 9d2d083..2e6c178 100644 --- a/Documentation/nvme-zns-offline-zone.1 +++ b/Documentation/nvme-zns-offline-zone.1 @@ -32,9 +32,10 @@ nvme-zns-offline-zone \- Offlines one or all zones .SH "SYNOPSIS" .sp .nf -\fInvme zns offline\-zone nvme zns id\-ctrl\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] +\fInvme zns offline\-zone\fR [\-\-namespace\-id= | \-n ] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -57,6 +58,11 @@ The starting LBA of the zone to offline\&. .RS 4 Select all zones for this action .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-open-zone.1 b/Documentation/nvme-zns-open-zone.1 index 8ea78f2..4120942 100644 --- a/Documentation/nvme-zns-open-zone.1 +++ b/Documentation/nvme-zns-open-zone.1 @@ -32,9 +32,10 @@ nvme-zns-open-zone \- Opens one or all zones .SH "SYNOPSIS" .sp .nf -\fInvme zns open\-zone nvme zns id\-ctrl\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] +\fInvme zns open\-zone\fR [\-\-namespace\-id= | \-n ] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -57,6 +58,11 @@ The starting LBA of the zone to open\&. .RS 4 Select all zones for this action .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-reset-zone.1 b/Documentation/nvme-zns-reset-zone.1 index b02d042..7452e8b 100644 --- a/Documentation/nvme-zns-reset-zone.1 +++ b/Documentation/nvme-zns-reset-zone.1 @@ -33,8 +33,9 @@ nvme-zns-reset-zone \- Resets one or all zones .sp .nf \fInvme zns reset\-zone\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba= | \-s ] - [\-\-select\-all | \-a] + [\-\-start\-lba= | \-s ] + [\-\-select\-all | \-a] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -57,6 +58,11 @@ The starting LBA of the zone to reset\&. .RS 4 Select all zones for this action .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-set-zone-desc.1 b/Documentation/nvme-zns-set-zone-desc.1 index a33b06a..7b9a52a 100644 --- a/Documentation/nvme-zns-set-zone-desc.1 +++ b/Documentation/nvme-zns-set-zone-desc.1 @@ -33,8 +33,9 @@ nvme-zns-set-zone-desc \- Set extended descriptor data for a zone .sp .nf \fInvme zns setzone\-desc\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba=, \-s ] - [\-data=, \-d ] + [\-\-start\-lba=, \-s ] + [\-data=, \-d ] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -55,6 +56,11 @@ The starting LBA of the zone to manage send\&. .RS 4 Optional file for data (default stdin) .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/Documentation/nvme-zns-zone-mgmt-send.1 b/Documentation/nvme-zns-zone-mgmt-send.1 index f74d8a3..5b58bbc 100644 --- a/Documentation/nvme-zns-zone-mgmt-send.1 +++ b/Documentation/nvme-zns-zone-mgmt-send.1 @@ -33,11 +33,12 @@ nvme-zns-zone-mgmt-send \- Zone Management Send command .sp .nf \fInvme zns zone\-mgmt\-send\fR [\-\-namespace\-id= | \-n ] - [\-\-start\-lba=, \-s ] - [\-\-select\-all, \-a] - [\-\-zsa=, \-z ] - [\-\-data\-len=, \-l ] - [\-data=, \-d ] + [\-\-start\-lba=, \-s ] + [\-\-select\-all, \-a] + [\-\-zsa=, \-z ] + [\-\-data\-len=, \-l ] + [\-data=, \-d ] + [\-\-timeout= | \-t ] .fi .SH "DESCRIPTION" .sp @@ -78,6 +79,11 @@ Buffer length if data required .RS 4 Optional file for data (default stdin) .RE +.PP +\-t , \-\-timeout= +.RS 4 +Override default timeout value\&. In milliseconds\&. +.RE .SH "EXAMPLES" .sp .RS 4 diff --git a/NVME-VERSION-GEN b/NVME-VERSION-GEN index 802bbd3..795f8ec 100755 --- a/NVME-VERSION-GEN +++ b/NVME-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=NVME-VERSION-FILE -DEF_VER=v1.14 +DEF_VER=v1.15 LF=' ' diff --git a/cmd_handler.h b/cmd_handler.h index d40740d..73b5962 100644 --- a/cmd_handler.h +++ b/cmd_handler.h @@ -5,7 +5,7 @@ */ #undef NAME -#define NAME(n, d) +#define NAME(n, d, v) #undef ENTRY #define ENTRY(n, h, f, ...) \ @@ -26,7 +26,7 @@ static int f(int argc, char **argv, struct command *command, struct plugin *plug */ #undef NAME -#define NAME(n, d) +#define NAME(n, d, v) #undef ENTRY_W_ALIAS #define ENTRY_W_ALIAS(n, h, f, a) \ @@ -63,7 +63,7 @@ static struct command f ## _cmd = { \ */ #undef NAME -#define NAME(n, d) +#define NAME(n, d, v) #undef ENTRY #define ENTRY(n, h, f, ...) &f ## _cmd, @@ -87,7 +87,7 @@ static struct command *commands[] = { \ */ #undef NAME -#define NAME(n, d) .name = n, .desc = d, +#define NAME(n, d, v) .name = n, .desc = d, .version = v, #undef COMMAND_LIST #define COMMAND_LIST(args...) diff --git a/completions/_nvme b/completions/_nvme index 9267522..b8070d6 100644 --- a/completions/_nvme +++ b/completions/_nvme @@ -11,6 +11,7 @@ _nvme () { 'id-ns:display information about the namespace' 'list-ns:identify all namespace(s) attached' 'id-iocs:display information about I/O command sets' + 'id-domain:display information about domain list' 'create-ns:create a new namespace before attachment' 'delete-ns:delete a detached namespace' 'attach-ns:attach namespace to controller' @@ -47,6 +48,7 @@ _nvme () { 'compare:compare data on device to data elsewhere' 'read:submit a read command' 'write:submit a write command' + 'capacity-mgmt: submit capacity management command' 'show-regs:shows the controller registers; requires admin character device' 'help:print brief descriptions of all nvme commands' ) @@ -113,6 +115,16 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme id-iocs options" _idiocs ;; + (id-domain) + local _iddomain + _iddomain=( + /dev/nvme':supply a device to use (required)' + --dom-id=':show infos for domain id ' + -d':alias of --dom-id' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme id-domain options" _iddomain + ;; nvm-id-ctrl) local _nvmidctrl _nvmidctrl=( @@ -232,14 +244,14 @@ _nvme () { --log-entries=': Number of pending NVM Set Entries log list' -e':alias to --log-entries' --rae': Retain an Asynchronous Event' - -r':alias to --rae + -r':alias to --rae' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' ) _arguments '*:: :->subcmds' _describe -t commands "nvme pred-lat-event-agg-log options" _predlateventagglog ;; - (predictablelatlog) + (predictable-lat-log) local _predictablelatlog _predictablelatlog=( /dev/nvme':supply a device to use (required)' @@ -306,7 +318,7 @@ _nvme () { --log-entries=': Number of Endurance Group Event Agg Entries log list' -e':alias to --log-entries' --rae': Retain an Asynchronous Event' - -r':alias to --rae + -r':alias to --rae' --raw-binary':dump infos in binary format' -b':alias of --raw-binary' ) @@ -318,7 +330,7 @@ _nvme () { _lbastatuslog=( /dev/nvme':supply a device to use (required)' --rae': Retain an Asynchronous Event' - -r':alias to --rae + -r':alias to --rae' ) _arguments '*:: :->subcmds' _describe -t commands "nvme lba-status-log options" _lbastatuslog @@ -343,6 +355,8 @@ _nvme () { -s':alias to --sel' --data-len=':buffer len for returned LBA Type Range or host identifier data' -l':alias for --data-len' + --uuid-index=':uuid index' + -U':alias for --uuid-index' --cdw11=':dword 11 value, used for interrupt vector configuration only' --raw-binary':dump infos in binary format' -b':alias to --raw-binary' @@ -364,6 +378,8 @@ _nvme () { -d':alias to --data' --value=':new value of feature (required)' -v'alias to --value' + --uuid-index=':uuid index' + -U':alias for --uuid-index' ) _arguments '*:: :->subcmds' _describe -t commands "nvme set-feature options" _setf @@ -414,6 +430,22 @@ _nvme () { _arguments '*:: :->subcmds' _describe -t commands "nvme fw-download options" _fwd ;; + (capacity-mgmt) + local _fwd + _fwd=( + /dev/nvme':supply a device to use (required)' + --operation=':Operation to be performed by the controller' + -o':alias of --operation' + --element-id=':specific to the value of the Operation field' + -i':alias of --element-id' + --cap-lower=':Least significant 32 bits of the capacity in bytes' + -l':alias of --cap-lower' + --cap-upper=':Most significant 32 bits of the capacity in bytes' + -u':alias of --cap-upper' + ) + _arguments '*:: :->subcmds' + _describe -t commands "nvme capacity-mgmt options" _fwd + ;; (admin-passthru) local _admin _admin=( @@ -558,7 +590,7 @@ _nvme () { -p':alias for --prkey' --rtype=':hexadecimal reservation type' -t':alias for --rtype' - --racqa=':reservation acquiry action' + --racqa=':reservation acquire action' -a':alias for --racqa' --iekey=':ignore existing reservation key' -i':alias for --iekey' @@ -611,7 +643,7 @@ _nvme () { --cptpl=':change persistence through power loss setting' -p':alias for --cptpl' --rrega=':reservation registration action to perform' - -a':alias for --rrega' + -r':alias for --rrega' --iekey':ignore existing reservation key' -i':alias for --iekey' ) @@ -788,7 +820,7 @@ _nvme () { 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 lba-status-log - resv-notif-log + resv-notif-log capacity-mgmt id-domain ) _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 c022b89..d3cca44 100644 --- a/completions/bash-nvme-completion.sh +++ b/completions/bash-nvme-completion.sh @@ -2,20 +2,115 @@ # (unfortunately, bash won't let me add descriptions to cmds) # Kelly Kaoudis kelly.n.kaoudis at intel.com, Aug. 2015 -_cmds="list id-ctrl id-ns list-ns id-iocs nvm-id-ctrl create-ns delete-ns \ - attach-ns detach-ns list-ctrl get-ns-id get-log persistent-event-log \ - pred-lat-event-agg-log fw-log smart-log smart-log-add error-log \ - predictable-lat-log get-feature set-feature format fw-activate \ - fw-download admin-passthru io-passthru security-send \ - security-recv resv-acquire resv-register resv-release \ - 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 \ - lba-status-log resv-notif-log" +# Constant to indicate command has no options +readonly NO_OPTS="" + +# Associative array of plugins and associated subcommands +# Order here is same as PLUGIN_OBJS in Makefile +typeset -A _plugin_subcmds +readonly _plugin_subcmds=( + [intel]="id-ctrl internal-log lat-stats \ + set-bucket-thresholds lat-stats-tracking \ + market-name smart-log-add temp-stats" + [amzn]="id-ctrl" + [lnvm]="list info id-ns chunk-log init create \ + remove factory diag-bbtbl diag-set-bbtbl" + [memblaze]="smart-log-add get-pm-status set-pm-status \ + select-download lat-stats lat-stats-print lat-log \ + lat-log-print clear-error-log" + [wdc]="cap-diag drive-log get-crash-dump get-pfail-dump \ + id-ctrl purge purge-monitor vs-internal-log \ + vs-nand-stats vs-smart-add-log clear-pcie-correctable-errors \ + drive-essentials get-drive-status clear-assert-dump \ + drive-resize vs-fw-activate-history clear-fw-activate-history \ + enc-get-log vs-telemetry-controller-option \ + vs-error-reason-identifier log-page-directory \ + namespace-resize vs-drive-info vs-temperature-stats \ + capabilities cloud-SSD-plugin-version vs-pcie-stats" + [huawei]="list id-ctrl" + [netapp]="smdevices ontapdevices" + [toshiba]="vs-smart-add-log vs-internal-log \ + clear-pcie-correctable-errors" + [micron]="select-download vs-temperature-stats vs-pcie-stats \ + clear-pcie-correctable-errors vs-internal-log \ + vs-telemetry-controller-option vs-nand-stats \ + vs-drive-info plugin-version cloud-SSD-plugin-version \ + log-page-directory vs-fw-activate-history \ + vs-error-reason-identifier vs-smart-add-log \ + clear-fw-activate-history vs-smbus-option" + [seagate]="vs-temperature-stats vs-log-page-sup \ + vs-smart-add-log vs-pcie-stats clear-pcie-correctable-errors \ + get-host-tele get-ctrl-tele vs-internal-log \ + plugin-version" + [virtium]="save-smart-to-vtview-log show-identify" + [shannon]="smart-log-add get-feature-add set-feature-add id-ctrl" + [dera]="smart-log-add" + [sfx]="smart-log-add lat-stats get-bad-block query-cap \ + change-cap set-feature get-feature" + [transcend]="healthvalue badblock" + [zns]="id-ctrl id-ns zone-mgmt-recv \ + zone-mgmt-send report-zones close-zone \ + finish-zone open-zone reset-zone offline-zone \ + set-zone-desc zone-append changed-zone-list" + [nvidia]="id-ctrl" + [ymtc]="smart-log-add" +) + +# Associative array mapping plugins to coresponding option completions +typeset -A _plugin_funcs +readonly _plugin_funcs=( + [intel]="plugin_intel_opts" + [amzn]="plugin_amzn_opts" + [lnvm]="plugin_lnvm_opts" + [memblaze]="plugin_memblaze_opts" + [wdc]="plugin_wdc_opts" + [huawei]="plugin_huawei_opts" + [toshiba]="plugin_toshiba_opts" + [micron]="plugin_micron_opts" + [seagate]="plugin_seagate_opts" + [virtium]="plugin_virtium_opts" + [shannon]="plugin_shannon_opts" + [dera]="plugin_dera_opts" + [sfx]="pluginx_sfx_opts" + [transcend]="plugin_transcend_opts" + [zns]="plugin_zns_opts" + [nvidia]="plugin_nvidia_opts" + [ymtc]="plugin_ymtc_opts" +) + +# Top level commands +_cmds="list list-subsys id-ctrl id-ns \ + id-ns-granularity list-ns list-ctrl \ + 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 \ + fw-log changed-ns-list-log smart-log ana-log \ + error-log effects-log endurance-log \ + predictable-lat-log pred-lat-event-agg-log \ + persistent-event-log endurance-agg-log \ + lba-status-log resv-notif-log get-feature \ + device-self-test self-test-log set-feature \ + set-property get-property format fw-commit \ + fw-download admin-passthru io-passthru \ + security-send security-recv get-lba-status \ + resv-acquire resv-register resv-release \ + resv-report dsm copy flush compare read \ + write write-zeros write-uncor verify \ + sanitize sanitize-log reset subsystem-reset \ + ns-rescan show-regs discover connect-all \ + connect disconnect disconnect-all gen-hostnqn \ + show-hostnqn dir-receive dir-send virt-mgmt \ + rpmb" + +# Add plugins: +for plugin in "${!_plugin_subcmds[@]}"; do + _cmds+=" $plugin" +done + +cmds+=" version help" nvme_list_opts () { - local opts="" + local opts="" local compargs="" local nonopt_args=0 @@ -31,34 +126,66 @@ nvme_list_opts () { opts+=" " + # Listed here in the same order as in nvme-builtin.h case "$1" in "list") - opts="" - ;; + opts+=$NO_OPTS + ;; + "list-subsys") + opts=+=" --output-format= -o --verbose -v" + ;; "id-ctrl") opts+=" --raw-binary -b --human-readable -H \ --vendor-specific -v --output-format= -o" - ;; + ;; "id-ns") opts+=" --namespace-id= -n --raw-binary -b \ --human-readable -H --vendor-specific -v \ --force -f --output-format= -o" ;; + "id-ns-granularity") + opts+=" --output-format= -o" + ;; "list-ns") - opts+=" --namespace-id= -n --al -a --csi= -y" + opts+=" --namespace-id= -n --al -a --csi= -y \ + --outputformat= -o" ;; - "id-iocs") - opts+=" --controller-id= -c" + "list-ctrl") + opts+=" --namespace-id= -n --cntid= -c \ + --output-format= -o" + ;; + "id-domain") + opts+=" --dom-id= -d --output-format= -o" ;; "nvm-id-ctrl") opts+=" --output-format= -o" ;; + "primary-ctrl-caps") + opts+=" --output-format= -o --human-readable -H" + ;; + "list-secondary") + opts+=" --cntid= -c --namespace-id= n --num-entries -e \ + --output-format= -o" + ;; + "ns-descs") + opts+=" --namespace-id= -n --output-format -o --raw-binary -b" + ;; + "id-nvmset") + opts+=" --nvmeset-id= -i --output-format= -o" + ;; + "id-uuid") + opts+=" --output-format= -o --raw-binary -b --human-readable -H" + ;; + "id-iocs") + opts+=" --controller-id= -c --output-format= -o --human-readable -H" + ;; "create-ns") opts+=" --nsze= -s --ncap= -c --flbas= -f \ - --dps= -d --nmic= -n --csi= -y" + --dps= -d --nmic= -n --anagrp-id= -a --nvmset-id= -i \ + --block-size= -b --timeout= -t--csi= -y" ;; "delete-ns") - opts+=" -namespace-id= -n" + opts+=" -namespace-id= -n --timeout= -t" ;; "attach-ns") opts+=" --namespace-id= -n --controllers= -c" @@ -66,41 +193,55 @@ nvme_list_opts () { "detach-ns") opts+=" --namespace-id= -n --controllers= -c" ;; - "list-ctrl") - opts+=" --namespace-id= -n --cntid= -c" - ;; "get-ns-id") + opts+=$NO_OPTS ;; "get-log") opts+=" --log-id= -i --log-len= -l --namespace-id= -n \ - --raw-binary= -b" - ;; - "persistent-event-log") - opts+=" --action= -a --log-len= -l \ - --raw-binary -b --output-format= -o" - ;; - "pred-lat-event-agg-log") - opts+=" --log-entries= -e --rae -r \ - --raw-binary -b --output-format= -o" + --aen= -a --lpo= -o --lsp= -s --lsi= -S \ + --rae -r --uuid-index= -U --csi= -y --ot -O \ + --raw-binary -b" ;; - "predictable-lat-log") - opts+=" --nvmset-id= -i --raw-binary -b \ - --output-format= -o" + "telemetry-log") + opts+=" --output-file= -o --host-generate= -g \ + --controller-init -c --data-area= -d" ;; "fw-log") opts+=" --raw-binary -b --output-format= -o" ;; + "changed-ns-list-log") + opts+=" --output-format= -o --raw-binary -b" + ;; "smart-log") opts+=" --namespace-id= -n --raw-binary -b \ --output-format= -o" ;; - "smart-log-add") - opts+=" --namespace-id= -n --raw-binary -b" + "ana-log") + opts+=" --output-format -o" ;; "error-log") - opts+=" --namespace-id= -n --raw-binary -b --log-entries= -e \ + opts+=" --raw-binary -b --log-entries= -e \ + --output-format= -o" + ;; + "effects-log") + opts+=" --output-format= -o --human-readable -H \ + --raw-binary -b" + ;; + "endurance-log") + opts+=" --output-format= -o --group-id -g" + ;; + "predictable-lat-log") + opts+=" --nvmset-id= -i --raw-binary -b \ --output-format= -o" ;; + "pred-lat-event-agg-log") + opts+=" --log-entries= -e --rae -r \ + --raw-binary -b --output-format= -o" + ;; + "persistent-event-log") + opts+=" --action= -a --log-len= -l \ + --raw-binary -b --output-format= -o" + ;; "endurance-event-agg-log") opts+=" --log-entries= -e --rae -r \ --raw-binary -b --output-format= -o" @@ -113,38 +254,58 @@ nvme_list_opts () { ;; "get-feature") opts+=" --namespace-id= -n --feature-id= -f --sel= -s \ - --data-len= -l --cdw11= --raw-binary -b \ + --data-len= -l --cdw11= --c -uuid-index= -U --raw-binary -b \ --human-readable -H" ;; + "device-self-test") + opts+=" --namespace-id= -n --self-test-code= -s" + ;; + "self-test-log") + opts+=" --dst-entries= -e --output-format= -o \ + --verbose -v" + ;; "set-feature") opts+=" --namespace-id= -n --feature-id= -f --value= -v \ - --data-len= -l -data= -d --value= --save -s" + --data-len= -l -data= -d --value= -v --save -s --uuid-index= -U \ + --cdw12= -c" + ;; + "set-property") + opts+=" --offset= -o --value= -v" + ;; + "get-property") + opts=+" --offset= -o --human-readable -H" ;; "format") opts+=" --namespace-id= -n --timeout= -t --lbaf= -l \ --ses= -s --pil= -p -pi= -i --ms= -m --reset -r" ;; - "fw-activate") - opts+=" --action= -a --slot= -s" + "fw-commit") + opts+=" --slot= -s --action= -a --bpid= -b" ;; "fw-download") opts+=" --fw= -f --xfer= -x --offset= -o" ;; + "capacity-mgmt") + opts+=" --operation= -f --element-id= -i --cap-lower= -l \ + --cap-upper= -u" + ;; "admin-passthru") opts+=" --opcode= -o --flags= -f --prefil= -p --rsvd= -R \ --namespace-id= -n --data-len= -l --metadata-len= -m \ --timeout= -t --cdw2= -2 --cdw3= -3 --cdw10= -4 \ --cdw11= -5 --cdw12= -6 --cdw13= -7 --cdw14= -8 \ - --cdw15= -9 --input-file= -i --raw-binary= -b \ - --show-command -s --dry-run -d --read -r --write -w" + --cdw15= -9 --input-file= -i --raw-binary -b \ + --show-command -s --dry-run -d --read -r --write -w \ + --latency -T" ;; "io-passthru") opts+=" --opcode= -o --flags= -f --prefill= -p --rsvd= -R \ --namespace-id= -n --data-len= -l --metadata-len= -m \ --timeout= -t --cdw2= -2 --cdw3= -3 --cdw10= -4 \ --cdw11= -5 --cdw12= -6 --cdw13= -7 --cdw14= -8 \ - --cdw15= -9 --input-file= -i --raw-binary= -b \ - --show-command -s --dry-run -d --read -r --write -w" + --cdw15= -9 --input-file= -i --raw-binary -b \ + --show-command -s --dry-run -d --read -r --write -w \ + --latency -T" ;; "security-send") opts+=" --namespace-id= -n --file= -f --nssf= -N --secp= -p \ @@ -154,6 +315,11 @@ nvme_list_opts () { opts+=" --namespace-id= -n --size= -x --secp= -p --spsp= -s \ --al= -t --raw-binary -b" ;; + "get-lba-status") + opts+=" --namespace-id= -n --start-lba= -s --max-dw= -m \ + --action= -a --range-len= -l --timeout= -t \ + --output-format= -o" + ;; "resv-acquire") opts+=" --namespace-id= -n --crkey= -c --prkey= -p \ --rtype= -t --racqa= -a --iekey= -i" @@ -167,15 +333,15 @@ nvme_list_opts () { --rrela= -a --iekey -i" ;; "resv-report") - opts+=" --namespace-id= -n --numd= -d --raw-binary= -b \ - --output-format= -o" + opts+=" --namespace-id= -n --numd= -d --cdw11 -c \ + --output-format= -o --raw-binary -b" ;; "dsm") - opts+=" --namespace-id= -n --ctx-attrs= -a --blocks= -b\ - -slbs= -s --ad -d --idw -w --idr -r --cdw11= -c" + opts+=" --namespace-id= -n --ctx-attrs= -a --blocks= -b \ + --slbs= -s --ad -d --idw -w --idr -r --cdw11= -c" ;; "copy") - opts+=" --sdlba= -d --blocks= -b --slbs= -s \ + opts+=" --namespace-id= -n --sdlba= -d --blocks= -b --slbs= -s \ --limited-retry -l --force-unit-access -f \ --prinfow= -p --prinfor= -P \ --ref-tag= -r --expected-ref-tag= -R \ @@ -191,7 +357,8 @@ nvme_list_opts () { --metadata-size= -y --ref-tag= -r --data= -d \ --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ - --force-unit-access -f --show-command -v \ + --force-unit-access -f --storage-tag-check -C \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ --dry-run -w --latency -t" ;; "read") @@ -199,7 +366,8 @@ nvme_list_opts () { --metadata-size= -y --ref-tag= -r --data= -d \ --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ - --force-unit-access -f --show-command -v \ + --force-unit-access -f --storage-tag-check -C \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ --dry-run -w --latency -t" ;; "write") @@ -207,66 +375,1004 @@ nvme_list_opts () { --metadata-size= -y --ref-tag= -r --data= -d \ --metadata= -M --prinfo= -p --app-tag-mask= -m \ --app-tag= -a --limited-retry -l \ - --force-unit-access -f --show-command -v \ + --force-unit-access -f --storage-tag-check -C \ + --dir-type= -T --dir-spec= -S --dsm= -D --show-command -v \ --dry-run -w --latency -t" ;; "write-zeros") opts+=" --namespace-id= -n --start-block= -s \ - --block-count= -c --limited-retry -l \ + --block-count= -c --deac -d --limited-retry -l \ --force-unit-access -f --prinfo= -p --ref-tag= -r \ - --app-tag-mask= -m --app-tag= -a" + --app-tag-mask= -m --app-tag= -a \ + --storage-tag= -S --storage-tag-check -C" ;; "write-uncor") opts+=" --namespace-id= -n --start-block= -s \ --block-count= -c" ;; + "verify") + opts+=" --namespace-id= -n --start-block= -s \ + --block-count= -c --limited-retry -l \ + --force-unit-access -f --prinfo= -p --ref-tag= -r \ + --app-tag= -a --app-tag-mask= -m \ + --storage-tag= -S --storage-tag-check -C" + ;; + "sanitize") + opts+=" --no-dealloc -d --oipbp -i --owpass= -n \ + --ause -u --sanact= -a --ovrpat= -p" + ;; + "sanitize-log") + opts+=" --rae -r --output-format= -o --human-readable -H \ + --raw-binary -b" + ;; "reset") - opts+="" + opts+=$NO_OPTS ;; "subsystem-reset") - opts+="" + opts+=$NO_OPTS + ;; + "ns-rescan") + opts+=$NO_OPTS ;; "show-regs") - opts+=" --human-readable -H" + opts+=" --output-format= -o --human-readable -H" ;; "discover") opts+=" --transport= -t -traddr= -a -trsvcid= -s \ - --hostnqn= -q --raw= -r" + --host-traddr= -w --hsot-iface= -f \ + --hostnqn= -q --hostid -I --raw= -r \ + --raw= -r --device= -d --keep-alive-tmo= -k \ + --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \ + --tos= -T --hdr-digest= -g --data-digest -G \ + --nr-io-queues= -i --nr-write-queues= -W \ + --nr-poll-queues= -P --queue-size= -Q \ + --persistent -p --quiet -S --matching -m \ + --output-format= -o" ;; "connect-all") - opts+=" --transport= -t --traddr= -a --trsvcid= -s - --hostnqn= -q --raw= -r" + opts+=" --transport= -t -traddr= -a -trsvcid= -s \ + --host-traddr= -w --hsot-iface= -f \ + --hostnqn= -q --hostid -I --raw= -r \ + --raw= -r --device= -d --keep-alive-tmo= -k \ + --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \ + --tos= -T --hdr-digest= -g --data-digest -G \ + --nr-io-queues= -i --nr-write-queues= -W \ + --nr-poll-queues= -P --queue-size= -Q \ + --persistent -p --quiet -S --matching -m \ + --output-format= -o" ;; "connect") opts+=" --transport= -t --nqn= -n --traddr= -a --trsvcid -s \ - --hostnqn= -q --nr-io-queues= -i --keep-alive-tmo -k \ - --reconnect-delay -r" + --hostnqn= -q --host-id= -I --nr-io-queues= -i \ + --nr-poll-queues= -P --queue-size= -Q \ + --keep-alive-tmo= -k --reconnect-delay= -r \ + --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \ + --tos= -T --duplicate-connect -D --disable-sqflow -d\ + --hdr-digest -g --data-digest -G --output-format= -o" ;; "disconnect") opts+=" --nqn -n --device -d" ;; + "disconnect-all") + opts+=$NO_OPTS + ;; + "gen-hostnqn") + opts+=$NO_OPTS + ;; + "show-hostnqn") + opts+=$NO_OPTS + ;; + "dir-receive") + opts+=" --namespace-id= -n --data-len= -l --raw-binary -b \ + --dir-type= -D --dir-spec= -S --dir-oper= -O \ + --req-resource= -r --human-readable -H" + ;; + "dir-send") + opts+=" --namespace-id= -n --data-len= -l --dir-type= -D \ + --target-dir= -T --dir-spec= -S --dir-oper= -O \ + --endir= -e --human-readable -H --raw-binary -b" + ;; + "virt-mgmt") + opts+=" --cntlid= -c --rt= -r --act= -a --nr= -n" + ;; + "rpmb") + opts+=" --cmd= -c --msgfile= -f --keyfile= -g \ + --key= -k --msg= -d --address= -o --blocks= -b \ + --target= -t" + ;; "version") - opts+="" + opts+=$NO_OPTS ;; "help") opts=$_cmds ;; esac - opts+=" -h --help" + opts+=" -h --help" COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) return 0 } -_nvme_subcmds () { - local cur prev words cword - _init_completion || return +plugin_intel_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "internal-log") + opts+=" --log= -l --region= -r --nlognum= -m \ + --namespace-id= -n --output-file= -o \ + --verbose-nlog -v" + ;; + "lat-stats") + opts+=" --write -w --raw-binary -b --json -j" + ;; + "set-bucket-thresholds") + opts+=" --write -w --bucket-thresholds= -t" + ;; + "lat-stats-tracking") + opts+=" --enable -e --disable -d" + ;; + "market-name") + opts+=" --raw-binary -b" + ;; + "smart-log-add") + opts+=" --namespace-id= -n --raw-binary -b \ + --json -j" + ;; + "temp-stats") + opts+=" --raw-binary -b" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_amzn_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_lnvm_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "list") + opts+=$NO_OPTS + ;; + "info") + opts+=$NO_OPTS + ;; + "id-ns") + opts+=" --namespace-id= -n --raw-binary -b --human-readable -H" + ;; + "chunk-log") + opts+=" --output-format= -o --human-readable -H" + ;; + "init") + opts+=" --device-name= -d --mediamgr-name -m" + ;; + "create") + opts+=" --device-name= -d --target-name= -n --target-type= -t \ + --lun-begin= -b --lun-end= -e --over-prov= -o --factory -f" + ;; + "remove") + opts+=" --target-name= -n" + ;; + "factory") + opts+=" --device-name= -d --erase-only-marked -e + --clear-host-side-blks -s --clear-bb-blks -b" + ;; + "diag-bbtbl") + opts+=" --namespace-id= -n --channel-id= -c --lun-id= -l \ + --raw-binary -b" + ;; + "diag-set-bbtbl") + opts+=" --namespace-id= -n --channel-id= -c --lun-id= -l \ + --plane-id= -p --block-id= -b --value= -v" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_memblaze_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-log-add") + opts+=" --namespace-id= -n --raw-binary -b" + ;; + "get-pm-status") + opts+=$NO_OPTS + ;; + "set-pm-status") + opts+=" --value= -v --save -s" + ;; + "select-download") + opts+=" --fw= -f --select= -s" + ;; + "lat-stats") + opts+=" --enable -e --disable -d" + ;; + "lat-stats-print") + opts+=" --write -w" + ;; + "lat-log") + opts+=" --param= -p" + ;; + "lat-log-print") + opts+=$NO_OPTS + ;; + "clear-error-log") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_wdc_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "cap-diag") + opts+=" --output-file= -o --transfer-size= -s" + ;; + "drive-log") + opts+=" --output-file= -o" + ;; + "get-crash-dump") + opts+=" --output-file= -o" + ;; + "get-pfail-dump") + opts+=" --output-file= -o" + ;; + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "purge") + opts+=$NO_OPTS + ;; + "purge-monitor") + opts+=$NO_OPTS + ;; + "vs-internal-log") + opts+=" --output-file= -o --transfer-size= -s --data-area= -d \ + --file-size= -f --offset= -e --type= -t --verbose -v" + ;; + "vs-nand-stats") + opts+=" --output-format= -o" + ;; + "vs-smart-add-log") + opts+=" --interval= -i --output-format= -o --log-page-version= -l \ + --log-page-mask= -p" + ;; + "clear-pcie-correctable-errors") + opts+=$NO_OPTS + ;; + "drive-essentials") + opts+=" --dir-name= -d" + ;; + "get-drive-status") + opts+=$NO_OPTS + ;; + "clear-assert-dump") + opts+=$NO_OPTS + ;; + "drive-resize") + opts+=" --size= -s" + ;; + "vs-fw-activate-history") + opts+=" --output-format= -o" + ;; + "clear-fw-activate-history") + opts+=$NO_OPTS + ;; + "enc-get-log") + opts+=" --output-file= -o --transfer-size= -s --log-id= -l" + ;; + "vs-telemetry-controller-option") + opts+=" --disable -d --enable -e --status -s" + ;; + "vs-error-reason-identifier") + opts+=" --log-id= -i --file= -o" + ;; + "log-page-directory") + opts+=" --output-format= -o" + ;; + "namespace-resize") + opts+=" --namespace-id= -n --op-option= -o" + ;; + "vs-drive-info") + opts+=" --output-format= -o" + ;; + "vs-temperature-stats") + opts+=" --output-format= -o" + ;; + "capabilities") + opts+=$NO_OPTS + ;; + "cloud-SSD-plugin-version") + opts+=$NO_OPTS + ;; + "vs-pcie-stats") + opts+=" --output-format= -o" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_huawei_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "list") + opts+=" --output-format= -o" + ;; + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_toshiba_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "vs-smart-add-log") + opts+=" --namespace-id= -n --output-file= -o --log= -l" + ;; + "vs-internal-log") + opts+=" --output-file= -o --prev-log -p" + ;; + "clear-pcie-correctable-errors") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_micron_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "select-download") + opts+=" --fw= -f --select= -s" + ;; + "vs-temperature-stats") + opts+=" --format= -f" + ;; + "vs-pcie-stats") + opts+=" --format= -f" + ;; + "clear-pcie-correctable-errors") + opts+=$NO_OPTS + ;; + "vs-internal-log") + opts+=" --type= -t --package= -p --data_area= -d" + ;; + "vs-telemetry-controller-option") + opts+=" --option= -o --select= -s" + ;; + "vs-nand-stats") + opts+=" --format= -f" + ;; + "vs-drive-info") + opts+=" --format= -f" + ;; + "plugin-version") + opts+=$NO_OPTS + ;; + "cloud-SSD-plugin-version") + opts+=$NO_OPTS + ;; + "log-page-directory") + opts+=$NO_OPTS + ;; + "vs-fw-activate-history") + opts+=" --format= -f" + ;; + "vs-error-reason-identifier") + opts+=" --format= -f" + ;; + "vs-smart-add-log") + opts+=" --format= -f" + ;; + "clear-fw-activate-history") + opts+=$NO_OPTS + ;; + "vs-smbus-option") + opts+=" --option= -o --value= -v --save= -s" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +lugin_seagate_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "vs-temperature-stats") + opts+=" --output-format= -o" + ;; + "vs-log-page-sup") + opts+=" --output-format= -o" + ;; + "vs-smart-add-log") + opts+=" --output-format= -o" + ;; + "vs-pcie-stats") + opts+=" --output-format= -o" + ;; + "clear-pcie-correctable-errors") + opts+=" --save -s" + ;; + "get-host-tele") + opts+=" --namespace-id= -n --log-specific= -i --raw-binary -b" + ;; + "get-ctrl-tele") + opts+=" --namespace-id= -n --raw-binary -b" + ;; + "vs-internal-log") + opts+=" --namespace-id= -n --dump-file= -f" + ;; + "plugin-version") + opts+=$NO_OPTS + ;; + "help") + opts+="" + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_virtium_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "save-smart-to-vtview-log") + opts+=" --run-time= -r --freq= -f --output-file= -o --test-name= -n" + ;; + "show-identify") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_shannon_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-log-add") + opts+=" --namespace-id= -n --raw-binary -b" + ;; + "get-feature-add") + opts+=" --namespace-id= -n --feature-id -f --sel= -s \ + --data-len= -l --raw-binary -b --cdw11= -c --human-readable -H" + ;; + "set-feature-add") + opts+=" --namespace-id= -n --feature-id= -f --value= -v \ + --data-len= -l --data= -d --save -s" + ;; + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_dera_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-log-add") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_sfx_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-log-add") + opts+=" --namespace-id= -n --raw-binary -b --json -j" + ;; + "lat-stats") + opts+=" --write -w --raw-binary -b" + ;; + "get-bad-block") + opts+=$NO_OPTS + ;; + "query-cap") + opts+=" --raw-binary --json" + ;; + "change-cap") + opts+=" --cap= -c --cap-byte= -z --force -f --raw-binary -b --json -j" + ;; + "set-feature") + opts+=" --namespace-id= -n --feature-id= -f --value= -v --force -s" + ;; + "get-feature") + opts+=" --namespace-id= -n --feature-id -f" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_transcend_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "healthvalue") + opts+=$NO_OPTS + ;; + "badblock") + opts+=$NO_OPTS + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_zns_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "id-ns") + opts+=" --namespace-id= -n --vendor-specific -v \ + --output-format= -o --human-readable -H" + ;; + "zone-mgmt-recv") + opts+=" --output-format= -o --namespace-id= -n \ + --start-lba= -s --zra= -z --zrasf= -S --partial -p \ + --data-len= -l" + ;; + "zone-mgmt-send") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --zsa= -z --data-len= -l \ + --data= -d --timeout= -t" + ;; + "report-zones") + opts+=" --namespace-id= -n --start-lba= -s \ + --descs= -d --state= -S --output-format= -o \ + --human-readable -H --extended -e --partial -p" + ;; + "close-zone") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --timeout= -t" + ;; + "finish-zone") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --timeout= -t" + ;; + "open-zone") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --timeout= -t" + ;; + "reset-zone") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --timeout= -t" + ;; + "offline-zone") + opts+=" --namespace-id= -n --start-lba= -s \ + --select-all -a --timeout= -t" + ;; + "set-zone-desc") + opts+=" --namespace-id= -n --start-lba= -s \ + --data= -d --timeout= -t" + ;; + "zone-append") + opts+=" --namespace-id= -n --zslba= -s --data-size= -z \ + --metadata-size= -y --data= -d --metadata= -M \ + --limited-retry -l --force-unit-access -f --ref-tag= -r + --app-tag-mask= -m --app-tag= -a --prinfo= -p \ + --piremap -P --latency -t" + ;; + "changed-zone-list") + opts+=" --namespace-id= -n --output-format= -o --rae -r" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_nvidia_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "id-ctrl") + opts+=" --raw-binary -b --human-readable -H \ + --vendor-specific -v --output-format= -o" + ;; + "help") + opts+=$NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +plugin_ymtc_opts () { + local opts="" + local compargs="" + + local nonopt_args=0 + for (( i=0; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} != -* ]]; then + let nonopt_args+=1 + fi + done + + if [ $nonopt_args -eq 3 ]; then + opts="/dev/nvme* " + fi + + opts+=" " + + case "$1" in + "smart-log-add") + opts+=" --namespace-id= -n --raw-binary -b" + ;; + "help") + opts+=NO_OPTS + ;; + esac + + COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) ) + + return 0 +} + +_nvme_subcmds () { + local cur prev words cword + _init_completion || return + + if [[ ${#words[*]} -lt 3 ]]; then + COMPREPLY+=( $(compgen -W "$_cmds" -- $cur ) ) + else + for subcmd in "${!_plugin_subcmds[@]}"; do + if [[ ${words[1]} == $subcmd ]]; then + if [[ ${#words[*]} -lt 4 ]]; then + COMPREPLY+=( $(compgen -W "${_plugin_subcmds[$subcmd]}" -- $cur ) ) + else + func=${_plugin_funcs[$subcmd]} + $func ${words[2]} $prev + fi + return 0 + fi + done - if [[ ${#words[*]} -lt 3 ]]; then - COMPREPLY+=( $(compgen -W "$_cmds" -- $cur ) ) - else nvme_list_opts ${words[1]} $prev fi diff --git a/etc/discovery.conf.in b/etc/discovery.conf.in index 14e0d9c..cfdac1e 100644 --- a/etc/discovery.conf.in +++ b/etc/discovery.conf.in @@ -1,4 +1,4 @@ # Used for extracting default parameters for discovery # # Example: -# --transport= --traddr= --trsvcid= --host-traddr= +# --transport= --traddr= --trsvcid= --host-traddr= --host-iface= diff --git a/fabrics.c b/fabrics.c index 7dd0d27..39bee97 100644 --- a/fabrics.c +++ b/fabrics.c @@ -66,9 +66,11 @@ const char *conarg_transport = "transport"; const char *conarg_traddr = "traddr"; const char *conarg_trsvcid = "trsvcid"; const char *conarg_host_traddr = "host_traddr"; +const char *conarg_host_iface = "host_iface"; struct fabrics_config fabrics_cfg = { .ctrl_loss_tmo = -1, + .fast_io_fail_tmo = -1, .output_format = "normal", }; @@ -78,6 +80,7 @@ struct connect_args { char *traddr; char *trsvcid; char *host_traddr; + char *host_iface; struct connect_args *next; struct connect_args *tail; }; @@ -300,6 +303,7 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args cargs.traddr = parse_conn_arg(addr, ' ', conarg_traddr); cargs.trsvcid = parse_conn_arg(addr, ' ', conarg_trsvcid); cargs.host_traddr = parse_conn_arg(addr, ' ', conarg_host_traddr); + cargs.host_iface = parse_conn_arg(addr, ' ', conarg_host_iface); if (!strcmp(cargs.subsysnqn, NVME_DISC_SUBSYS_NAME)) { char *kato_str = nvme_get_ctrl_attr(path, "kato"), *p; @@ -331,7 +335,9 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args (!strcmp(cargs.trsvcid, args->trsvcid) || !strcmp(args->trsvcid, "none")) && (!strcmp(cargs.host_traddr, args->host_traddr) || - !strcmp(args->host_traddr, "none"))) + !strcmp(args->host_traddr, "none")) && + (!strcmp(cargs.host_iface, args->host_iface) || + !strcmp(args->host_iface, "none"))) found = true; free(cargs.subsysnqn); @@ -339,6 +345,7 @@ static bool ctrl_matches_connectargs(const char *name, struct connect_args *args free(cargs.traddr); free(cargs.trsvcid); free(cargs.host_traddr); + free(cargs.host_iface); free(addr); free(path); @@ -394,6 +401,7 @@ static struct connect_args *extract_connect_args(char *argstr) cargs->traddr = parse_conn_arg(argstr, ',', conarg_traddr); cargs->trsvcid = parse_conn_arg(argstr, ',', conarg_trsvcid); cargs->host_traddr = parse_conn_arg(argstr, ',', conarg_host_traddr); + cargs->host_iface = parse_conn_arg(argstr, ',', conarg_host_iface); return cargs; } @@ -404,6 +412,7 @@ static void destruct_connect_args(struct connect_args *cargs) free(cargs->traddr); free(cargs->trsvcid); free(cargs->host_traddr); + free(cargs->host_iface); } static void free_connect_args(struct connect_args *cargs) @@ -670,11 +679,17 @@ static int space_strip_len(int max, const char *str) return i + 1; } -static void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) +static void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec, + int instance) { int i; - printf("\nDiscovery Log Number of Records %d, " + printf("\n"); + + if (fabrics_cfg.persistent) + printf("Persistent device: nvme%d\n", instance); + + printf("Discovery Log Number of Records %d, " "Generation counter %"PRIu64"\n", numrec, le64_to_cpu(log->genctr)); @@ -704,7 +719,7 @@ static void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) printf("rdma_cms: %s\n", cms_str(e->tsas.rdma.cms)); printf("rdma_pkey: 0x%04x\n", - e->tsas.rdma.pkey); + le16_to_cpu(e->tsas.rdma.pkey)); break; case NVMF_TRTYPE_TCP: printf("sectype: %s\n", @@ -714,14 +729,20 @@ static void print_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) } } -static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) +static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec, + int instance) { struct json_object *root; struct json_object *entries; + char *dev_name = NULL; int i; + if (asprintf(&dev_name, "nvme%d", instance) < 0) + return; + root = json_create_object(); entries = json_create_array(); + json_object_add_value_string(root, "device", dev_name); json_object_add_value_uint(root, "genctr", le64_to_cpu(log->genctr)); json_object_add_value_array(root, "records", entries); @@ -729,6 +750,10 @@ static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) struct nvmf_disc_rsp_page_entry *e = &log->entries[i]; struct json_object *entry = json_create_object(); + nvme_strip_spaces(e->trsvcid, NVMF_TRSVCID_SIZE); + nvme_strip_spaces(e->subnqn, NVMF_NQN_SIZE); + nvme_strip_spaces(e->traddr, NVMF_TRADDR_SIZE); + json_object_add_value_string(entry, "trtype", trtype_str(e->trtype)); json_object_add_value_string(entry, "adrfam", @@ -738,8 +763,7 @@ static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) json_object_add_value_string(entry,"treq", treq_str(e->treq)); json_object_add_value_uint(entry, "portid", e->portid); - json_object_add_value_string(entry, "trsvcid", - e->trsvcid); + json_object_add_value_string(entry, "trsvcid", e->trsvcid); json_object_add_value_string(entry, "subnqn", e->subnqn); json_object_add_value_string(entry, "traddr", e->traddr); @@ -752,7 +776,7 @@ static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) json_object_add_value_string(entry, "rdma_cms", cms_str(e->tsas.rdma.cms)); json_object_add_value_uint(entry, "rdma_pkey", - e->tsas.rdma.pkey); + le16_to_cpu(e->tsas.rdma.pkey)); break; case NVMF_TRTYPE_TCP: json_object_add_value_string(entry, "sectype", @@ -764,6 +788,7 @@ static void json_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) json_print_object(root, NULL); printf("\n"); json_free_object(root); + free(dev_name); } static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) @@ -790,6 +815,28 @@ static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec) close(fd); } +static void print_connect_msg(int instance) +{ + printf("device: nvme%d\n", instance); +} + +static void json_connect_msg(int instance) +{ + struct json_object *root; + char *dev_name = NULL; + + if (asprintf(&dev_name, "nvme%d", instance) < 0) + return; + + root = json_create_object(); + json_object_add_value_string(root, "device", dev_name); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + free(dev_name); +} + static char *hostnqn_read_file(void) { FILE *f; @@ -969,6 +1016,7 @@ int build_options(char *argstr, int max_len, bool discover) if (add_argument(&argstr, &max_len, "transport", fabrics_cfg.transport) || add_argument(&argstr, &max_len, "traddr", fabrics_cfg.traddr) || add_argument(&argstr, &max_len, "host_traddr", fabrics_cfg.host_traddr) || + add_argument(&argstr, &max_len, "host_iface", fabrics_cfg.host_iface) || add_argument(&argstr, &max_len, "trsvcid", fabrics_cfg.trsvcid) || ((fabrics_cfg.hostnqn || nvmf_hostnqn_file()) && add_argument(&argstr, &max_len, "hostnqn", fabrics_cfg.hostnqn)) || @@ -991,6 +1039,8 @@ int build_options(char *argstr, int max_len, bool discover) (strncmp(fabrics_cfg.transport, "loop", 4) && add_int_argument(&argstr, &max_len, "ctrl_loss_tmo", fabrics_cfg.ctrl_loss_tmo, true)) || + add_int_argument(&argstr, &max_len, "fast_io_fail_tmo", + fabrics_cfg.fast_io_fail_tmo, true) || add_int_argument(&argstr, &max_len, "tos", fabrics_cfg.tos, true) || add_bool_argument(&argstr, &max_len, "duplicate_connect", @@ -1014,11 +1064,16 @@ static void set_discovery_kato(struct fabrics_config *cfg) cfg->keep_alive_tmo = 0; } -static void discovery_trsvcid(struct fabrics_config *fabrics_cfg) +static void discovery_trsvcid(struct fabrics_config *fabrics_cfg, bool discover) { if (!strcmp(fabrics_cfg->transport, "tcp")) { - /* Default port for NVMe/TCP discovery controllers */ - fabrics_cfg->trsvcid = __stringify(NVME_DISC_IP_PORT); + if (discover) { + /* Default port for NVMe/TCP discovery controllers */ + fabrics_cfg->trsvcid = __stringify(NVME_DISC_IP_PORT); + } else { + /* Default port for NVMe/TCP io controllers */ + fabrics_cfg->trsvcid = __stringify(NVME_RDMA_IP_PORT); + } } else if (!strcmp(fabrics_cfg->transport, "rdma")) { /* Default port for NVMe/RDMA controllers */ fabrics_cfg->trsvcid = __stringify(NVME_RDMA_IP_PORT); @@ -1158,6 +1213,13 @@ retry: p+= len; } + if (fabrics_cfg.host_iface && strcmp(fabrics_cfg.host_iface, "none")) { + len = sprintf(p, ",host_iface=%s", fabrics_cfg.host_iface); + if (len < 0) + return -EINVAL; + p+= len; + } + if (fabrics_cfg.reconnect_delay) { len = sprintf(p, ",reconnect_delay=%d", fabrics_cfg.reconnect_delay); if (len < 0) @@ -1172,6 +1234,13 @@ retry: p += len; } + if (fabrics_cfg.fast_io_fail_tmo) { + len = sprintf(p, ",fast_io_fail_tmo=%d", fabrics_cfg.fast_io_fail_tmo); + if (len < 0) + return -EINVAL; + p += len; + } + if (fabrics_cfg.tos != -1) { len = sprintf(p, ",tos=%d", fabrics_cfg.tos); if (len < 0) @@ -1290,6 +1359,7 @@ static bool cargs_match_found(struct nvmf_disc_rsp_page_entry *entry) cargs.subsysnqn = strdup(entry->subnqn); cargs.trsvcid = strdup(entry->trsvcid); cargs.host_traddr = strdup(fabrics_cfg.host_traddr ?: "\0"); + cargs.host_iface = strdup(fabrics_cfg.host_iface ?: "\0"); /* check if we have a match in the discovery recursion */ while (c) { @@ -1297,7 +1367,8 @@ static bool cargs_match_found(struct nvmf_disc_rsp_page_entry *entry) !strcmp(cargs.transport, c->transport) && !strcmp(cargs.traddr, c->traddr) && !strcmp(cargs.trsvcid, c->trsvcid) && - !strcmp(cargs.host_traddr, c->host_traddr)) + !strcmp(cargs.host_traddr, c->host_traddr) && + !strcmp(cargs.host_iface, c->host_iface)) return true; c = c->next; } @@ -1313,6 +1384,10 @@ static bool should_connect(struct nvmf_disc_rsp_page_entry *entry) if (cargs_match_found(entry)) return false; + /* skip connect if the transport type doesn't match */ + if (strcmp(fabrics_cfg.transport, trtype_str(entry->trtype))) + return false; + if (!fabrics_cfg.matching_only || !fabrics_cfg.traddr) return true; @@ -1404,8 +1479,6 @@ int do_discover(char *argstr, bool connect, enum nvme_print_flags flags) return -errno; ret = nvmf_get_log_page_discovery(dev_name, &log, &numrec, &status); free(dev_name); - if (fabrics_cfg.persistent) - msg(LOG_NOTICE, "Persistent device: nvme%d\n", instance); if (!fabrics_cfg.device && !fabrics_cfg.persistent) { err = remove_ctrl(instance); if (err) @@ -1419,9 +1492,9 @@ int do_discover(char *argstr, bool connect, enum nvme_print_flags flags) else if (fabrics_cfg.raw || flags == BINARY) save_discovery_log(log, numrec); else if (flags == JSON) - json_discovery_log(log, numrec); + json_discovery_log(log, numrec, instance); else - print_discovery_log(log, numrec); + print_discovery_log(log, numrec, instance); break; case DISC_GET_NUMRECS: msg(LOG_ERR, @@ -1513,7 +1586,7 @@ static int discover_from_conf_file(const char *desc, char *argstr, } if (!fabrics_cfg.trsvcid) - discovery_trsvcid(&fabrics_cfg); + discovery_trsvcid(&fabrics_cfg, true); err = build_options(argstr, BUF_SIZE, true); if (err) { @@ -1529,7 +1602,8 @@ free_and_continue: free(all_args); free(argv); fabrics_cfg.transport = fabrics_cfg.traddr = - fabrics_cfg.trsvcid = fabrics_cfg.host_traddr = NULL; + fabrics_cfg.trsvcid = fabrics_cfg.host_traddr = + fabrics_cfg.host_iface = NULL; } out: @@ -1548,7 +1622,8 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) OPT_LIST("transport", 't', &fabrics_cfg.transport, "transport type"), OPT_LIST("traddr", 'a', &fabrics_cfg.traddr, "transport address"), OPT_LIST("trsvcid", 's', &fabrics_cfg.trsvcid, "transport service id (e.g. IP port)"), - OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's)"), + OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's or IP source address)"), + OPT_LIST("host-iface", 'f', &fabrics_cfg.host_iface, "host transport interface (e.g. IP eth1, enp2s0)"), OPT_LIST("hostnqn", 'q', &fabrics_cfg.hostnqn, "user-defined hostnqn (if default not used)"), OPT_LIST("hostid", 'I', &fabrics_cfg.hostid, "user-defined hostid (if default not used)"), OPT_LIST("raw", 'r', &fabrics_cfg.raw, "raw output file"), @@ -1556,6 +1631,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) OPT_INT("keep-alive-tmo", 'k', &fabrics_cfg.keep_alive_tmo, "keep alive timeout period in seconds"), OPT_INT("reconnect-delay", 'c', &fabrics_cfg.reconnect_delay, "reconnect timeout period in seconds"), OPT_INT("ctrl-loss-tmo", 'l', &fabrics_cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"), + OPT_INT("fast_io_fail_tmo",'f',&fabrics_cfg.fast_io_fail_tmo, "fast I/O fail timeout (default off)"), OPT_INT("tos", 'T', &fabrics_cfg.tos, "type of service"), OPT_FLAG("hdr_digest", 'g', &fabrics_cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"), OPT_FLAG("data_digest", 'G', &fabrics_cfg.data_digest, "enable transport protocol data digest (TCP transport)"), @@ -1564,7 +1640,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) OPT_INT("nr-poll-queues", 'P', &fabrics_cfg.nr_poll_queues, "number of poll queues to use (default 0)"), OPT_INT("queue-size", 'Q', &fabrics_cfg.queue_size, "number of io queue elements to use (default 128)"), OPT_FLAG("persistent", 'p', &fabrics_cfg.persistent, "persistent discovery connection"), - OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), + OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"), OPT_FLAG("matching", 'm', &fabrics_cfg.matching_only, "connect only records matching the traddr"), OPT_FMT("output-format", 'o', &fabrics_cfg.output_format, output_format), OPT_END() @@ -1606,7 +1682,7 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect) } if (!fabrics_cfg.trsvcid) - discovery_trsvcid(&fabrics_cfg); + discovery_trsvcid(&fabrics_cfg, true); ret = build_options(argstr, BUF_SIZE, true); if (ret) @@ -1623,13 +1699,15 @@ int fabrics_connect(const char *desc, int argc, char **argv) { char argstr[BUF_SIZE]; int instance, ret; + enum nvme_print_flags flags = -1; OPT_ARGS(opts) = { OPT_LIST("transport", 't', &fabrics_cfg.transport, "transport type"), OPT_LIST("nqn", 'n', &fabrics_cfg.nqn, "nqn name"), OPT_LIST("traddr", 'a', &fabrics_cfg.traddr, "transport address"), OPT_LIST("trsvcid", 's', &fabrics_cfg.trsvcid, "transport service id (e.g. IP port)"), - OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's)"), + OPT_LIST("host-traddr", 'w', &fabrics_cfg.host_traddr, "host traddr (e.g. FC WWN's or IP source address)"), + OPT_LIST("host-iface", 'f', &fabrics_cfg.host_iface, "host transport interface (e.g. IP eth1, enp2s0)"), OPT_LIST("hostnqn", 'q', &fabrics_cfg.hostnqn, "user-defined hostnqn"), OPT_LIST("hostid", 'I', &fabrics_cfg.hostid, "user-defined hostid (if default not used)"), OPT_INT("nr-io-queues", 'i', &fabrics_cfg.nr_io_queues, "number of io queues to use (default is core count)"), @@ -1639,25 +1717,42 @@ int fabrics_connect(const char *desc, int argc, char **argv) OPT_INT("keep-alive-tmo", 'k', &fabrics_cfg.keep_alive_tmo, "keep alive timeout period in seconds"), OPT_INT("reconnect-delay", 'c', &fabrics_cfg.reconnect_delay, "reconnect timeout period in seconds"), OPT_INT("ctrl-loss-tmo", 'l', &fabrics_cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"), + OPT_INT("fast_io_fail_tmo", 'f', &fabrics_cfg.fast_io_fail_tmo, "fast I/O fail timeout (default off)"), OPT_INT("tos", 'T', &fabrics_cfg.tos, "type of service"), OPT_FLAG("duplicate-connect", 'D', &fabrics_cfg.duplicate_connect, "allow duplicate connections between same transport host and subsystem port"), OPT_FLAG("disable-sqflow", 'd', &fabrics_cfg.disable_sqflow, "disable controller sq flow control (default false)"), OPT_FLAG("hdr-digest", 'g', &fabrics_cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"), OPT_FLAG("data-digest", 'G', &fabrics_cfg.data_digest, "enable transport protocol data digest (TCP transport)"), + OPT_FMT("output-format", 'o', &fabrics_cfg.output_format, "Output format: normal|json"), OPT_END() }; + fabrics_cfg.output_format = ""; fabrics_cfg.tos = -1; ret = argconfig_parse(argc, argv, desc, opts); if (ret) goto out; + if (!strcmp(fabrics_cfg.output_format, "")) + flags = -1; + else if (!strcmp(fabrics_cfg.output_format, "normal")) + flags = NORMAL; + else if (!strcmp(fabrics_cfg.output_format, "json")) + flags = JSON; + else { + ret = -EINVAL; + goto out; + } + if (traddr_is_hostname(&fabrics_cfg)) { ret = hostname2traddr(&fabrics_cfg); if (ret) goto out; } + if (!fabrics_cfg.trsvcid) + discovery_trsvcid(&fabrics_cfg, false); + ret = build_options(argstr, BUF_SIZE, false); if (ret) goto out; @@ -1671,6 +1766,12 @@ int fabrics_connect(const char *desc, int argc, char **argv) instance = add_ctrl(argstr); if (instance < 0) ret = instance; + else { + if (flags == NORMAL) + print_connect_msg(instance); + else if (flags == JSON) + json_connect_msg(instance); + } out: return nvme_status_to_errno(ret, true); diff --git a/fabrics.h b/fabrics.h index 41e6a2d..9b2554e 100644 --- a/fabrics.h +++ b/fabrics.h @@ -20,6 +20,7 @@ struct fabrics_config { const char *traddr; const char *trsvcid; const char *host_traddr; + const char *host_iface; const char *hostnqn; const char *hostid; int nr_io_queues; @@ -29,6 +30,7 @@ struct fabrics_config { int keep_alive_tmo; int reconnect_delay; int ctrl_loss_tmo; + int fast_io_fail_tmo; int tos; const char *raw; char *device; diff --git a/linux/nvme.h b/linux/nvme.h index 4ad09ee..589108b 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -147,6 +147,8 @@ enum { NVME_IOCS_ZONED = 0x02, }; +#define NVME_NUM_IOCS_COMBINATIONS 512 + #define NVME_AQ_DEPTH 32 #define NVME_NR_AEN_COMMANDS 1 #define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS) @@ -288,7 +290,10 @@ struct nvme_id_ctrl { __le16 crdt1; __le16 crdt2; __le16 crdt3; - __u8 rsvd134[122]; + __u8 rsvd134[119]; + __u8 nvmsr; + __u8 vwci; + __u8 mec; __le16 oacs; __u8 acl; __u8 aerl; @@ -323,7 +328,10 @@ struct nvme_id_ctrl { __le32 anagrpmax; __le32 nanagrpid; __le32 pels; - __u8 rsvd356[156]; + __le16 domainid; + __u8 rsvd358[10]; + __u8 megcap[16]; + __u8 rsvd384[128]; __u8 sqes; __u8 cqes; __le16 maxcmd; @@ -337,10 +345,12 @@ struct nvme_id_ctrl { __u8 icsvscc; __u8 nwpc; __le16 acwu; - __u8 rsvd534[2]; + __le16 ocfs; __le32 sgls; __le32 mnan; - __u8 rsvd544[224]; + __u8 maxdna[16]; + __le32 maxcna; + __u8 rsvd564[204]; char subnqn[256]; __u8 rsvd1024[768]; __le32 ioccsz; @@ -425,7 +435,7 @@ struct nvme_id_ns { }; struct nvme_id_iocs { - __le64 iocs[512]; + __le64 iocs[NVME_NUM_IOCS_COMBINATIONS]; }; enum { @@ -445,6 +455,7 @@ enum { NVME_ID_CNS_SCNDRY_CTRL_LIST = 0x15, NVME_ID_CNS_NS_GRANULARITY = 0x16, NVME_ID_CNS_UUID_LIST = 0x17, + NVME_ID_CNS_DOMAIN_LIST = 0x18, NVME_ID_CNS_CSI_NS_PRESENT_LIST = 0x1a, NVME_ID_CNS_CSI_NS_PRESENT = 0x1b, NVME_ID_CNS_CSI = 0x1c, @@ -672,17 +683,17 @@ struct nvme_fw_slot_info_log { }; struct nvme_lba_status_desc { - __u64 dslba; - __u32 nlb; - __u8 rsvd_12; - __u8 status; - __u8 rsvd_15_14[2]; + __le64 dslba; + __le32 nlb; + __u8 rsvd_12; + __u8 status; + __u8 rsvd_15_14[2]; }; struct nvme_lba_status { - __u32 nlsd; - __u8 cmpc; - __u8 rsvd_7_5[3]; + __le32 nlsd; + __u8 cmpc; + __u8 rsvd_7_5[3]; struct nvme_lba_status_desc descs[0]; }; @@ -964,8 +975,8 @@ struct nvme_lba_range_type { __u8 type; __u8 attributes; __u8 rsvd2[14]; - __u64 slba; - __u64 nlb; + __le64 slba; + __le64 nlb; __u8 guid[16]; __u8 rsvd48[16]; }; @@ -1160,6 +1171,7 @@ enum { NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12, NVME_RW_PRINFO_PRACT = 1 << 13, NVME_RW_DTYPE_STREAMS = 1 << 4, + NVME_RW_STORAGE_TAG_CHECK = 1 << 8, }; enum { @@ -1191,6 +1203,31 @@ struct nvme_feat_auto_pst { __le64 entries[32]; }; +struct nvme_mi_host_metadata_element_desc { + __u8 type; /* Element Type */ + __u8 rev; /* Element Revision */ + __u16 len; /* Element Length */ + __u8 val[0]; /* Element Value (UTF-8) */ +}; + +struct nvme_mi_host_metadata { + __u8 ndesc; + __u8 rsvd1; + struct nvme_mi_host_metadata_element_desc descs[0]; +}; + +enum { + NVME_MI_CTRL_METADATA_OS_CTRL_NAME = 0x01, + NVME_MI_CTRL_METADATA_OS_DRIVER_NAME = 0x02, + NVME_MI_CTRL_METADATA_OS_DRIVER_VER = 0x03, + NVME_MI_CTRL_METADATA_PRE_BOOT_CTRL_NAME = 0x04, + NVME_MI_CTRL_METADATA_PRE_BOOT_DRIVER_NAME = 0x05, + NVME_MI_CTRL_METADATA_PRE_BOOT_DRIVER_VER = 0x06, + + NVME_MI_NS_METADATA_OS_NS_NAME = 0x01, + NVME_MI_NS_METADATA_PRE_BOOT_NS_NAME = 0x02, +}; + enum { NVME_HOST_MEM_ENABLE = (1 << 0), NVME_HOST_MEM_RETURN = (1 << 1), @@ -1220,6 +1257,7 @@ enum nvme_admin_opcode { nvme_admin_virtual_mgmt = 0x1c, nvme_admin_nvme_mi_send = 0x1d, nvme_admin_nvme_mi_recv = 0x1e, + nvme_admin_capacity_mgmt = 0x20, nvme_admin_dbbuf = 0x7C, nvme_admin_format_nvm = 0x80, nvme_admin_security_send = 0x81, @@ -1284,13 +1322,17 @@ enum nvme_feat { NVME_LBA_STATUS_INFO = 0x15, NVME_FEAT_HOST_BEHAVIOR = 0x16, NVME_FEAT_SANITIZE = 0x17, - NVME_FEAT_ENDURANCE = 0x18, + NVME_FEAT_ENDURANCE = 0x18, NVME_FEAT_IOCS_PROFILE = 0x19, NVME_FEAT_SW_PROGRESS = 0x80, NVME_FEAT_HOST_ID = 0x81, NVME_FEAT_RESV_MASK = 0x82, NVME_FEAT_RESV_PERSIST = 0x83, NVME_FEAT_WRITE_PROTECT = 0x84, + + NVME_MI_FEAT_CTRL_METADATA = 0x7E, + NVME_MI_FEAT_NS_METADATA = 0x7F, + } __attribute__ ((__packed__)); enum { @@ -1329,7 +1371,7 @@ enum { struct nvme_host_mem_buf_desc { __le64 addr; __le32 size; - __u32 rsvd; + __u8 rsvd[4]; }; /* Sanitize Log Page */ @@ -1392,7 +1434,7 @@ struct nvmf_disc_rsp_page_entry { __u8 prtype; __u8 cms; __u8 resv3[5]; - __u16 pkey; + __le16 pkey; __u8 resv10[246]; } rdma; struct tcp { @@ -1456,21 +1498,21 @@ struct nvme_error_log_page { struct nvme_firmware_log_page { __u8 afi; __u8 resv[7]; - __u64 frs[7]; + __u8 frs[7][8]; __u8 resv2[448]; }; struct nvme_host_mem_buffer { - __u32 hsize; - __u32 hmdlal; - __u32 hmdlau; - __u32 hmdlec; + __le32 hsize; + __le32 hmdlal; + __le32 hmdlau; + __le32 hmdlec; __u8 rsvd16[4080]; }; struct nvme_auto_pst { - __u32 data; - __u32 rsvd32; + __le32 data; + __u8 rsvd[4]; }; struct nvme_timestamp { @@ -1498,10 +1540,10 @@ struct nvme_primary_ctrl_caps { __u8 rsvd48[16]; __le32 vifrt; /* VI Resources Flexible Total */ __le32 virfa; /* VI Resources Flexible Assigned */ - __u16 virfap; /* VI Resources Flexible Allocated to Primary */ - __u16 viprt; /* VI Resources Private Total */ - __u16 vifrsm; /* VI Resources Flexible Secondary Maximum */ - __u16 vigran; /* VI Flexible Resource Preferred Granularity */ + __le16 virfap; /* VI Resources Flexible Allocated to Primary */ + __le16 viprt; /* VI Resources Private Total */ + __le16 vifrsm; /* VI Resources Flexible Secondary Maximum */ + __le16 vigran; /* VI Flexible Resource Preferred Granularity */ __u8 rsvd80[4016]; }; @@ -1523,10 +1565,10 @@ struct nvme_secondary_controllers_list { }; struct nvme_bar_cap { - __u16 mqes; + __le16 mqes; __u8 ams_cqr; __u8 to; - __u16 bps_css_nssrs_dstrd; + __le16 bps_css_nssrs_dstrd; __u8 mpsmax_mpsmin; __u8 rsvd_cmbs_pmrs; }; @@ -1595,10 +1637,14 @@ enum { NVME_SC_PREEMPT_ABORT = 0x1B, NVME_SC_SANITIZE_FAILED = 0x1C, NVME_SC_SANITIZE_IN_PROGRESS = 0x1D, + NVME_SC_SGL_DATA_BLK_GRAN_INVALID= 0x1e, + NVME_SC_CMD_NOT_SUP_QUEUE_IN_CMB = 0x1f, NVME_SC_NS_WRITE_PROTECTED = 0x20, NVME_SC_CMD_INTERRUPTED = 0x21, NVME_SC_TRANSIENT_TRANSPORT = 0x22, + NVME_SC_PROHIBITED_BY_CMD_AND_FEAT = 0x23, + NVME_SC_ADMIN_CMD_MEDIA_NOT_READY = 0x24, NVME_SC_LBA_RANGE = 0x80, NVME_SC_CAP_EXCEEDED = 0x81, @@ -1646,6 +1692,9 @@ enum { NVME_SC_PMR_SAN_PROHIBITED = 0x123, NVME_SC_ANA_INVALID_GROUP_ID= 0x124, NVME_SC_ANA_ATTACH_FAIL = 0x125, + NVME_SC_INSUFFICIENT_CAP = 0x126, + NVME_SC_NS_ATTACHMENT_LIMIT_EXCEEDED = 0x127, + NVME_SC_PROHIBIT_CMD_EXEC_NOT_SUPPORTED = 0x128, /* * Command Set Specific - Namespace Types commands: @@ -1654,6 +1703,7 @@ enum { NVME_SC_IOCS_NOT_ENABLED = 0x12A, NVME_SC_IOCS_COMBINATION_REJECTED = 0x12B, NVME_SC_INVALID_IOCS = 0x12C, + NVME_SC_ID_UNAVAILABLE = 0x12D, /* * I/O Command Set Specific - NVM commands: @@ -1698,6 +1748,7 @@ enum { NVME_SC_COMPARE_FAILED = 0x285, NVME_SC_ACCESS_DENIED = 0x286, NVME_SC_UNWRITTEN_BLOCK = 0x287, + NVME_SC_STORAGE_TAG_CHECK = 0x288, /* * Path-related Errors: @@ -1770,8 +1821,8 @@ struct nvme_id_ctrl_nvm { __u8 wzsl; __u8 wusl; __u8 dmrl; - __u32 dmrsl; - __u64 dmsl; + __le32 dmrsl; + __le64 dmsl; __u8 rsvd16[4080]; }; @@ -1874,4 +1925,20 @@ enum nvme_zns_report_options { NVME_ZNS_ZRAS_REPORT_READ_ONLY = 0x6, NVME_ZNS_ZRAS_REPORT_OFFLINE = 0x7, }; + +struct nvme_id_domain_attr_entry { + __le16 dom_id; + __u8 rsvd2[14]; + __u8 dom_cap[16]; + __u8 unalloc_dom_cap[16]; + __u8 max_egrp_dom_cap[16]; + __u8 rsvd64[64]; +}; + +struct nvme_id_domain_list { + __u8 num_entries; + __u8 rsvd1[127]; + struct nvme_id_domain_attr_entry domain_attr[]; +}; + #endif /* _LINUX_NVME_H */ diff --git a/linux/nvme_ioctl.h b/linux/nvme_ioctl.h index d569414..b4fd4e2 100644 --- a/linux/nvme_ioctl.h +++ b/linux/nvme_ioctl.h @@ -18,21 +18,6 @@ #include #include -struct nvme_user_io { - __u8 opcode; - __u8 flags; - __u16 control; - __u16 nblocks; - __u16 rsvd; - __u64 metadata; - __u64 addr; - __u64 slba; - __u32 dsmgmt; - __u32 reftag; - __u16 apptag; - __u16 appmask; -}; - struct nvme_passthru_cmd { __u8 opcode; __u8 flags; @@ -80,7 +65,6 @@ struct nvme_passthru_cmd64 { #define NVME_IOCTL_ID _IO('N', 0x40) #define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd) -#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io) #define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd) #define NVME_IOCTL_RESET _IO('N', 0x44) #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) diff --git a/nvme-builtin.h b/nvme-builtin.h index a413d00..8083941 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -21,6 +21,7 @@ COMMAND_LIST( ENTRY("id-nvmset", "Send NVMe Identify NVM Set List, display structure", id_nvmset) ENTRY("id-uuid", "Send NVMe Identify UUID List, display structure", id_uuid) ENTRY("id-iocs", "Send NVMe Identify I/O Command Set, display structure", id_iocs) + ENTRY("id-domain", "Send NVMe Identify Domain List, display structure", id_domain) ENTRY("create-ns", "Creates a namespace with the provided parameters", create_ns) ENTRY("delete-ns", "Deletes a namespace from the controller", delete_ns) ENTRY("attach-ns", "Attaches a namespace to requested controller(s)", attach_ns) @@ -55,6 +56,7 @@ COMMAND_LIST( ENTRY("security-send", "Submit a Security Send command, return results", sec_send) ENTRY("security-recv", "Submit a Security Receive command, return results", sec_recv) ENTRY("get-lba-status", "Submit a Get LBA Status command, return results", get_lba_status) + ENTRY("capacity-mgmt", "Submit Capacity Management Command, return results", capacity_mgmt) ENTRY("resv-acquire", "Submit a Reservation Acquire, return results", resv_acquire) ENTRY("resv-register", "Submit a Reservation Register, return results", resv_register) ENTRY("resv-release", "Submit a Reservation Release, return results", resv_release) diff --git a/nvme-ioctl.c b/nvme-ioctl.c index 2801075..c511808 100644 --- a/nvme-ioctl.c +++ b/nvme-ioctl.c @@ -68,7 +68,7 @@ int nvme_get_nsid(int fd) int err = fstat(fd, &nvme_stat); if (err < 0) - return -errno; + return err; return ioctl(fd, NVME_IOCTL_ID); } @@ -124,33 +124,37 @@ int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, return err; } -int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control, - __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data, - void *metadata) +int nvme_io(int fd, __u8 opcode, __u32 nsid, __u64 slba, __u16 nblocks, + __u16 control, __u32 dsmgmt, __u32 reftag, __u16 apptag, + __u16 appmask, __u64 storage_tag, void *data, void *metadata) { - struct nvme_user_io io = { + struct nvme_passthru_cmd cmd = { .opcode = opcode, - .flags = 0, - .control = control, - .nblocks = nblocks, - .rsvd = 0, + .nsid = nsid, .metadata = (__u64)(uintptr_t) metadata, .addr = (__u64)(uintptr_t) data, - .slba = slba, - .dsmgmt = dsmgmt, - .reftag = reftag, - .appmask = appmask, - .apptag = apptag, + .cdw2 = storage_tag & 0xffffffff, + .cdw3 = (storage_tag >> 32) & 0xffff, + .cdw10 = slba & 0xffffffff, + .cdw11 = slba >> 32, + .cdw12 = nblocks | (control << 16), + .cdw13 = dsmgmt, + .cdw14 = reftag, + .cdw15 = apptag | (appmask << 16), }; - return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io); + + return nvme_submit_io_passthru(fd, &cmd); } int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks, - __u16 control, __u32 reftag, __u16 apptag, __u16 appmask) + __u16 control, __u32 reftag, __u16 apptag, __u16 appmask, + __u64 storage_tag) { struct nvme_passthru_cmd cmd = { .opcode = nvme_cmd_verify, .nsid = nsid, + .cdw2 = storage_tag & 0xffffffff, + .cdw3 = (storage_tag >> 32) & 0xffff, .cdw10 = slba & 0xffffffff, .cdw11 = slba >> 32, .cdw12 = nblocks | (control << 16), @@ -174,11 +178,14 @@ int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd, } int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb, - __u16 control, __u32 reftag, __u16 apptag, __u16 appmask) + __u16 control, __u32 reftag, __u16 apptag, __u16 appmask, + __u64 storage_tag) { struct nvme_passthru_cmd cmd = { .opcode = nvme_cmd_write_zeroes, .nsid = nsid, + .cdw2 = storage_tag & 0xffffffff, + .cdw3 = (storage_tag >> 32) & 0xffff, .cdw10 = slba & 0xffffffff, .cdw11 = slba >> 32, .cdw12 = nlb | (control << 16), @@ -401,11 +408,6 @@ int nvme_identify_ns_list_csi(int fd, __u32 nsid, __u8 csi, bool all, void *data return nvme_identify13(fd, nsid, cns, csi << 24, data); } -int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data) -{ - return nvme_identify_ns_list_csi(fd, nsid, 0x0, all, data); -} - int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data) { int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST; @@ -464,12 +466,19 @@ int nvme_identify_iocs(int fd, __u16 cntid, void *data) return nvme_identify(fd, 0, (cntid << 16) | NVME_ID_CNS_CSI, data); } +int nvme_identify_domain_list(int fd, __u16 dom_id, void *data) +{ + return nvme_identify13(fd, 0, NVME_ID_CNS_DOMAIN_LIST, dom_id, data); +} + int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, - __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data) + __u16 lsi, bool rae, __u8 uuid_ix, __u8 csi, bool ot, + __u32 data_len, void *data) { __u32 numd = (data_len >> 2) - 1; __u16 numdu = numd >> 16, numdl = numd & 0xffff; __u32 cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0) | lsp << 8; + __u32 cdw14 = uuid_ix | (ot ? 1 << 23 : 0) | csi << 24; struct nvme_admin_cmd cmd = { .opcode = nvme_admin_get_log_page, @@ -480,7 +489,7 @@ int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, .cdw11 = numdu | (lsi << 16), .cdw12 = lpo & 0xffffffff, .cdw13 = lpo >> 32, - .cdw14 = uuid_ix, + .cdw14 = cdw14, }; return nvme_submit_admin_passthru(fd, &cmd); @@ -491,7 +500,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, void *data) { return nvme_get_log14(fd, nsid, log_id, lsp, lpo, lsi, rae, 0, - data_len, data); + 0, false, data_len, data); } int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae, @@ -646,7 +655,7 @@ int nvme_resv_notif_log(int fd, struct nvme_resv_notif_log *resv) } int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11, - __u32 cdw12, __u32 data_len, void *data, __u32 *result) + __u32 cdw12, __u32 cdw14, __u32 data_len, void *data, __u32 *result) { struct nvme_admin_cmd cmd = { .opcode = opcode, @@ -654,6 +663,7 @@ int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11, .cdw10 = cdw10, .cdw11 = cdw11, .cdw12 = cdw12, + .cdw14 = cdw14, .addr = (__u64)(uintptr_t) data, .data_len = data_len, }; @@ -666,12 +676,13 @@ int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11, } int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12, - bool save, __u32 data_len, void *data, __u32 *result) + bool save, __u8 uuid_index, __u32 data_len, void *data, __u32 *result) { __u32 cdw10 = fid | (save ? 1 << 31 : 0); + __u32 cdw14 = uuid_index; return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value, - cdw12, data_len, data, result); + cdw12, cdw14, data_len, data, result); } @@ -740,18 +751,23 @@ int nvme_set_property(int fd, int offset, uint64_t value) } int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11, - __u32 data_len, void *data, __u32 *result) + __u8 uuid_index, __u32 data_len, void *data, __u32 *result) { __u32 cdw10 = fid | sel << 8; + __u32 cdw14 = uuid_index; return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11, - 0, data_len, data, result); + 0, cdw14, data_len, data, result); } int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi, __u8 pil, __u8 ms, __u32 timeout) { - __u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9; + __u8 lbafl = lbaf & 0xf; + __u8 lbafu = (lbaf >> 4) & 0x3; + __u32 cdw10 = lbafl | ms << 4 | pi << 5 | pil << 8 | ses << 9 | + lbafu << 12; + struct nvme_admin_cmd cmd = { .opcode = nvme_admin_format_nvm, .nsid = nsid, @@ -839,18 +855,23 @@ int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data) return nvme_submit_admin_passthru(fd, &cmd); } -int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid) +int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid, __u32 *result) { + int err; + struct nvme_admin_cmd cmd = { .opcode = nvme_admin_activate_fw, .cdw10 = (bpid << 31) | (action << 3) | slot, }; - return nvme_submit_admin_passthru(fd, &cmd); + err = nvme_submit_admin_passthru(fd, &cmd); + if (!err && result) + *result = cmd.result; + return err; } int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp, - __u8 secp, __u32 tl, __u32 data_len, void *data) + __u8 secp, __u32 data_len, void *data) { struct nvme_admin_cmd cmd = { .opcode = nvme_admin_security_send, @@ -858,7 +879,7 @@ int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp, .data_len = data_len, .nsid = nsid, .cdw10 = secp << 24 | spsp << 8 | nssf, - .cdw11 = tl, + .cdw11 = data_len, }; return nvme_submit_admin_passthru(fd, &cmd); @@ -900,41 +921,60 @@ int nvme_get_lba_status(int fd, __u32 namespace_id, __u64 slba, __u32 mndw, int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, __u32 data_len, __u32 dw12, void *data, __u32 *result) { - struct nvme_admin_cmd cmd = { - .opcode = nvme_admin_directive_send, - .addr = (__u64)(uintptr_t) data, - .data_len = data_len, - .nsid = nsid, - .cdw10 = data_len? (data_len >> 2) - 1 : 0, - .cdw11 = dspec << 16 | dtype << 8 | doper, - .cdw12 = dw12, - }; - int err; + struct nvme_admin_cmd cmd = { + .opcode = nvme_admin_directive_send, + .addr = (__u64)(uintptr_t) data, + .data_len = data_len, + .nsid = nsid, + .cdw10 = data_len? (data_len >> 2) - 1 : 0, + .cdw11 = dspec << 16 | dtype << 8 | doper, + .cdw12 = dw12, + }; + int err; - err = nvme_submit_admin_passthru(fd, &cmd); - if (!err && result) - *result = cmd.result; - return err; + err = nvme_submit_admin_passthru(fd, &cmd); + if (!err && result) + *result = cmd.result; + return err; } int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, __u32 data_len, __u32 dw12, void *data, __u32 *result) { - struct nvme_admin_cmd cmd = { - .opcode = nvme_admin_directive_recv, - .addr = (__u64)(uintptr_t) data, - .data_len = data_len, - .nsid = nsid, - .cdw10 = data_len? (data_len >> 2) - 1 : 0, - .cdw11 = dspec << 16 | dtype << 8 | doper, - .cdw12 = dw12, - }; - int err; + struct nvme_admin_cmd cmd = { + .opcode = nvme_admin_directive_recv, + .addr = (__u64)(uintptr_t) data, + .data_len = data_len, + .nsid = nsid, + .cdw10 = data_len? (data_len >> 2) - 1 : 0, + .cdw11 = dspec << 16 | dtype << 8 | doper, + .cdw12 = dw12, + }; + int err; - err = nvme_submit_admin_passthru(fd, &cmd); - if (!err && result) - *result = cmd.result; - return err; + err = nvme_submit_admin_passthru(fd, &cmd); + if (!err && result) + *result = cmd.result; + return err; +} + +int nvme_cap_mgmt(int fd, __u8 op, __u16 element_id, __u32 dw11, + __u32 dw12, __u32 *result) +{ + int err; + __u32 dw10 = op | element_id << 16; + + struct nvme_admin_cmd cmd = { + .opcode = nvme_admin_capacity_mgmt, + .cdw10 = dw10, + .cdw11 = dw11, + .cdw12 = dw12, + }; + + err = nvme_submit_admin_passthru(fd, &cmd); + if (!err && result) + *result = cmd.result; + return err; } int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp, @@ -979,7 +1019,7 @@ int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result) } int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all, - enum nvme_zns_send_action zsa, __u32 data_len, + __u32 timeout, enum nvme_zns_send_action zsa, __u32 data_len, void *data) { __u32 cdw10 = slba & 0xffffffff; @@ -994,6 +1034,7 @@ int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all, .cdw13 = cdw13, .addr = (__u64)(uintptr_t)data, .data_len = data_len, + .timeout_ms = timeout, }; return nvme_submit_io_passthru(fd, &cmd); diff --git a/nvme-ioctl.h b/nvme-ioctl.h index b0184c7..2e24b83 100644 --- a/nvme-ioctl.h +++ b/nvme-ioctl.h @@ -25,9 +25,9 @@ int nvme_passthru(int fd, unsigned long ioctl_cmd, __u8 opcode, __u8 flags, /* NVME_SUBMIT_IO */ -int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control, - __u32 dsmgmt, __u32 reftag, __u16 apptag, - __u16 appmask, void *data, void *metadata); +int nvme_io(int fd, __u8 opcode, __u32 nsid, __u64 slba, __u16 nblocks, + __u16 control, __u32 dsmgmt, __u32 reftag, __u16 apptag, + __u16 appmask, __u64 storage_tag, void *data, void *metadata); /* NVME_IO_CMD */ int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd, @@ -38,12 +38,14 @@ int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd, void *metadata, __u32 timeout); int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb, - __u16 control, __u32 reftag, __u16 apptag, __u16 appmask); + __u16 control, __u32 reftag, __u16 apptag, __u16 appmask, + __u64 storage_tag); int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb); int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks, - __u16 control, __u32 reftag, __u16 apptag, __u16 appmask); + __u16 control, __u32 reftag, __u16 apptag, __u16 appmask, + __u64 storage_tag); int nvme_flush(int fd, __u32 nsid); @@ -73,7 +75,6 @@ int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data); int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data); int nvme_identify_ctrl(int fd, void *data); int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data); -int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data); int nvme_identify_ns_list_csi(int fd, __u32 nsid, __u8 csi, bool all, void *data); int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data); int nvme_identify_ns_descs(int fd, __u32 nsid, void *data); @@ -86,10 +87,11 @@ int nvme_identify_ctrl_nvm(int fd, void *data); int nvme_zns_identify_ctrl(int fd, void *data); int nvme_zns_identify_ns(int fd, __u32 nsid, void *data); int nvme_identify_iocs(int fd, __u16 cntid, void *data); +int nvme_identify_domain_list(int fd, __u16 dom_id, void *data); int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae, __u8 lsp, __u32 data_len, void *data); int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, - __u16 group_id, bool rae, __u8 uuid_ix, + __u16 group_id, bool rae, __u8 uuid_ix, __u8 csi, bool ot, __u32 data_len, void *data); int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, __u16 lsi, bool rae, __u32 data_len, @@ -119,12 +121,12 @@ int nvme_lba_status_log(int fd, void *lba_status, bool rae, __u32 size); int nvme_resv_notif_log(int fd, struct nvme_resv_notif_log *resv); int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, - __u32 cdw11, __u32 cdw12, __u32 data_len, void *data, + __u32 cdw11, __u32 cdw12, __u32 cdw14, __u32 data_len, void *data, __u32 *result); int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12, - bool save, __u32 data_len, void *data, __u32 *result); + bool save, __u8 uuid_index, __u32 data_len, void *data, __u32 *result); int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, - __u32 cdw11, __u32 data_len, void *data, __u32 *result); + __u32 cdw11, __u8 uuid_index, __u32 data_len, void *data, __u32 *result); int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi, __u8 pil, __u8 ms, __u32 timeout); @@ -138,10 +140,10 @@ int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist, bool attach); int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data); -int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid); +int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid, __u32 *result); int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp, - __u8 secp, __u32 tl, __u32 data_len, void *data); + __u8 secp, __u32 data_len, void *data); int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp, __u8 secp, __u32 al, __u32 data_len, void *data); @@ -155,6 +157,8 @@ int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, __u32 data_len, __u32 dw12, void *data, __u32 *result); int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper, __u32 data_len, __u32 dw12, void *data, __u32 *result); +int nvme_cap_mgmt(int fd, __u8 op, __u16 element_id, __u32 dw11, + __u32 dw12, __u32 *result); int nvme_get_properties(int fd, void **pbar); int nvme_set_property(int fd, int offset, uint64_t value); int nvme_get_property(int fd, int offset, uint64_t *value); @@ -165,7 +169,7 @@ int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_ int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result); int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all, - enum nvme_zns_send_action zsa, __u32 data_len, + __u32 timeout, enum nvme_zns_send_action zsa, __u32 data_len, void *data); int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba, enum nvme_zns_recv_action zra, __u8 zrasf, diff --git a/nvme-print.c b/nvme-print.c index b01a842..1d2fb0c 100755 --- a/nvme-print.c +++ b/nvme-print.c @@ -11,6 +11,13 @@ #include "util/suffix.h" #include "common.h" +#define ABSOLUTE_ZERO_CELSIUS -273 + +static inline long kelvin_to_celsius(long t) +{ + return t + ABSOLUTE_ZERO_CELSIUS; +} + static const uint8_t zero_uuid[16] = { 0 }; static const uint8_t invalid_uuid[16] = {[0 ... 15] = 0xff }; static const char dash[100] = {[0 ... 99] = '-'}; @@ -97,16 +104,12 @@ const char *nvme_cmd_to_string(int admin, __u8 opcode) return "Unknown"; } -static const char *fw_to_string(__u64 fw) +static char *fw_to_string(__u8 fw[]) { - static char ret[9]; - char *c = (char *)&fw; - int i; + static char frs[9]; - for (i = 0; i < 8; i++) - ret[i] = c[i] >= '!' && c[i] <= '~' ? c[i] : '.'; - ret[i] = '\0'; - return ret; + snprintf(frs, sizeof(frs), "%-.*s", 8, fw); + return frs; } static const char *get_sanitize_log_sstat_status_str(__u16 status) @@ -216,6 +219,8 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, long double tnvmcap = int128_to_double(ctrl->tnvmcap); long double unvmcap = int128_to_double(ctrl->unvmcap); + long double megcap = int128_to_double(ctrl->megcap); + long double maxdna = int128_to_double(ctrl->maxdna); char sn[sizeof(ctrl->sn) + 1], mn[sizeof(ctrl->mn) + 1], fr[sizeof(ctrl->fr) + 1], subnqn[sizeof(ctrl->subnqn) + 1]; @@ -249,6 +254,9 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, json_object_add_value_int(root, "crdt1", le16_to_cpu(ctrl->crdt1)); json_object_add_value_int(root, "crdt2", le16_to_cpu(ctrl->crdt2)); json_object_add_value_int(root, "crdt3", le16_to_cpu(ctrl->crdt3)); + json_object_add_value_int(root, "nvmsr", ctrl->nvmsr); + json_object_add_value_int(root, "vwci", ctrl->vwci); + json_object_add_value_int(root, "mec", ctrl->mec); json_object_add_value_int(root, "oacs", le16_to_cpu(ctrl->oacs)); json_object_add_value_int(root, "acl", ctrl->acl); json_object_add_value_int(root, "aerl", ctrl->aerl); @@ -285,6 +293,8 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, le32_to_cpu(ctrl->anagrpmax)); json_object_add_value_int(root, "nanagrpid", le32_to_cpu(ctrl->nanagrpid)); + json_object_add_value_int(root, "domainid", le16_to_cpu(ctrl->domainid)); + json_object_add_value_float(root, "megcap", megcap); json_object_add_value_int(root, "sqes", ctrl->sqes); json_object_add_value_int(root, "cqes", ctrl->cqes); json_object_add_value_int(root, "maxcmd", le16_to_cpu(ctrl->maxcmd)); @@ -298,7 +308,10 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, json_object_add_value_int(root, "icsvscc", ctrl->icsvscc); json_object_add_value_int(root, "nwpc", ctrl->nwpc); json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu)); + json_object_add_value_int(root, "ocfs", le16_to_cpu(ctrl->ocfs)); json_object_add_value_int(root, "sgls", le32_to_cpu(ctrl->sgls)); + json_object_add_value_float(root, "maxdna", maxdna); + json_object_add_value_int(root, "maxcna", le32_to_cpu(ctrl->maxcna)); if (strlen(subnqn)) json_object_add_value_string(root, "subnqn", subnqn); @@ -471,27 +484,26 @@ static void json_nvme_resv_report(struct nvme_reservation_status *status, static void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname) { + int i; struct json_object *root; struct json_object *fwsi; char fmt[21]; - char str[32]; - int i; root = json_create_object(); fwsi = json_create_object(); json_object_add_value_int(fwsi, "Active Firmware Slot (afi)", fw_log->afi); + for (i = 0; i < 7; i++) { - if (fw_log->frs[i]) { + if (strcmp(fw_to_string(fw_log->frs[i]), "\0")) { snprintf(fmt, sizeof(fmt), "Firmware Rev Slot %d", i + 1); - snprintf(str, sizeof(str), "%"PRIu64" (%s)", - (uint64_t)fw_log->frs[i], - fw_to_string(fw_log->frs[i])); - json_object_add_value_string(fwsi, fmt, str); + json_object_add_value_string(fwsi, fmt, + fw_to_string(fw_log->frs[i])); } } + json_object_add_value_object(root, devname, fwsi); json_print_object(root, NULL); @@ -1882,6 +1894,9 @@ static void nvme_show_registers_cap(struct nvme_bar_cap *cap) (cap->bps_css_nssrs_dstrd & 0x0020) ? "Supported" : "Not Supported"); printf("\t One or more I/O Command Sets are %s\n", (cap->bps_css_nssrs_dstrd & 0x0800) ? "Supported" : "Not Supported"); + printf("\t %s\n", + (cap->bps_css_nssrs_dstrd & 0x1000) ? "Only Admin Command Set Supported" : + "I/O Command Set is Supported"); printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", (cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No"); printf("\tDoorbell Stride (DSTRD): %u bytes\n", @@ -2089,11 +2104,6 @@ static void nvme_show_registers_bpinfo_brs(__u8 brs) static void nvme_show_registers_bpinfo(__u32 bpinfo) { - if (bpinfo == 0) { - printf("\tBoot Partition feature is not supported\n\n"); - return; - } - printf("\tActive Boot Partition ID (ABPID): %u\n", (bpinfo & 0x80000000) >> 31); nvme_show_registers_bpinfo_brs((bpinfo & 0x03000000) >> 24); @@ -2103,11 +2113,6 @@ static void nvme_show_registers_bpinfo(__u32 bpinfo) static void nvme_show_registers_bprsel(__u32 bprsel) { - if (bprsel == 0) { - printf("\tBoot Partition feature is not supported\n\n"); - return; - } - printf("\tBoot Partition Identifier (BPID): %u\n", (bprsel & 0x80000000) >> 31); printf("\tBoot Partition Read Offset (BPROF): %x\n", @@ -2118,10 +2123,6 @@ static void nvme_show_registers_bprsel(__u32 bprsel) static void nvme_show_registers_bpmbl(uint64_t bpmbl) { - if (bpmbl == 0) { - printf("\tBoot Partition feature is not supported\n\n"); - return; - } printf("\tBoot Partition Memory Buffer Base Address (BMBBA): %"PRIx64"\n", bpmbl); @@ -2714,46 +2715,61 @@ static void nvme_show_id_ctrl_cmic(__u8 cmic) static void nvme_show_id_ctrl_oaes(__le32 ctrl_oaes) { __u32 oaes = le32_to_cpu(ctrl_oaes); - __u32 rsvd0 = (oaes & 0xF0000000) >> 28; + __u32 disc = (oaes >> 31) & 0x1; + __u32 rsvd0 = (oaes & 0x70000000) >> 28; __u32 zicn = (oaes & 0x08000000) >> 27; - __u32 rsvd1 = (oaes & 0x07FF8000) >> 15; - __u32 nace = (oaes & 0x100) >> 8; - __u32 fan = (oaes & 0x200) >> 9; - __u32 anacn = (oaes & 0x800) >> 11; - __u32 plealcn = (oaes & 0x1000) >> 12; - __u32 lbasin = (oaes & 0x2000) >> 13; + __u32 rsvd1 = (oaes & 0x07FF0000) >> 16; + __u32 normal_shn = (oaes >> 15) & 0x1; __u32 egealpcn = (oaes & 0x4000) >> 14; - __u32 rsvd2 = oaes & 0xFF; + __u32 lbasin = (oaes & 0x2000) >> 13; + __u32 plealcn = (oaes & 0x1000) >> 12; + __u32 anacn = (oaes & 0x800) >> 11; + __u32 rsvd2 = (oaes >> 10) & 0x1; + __u32 fan = (oaes & 0x200) >> 9; + __u32 nace = (oaes & 0x100) >> 8; + __u32 rsvd3 = oaes & 0xFF; + printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n", + disc, disc ? "" : "Not "); if (rsvd0) - printf(" [31:28] : %#x\tReserved\n", rsvd0); - printf("[27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", + printf(" [30:28] : %#x\tReserved\n", rsvd0); + printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n", zicn, zicn ? "" : "Not "); if (rsvd1) - printf(" [26:15] : %#x\tReserved\n", rsvd1); - printf("[14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ + printf(" [26:16] : %#x\tReserved\n", rsvd1); + printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n", + normal_shn, normal_shn ? "" : "Not "); + printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page"\ " Change Notice %sSupported\n", egealpcn, egealpcn ? "" : "Not "); - printf("[13:13] : %#x\tLBA Status Information Notices %sSupported\n", + printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n", lbasin, lbasin ? "" : "Not "); - printf("[12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\ + printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\ " Notices %sSupported\n", plealcn, plealcn ? "" : "Not "); - printf("[11:11] : %#x\tAsymmetric Namespace Access Change Notices"\ + printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices"\ " %sSupported\n", anacn, anacn ? "" : "Not "); + if (rsvd2) + printf(" [10:10] : %#x\tReserved\n", rsvd2); printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n", fan, fan ? "" : "Not "); printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n", nace, nace ? "" : "Not "); - if (rsvd2) - printf(" [7:0] : %#x\tReserved\n", rsvd1); + if (rsvd3) + printf(" [7:0] : %#x\tReserved\n", rsvd3); printf("\n"); } static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt) { __u32 ctratt = le32_to_cpu(ctrl_ctratt); - __u32 rsvd = ctratt >> 10; + __u32 rsvd = ctratt >> 16; + __u32 elbas = (ctratt >> 15) & 0x1; + __u32 delnvmset = (ctratt >> 14) & 0x1; + __u32 delegrp = (ctratt >> 13) & 0x1; + __u32 vcap = (ctratt >> 12) & 0x1; + __u32 fcap = (ctratt >> 11) & 0x1; + __u32 mds = (ctratt >> 10) & 0x1; __u32 hostid128 = (ctratt & NVME_CTRL_CTRATT_128_ID) >> 0; __u32 psp = (ctratt & NVME_CTRL_CTRATT_NON_OP_PSP) >> 1; __u32 sets = (ctratt & NVME_CTRL_CTRATT_NVM_SETS) >> 2; @@ -2766,8 +2782,19 @@ static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt) __u32 rsvd8 = (ctratt & 0x00000100) >> 8; if (rsvd) - printf(" [31:10] : %#x\tReserved\n", rsvd); - + printf(" [31:16] : %#x\tReserved\n", rsvd); + printf(" [15:15] : %#x\tExtended LBA Formats %sSupported\n", + elbas, elbas ? "" : "Not "); + printf(" [14:14] : %#x\tDelete NVM Set %sSupported\n", + delnvmset, delnvmset ? "" : "Not "); + printf(" [13:13] : %#x\tDelete Endurance Group %sSupported\n", + delegrp, delegrp ? "" : "Not "); + printf(" [12:12] : %#x\tVariable Capacity Management %sSupported\n", + vcap, vcap ? "" : "Not "); + printf(" [11:11] : %#x\tFixed Capacity Management %sSupported\n", + fcap, fcap ? "" : "Not "); + printf(" [10:10] : %#x\tMulti Domain Subsystem %sSupported\n", + mds, mds ? "" : "Not "); printf(" [9:9] : %#x\tUUID List %sSupported\n", uuidlist, uuidlist ? "" : "Not "); if (rsvd8) @@ -2807,10 +2834,54 @@ static void nvme_show_id_ctrl_cntrltype(__u8 cntrltype) printf(" [1:0] : %#x\t%s\n", cntrltype, type[cntrl]); } +static void nvme_show_id_ctrl_nvmsr(__u8 nvmsr) +{ + __u8 rsvd = (nvmsr >> 2) & 0xfc; + __u8 nvmee = (nvmsr >> 1) & 0x1; + __u8 nvmesd = nvmsr & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tNVM subsystem %spart of an Enclosure\n", + nvmee, nvmee ? "" : "Not "); + printf(" [0:0] : %#x\tNVM subsystem %spart of an Storage Device\n", + nvmesd, nvmesd ? "" : "Not "); + printf("\n"); +} + +static void nvme_show_id_ctrl_vwci(__u8 vwci) +{ + __u8 vwcrv = (vwci >> 7) & 0x1; + __u8 vwcr = vwci & 0xfe; + + printf(" [7:7] : %#x\tVPD Write Cycles Remaining field is %svalid.\n", + vwcrv, vwcrv ? "" : "Not "); + printf(" [6:0] : %#x\tVPD Write Cycles Remaining \n", vwcr); + printf("\n"); + +} + +static void nvme_show_id_ctrl_mec(__u8 mec) +{ + __u8 rsvd = (mec >> 2) & 0xfc; + __u8 pcieme = (mec >> 1) & 0x1; + __u8 smbusme = mec & 0x1; + + if (rsvd) + printf(" [7:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint"\ + " on a PCIe port\n", pcieme, pcieme ? "" : "Not "); + printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint"\ + " on an SMBus/I2C port\n", smbusme, smbusme ? "" : "Not "); + printf("\n"); + +} + static void nvme_show_id_ctrl_oacs(__le16 ctrl_oacs) { __u16 oacs = le16_to_cpu(ctrl_oacs); - __u16 rsvd = (oacs & 0xFC00) >> 10; + __u16 rsvd = (oacs & 0xF800) >> 11; + __u16 lock = (oacs >> 10) & 0x1; __u16 glbas = (oacs & 0x200) >> 9; __u16 dbc = (oacs & 0x100) >> 8; __u16 vir = (oacs & 0x80) >> 7; @@ -2823,7 +2894,9 @@ static void nvme_show_id_ctrl_oacs(__le16 ctrl_oacs) __u16 sec = oacs & 0x1; if (rsvd) - printf(" [15:9] : %#x\tReserved\n", rsvd); + printf(" [15:11] : %#x\tReserved\n", rsvd); + printf(" [10:10] : %#x\tLockdown Command and Feature %sSupported\n", + lock, lock ? "" : "Not "); printf(" [9:9] : %#x\tGet LBA Status Capability %sSupported\n", glbas, glbas ? "" : "Not "); printf(" [8:8] : %#x\tDoorbell Buffer Config %sSupported\n", @@ -2849,13 +2922,16 @@ static void nvme_show_id_ctrl_oacs(__le16 ctrl_oacs) static void nvme_show_id_ctrl_frmw(__u8 frmw) { - __u8 rsvd = (frmw & 0xE0) >> 5; + __u8 rsvd = (frmw & 0xC0) >> 6; + __u8 smud = (frmw >> 5) & 0x1; __u8 fawr = (frmw & 0x10) >> 4; __u8 nfws = (frmw & 0xE) >> 1; __u8 s1ro = frmw & 0x1; if (rsvd) - printf(" [7:5] : %#x\tReserved\n", rsvd); + printf(" [7:6] : %#x\tReserved\n", rsvd); + printf(" [5:5] : %#x\tMultiple FW or Boot Update Detection %sSupported\n", + smud, smud ? "" : "Not "); printf(" [4:4] : %#x\tFirmware Activate Without Reset %sSupported\n", fawr, fawr ? "" : "Not "); printf(" [3:1] : %#x\tNumber of Firmware Slots\n", nfws); @@ -2866,7 +2942,9 @@ static void nvme_show_id_ctrl_frmw(__u8 frmw) static void nvme_show_id_ctrl_lpa(__u8 lpa) { - __u8 rsvd = (lpa & 0xE0) >> 5; + __u8 rsvd = (lpa & 0x80) >> 7; + __u8 tel = (lpa >> 6) & 0x1; + __u8 lid_sup = (lpa >> 5) & 0x1; __u8 persevnt = (lpa & 0x10) >> 4; __u8 telem = (lpa & 0x8) >> 3; __u8 ed = (lpa & 0x4) >> 2; @@ -2874,7 +2952,11 @@ static void nvme_show_id_ctrl_lpa(__u8 lpa) __u8 smlp = lpa & 0x1; if (rsvd) - printf(" [7:4] : %#x\tReserved\n", rsvd); + printf(" [7:7] : %#x\tReserved\n", rsvd); + printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n", + tel, tel ? "" : "Not "); + printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, "\ + "0x12, 0x13 %sSupported\n", lid_sup, lid_sup ? "" : "Not "); printf(" [4:4] : %#x\tPersistent Event log %sSupported\n", persevnt, persevnt ? "" : "Not "); printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n", @@ -2910,6 +2992,20 @@ static void nvme_show_id_ctrl_apsta(__u8 apsta) printf("\n"); } +static void nvme_show_id_ctrl_wctemp(__le16 wctemp) +{ + printf(" [16:0] : %ld C (%u Kelvin)\tWarning temperature (WCTEMP)\n", + kelvin_to_celsius(le16_to_cpu(wctemp)), le16_to_cpu(wctemp)); + printf("\n"); +} + +static void nvme_show_id_ctrl_cctemp(__le16 cctemp) +{ + printf(" [16:0] : %ld C (%u Kelvin)\tCritical temperature (CCTEMP)\n", + kelvin_to_celsius(le16_to_cpu(cctemp)), le16_to_cpu(cctemp)); + printf("\n"); +} + void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs) { __u32 rpmbs = le32_to_cpu(ctrl_rpmbs); @@ -3072,12 +3168,15 @@ static void nvme_show_id_ctrl_fuses(__le16 ctrl_fuses) static void nvme_show_id_ctrl_fna(__u8 fna) { - __u8 rsvd = (fna & 0xF8) >> 3; + __u8 rsvd = (fna & 0xF0) >> 4; + __u8 bcnsid = (fna & 0x8) >> 3; __u8 cese = (fna & 0x4) >> 2; __u8 cens = (fna & 0x2) >> 1; __u8 fmns = fna & 0x1; if (rsvd) - printf(" [7:3] : %#x\tReserved\n", rsvd); + printf(" [7:4] : %#x\tReserved\n", rsvd); + printf(" [3:3] : %#x\tFormatNVM Broadcast NSID (FFFFFFFFh) %sSupported\n", + bcnsid, bcnsid ? "Not " : ""); printf(" [2:2] : %#x\tCrypto Erase %sSupported as part of Secure Erase\n", cese, cese ? "" : "Not "); printf(" [1:1] : %#x\tCrypto Erase Applies to %s Namespace(s)\n", @@ -3138,6 +3237,21 @@ static void nvme_show_id_ctrl_nwpc(__u8 nwpc) printf("\n"); } +static void nvme_show_id_ctrl_ocfs(__le16 ctrl_ocfs) +{ + __u16 ocfs = le16_to_cpu(ctrl_ocfs); + __u16 rsvd = (ocfs & 0xfffc) >> 2; + __u8 copy_fmt_1 = (ocfs >> 1) & 0x1; + __u8 copy_fmt_0 = ocfs & 0x1; + if (rsvd) + printf(" [15:2] : %#x\tReserved\n", rsvd); + printf(" [1:1] : %#x\tController Copy Format 1h %sSupported\n", + copy_fmt_1, copy_fmt_1 ? "" : "Not "); + printf(" [0:0] : %#x\tController Copy Format 0h %sSupported\n", + copy_fmt_0, copy_fmt_0 ? "" : "Not "); + printf("\n"); +} + static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls) { __u32 sgls = le32_to_cpu(ctrl_sgls); @@ -3148,7 +3262,8 @@ static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls) __u32 sglltb = (sgls & 0x40000) >> 18; __u32 bacmdb = (sgls & 0x20000) >> 17; __u32 bbs = (sgls & 0x10000) >> 16; - __u32 rsvd1 = (sgls & 0xFFF8) >> 3; + __u32 sdt = (sgls >> 8) & 0xff; + __u32 rsvd1 = (sgls & 0xF8) >> 3; __u32 key = (sgls & 0x4) >> 2; __u32 sglsp = sgls & 0x3; @@ -3173,8 +3288,9 @@ static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls) if (sglsp || (!sglsp && bbs)) printf(" [16:16]: %#x\tSGL Bit-Bucket %sSupported\n", bbs, bbs ? "" : "Not "); + printf(" [15:8] : %#x\tSGL Descriptor Threshold\n", sdt); if (rsvd1) - printf(" [15:3] : %#x\tReserved\n", rsvd1); + printf(" [7:3] : %#x\tReserved\n", rsvd1); if (sglsp || (!sglsp && key)) printf(" [2:2] : %#x\tKeyed SGL Data Block descriptor %sSupported\n", key, key ? "" : "Not "); @@ -3702,7 +3818,7 @@ static void nvme_show_id_ctrl_power(struct nvme_id_ctrl *ctrl) void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, void (*vendor_show)(__u8 *vs, struct json_object *root)) { - int human = flags & VERBOSE, vs = flags & VS; + bool human = flags & VERBOSE, vs = flags & VS; if (flags & BINARY) return d_raw((unsigned char *)ctrl, sizeof(*ctrl)); @@ -3740,6 +3856,15 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, printf("crdt1 : %u\n", le16_to_cpu(ctrl->crdt1)); printf("crdt2 : %u\n", le16_to_cpu(ctrl->crdt2)); printf("crdt3 : %u\n", le16_to_cpu(ctrl->crdt3)); + printf("nvmsr : %u\n", ctrl->nvmsr); + if (human) + nvme_show_id_ctrl_nvmsr(ctrl->nvmsr); + printf("vwci : %u\n", ctrl->vwci); + if (human) + nvme_show_id_ctrl_vwci(ctrl->vwci); + printf("mec : %u\n", ctrl->mec); + if (human) + nvme_show_id_ctrl_mec(ctrl->vwci); printf("oacs : %#x\n", le16_to_cpu(ctrl->oacs)); if (human) @@ -3761,7 +3886,11 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, if (human) nvme_show_id_ctrl_apsta(ctrl->apsta); printf("wctemp : %d\n", le16_to_cpu(ctrl->wctemp)); + if (human) + nvme_show_id_ctrl_wctemp(ctrl->wctemp); printf("cctemp : %d\n", le16_to_cpu(ctrl->cctemp)); + if (human) + nvme_show_id_ctrl_cctemp(ctrl->cctemp); printf("mtfa : %d\n", le16_to_cpu(ctrl->mtfa)); printf("hmpre : %d\n", le32_to_cpu(ctrl->hmpre)); printf("hmmin : %d\n", le32_to_cpu(ctrl->hmmin)); @@ -3793,6 +3922,8 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, printf("anagrpmax : %d\n", ctrl->anagrpmax); printf("nanagrpid : %d\n", le32_to_cpu(ctrl->nanagrpid)); printf("pels : %d\n", le32_to_cpu(ctrl->pels)); + printf("domainid : %d\n", le16_to_cpu(ctrl->domainid)); + printf("megcap : %.0Lf\n", int128_to_double(ctrl->megcap)); printf("sqes : %#x\n", ctrl->sqes); if (human) nvme_show_id_ctrl_sqes(ctrl->sqes); @@ -3822,10 +3953,15 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags, if (human) nvme_show_id_ctrl_nwpc(ctrl->nwpc); printf("acwu : %d\n", le16_to_cpu(ctrl->acwu)); + printf("ocfs : %#x\n", le16_to_cpu(ctrl->ocfs)); + if (human) + nvme_show_id_ctrl_ocfs(ctrl->ocfs); printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls)); if (human) nvme_show_id_ctrl_sgls(ctrl->sgls); printf("mnan : %d\n", le32_to_cpu(ctrl->mnan)); + printf("maxdna : %.0Lf\n", int128_to_double(ctrl->maxdna)); + printf("maxcna : %d\n", le32_to_cpu(ctrl->maxcna)); printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn); printf("ioccsz : %d\n", le32_to_cpu(ctrl->ioccsz)); printf("iorcsz : %d\n", le32_to_cpu(ctrl->iorcsz)); @@ -3861,8 +3997,8 @@ static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm) json_object_add_value_uint(root, "wzsl", ctrl_nvm->wzsl); json_object_add_value_uint(root, "wusl", ctrl_nvm->wusl); json_object_add_value_uint(root, "dmrl", ctrl_nvm->dmrl); - json_object_add_value_uint(root, "dmrsl", ctrl_nvm->dmrsl); - json_object_add_value_uint(root, "dmsl", ctrl_nvm->dmsl); + json_object_add_value_uint(root, "dmrsl", le32_to_cpu(ctrl_nvm->dmrsl)); + json_object_add_value_uint(root, "dmsl", le64_to_cpu(ctrl_nvm->dmsl)); json_print_object(root, NULL); printf("\n"); @@ -4044,6 +4180,42 @@ void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns, } } +static void json_nvme_list_ns(__u32 *ns_list) +{ + struct json_object *root; + struct json_object *valid_attrs; + struct json_object *valid; + int i; + + root = json_create_object(); + valid = json_create_array(); + + for (i = 0; i < 1024; i++) { + if (ns_list[i]) { + valid_attrs = json_create_object(); + json_object_add_value_uint(valid_attrs, "nsid", + le32_to_cpu(ns_list[i])); + json_array_add_value_object(valid, valid_attrs); + } + } + json_object_add_value_array(root, "nsid_list", valid); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_list_ns(__u32 *ns_list, enum nvme_print_flags flags) +{ + int i; + if (flags & JSON) + return json_nvme_list_ns(ns_list); + + for (i = 0; i < 1024; i++) { + if (ns_list[i]) + printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list[i])); + } +} + void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log, unsigned long flags) { @@ -4134,6 +4306,48 @@ void nvme_show_zns_report_zones(void *report, __u32 descs, } } +static void json_nvme_list_ctrl(struct nvme_controller_list *ctrl_list, __u16 num) +{ + struct json_object *root; + struct json_object *valid_attrs; + struct json_object *valid; + int i; + + root = json_create_object(); + valid = json_create_array(); + + json_object_add_value_uint(root, "num_ctrl", + le16_to_cpu(ctrl_list->num)); + + for (i = 0; i < min(num, 2047); i++) { + + valid_attrs = json_create_object(); + json_object_add_value_uint(valid_attrs, "ctrl_id", + le16_to_cpu(ctrl_list->identifier[i])); + json_array_add_value_object(valid, valid_attrs); + } + + json_object_add_value_array(root, "ctrl_list", valid); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_list_ctrl(struct nvme_controller_list *ctrl_list, + enum nvme_print_flags flags) +{ + int i; + __u16 num = le16_to_cpu(ctrl_list->num); + + if (flags & JSON) + return json_nvme_list_ctrl(ctrl_list, num); + + printf("num of ctrls present: %u\n", num); + for (i = 0; i < min(num, 2047); i++) { + printf("[%4u]:%#x\n", i, le16_to_cpu(ctrl_list->identifier[i])); + } +} + static void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset) { __u32 nent = nvmset->nid; @@ -4188,7 +4402,7 @@ void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id, printf(".................\n"); printf("nvmset_id : %d\n", le16_to_cpu(nvmset->ent[i].id)); - printf("enduracne_group_id : %d\n", + printf("endurance_group_id : %d\n", le16_to_cpu(nvmset->ent[i].endurance_group_id)); printf("random_4k_read_typical : %u\n", le32_to_cpu(nvmset->ent[i].random_4k_read_typical)); @@ -4487,14 +4701,122 @@ void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, } } -void nvme_show_id_iocs(struct nvme_id_iocs *iocs) +static void nvme_show_iocs_vector(__u64 iocs_vec) +{ + __u64 rsvd3 = iocs_vec >> 3; + __u8 zns_cmd_set = (iocs_vec >> 2) & 0x1; + __u8 kv_cmd_set = (iocs_vec >> 1) & 0x1; + __u8 nvm_cmd_set = iocs_vec & 0x1; + + if (rsvd3) + printf(" [63:3] : %"PRIx64"\tReserved3\n", le64_to_cpu(rsvd3)); + printf(" [2:2] : %#x\tZNS Command Set %sSelected\n", + zns_cmd_set, zns_cmd_set ? "" : "not "); + printf(" [1:1] : %#x\tKV Command Set %sSelected\n", + kv_cmd_set, kv_cmd_set ? "" : "not "); + printf(" [0:0] : %#x\tNVM Command Set %sSelected\n", + nvm_cmd_set, nvm_cmd_set ? "" : "not "); + printf("\n"); +} + +static void json_id_iocs(struct nvme_id_iocs *iocs) { - __u16 i; + struct json_object *root; + struct json_object *entries; + int i; + + root = json_create_object(); + entries = json_create_array(); - for (i = 0; i < 512; i++) - if (iocs->iocs[i]) - printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i, + for (i = 0; i < NVME_NUM_IOCS_COMBINATIONS; i++) { + if (iocs->iocs[i]) { + struct json_object *entry = json_create_object(); + json_object_add_value_uint(entry, "iocs", + le64_to_cpu(iocs->iocs[i])); + json_array_add_value_object(entries, entry); + } + } + + json_object_add_value_array(root, "iocs_list", entries); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + +} + +void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags) +{ + if (flags & BINARY) + return d_raw((unsigned char *)iocs, sizeof(*iocs)); + else if (flags & JSON) + return json_id_iocs(iocs); + + bool human = flags & VERBOSE; + int i; + + for (i = 0; i < NVME_NUM_IOCS_COMBINATIONS; i++) { + if (iocs->iocs[i]) { + printf("I/O Command Set Combination[%u]: %"PRIx64"\n", i, (uint64_t)le64_to_cpu(iocs->iocs[i])); + if (human) + nvme_show_iocs_vector(le64_to_cpu(iocs->iocs[i])); + } + } +} + +static void json_id_domain_list(struct nvme_id_domain_list *id_dom) +{ + struct json_object *root; + struct json_object *entries; + struct json_object *entry; + int i; + long double dom_cap, unalloc_dom_cap, max_egrp_dom_cap; + + root = json_create_object(); + entries = json_create_array(); + + json_object_add_value_uint(root, "num_dom_entries", id_dom->num_entries); + + for (i = 0; i < id_dom->num_entries; i++) { + entry = json_create_object(); + dom_cap = int128_to_double(id_dom->domain_attr[i].dom_cap); + unalloc_dom_cap = int128_to_double(id_dom->domain_attr[i].unalloc_dom_cap); + max_egrp_dom_cap = int128_to_double(id_dom->domain_attr[i].max_egrp_dom_cap); + + json_object_add_value_uint(entry, "dom_id", le16_to_cpu(id_dom->domain_attr[i].dom_id)); + json_object_add_value_float(entry, "dom_cap", dom_cap); + json_object_add_value_float(entry, "unalloc_dom_cap", unalloc_dom_cap); + json_object_add_value_float(entry, "max_egrp_dom_cap", max_egrp_dom_cap); + + json_array_add_value_object(entries, entry); + } + + json_object_add_value_array(root, "domain_list", entries); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + +void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom, + enum nvme_print_flags flags) +{ + int i; + if (flags & BINARY) + return d_raw((unsigned char *)id_dom, sizeof(*id_dom)); + else if (flags & JSON) + return json_id_domain_list(id_dom); + + printf("Number of Domain Entires: %u\n", id_dom->num_entries); + for (i = 0; i < id_dom->num_entries; i++) { + printf("Domain Id for Attr Entry[%u]: %u\n", i, + le16_to_cpu(id_dom->domain_attr[i].dom_id)); + printf("Domain Capacity for Attr Entry[%u]: %.0Lf\\n", i, + int128_to_double(id_dom->domain_attr[i].dom_cap)); + printf("Unallocated Domain Capacity for Attr Entry[%u]: %.0Lf\n", i, + int128_to_double(id_dom->domain_attr[i].unalloc_dom_cap)); + printf("Max Endurange Group Domain Capacity for Attr Entry[%u]: %.0Lf\n", i, + int128_to_double(id_dom->domain_attr[i].max_egrp_dom_cap)); + } } static const char *nvme_trtype_to_string(__u8 trtype) @@ -4620,7 +4942,6 @@ void nvme_show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname, enum nvme_print_flags flags) { int i; - if (flags & BINARY) return d_raw((unsigned char *)fw_log, sizeof(*fw_log)); if (flags & JSON) @@ -4629,10 +4950,8 @@ void nvme_show_fw_log(struct nvme_firmware_log_page *fw_log, printf("Firmware Log for device:%s\n", devname); printf("afi : %#x\n", fw_log->afi); for (i = 0; i < 7; i++) { - if (fw_log->frs[i]) - printf("frs%d : %#016"PRIx64" (%s)\n", i + 1, - (uint64_t)fw_log->frs[i], - fw_to_string(fw_log->frs[i])); + if (strcmp(fw_to_string(fw_log->frs[i]), "\0")) + printf("frs%d : %s\n", i + 1, fw_to_string(fw_log->frs[i])); } } @@ -4771,10 +5090,9 @@ void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log, void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname, enum nvme_print_flags flags) { - /* convert temperature from Kelvin to Celsius */ - int temperature = ((smart->temperature[1] << 8) | - smart->temperature[0]) - 273; - int i, human = flags & VERBOSE; + __u16 temperature = smart->temperature[1] << 8 | smart->temperature[0]; + int i; + bool human = flags & VERBOSE; if (flags & BINARY) return d_raw((unsigned char *)smart, sizeof(*smart)); @@ -4794,8 +5112,8 @@ void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, printf(" Persistent Mem. RO[5] : %d\n", (smart->critical_warning & 0x20) >> 5); } - printf("temperature : %d C\n", - temperature); + printf("temperature : %ld C (%u Kelvin)\n", + kelvin_to_celsius(temperature), temperature); printf("available_spare : %u%%\n", smart->avail_spare); printf("available_spare_threshold : %u%%\n", @@ -4833,8 +5151,8 @@ void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, if (temp == 0) continue; - printf("Temperature Sensor %d : %d C\n", i + 1, - temp - 273); + printf("Temperature Sensor %d : %ld C (%u Kelvin)\n", + i + 1, kelvin_to_celsius(temp), temp); } printf("Thermal Management T1 Trans Count : %u\n", le32_to_cpu(smart->thm_temp1_trans_count)); @@ -5030,11 +5348,9 @@ void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize, __u16 status = le16_to_cpu(sanitize->status) & NVME_SANITIZE_LOG_STATUS_MASK; if (flags & BINARY) - d_raw((unsigned char *)sanitize, sizeof(*sanitize)); - else if (flags & JSON) { - json_sanitize_log(sanitize, devname); - return; - } + return d_raw((unsigned char *)sanitize, sizeof(*sanitize)); + else if (flags & JSON) + return json_sanitize_log(sanitize, devname); printf("Sanitize Progress (SPROG) : %u", le16_to_cpu(sanitize->progress)); @@ -5088,7 +5404,7 @@ const char *nvme_feature_to_string(enum nvme_feat feature) case NVME_FEAT_PLM_CONFIG: return "Predicatable Latency Mode Config"; case NVME_FEAT_PLM_WINDOW: return "Predicatable Latency Mode Window"; case NVME_LBA_STATUS_INFO: return "LBA Status Infomation Attributes"; - case NVME_FEAT_ENDURANCE: return "Enduarance Event Group Configuration"; + case NVME_FEAT_ENDURANCE: return "Enduarance Event Group Configuration"; case NVME_FEAT_IOCS_PROFILE: return "I/O Command Set Profile"; case NVME_FEAT_SW_PROGRESS: return "Software Progress"; case NVME_FEAT_HOST_ID: return "Host Identifier"; @@ -5099,6 +5415,8 @@ const char *nvme_feature_to_string(enum nvme_feat feature) case NVME_FEAT_HCTM: return "Host Controlled Thermal Management"; case NVME_FEAT_HOST_BEHAVIOR: return "Host Behavior"; case NVME_FEAT_SANITIZE: return "Sanitize"; + case NVME_MI_FEAT_CTRL_METADATA:return "MI Controller Metadata"; + case NVME_MI_FEAT_NS_METADATA: return "MI Namespace Metadata"; } /* * We don't use the "default:" statement to let the compiler warning if @@ -5209,6 +5527,10 @@ const char *nvme_status_to_string(__u16 status) return "SANITIZE_FAILED: The most recent sanitize operation failed and no recovery actions has been successfully completed"; case NVME_SC_SANITIZE_IN_PROGRESS: return "SANITIZE_IN_PROGRESS: The requested function is prohibited while a sanitize operation is in progress"; + case NVME_SC_SGL_DATA_BLK_GRAN_INVALID: + return "NVME_SC_SGL_DATA_BLK_GRAN_INVALID: Address alignment or Length granularity for an SGL Data Block descriptor is invalid"; + case NVME_SC_CMD_NOT_SUP_QUEUE_IN_CMB: + return "NVME_SC_CMD_NOT_SUP_QUEUE_IN_CMB: does not support submission of the command to a SQ or completion to a CQ in the CMB"; case NVME_SC_IOCS_NOT_SUPPORTED: return "IOCS_NOT_SUPPORTED: The I/O command set is not supported"; case NVME_SC_IOCS_NOT_ENABLED: @@ -5217,12 +5539,18 @@ const char *nvme_status_to_string(__u16 status) return "IOCS_COMBINATION_REJECTED: The I/O command set combination is rejected"; case NVME_SC_INVALID_IOCS: return "INVALID_IOCS: the I/O command set is invalid"; + case NVME_SC_ID_UNAVAILABLE: + return "NVME_SC_ID_UNAVAILABLE: The number of Endurance Groups or NVM Sets supported has been exceeded."; case NVME_SC_LBA_RANGE: return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace"; case NVME_SC_NS_WRITE_PROTECTED: return "NS_WRITE_PROTECTED: The command is prohibited while the namespace is write protected by the host."; case NVME_SC_TRANSIENT_TRANSPORT: return "TRANSIENT_TRANSPORT: A transient transport error was detected."; + case NVME_SC_PROHIBITED_BY_CMD_AND_FEAT: + return "NVME_SC_PROHIBITED_BY_CMD_AND_FEAT: command was aborted due to execution being prohibited by the Command and Feature Lockdown"; + case NVME_SC_ADMIN_CMD_MEDIA_NOT_READY: + return "NVME_SC_ADMIN_CMD_MEDIA_NOT_READY: Admin command requires access to media and the media is not ready"; case NVME_SC_CAP_EXCEEDED: return "CAP_EXCEEDED: The execution of the command has caused the capacity of the namespace to be exceeded"; case NVME_SC_NS_NOT_READY: @@ -5319,6 +5647,12 @@ const char *nvme_status_to_string(__u16 status) return "ANA_INVALID_GROUP_ID: The specified ANA Group Identifier (ANAGRPID) is not supported in the submitted command."; case NVME_SC_ANA_ATTACH_FAIL: return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition"; + case NVME_SC_INSUFFICIENT_CAP: + return "NVME_SC_INSUFFICIENT_CAP: Requested operation requires more free space than is currently available"; + case NVME_SC_NS_ATTACHMENT_LIMIT_EXCEEDED: + return "NVME_SC_NS_ATTACHMENT_LIMIT_EXCEEDED: Attaching the ns to a controller causes max number of ns attachments allowed to be exceeded"; + case NVME_SC_PROHIBIT_CMD_EXEC_NOT_SUPPORTED: + return "NVME_SC_PROHIBIT_CMD_EXEC_NOT_SUPPORTED: Prohibition of Command Execution Not Supported"; case NVME_SC_BAD_ATTRIBUTES: return "BAD_ATTRIBUTES: Bad attributes were given"; case NVME_SC_INVALID_PI: @@ -5343,6 +5677,8 @@ const char *nvme_status_to_string(__u16 status) return "ACCESS_DENIED: Access to the namespace and/or LBA range is denied due to lack of access rights"; case NVME_SC_UNWRITTEN_BLOCK: return "UNWRITTEN_BLOCK: The command failed due to an attempt to read from an LBA range containing a deallocated or unwritten logical block"; + case NVME_SC_STORAGE_TAG_CHECK: + return "NVME_SC_STORAGE_TAG_CHECK: command was aborted due to an end-to-end storage tag check failure"; case NVME_SC_INTERNAL_PATH_ERROR: return "INTERNAL_PATH_ERROT: The command was not completed as the result of a controller internal error"; case NVME_SC_ANA_PERSISTENT_LOSS: @@ -5396,8 +5732,8 @@ void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges) ((lbrt[i].attributes & 0x0002) >> 1) ? "LBA range should be hidden from the OS/EFI/BIOS" : "LBA range should be visible from the OS/EFI/BIOS"); - printf("\tslba : %#"PRIx64"\n", (uint64_t)(lbrt[i].slba)); - printf("\tnlb : %#"PRIx64"\n", (uint64_t)(lbrt[i].nlb)); + printf("\tslba : %#"PRIx64"\n", le64_to_cpu(lbrt[i].slba)); + printf("\tnlb : %#"PRIx64"\n", le64_to_cpu(lbrt[i].nlb)); printf("\tguid : "); for (j = 0; j < 16; j++) printf("%02x", lbrt[i].guid[j]); @@ -5451,9 +5787,9 @@ static void nvme_show_auto_pst(struct nvme_auto_pst *apst) printf("\tEntry[%2d] \n", i); printf("\t.................\n"); printf("\tIdle Time Prior to Transition (ITPT): %u ms\n", - (apst[i].data & 0xffffff00) >> 8); + (le32_to_cpu(apst[i].data) & 0xffffff00) >> 8); printf("\tIdle Transition Power State (ITPS): %u\n", - (apst[i].data & 0x000000f8) >> 3); + (le32_to_cpu(apst[i].data) & 0x000000f8) >> 3); printf("\t.................\n"); } } @@ -5493,6 +5829,22 @@ static void nvme_show_host_mem_buffer(struct nvme_host_mem_buffer *hmb) le32_to_cpu(hmb->hsize)); } +static const char *nvme_show_ns_write_protect_config(__u8 state) +{ + switch (state) { + case NVME_NS_NO_WRITE_PROTECT: + return "No Write Protect"; + case NVME_NS_WRITE_PROTECT: + return "Write Protect"; + case NVME_NS_WRITE_PROTECT_POWER_CYCLE: + return "Write Protect Until Power Cycle"; + case NVME_NS_WRITE_PROTECT_PERMANENT: + return "Permanent Write Protect"; + default: + return "Reserved"; + } +} + static void nvme_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result, unsigned char *buf) { @@ -5592,7 +5944,8 @@ static const char *nvme_plm_window(__u32 plm) } } -void nvme_show_lba_status_info(__u32 result) { +void nvme_show_lba_status_info(__u32 result) +{ printf("\tLBA Status Information Poll Interval (LSIPI) : %u\n", (result >> 16) & 0xffff); printf("\tLBA Status Information Report Interval (LSIRI): %u\n", result & 0xffff); } @@ -5605,15 +5958,75 @@ static void nvme_show_plm_config(struct nvme_plm_config *plmcfg) printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_time_thresh)); } -void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned char *buf) +static char* nvme_show_mi_host_metadata_type_to_string(enum nvme_feat fid, __u8 type) +{ + switch (fid) { + case NVME_MI_FEAT_CTRL_METADATA: + switch (type) { + case NVME_MI_CTRL_METADATA_OS_CTRL_NAME: + return "Operating System Controller Name"; + case NVME_MI_CTRL_METADATA_OS_DRIVER_NAME: + return "Operating System Driver Name"; + case NVME_MI_CTRL_METADATA_OS_DRIVER_VER: + return "Operating System Driver Version"; + case NVME_MI_CTRL_METADATA_PRE_BOOT_CTRL_NAME: + return "Pre-boot Controller Name"; + case NVME_MI_CTRL_METADATA_PRE_BOOT_DRIVER_NAME: + return "Pre-boot Driver Name"; + case NVME_MI_CTRL_METADATA_PRE_BOOT_DRIVER_VER: + return "Pre-boot Driver Version"; + default: + return "Unknown Controller Type"; + } + case NVME_MI_FEAT_NS_METADATA: + switch (type) { + case NVME_MI_NS_METADATA_OS_NS_NAME: + return "Operating System Namespace Name"; + case NVME_MI_NS_METADATA_PRE_BOOT_NS_NAME: + return "Pre-boot Namespace Name"; + default: + return "Unknown Namespace Type"; + } + default: + return "Unknown Feature"; + } +} + +static void nvme_show_mi_host_metadata(enum nvme_feat fid, + struct nvme_mi_host_metadata *data) +{ + struct nvme_mi_host_metadata_element_desc *desc = &data->descs[0]; + int i; + char val[4096]; + __u16 len; + + printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc); + for (i = 0; i < data->ndesc; i++) { + len = le16_to_cpu(desc->len); + strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len)); + + printf("\tElement[%-3d]:\n", i); + printf("\t\tType : 0x%02x (%s)\n", desc->type, + nvme_show_mi_host_metadata_type_to_string(fid, desc->type)); + printf("\t\tRevision : %d\n", desc->rev); + printf("\t\tLength : %d\n", len); + printf("\t\tValue : %s\n", val); + + desc = (struct nvme_mi_host_metadata_element_desc *) + &desc->val[desc->len]; + } +} + +void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, + unsigned char *buf) { __u8 field; uint64_t ull; switch (fid) { - case NVME_FEAT_NONE: - printf("\tFeature Identifier Reserved\n"); - break; + case NVME_FEAT_NONE: + printf("\tFeature Identifier Reserved\n"); + break; case NVME_FEAT_ARBITRATION: printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1); printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1); @@ -5639,7 +6052,8 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned printf("\tThreshold Type Select (THSEL): %u - %s\n", field, nvme_feature_temp_type_to_string(field)); field = (result & 0x000f0000) >> 16; printf("\tThreshold Temperature Select (TMPSEL): %u - %s\n", field, nvme_feature_temp_sel_to_string(field)); - printf("\tTemperature Threshold (TMPTH): %d C\n", (result & 0x0000ffff) - 273); + printf("\tTemperature Threshold (TMPTH): %ld C (%u Kelvin)\n", + kelvin_to_celsius(result & 0x0000ffff), result & 0x0000ffff); break; case NVME_FEAT_ERR_RECOVERY: printf("\tDeallocated or Unwritten Logical Block Error Enable (DULBE): %s\n", ((result & 0x00010000) >> 16) ? "Enabled":"Disabled"); @@ -5664,6 +6078,7 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False"); break; case NVME_FEAT_ASYNC_EVENT: + printf("\tZone Descriptor Changed Notices: %s\n", ((result >> 27) & 0x1) ? "Send async event":"Do not send async event"); printf("\tEndurance Group Event Aggregate Log Change Notices: %s\n", ((result & 0x00004000) >> 14) ? "Send async event":"Do not send async event"); printf("\tLBA Status Information Notices : %s\n", ((result & 0x00002000) >> 13) ? "Send async event":"Do not send async event"); printf("\tPredictable Latency Event Aggregate Log Change Notices: %s\n", ((result & 0x00001000) >> 12) ? "Send async event":"Do not send async event"); @@ -5694,10 +6109,10 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned case NVME_LBA_STATUS_INFO: nvme_show_lba_status_info(result); break; - case NVME_FEAT_ENDURANCE: - printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff); - printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); - break; + case NVME_FEAT_ENDURANCE: + printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff); + printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff); + break; case NVME_FEAT_IOCS_PROFILE: printf("\tI/O Command Set Comination Index(IOCSCI): %u\n", result & 0x1ff); break; @@ -5716,14 +6131,16 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True":"False"); break; case NVME_FEAT_WRITE_PROTECT: - printf("\tNamespace Write Protect: %s\n", result != NVME_NS_NO_WRITE_PROTECT ? "True" : "False"); + printf("\tNamespace Write Protect state: %s\n", nvme_show_ns_write_protect_config(result & 0x7)); break; case NVME_FEAT_TIMESTAMP: nvme_show_timestamp((struct nvme_timestamp *)buf); break; case NVME_FEAT_HCTM: - printf("\tThermal Management Temperature 1 (TMT1) : %u Kelvin\n", (result >> 16)); - printf("\tThermal Management Temperature 2 (TMT2) : %u Kelvin\n", (result & 0x0000ffff)); + printf("\tThermal Management Temperature 1 (TMT1) : %u Kelvin (%ld C)\n", + result >> 16, kelvin_to_celsius(result >> 16)); + printf("\tThermal Management Temperature 2 (TMT2) : %u Kelvin (%ld C)\n", + result & 0x0000ffff, kelvin_to_celsius(result & 0x0000ffff)); break; case NVME_FEAT_KATO: printf("\tKeep Alive Timeout (KATO) in milliseconds: %u\n", result); @@ -5740,6 +6157,10 @@ void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned case NVME_FEAT_RRL: printf("\tRead Recovery Level (RRL): %u\n", result & 0xf); break; + case NVME_MI_FEAT_CTRL_METADATA: + case NVME_MI_FEAT_NS_METADATA: + nvme_show_mi_host_metadata(fid, (struct nvme_mi_host_metadata *)buf); + break; } } @@ -5751,8 +6172,8 @@ void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len, if (flags & BINARY) return d_raw((unsigned char *)list, len); - printf("Number of LBA Status Descriptors(NLSD): %" PRIu64 "\n", - le64_to_cpu(list->nlsd)); + printf("Number of LBA Status Descriptors(NLSD): %" PRIu32 "\n", + le32_to_cpu(list->nlsd)); printf("Completion Condition(CMPC): %u\n", list->cmpc); switch (list->cmpc) { @@ -5791,6 +6212,9 @@ static void nvme_show_list_item(struct nvme_namespace *n) struct stat st; int ret; + if (!n->ctrl) + return; + sprintf(path, "%s%s", n->ctrl->path, n->name); ret = stat(path, &st); if (ret < 0) @@ -5847,6 +6271,9 @@ static void nvme_show_details_ns(struct nvme_namespace *n, bool ctrl) char usage[128]; char format[128]; + if (!n->ctrl) + return; + sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix); sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix, @@ -6063,6 +6490,9 @@ static void json_simple_ns(struct nvme_namespace *n, struct json_object *devices char *devnode; struct stat st; + if (!n->ctrl) + return; + if (asprintf(&devnode, "%s%s", n->ctrl->path, n->name) < 0) return; diff --git a/nvme-print.h b/nvme-print.h index 2d8ed4d..08be8f2 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -83,7 +83,12 @@ void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list * enum nvme_print_flags flags); void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list, enum nvme_print_flags flags); -void nvme_show_id_iocs(struct nvme_id_iocs *iocs); +void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags); +void nvme_show_list_ctrl(struct nvme_controller_list *ctrl_list, + enum nvme_print_flags flags); +void nvme_show_list_ns(__u32 *ns_list, enum nvme_print_flags flags); +void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom, + enum nvme_print_flags flags); void nvme_feature_show_fields(enum nvme_feat fid, unsigned int result, unsigned char *buf); void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, diff --git a/nvme-rpmb.c b/nvme-rpmb.c index 0e11ef3..a7658f5 100644 --- a/nvme-rpmb.c +++ b/nvme-rpmb.c @@ -266,7 +266,7 @@ struct rpmb_config_block_t { #define RPMB_NVME_SPSP 0x0001 #define SEND_RPMB_REQ(tgt, size, req) \ -nvme_sec_send(fd, 0, tgt, RPMB_NVME_SPSP, RPMB_NVME_SECP, size, size, \ +nvme_sec_send(fd, 0, tgt, RPMB_NVME_SPSP, RPMB_NVME_SECP, size, \ (unsigned char *)(req)) #define RECV_RPMB_RSP(tgt, size, rsp) \ diff --git a/nvme-topology.c b/nvme-topology.c index 31cf7f9..0a22f6b 100644 --- a/nvme-topology.c +++ b/nvme-topology.c @@ -155,23 +155,23 @@ static int scan_namespace(struct nvme_namespace *n) return ret; fd = open(path, O_RDONLY); - if (fd < 0) + if (fd < 0) { + ret = fd; goto free; - + } if (!n->nsid) { - n->nsid = nvme_get_nsid(fd); - if (n->nsid < 0) + ret = nvme_get_nsid(fd); + if (ret < 0) goto close_fd; + n->nsid = ret; } ret = nvme_identify_ns(fd, n->nsid, 0, &n->ns); - if (ret < 0) - goto close_fd; close_fd: close(fd); free: free(path); - return 0; + return ret; } static char *get_nvme_ctrl_path_ana_state(char *path, int nsid) @@ -319,10 +319,8 @@ static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance) return ret; fd = open(path, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Failed to open %s\n", path); + if (fd < 0) goto free; - } ret = nvme_identify_ctrl(fd, &c->id); if (ret < 0) @@ -384,8 +382,12 @@ static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance, int nsid) for (i = 0; i < s->nr_namespaces; i++) { n = &s->namespaces[i]; n->name = strdup(ns[i]->d_name); - n->ctrl = &s->ctrls[0]; - scan_namespace(n); + for (j = 0; j < s->nr_ctrls; j++) { + n->ctrl = &s->ctrls[j]; + if (!strcmp(n->ctrl->state, "live") && + !scan_namespace(n)) + break; + } } } else { i = s->nr_namespaces; @@ -666,6 +668,30 @@ char *nvme_char_from_block(char *dev) return path; } +int nvme_logical_block_size_from_ns_char(const char *dev) +{ + int ret; + int id, nsid; + char *path = NULL; + char *s; + + ret = sscanf(dev, "ng%dn%d", &id, &nsid); + if (ret != 2) + return -EINVAL; + + if (asprintf(&path, "/sys/block/nvme%dn%d/queue", id, nsid) < 0) + path = NULL; + + if (!path) + return -EINVAL; + + s = nvme_get_ctrl_attr(path, "logical_block_size"); + if (!s) + return -EINVAL; + + return atoi(s); +} + void *mmap_registers(const char *dev) { int fd; diff --git a/nvme.c b/nvme.c index a2075bf..c10932f 100644 --- a/nvme.c +++ b/nvme.c @@ -91,7 +91,9 @@ static __u16 nvme_feat_buf_len[0x100] = { [NVME_FEAT_HOST_ID] = 8, [NVME_FEAT_PLM_CONFIG] = 512, [NVME_FEAT_TIMESTAMP] = 8, - [NVME_FEAT_HOST_BEHAVIOR] = 512 + [NVME_FEAT_HOST_BEHAVIOR] = 512, + [NVME_MI_FEAT_CTRL_METADATA] = 4096, + [NVME_MI_FEAT_NS_METADATA] = 4096, }; const char *output_format = "Output format: normal|json|binary"; @@ -156,6 +158,11 @@ static bool is_blkdev(void) return S_ISBLK(nvme_stat.st_mode); } +static bool is_ns_chardev(void) +{ + return !strncmp(devicename, "ng", 2) && S_ISCHR(nvme_stat.st_mode); +} + static int open_dev(char *dev) { int err, fd; @@ -242,7 +249,7 @@ static int get_smart_log(int argc, char **argv, struct command *cmd, struct plug const char *raw = "output in binary format"; const char *human_readable = "show info in readable format"; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -297,7 +304,7 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, const char *desc = "Retrieve ANA log for the given device in " \ "decoded format (default), json or binary."; void *ana_log; - int err, fd; + int err = -1, fd; int groups = 0; /* Right now get all the per ANA group NSIDS */ size_t ana_log_len; struct nvme_id_ctrl ctrl; @@ -339,7 +346,8 @@ static int get_ana_log(int argc, char **argv, struct command *cmd, ana_log = malloc(ana_log_len); if (!ana_log) { perror("malloc"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -367,7 +375,7 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct const size_t bs = 512; struct nvme_telemetry_log_page_hdr *hdr; size_t full_size, offset = bs; - int err = 0, fd, output; + int err = -1, fd, output; void *page_log; struct config { @@ -397,7 +405,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct if (!cfg.file_name) { fprintf(stderr, "Please provide an output file!\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -406,7 +415,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct page_log = malloc(bs); if (!hdr || !page_log) { perror("failed to allocate buf for log\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto free_mem; } memset(hdr, 0, bs); @@ -446,7 +456,8 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct break; default: fprintf(stderr, "Invalid data area requested\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_output; } @@ -491,7 +502,7 @@ static int get_endurance_log(int argc, char **argv, struct command *cmd, struct const char *desc = "Retrieves endurance groups log page and prints the log."; const char *group_id = "The endurance group identifier"; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { char *output_format; @@ -505,7 +516,7 @@ static int get_endurance_log(int argc, char **argv, struct command *cmd, struct OPT_ARGS(opts) = { OPT_FMT("output-format", 'o', &cfg.output_format, output_format), - OPT_UINT("group-id", 'g', &cfg.group_id, group_id), + OPT_SHRT("group-id", 'g', &cfg.group_id, group_id), OPT_END() }; @@ -537,7 +548,7 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl const char *human_readable = "show log in readable format"; struct nvme_effects_log_page effects; - int err, fd; + int err = -1, fd; enum nvme_print_flags flags; struct config { @@ -592,7 +603,7 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug struct nvme_error_log_page *err_log; struct nvme_id_ctrl ctrl; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { __u32 log_entries; @@ -624,7 +635,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug if (!cfg.log_entries) { fprintf(stderr, "non-zero log-entries is required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -634,7 +646,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug goto close_fd; } else if (err) { fprintf(stderr, "could not identify controller\n"); - err = -ENODEV; + errno = ENODEV; + err = -1; goto close_fd; } @@ -642,7 +655,8 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug err_log = calloc(cfg.log_entries, sizeof(struct nvme_error_log_page)); if (!err_log) { perror("could not alloc buffer for error log\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -667,7 +681,7 @@ static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin const char *raw = "use binary output"; struct nvme_firmware_log_page fw_log; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { int raw_binary; @@ -715,7 +729,7 @@ static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, s "(default) or binary."; const char *raw = "output in binary format"; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { int raw_binary; @@ -766,7 +780,7 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv, const char *raw = "use binary output"; struct nvme_predlat_per_nvmset_log_page plpns_log; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { __u16 nvmset_id; @@ -780,7 +794,7 @@ static int get_pred_lat_per_nvmset_log(int argc, char **argv, }; OPT_ARGS(opts) = { - OPT_UINT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id), + OPT_SHRT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_END() @@ -826,7 +840,7 @@ static int get_pred_lat_event_agg_log(int argc, char **argv, void *pea_log; struct nvme_id_ctrl ctrl; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; __u32 log_size; struct config { @@ -862,7 +876,8 @@ static int get_pred_lat_event_agg_log(int argc, char **argv, if (!cfg.log_entries) { fprintf(stderr, "non-zero log-entries is required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -881,7 +896,8 @@ static int get_pred_lat_event_agg_log(int argc, char **argv, if (!pea_log) { perror("could not alloc buffer for predictable " \ "latency event agggregate log entries\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -913,9 +929,9 @@ static int get_persistent_event_log(int argc, char **argv, const char *log_len = "number of bytes to retrieve"; const char *raw = "use binary output"; void *pevent_log_info; - struct nvme_persistent_event_log_head *pevent_log_head; + struct nvme_persistent_event_log_head *pevent_log_head = NULL; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; bool huge; struct config { @@ -932,7 +948,7 @@ static int get_persistent_event_log(int argc, char **argv, }; OPT_ARGS(opts) = { - OPT_UINT("action", 'a', &cfg.action, action), + OPT_BYTE("action", 'a', &cfg.action, action), OPT_UINT("log_len", 'l', &cfg.log_len, log_len), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), @@ -949,11 +965,19 @@ static int get_persistent_event_log(int argc, char **argv, if (cfg.raw_binary) flags = BINARY; + if (cfg.action > 3) { + fprintf(stderr, "invalid action field: %u\n", cfg.action); + errno = EINVAL; + err = -1; + goto close_fd; + } + pevent_log_head = calloc(sizeof(*pevent_log_head), 1); if (!pevent_log_head) { perror("could not alloc buffer for persistent " \ "event log header\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -992,7 +1016,8 @@ static int get_persistent_event_log(int argc, char **argv, pevent_log_info = nvme_alloc(cfg.log_len, &huge); if (!pevent_log_info) { perror("could not alloc buffer for persistent event log page\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } err = nvme_persistent_event_log(fd, cfg.action, @@ -1028,7 +1053,7 @@ static int get_endurance_event_agg_log(int argc, char **argv, void *endurance_log; struct nvme_id_ctrl ctrl; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; __u32 log_size; struct config { @@ -1064,7 +1089,8 @@ static int get_endurance_event_agg_log(int argc, char **argv, if (!cfg.log_entries) { fprintf(stderr, "non-zero log-entries is required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -1074,7 +1100,8 @@ static int get_endurance_event_agg_log(int argc, char **argv, goto close_fd; } else if (err) { fprintf(stderr, "could not identify controller\n"); - err = -ENODEV; + errno = ENODEV; + err = -1; goto close_fd; } @@ -1084,7 +1111,8 @@ static int get_endurance_event_agg_log(int argc, char **argv, if (!endurance_log) { perror("could not alloc buffer for endurance group" \ " event agggregate log entries\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -1114,7 +1142,7 @@ static int get_lba_status_log(int argc, char **argv, const char *rae = "Retain an Asynchronous Event"; void *lab_status; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; __u32 lslplen; struct config { @@ -1153,7 +1181,8 @@ static int get_lba_status_log(int argc, char **argv, lab_status = calloc(lslplen, 1); if (!lab_status) { perror("could not alloc buffer for lba status log"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -1182,7 +1211,7 @@ static int get_resv_notif_log(int argc, char **argv, "json or binary."; struct nvme_resv_notif_log resv; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { char *output_format; @@ -1231,12 +1260,17 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl const char *aen = "result of the aen, use to override log id"; const char *lsp = "log specific field"; const char *lpo = "log page offset specifies the location within a log page from where to start returning data"; + const char *lsi = "log specific identifier specifies an identifier that is required for a particular log page"; const char *rae = "retain an asynchronous event"; const char *raw = "output in raw format"; const char *uuid_index = "UUID index"; - int err, fd; + const char *csi = "command set identifier"; + const char *offset_type = "offset type"; + int err = -1, fd; + unsigned char *log; struct config { + __u16 lsi; __u32 namespace_id; __u8 log_id; __u32 log_len; @@ -1244,6 +1278,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl __u64 lpo; __u8 lsp; __u8 uuid_index; + __u8 csi; + int ot; int rae; int raw_binary; }; @@ -1254,19 +1290,25 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl .log_len = 0, .lpo = NVME_NO_LOG_LPO, .lsp = NVME_NO_LOG_LSP, + .lsi = 0, .rae = 0, .uuid_index = 0, + .csi = 0, + .ot = 0, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("log-id", 'i', &cfg.log_id, log_id), + OPT_BYTE("log-id", 'i', &cfg.log_id, log_id), OPT_UINT("log-len", 'l', &cfg.log_len, log_len), OPT_UINT("aen", 'a', &cfg.aen, aen), - OPT_LONG("lpo", 'o', &cfg.lpo, lpo), + OPT_SUFFIX("lpo", 'o', &cfg.lpo, lpo), OPT_BYTE("lsp", 's', &cfg.lsp, lsp), + OPT_SHRT("lsi", 'S', &cfg.lsi, lsi), OPT_FLAG("rae", 'r', &cfg.rae, rae), OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), + OPT_BYTE("csi", 'y', &cfg.csi, csi), + OPT_FLAG("ot", 'O', &cfg.ot, offset_type), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_END() }; @@ -1282,34 +1324,49 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl if (!cfg.log_len) { fprintf(stderr, "non-zero log-len is required param\n"); - err = -EINVAL; - } else { - unsigned char *log; + errno = EINVAL; + err = -1; + goto close_fd; + } - log = malloc(cfg.log_len); - if (!log) { - perror("could not alloc buffer for log\n"); - err = -ENOMEM; - goto close_fd; - } + if (cfg.lsp > 128) { + fprintf(stderr, "invalid lsp param: %u\n", cfg.lsp); + errno = EINVAL; + err = -1; + goto close_fd; + } - err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id, - cfg.lsp, cfg.lpo, 0, cfg.rae, - cfg.uuid_index, cfg.log_len, log); - if (!err) { - if (!cfg.raw_binary) { - printf("Device:%s log-id:%d namespace-id:%#x\n", - devicename, cfg.log_id, - cfg.namespace_id); - d(log, cfg.log_len, 16, 1); - } else - d_raw((unsigned char *)log, cfg.log_len); - } else if (err > 0) - nvme_show_status(err); - else - perror("log page"); - free(log); + if (cfg.uuid_index > 128) { + fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index); + errno = EINVAL; + err = -1; + goto close_fd; } + + log = malloc(cfg.log_len); + if (!log) { + perror("could not alloc buffer for log\n"); + err = -ENOMEM; + goto close_fd; + } + + err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id, + cfg.lsp, cfg.lpo, cfg.lsi, cfg.rae, + cfg.uuid_index, cfg.csi, cfg.ot, cfg.log_len, log); + if (!err) { + if (!cfg.raw_binary) { + printf("Device:%s log-id:%d namespace-id:%#x\n", + devicename, cfg.log_id, + cfg.namespace_id); + d(log, cfg.log_len, 16, 1); + } else + d_raw((unsigned char *)log, cfg.log_len); + } else if (err > 0) + nvme_show_status(err); + else + perror("log page"); + free(log); + close_fd: close(fd); ret: @@ -1324,7 +1381,7 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p const char *human_readable = "show log in readable format"; struct nvme_sanitize_log_page sanitize_log; enum nvme_print_flags flags; - int fd, err; + int fd, err = -1; struct config { bool rae; @@ -1377,21 +1434,25 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin * "given device is part of, or optionally controllers attached to a specific namespace."; const char *controller = "controller to display"; const char *namespace_id = "optional namespace attached to controller"; - int err, i, fd; + int err = -1, fd; struct nvme_controller_list *cntlist; + enum nvme_print_flags flags; struct config { __u16 cntid; __u32 namespace_id; + char *output_format; }; struct config cfg = { .cntid = 0, + .output_format = "normal", }; OPT_ARGS(opts) = { - OPT_SHRT("cntid", 'c', &cfg.cntid, controller), - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_SHRT("cntid", 'c', &cfg.cntid, controller), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_END() }; @@ -1399,19 +1460,25 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin * if (fd < 0) goto ret; + err = flags = validate_output_format(cfg.output_format); + if (flags < 0) + goto close_fd; + if (flags != JSON && flags != NORMAL) { + err = -EINVAL; + goto close_fd; + } + if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000)) { fprintf(stderr, "can not allocate controller list payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } err = nvme_identify_ctrl_list(fd, cfg.namespace_id, cfg.cntid, cntlist); - if (!err) { - __u16 num = le16_to_cpu(cntlist->num); - - for (i = 0; i < (min(num, 2048)); i++) - printf("[%4u]:%#x\n", i, le16_to_cpu(cntlist->identifier[i])); - } else if (err > 0) + if (!err) + nvme_show_list_ctrl(cntlist, flags); + else if (err > 0) nvme_show_status(err); else perror("id controller list"); @@ -1430,23 +1497,27 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl const char *namespace_id = "first nsid returned list should start from"; const char *csi = "I/O command set identifier"; const char *all = "show all namespaces in the subsystem, whether attached or inactive"; - int err, i, fd; + int err = -1, fd; __le32 ns_list[1024]; + enum nvme_print_flags flags; struct config { __u32 namespace_id; int all; - __u16 csi; + __u8 csi; + char *output_format; }; struct config cfg = { .namespace_id = 1, + .output_format = "normal", }; OPT_ARGS(opts) = { - OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_BYTE("csi", 'y', &cfg.csi, csi), - OPT_FLAG("all", 'a', &cfg.all, all), + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), + OPT_BYTE("csi", 'y', &cfg.csi, csi), + OPT_FLAG("all", 'a', &cfg.all, all), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary), OPT_END() }; @@ -1454,19 +1525,26 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl if (fd < 0) goto ret; - if (!cfg.namespace_id) { + err = flags = validate_output_format(cfg.output_format); + if (flags < 0) + goto close_fd; + if (flags != JSON && flags != NORMAL) { err = -EINVAL; + goto close_fd; + } + + if (!cfg.namespace_id) { + errno = EINVAL; + err = -1; fprintf(stderr, "invalid nsid parameter\n"); goto close_fd; } err = nvme_identify_ns_list_csi(fd, cfg.namespace_id - 1, cfg.csi, !!cfg.all, ns_list); - if (!err) { - for (i = 0; i < 1024; i++) - if (ns_list[i]) - printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list[i])); - } else if (err > 0) + if (!err) + nvme_show_list_ns(ns_list, flags); + else if (err > 0) nvme_show_status(err); else perror("id namespace list"); @@ -1486,7 +1564,7 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin * "the namespace is not already inactive, once deleted."; const char *namespace_id = "namespace to delete"; const char *timeout = "timeout value, in milliseconds"; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -1533,7 +1611,7 @@ ret: static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd) { - int err, num, i, fd, list[2048]; + int err = -1, num, i, fd, list[2048]; __u16 ctrlist[2048]; const char *namespace_id = "namespace to attach"; @@ -1562,7 +1640,8 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s if (!cfg.namespace_id) { fprintf(stderr, "%s: namespace-id parameter required\n", cmd->name); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -1574,7 +1653,8 @@ static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, s if (num == -1) { fprintf(stderr, "%s: controller id list is malformed\n", cmd->name); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -1635,7 +1715,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * const char *bs = "target block size, specify only if \'FLBAS\' "\ "value not entered"; - int err = 0, fd, i; + int err = -1, fd, i; struct nvme_id_ns ns; __u32 nsid; @@ -1681,7 +1761,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * if (cfg.flbas != 0xff && cfg.bs != 0x00) { fprintf(stderr, "Invalid specification of both FLBAS and Block Size, please specify only one\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.bs) { @@ -1689,7 +1770,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * fprintf(stderr, "Invalid value for block size (%"PRIu64"). Block size must be a power of two\n", (uint64_t)cfg.bs); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } err = nvme_identify_ns(fd, NVME_NSID_ALL, 0, &ns); @@ -1717,7 +1799,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin * fprintf(stderr, "Please correct block size, or specify FLBAS directly\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -1746,7 +1829,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd, const char *desc = "Retrieve information for subsystems"; const char *verbose = "Increase output verbosity"; __u32 ns_instance = 0; - int err, nsid = 0; + int err = -1, nsid = 0; struct config { char *output_format; @@ -1777,7 +1860,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) { fprintf(stderr, "%s is not a NVMe namespace device\n", argv[optind]); - err = -EINVAL; + errno = EINVAL; + err = -1; goto ret; } sprintf(path, "/dev/%s", devicename); @@ -1785,7 +1869,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (fd < 0) { fprintf(stderr, "Cannot read nsid from %s\n", devicename); - err = -EINVAL; + errno = EINVAL; + err = -1; goto ret; } nsid = nvme_get_nsid(fd); @@ -1793,7 +1878,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (nsid < 0) { fprintf(stderr, "Cannot read nsid from %s\n", devicename); - err = -EINVAL; + errno = EINVAL; + err = -1; goto ret; } sprintf(path, "/sys/block/%s/device", devicename); @@ -1801,7 +1887,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (!subsysnqn) { fprintf(stderr, "Cannot read subsys NQN from %s\n", devicename); - err = -EINVAL; + errno = EINVAL; + err = -1; goto ret; } optind++; @@ -1811,7 +1898,8 @@ static int list_subsys(int argc, char **argv, struct command *cmd, if (flags < 0) goto free; if (flags != JSON && flags != NORMAL) { - err = -EINVAL; + errno = EINVAL; + err = -1; goto free; } if (cfg.verbose) @@ -1837,7 +1925,7 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi const char *verbose = "Increase output verbosity"; struct nvme_topology t = { }; enum nvme_print_flags flags; - int err = 0; + int err = -1; struct config { char *device_dir; @@ -1896,7 +1984,7 @@ int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, const char *human_readable = "show identify in readable format"; enum nvme_print_flags flags; struct nvme_id_ctrl ctrl; - int err, fd; + int err = -1, fd; struct config { int vendor_specific; @@ -2001,7 +2089,7 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p const char *raw = "show descriptors in binary format"; const char *namespace_id = "identifier of desired namespace"; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; void *nsdescs; struct config { @@ -2042,7 +2130,8 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) { fprintf(stderr, "can not allocate controller list payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -2074,7 +2163,7 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug enum nvme_print_flags flags; struct nvme_id_ns ns; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -2143,7 +2232,7 @@ static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct struct nvme_id_ns_granularity_list *granularity_list; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { char *output_format; @@ -2168,7 +2257,8 @@ static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct if (posix_memalign((void *)&granularity_list, getpagesize(), NVME_IDENTIFY_DATA_SIZE)) { fprintf(stderr, "can not allocate granularity list payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -2196,7 +2286,7 @@ static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin * struct nvme_id_nvmset nvmset; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { __u16 nvmset_id; @@ -2209,7 +2299,7 @@ static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin * }; OPT_ARGS(opts) = { - OPT_UINT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id), + OPT_SHRT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_END() }; @@ -2246,7 +2336,7 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl struct nvme_id_uuid_list uuid_list; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { int raw_binary; @@ -2265,9 +2355,9 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl OPT_END() }; - fd = parse_and_open(argc, argv, desc, opts); + err = fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) - return fd; + goto ret; err = flags = validate_output_format(cfg.output_format); if (flags < 0) @@ -2286,7 +2376,8 @@ static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *pl perror("identify UUID list"); close_fd: close(fd); - return err; +ret: + return nvme_status_to_errno(err, false);; } static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -2295,19 +2386,26 @@ static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *pl "given device, returns properties of the specified controller "\ "in either human-readable or binary format."; const char *controller_id = "identifier of desired controller"; + const char *human_readable = "show info in human readable format"; struct nvme_id_iocs iocs; + enum nvme_print_flags flags; int err, fd; struct config { __u16 cntid; + char *output_format; + int human_readable; }; struct config cfg = { .cntid = 0xffff, + .output_format = "normal", }; OPT_ARGS(opts) = { - OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id), + OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable), OPT_END() }; @@ -2317,15 +2415,73 @@ static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *pl goto ret; } + err = flags = validate_output_format(cfg.output_format); + if (flags < 0) + goto close_fd; + if (cfg.human_readable) + flags |= VERBOSE; + err = nvme_identify_iocs(fd, cfg.cntid, &iocs); if (!err) { printf("NVMe Identify I/O Command Set:\n"); - nvme_show_id_iocs(&iocs); + nvme_show_id_iocs(&iocs, flags); } else if (err > 0) nvme_show_status(err); else perror("NVMe Identify I/O Command Set"); +close_fd: + close(fd); +ret: + return nvme_status_to_errno(err, false); +} + +static int id_domain(int argc, char **argv, struct command *cmd, struct plugin *plugin) { + const char *desc = "Send an Identify Domain List command to the "\ + "given device, returns properties of the specified domain "\ + "in either normal|json|binary format."; + const char *domain_id = "identifier of desired domain"; + struct nvme_id_domain_list id_domain; + enum nvme_print_flags flags; + int err, fd; + + struct config { + __u16 dom_id; + char *output_format; + }; + + struct config cfg = { + .dom_id = 0xffff, + .output_format = "normal", + }; + + OPT_ARGS(opts) = { + OPT_SHRT("dom-id", 'd', &cfg.dom_id, domain_id), + OPT_FMT("output-format", 'o', &cfg.output_format, output_format), + OPT_END() + }; + + fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) { + err = fd; + goto ret; + } + + err = flags = validate_output_format(cfg.output_format); + if (flags < 0) + goto close_fd; + + err = nvme_identify_domain_list(fd, cfg.dom_id, &id_domain); + if (!err) { + printf("NVMe Identify command for Domain List is successful:\n"); + printf("NVMe Identify Domain List:\n"); + nvme_show_id_domain_list(&id_domain, flags); + } else if (err > 0) + nvme_show_status(err); + else + perror("NVMe Identify Domain List"); + +close_fd: close(fd); ret: return nvme_status_to_errno(err, false); @@ -2376,7 +2532,7 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi "8h: Secondary Assign\n"\ "9h: Secondary Online"; const char *nr = "Number of Controller Resources(NR)"; - int fd, err; + int fd, err = -1; __u32 result, cdw10; struct config { @@ -2395,9 +2551,9 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi OPT_ARGS(opts) = { OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid), - OPT_UINT("rt", 'r', &cfg.rt, rt), - OPT_UINT("act", 'a', &cfg.act, act), - OPT_UINT("nr", 'n', &cfg.nr, nr), + OPT_BYTE("rt", 'r', &cfg.rt, rt), + OPT_BYTE("act", 'a', &cfg.act, act), + OPT_SHRT("nr", 'n', &cfg.nr, nr), OPT_END() }; @@ -2429,7 +2585,7 @@ static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct const char *human_readable = "show info in readable format"; struct nvme_primary_ctrl_caps caps; - int err, fd; + int err = -1, fd; enum nvme_print_flags flags; struct config { @@ -2480,7 +2636,7 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc struct nvme_secondary_controllers_list *sc_list; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; struct config { __u16 cntid; @@ -2514,13 +2670,15 @@ static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struc if (!cfg.num_entries) { fprintf(stderr, "non-zero num-entries is required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (posix_memalign((void *)&sc_list, getpagesize(), sizeof(*sc_list))) { fprintf(stderr, "can not allocate controller list payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -2551,7 +2709,7 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p "2h Start a extended device self-test operation\n"\ "eh Start a vendor specific device self-test operation\n"\ "fh abort the device self-test operation\n"; - int fd, err; + int fd, err = -1; struct config { __u32 namespace_id; @@ -2565,7 +2723,7 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("self-test-code", 's', &cfg.stc, self_test_code), + OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code), OPT_END() }; @@ -2602,7 +2760,7 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug struct nvme_self_test_log self_test_log; enum nvme_print_flags flags; - int err, fd; + int err = -1, fd; __u32 log_size; struct config { @@ -2617,7 +2775,7 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug }; OPT_ARGS(opts) = { - OPT_UINT("dst-entries", 'e', &cfg.dst_entries, dst_entries), + OPT_BYTE("dst-entries", 'e', &cfg.dst_entries, dst_entries), OPT_FMT("output-format", 'o', &cfg.output_format, output_format), OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), OPT_END() @@ -2666,7 +2824,8 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin const char *data_len = "buffer len if data is returned through host memory buffer"; const char *cdw11 = "dword 11 for interrupt vector config"; const char *human_readable = "show feature in readable format"; - int err, fd; + const char *uuid_index = "specify uuid index"; + int err = -1, fd; __u32 result; void *buf = NULL; @@ -2675,6 +2834,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin __u8 feature_id; __u8 sel; __u32 cdw11; + __u8 uuid_index; __u32 data_len; int raw_binary; int human_readable; @@ -2685,16 +2845,18 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin .feature_id = 0, .sel = 0, .cdw11 = 0, + .uuid_index = 0, .data_len = 0, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), + OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), OPT_BYTE("sel", 's', &cfg.sel, sel), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable), OPT_END() }; @@ -2717,16 +2879,26 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin if (cfg.sel > 7) { fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } - cfg.data_len = nvme_feat_buf_len[cfg.feature_id]; + if (cfg.uuid_index > 128) { + fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index); + errno = EINVAL; + err = -1; + goto close_fd; + } + + if (!cfg.data_len) + cfg.data_len = nvme_feat_buf_len[cfg.feature_id]; /* check for Extended Host Identifier */ if (cfg.feature_id == NVME_FEAT_HOST_ID && (cfg.cdw11 & 0x1)) @@ -2738,19 +2910,22 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin if (cfg.data_len) { if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { fprintf(stderr, "can not allocate feature payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } memset(buf, 0, cfg.data_len); } err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11, - cfg.data_len, buf, &result); + cfg.uuid_index, cfg.data_len, buf, &result); if (!err) { if (!cfg.raw_binary || !buf) { - printf("get-feature:%#02x (%s), %s value:%#08x\n", cfg.feature_id, - nvme_feature_to_string(cfg.feature_id), - nvme_select_to_string(cfg.sel), result); + printf("get-feature:%#0*x (%s), %s value:%#0*x\n", + cfg.feature_id ? 4 : 2, cfg.feature_id, + nvme_feature_to_string(cfg.feature_id), + nvme_select_to_string(cfg.sel), result ? 10 : 8, + result); if (cfg.sel == 3) nvme_show_select_result(result); else if (cfg.human_readable) @@ -2785,7 +2960,7 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin const char *fw = "firmware file (required)"; const char *xfer = "transfer chunksize limit"; const char *offset = "starting dword offset, default 0"; - int err, fd, fw_fd = -1; + int err = -1, fd, fw_fd = -1; unsigned int fw_size; struct stat sb; void *fw_buf, *buf; @@ -2819,7 +2994,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin if (fw_fd < 0) { fprintf(stderr, "Failed to open firmware file %s: %s\n", cfg.fw, strerror(errno)); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -2832,7 +3008,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin fw_size = sb.st_size; if ((fw_size & 0x3) || (fw_size == 0)) { fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fw_fd; } @@ -2846,7 +3023,8 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin if (!fw_buf) { perror("No memory for f/w size:\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fw_fd; } @@ -2905,7 +3083,8 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin * const char *slot = "[0-7]: firmware slot for commit action"; const char *action = "[0-7]: commit action"; const char *bpid = "[0,1]: boot partition identifier, if applicable (default: 0)"; - int err, fd; + int err = -1, fd; + __u32 result; struct config { __u8 slot; @@ -2932,21 +3111,24 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin * if (cfg.slot > 7) { fprintf(stderr, "invalid slot:%d\n", cfg.slot); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.action > 7 || cfg.action == 4 || cfg.action == 5) { fprintf(stderr, "invalid action:%d\n", cfg.action); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.bpid > 1) { fprintf(stderr, "invalid boot partition id:%d\n", cfg.bpid); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } - err = nvme_fw_commit(fd, cfg.slot, cfg.action, cfg.bpid); + err = nvme_fw_commit(fd, cfg.slot, cfg.action, cfg.bpid, &result); if (err < 0) perror("fw-commit"); else if (err != 0) @@ -2972,6 +3154,16 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin * printf("\n"); } + if (err >= 0) { + printf("Multiple Update Detected (MUD) Value: %u\n", result); + if (result & 0x1) + printf("Detected an overlapping firmware/boot partition image update command "\ + "sequence due to processing a command from a Management Endpoint"); + if ((result >> 1) & 0x1) + printf("Detected an overlapping firmware/boot partition image update command "\ + "sequence due to processing a command from an Admin SQ on a controller"); + } + close_fd: close(fd); ret: @@ -2981,7 +3173,7 @@ ret: static int subsystem_reset(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Resets the NVMe subsystem\n"; - int err, fd; + int err = -1, fd; OPT_ARGS(opts) = { OPT_END() @@ -3008,7 +3200,7 @@ ret: static int reset(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Resets the NVMe controller\n"; - int err, fd; + int err = -1, fd; OPT_ARGS(opts) = { OPT_END() @@ -3059,7 +3251,7 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p const char *sanact_desc = "Sanitize action."; const char *ovrpat_desc = "Overwrite pattern."; - int fd, ret; + int fd, ret = -1; struct config { int no_dealloc; @@ -3101,14 +3293,16 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p break; default: fprintf(stderr, "Invalid Sanitize Action\n"); - ret = -EINVAL; + errno = EINVAL; + ret = -1; goto close_fd; } if (cfg.sanact == NVME_SANITIZE_ACT_EXIT) { if (cfg.ause || cfg.no_dealloc) { fprintf(stderr, "SANACT is Exit Failure Mode\n"); - ret = -EINVAL; + errno = EINVAL; + ret = -1; goto close_fd; } } @@ -3116,13 +3310,15 @@ static int sanitize(int argc, char **argv, struct command *cmd, struct plugin *p if (cfg.sanact == NVME_SANITIZE_ACT_OVERWRITE) { if (cfg.owpass >= 16) { fprintf(stderr, "OWPASS out of range [0-15]\n"); - ret = -EINVAL; + errno = EINVAL; + ret = -1; goto close_fd; } } else { if (cfg.owpass || cfg.oipbp || cfg.ovrpat) { fprintf(stderr, "SANACT is not Overwrite\n"); - ret = -EINVAL; + errno = EINVAL; + ret = -1; goto close_fd; } } @@ -3149,7 +3345,7 @@ static int show_registers(int argc, char **argv, struct command *cmd, struct plu enum nvme_print_flags flags; bool fabrics = true; - int fd, err; + int fd, err = -1; void *bar; struct config { @@ -3207,7 +3403,7 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi const char *offset = "offset of the requested property"; const char *human_readable = "show property in readable format"; - int fd, err; + int fd, err = -1; uint64_t value; struct config { @@ -3232,7 +3428,8 @@ static int get_property(int argc, char **argv, struct command *cmd, struct plugi if (cfg.offset == -1) { fprintf(stderr, "offset required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -3257,7 +3454,7 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi "for NVMe ove Fabric"; const char *offset = "the offset of the property"; const char *value = "the value of the property to be set"; - int fd, err; + int fd, err = -1; struct config { int offset; @@ -3281,12 +3478,14 @@ static int set_property(int argc, char **argv, struct command *cmd, struct plugi if (cfg.offset == -1) { fprintf(stderr, "offset required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.value == -1) { fprintf(stderr, "value required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -3313,7 +3512,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu "data erase) or delete data encryption key if specified. "\ "Can also be used to change LBAF to change the namespaces reported physical block format."; const char *namespace_id = "identifier of desired namespace"; - const char *lbaf = "LBA format to apply (required)"; + const char *lbaf = "[0-63]: LBA format lower (LBAFL) and upper (LBAFU), "\ + "mention directly LBAF format that needs be applied (required)"; const char *ses = "[0-2]: secure erase"; const char *pil = "[0-1]: protection info location last/first 8 bytes of metadata"; const char *pi = "[0-3]: protection info off/Type 1/Type 2/Type 3"; @@ -3324,7 +3524,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command"; struct nvme_id_ns ns; struct nvme_id_ctrl ctrl; - int err, fd, i; + int err = -1, fd, i; int block_size; __u8 prev_lbaf = 0; @@ -3373,7 +3573,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu if (cfg.lbaf != 0xff && cfg.bs !=0) { fprintf(stderr, "Invalid specification of both LBAF and Block Size, please specify only one\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.bs) { @@ -3381,7 +3582,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu fprintf(stderr, "Invalid value for block size (%"PRIu64"), must be a power of two\n", (uint64_t) cfg.bs); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } } @@ -3412,7 +3614,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu "Invalid namespace ID, " "specify a namespace to format or use '-n 0xffffffff' " "to format all namespaces on this controller.\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -3443,7 +3646,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu (uint64_t)cfg.bs); fprintf(stderr, "Please correct block size, or specify LBAF directly\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } } else if (cfg.lbaf == 0xff) @@ -3455,27 +3659,32 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu /* ses & pi checks set to 7 for forward-compatibility */ if (cfg.ses > 7) { fprintf(stderr, "invalid secure erase settings:%d\n", cfg.ses); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } - if (cfg.lbaf > 15) { + if (cfg.lbaf > 63) { fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.pi > 7) { fprintf(stderr, "invalid pi:%d\n", cfg.pi); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.pil > 1) { fprintf(stderr, "invalid pil:%d\n", cfg.pil); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.ms > 1) { fprintf(stderr, "invalid ms:%d\n", cfg.ms); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -3561,12 +3770,11 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin const char *value = "new value of feature (required)"; const char *cdw12 = "feature cdw12, if used"; const char *save = "specifies that the controller shall save the attribute"; - int err; + const char *uuid_index = "specify uuid index"; + int err = -1; __u32 result; void *buf = NULL; int fd, ffd = STDIN_FILENO; - char *endptr = NULL; - uint64_t number = 0; struct config { char *file; @@ -3574,6 +3782,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin __u8 feature_id; __u64 value; __u32 cdw12; + __u8 uuid_index; __u32 data_len; int save; }; @@ -3583,15 +3792,17 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin .namespace_id = 0, .feature_id = 0, .value = 0, + .uuid_index = 0, .data_len = 0, .save = 0, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id), - OPT_LONG("value", 'v', &cfg.value, value), + OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id), + OPT_SUFFIX("value", 'v', &cfg.value, value), OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12), + OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index), OPT_UINT("data-len", 'l', &cfg.data_len, data_len), OPT_FILE("data", 'd', &cfg.file, data), OPT_FLAG("save", 's', &cfg.save, save), @@ -3616,59 +3827,72 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin if (!cfg.feature_id) { fprintf(stderr, "feature-id required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } - cfg.data_len = nvme_feat_buf_len[cfg.feature_id]; + if (cfg.uuid_index > 128) { + fprintf(stderr, "invalid uuid index param: %u\n", cfg.uuid_index); + errno = EINVAL; + err = -1; + goto close_fd; + } + + if (!cfg.data_len) + cfg.data_len = nvme_feat_buf_len[cfg.feature_id]; if (cfg.data_len) { if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { fprintf(stderr, "can not allocate feature payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } memset(buf, 0, cfg.data_len); } if (buf) { - /* if feature ID is 0x0E, get timestamp value by -v option */ - if (NVME_FEAT_TIMESTAMP == cfg.feature_id && cfg.value) { - memcpy(buf, &cfg.value, NVME_FEAT_TIMESTAMP_DATA_SIZE); - } else { - if (strlen(cfg.file)) { - ffd = open(cfg.file, O_RDONLY); - if (ffd <= 0) { - fprintf(stderr, "Failed to open file %s: %s\n", - cfg.file, strerror(errno)); - err = -EINVAL; - goto free; - } - } - err = read(ffd, (void *)buf, cfg.data_len); - if (err < 0) { - err = -errno; - fprintf(stderr, "failed to read data buffer from input" - " file: %s\n", strerror(errno)); - goto close_ffd; - } - /* if feature ID is 0x0E, then change string from file to integer */ - if (NVME_FEAT_TIMESTAMP == cfg.feature_id) { - number = strtoul(buf, &endptr, STRTOUL_AUTO_BASE); - memset(buf, 0, cfg.data_len); - memcpy(buf, &number, NVME_FEAT_TIMESTAMP_DATA_SIZE); - } - } + /* + * Use the '-v' value for the timestamp feature if provided as + * a convenience since it can often fit in 4-bytes. The user + * should use the buffer method if the value exceeds this + * length. + */ + if (NVME_FEAT_TIMESTAMP == cfg.feature_id && cfg.value) { + memcpy(buf, &cfg.value, NVME_FEAT_TIMESTAMP_DATA_SIZE); + } else { + if (strlen(cfg.file)) { + ffd = open(cfg.file, O_RDONLY); + if (ffd <= 0) { + errno = EINVAL; + fprintf(stderr, "Failed to open file %s: %s\n", + cfg.file, strerror(errno)); + err = -1; + goto free; + } + } + + err = read(ffd, (void *)buf, cfg.data_len); + if (err < 0) { + err = -errno; + fprintf(stderr, "failed to read data buffer from input" + " file: %s\n", strerror(errno)); + goto close_ffd; + } + } } err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value, - cfg.cdw12, cfg.save, cfg.data_len, buf, &result); + cfg.cdw12, cfg.save, cfg.uuid_index, cfg.data_len, buf, &result); if (err < 0) { perror("set-feature"); } else if (!err) { - printf("set-feature:%#02x (%s), value:%#08"PRIx64", cdw12:%#08"PRIx32", \ - save:%#x\n", cfg.feature_id, nvme_feature_to_string(cfg.feature_id), - (uint64_t)cfg.value, cfg.cdw12, cfg.save); + printf("set-feature:%#0*x (%s), value:%#0*"PRIx64", cdw12:%#0*x, save:%#x\n", + cfg.feature_id ? 4 : 2, cfg.feature_id, + nvme_feature_to_string(cfg.feature_id), + cfg.value ? 10 : 8, (uint64_t)cfg.value, + cfg.cdw12 ? 10 : 8, cfg.cdw12, cfg.save); if (cfg.feature_id == NVME_LBA_STATUS_INFO) { nvme_show_lba_status_info(result); } @@ -3706,7 +3930,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p const char *tl = "transfer length (cf. SPC-4)"; const char *namespace_id = "desired namespace"; const char *nssf = "NVMe Security Specific Field"; - int err, fd, sec_fd = -1; + int err = -1, fd, sec_fd = -1; void *sec_buf; unsigned int sec_size; @@ -3740,27 +3964,55 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p if (fd < 0) goto ret; + if (cfg.tl == 0) { + fprintf(stderr, "--tl unspecified or zero\n"); + err = -EINVAL; + goto close_fd; + } + sec_fd = open(cfg.file, O_RDONLY); if (sec_fd < 0) { fprintf(stderr, "Failed to open %s: %s\n", cfg.file, strerror(errno)); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } - err = fstat(sec_fd, &sb); - if (err < 0) { - perror("fstat"); - goto close_sec_fd; + if ((cfg.tl & 3) != 0) + fprintf(stderr, "WARNING: --tl not dword aligned; unaligned bytes may be truncated\n"); + + if (strlen(cfg.file) == 0) { + sec_fd = STDIN_FILENO; + sec_size = cfg.tl; + } else { + sec_fd = open(cfg.file, O_RDONLY); + if (sec_fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", + cfg.file, strerror(errno)); + err = -EINVAL; + goto close_fd; + } + + err = fstat(sec_fd, &sb); + if (err < 0) { + perror("fstat"); + goto close_sec_fd; + } + + sec_size = cfg.tl > sb.st_size ? cfg.tl : sb.st_size; } sec_size = sb.st_size; if (posix_memalign(&sec_buf, getpagesize(), sec_size)) { fprintf(stderr, "No memory for security size:%d\n", sec_size); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_sec_fd; } + memset(sec_buf, 0, cfg.tl); // ensure zero fill if cfg.tl > sec_size + err = read(sec_fd, sec_buf, sec_size); if (err < 0) { err = -errno; @@ -3770,7 +4022,7 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p } err = nvme_sec_send(fd, cfg.namespace_id, cfg.nssf, cfg.spsp, cfg.secp, - cfg.tl, sec_size, sec_buf); + cfg.tl, sec_buf); if (err < 0) perror("security-send"); else if (err != 0) @@ -3801,7 +4053,7 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p const char *endir = "directive enable"; const char *ttype = "target directive type to be enabled/disabled"; const char *human_readable = "show directive in readable format"; - int err, fd; + int err = -1, fd; __u32 result; __u32 dw12 = 0; void *buf = NULL; @@ -3854,14 +4106,16 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p case NVME_DIR_SND_ID_OP_ENABLE: if (!cfg.ttype) { fprintf(stderr, "target-dir required param\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } dw12 = cfg.ttype << 8 | cfg.endir; break; default: fprintf(stderr, "invalid directive operations for Identify Directives\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } break; @@ -3872,20 +4126,23 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p break; default: fprintf(stderr, "invalid directive operations for Streams Directives\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } break; default: fprintf(stderr, "invalid directive type\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.data_len) { if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } memset(buf, 0, cfg.data_len); @@ -3897,7 +4154,8 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p if (ffd <= 0) { fprintf(stderr, "Failed to open file %s: %s\n", cfg.file, strerror(errno)); - err = -EINVAL; + errno = EINVAL; + err = -1; goto free; } } @@ -3940,7 +4198,7 @@ ret: static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - int err, fd; + int err = -1, fd; const char *desc = "The Write Uncorrectable command is used to set a "\ "range of logical blocks to invalid."; const char *namespace_id = "desired namespace"; @@ -3995,7 +4253,7 @@ ret: static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - int err, fd; + int err = -1, fd; __u16 control = 0; const char *desc = "The Write Zeroes command is used to set a "\ "range of logical blocks to zero."; @@ -4008,7 +4266,11 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi const char *ref_tag = "reference tag (for end to end PI)"; const char *app_tag_mask = "app tag mask (for end to end PI)"; const char *app_tag = "app tag (for end to end PI)"; + const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ + "(for end to end PI)"; const char *deac = "Set DEAC bit, requesting controller to deallocate specified logical blocks"; + const char *storage_tag_check = "This bit specifies the Storage Tag field shall be checked as "\ + "part of end-to-end data protection processing"; struct config { __u64 start_block; @@ -4018,18 +4280,22 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi __u16 app_tag_mask; __u16 block_count; __u8 prinfo; + __u64 storage_tag; int deac; int limited_retry; int force_unit_access; + int storage_tag_check; }; struct config cfg = { - .start_block = 0, - .block_count = 0, - .prinfo = 0, - .ref_tag = 0, - .app_tag_mask = 0, - .app_tag = 0, + .start_block = 0, + .block_count = 0, + .prinfo = 0, + .ref_tag = 0, + .app_tag_mask = 0, + .app_tag = 0, + .storage_tag = 0, + .storage_tag_check = 0, }; OPT_ARGS(opts) = { @@ -4043,6 +4309,8 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), + OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), OPT_END() }; @@ -4051,7 +4319,9 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi goto ret; if (cfg.prinfo > 0xf) { - err = -EINVAL; + fprintf(stderr, "invalid prinfo: %u\n", cfg.prinfo); + errno = EINVAL; + err = -1; goto close_fd; } @@ -4062,6 +4332,8 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi control |= NVME_RW_FUA; if (cfg.deac) control |= NVME_RW_DEAC; + if (cfg.storage_tag_check) + control |= NVME_RW_STORAGE_TAG_CHECK; if (!cfg.namespace_id) { err = cfg.namespace_id = nvme_get_nsid(fd); if (err < 0) { @@ -4071,7 +4343,7 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi } err = nvme_write_zeros(fd, cfg.namespace_id, cfg.start_block, cfg.block_count, - control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask); + control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, cfg.storage_tag); if (err < 0) perror("write-zeroes"); else if (err != 0) @@ -4100,7 +4372,7 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin const char *idr = "Attribute Integral Dataset for Read"; const char *cdw11 = "All the command DWORD 11 attributes. Use instead of specifying individual attributes"; - int err, fd; + int err = -1, fd; uint16_t nr, nc, nb, ns; int ctx_attrs[256] = {0,}; int nlbs[256] = {0,}; @@ -4151,7 +4423,8 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin nr = max(nc, max(nb, ns)); if (!nr || nr > 256) { fprintf(stderr, "No range definition provided\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4168,7 +4441,8 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin dsm = nvme_setup_dsm_range(ctx_attrs, nlbs, slbas, nr); if (!dsm) { fprintf(stderr, "failed to allocate data set payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -4213,7 +4487,7 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi const char *d_dspec = "directive specific (write part)"; const char *d_format = "source range entry format"; - int err, fd; + int err = -1, fd; uint16_t nr, nb, ns, nrts, natms, nats; int nlbs[128] = { 0 }; unsigned long long slbas[128] = {0,}; @@ -4287,7 +4561,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi nr = max(nb, max(ns, max(nrts, max(natms, nats)))); if (!nr || nr > 128) { fprintf(stderr, "invalid range\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4302,7 +4577,8 @@ static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugi copy = nvme_setup_copy_range(nlbs, slbas, eilbrts, elbatms, elbats, nr); if (!copy) { fprintf(stderr, "failed to allocate payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -4332,14 +4608,14 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug "flushed by the controller, from any namespace, depending on controller and "\ "associated namespace status."; const char *namespace_id = "identifier of desired namespace"; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; }; struct config cfg = { - .namespace_id = NVME_NSID_ALL, + .namespace_id = 0, }; OPT_ARGS(opts) = { @@ -4384,9 +4660,9 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi const char *crkey = "current reservation key"; const char *prkey = "pre-empt reservation key"; const char *rtype = "reservation type"; - const char *racqa = "reservation acquiry action"; + const char *racqa = "reservation acquire action"; const char *iekey = "ignore existing res. key"; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -4407,8 +4683,8 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_LONG("crkey", 'c', &cfg.crkey, crkey), - OPT_LONG("prkey", 'p', &cfg.prkey, prkey), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), + OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey), OPT_BYTE("rtype", 't', &cfg.rtype, rtype), OPT_BYTE("racqa", 'a', &cfg.racqa, racqa), OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), @@ -4428,7 +4704,8 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi } if (cfg.racqa > 7) { fprintf(stderr, "invalid racqa:%d\n", cfg.racqa); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4458,7 +4735,7 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug const char *nrkey = "new reservation key"; const char *rrega = "reservation registration action"; const char *cptpl = "change persistence through power loss setting"; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -4479,8 +4756,8 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_LONG("crkey", 'c', &cfg.crkey, crkey), - OPT_LONG("nrkey", 'k', &cfg.nrkey, nrkey), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), + OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey), OPT_BYTE("rrega", 'r', &cfg.rrega, rrega), OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl), OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), @@ -4500,13 +4777,15 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug } if (cfg.cptpl > 3) { fprintf(stderr, "invalid cptpl:%d\n", cfg.cptpl); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.rrega > 7) { fprintf(stderr, "invalid rrega:%d\n", cfg.rrega); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4540,7 +4819,7 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi const char *iekey = "ignore existing res. key"; const char *rtype = "reservation type"; const char *rrela = "reservation release action"; - int err, fd; + int err = -1, fd; struct config { __u32 namespace_id; @@ -4560,7 +4839,7 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_LONG("crkey", 'c', &cfg.crkey, crkey), + OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey), OPT_BYTE("rtype", 't', &cfg.rtype, rtype), OPT_BYTE("rrela", 'a', &cfg.rrela, rrela), OPT_FLAG("iekey", 'i', &cfg.iekey, iekey), @@ -4580,7 +4859,8 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi } if (cfg.rrela > 7) { fprintf(stderr, "invalid rrela:%d\n", cfg.rrela); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4613,7 +4893,7 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin struct nvme_reservation_status *status; enum nvme_print_flags flags; - int err, fd, size; + int err = -1, fd, size; struct config { __u32 namespace_id; @@ -4666,7 +4946,8 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin if (posix_memalign((void **)&status, getpagesize(), size)) { fprintf(stderr, "No memory for resv report:%d\n", size); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } memset(status, 0, size); @@ -4698,7 +4979,7 @@ static int submit_io(int opcode, char *command, const char *desc, { struct timeval start_time, end_time; void *buffer, *mbuffer = NULL; - int err = 0; + int err = -1; int dfd, mfd, fd; int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT; int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH; @@ -4710,6 +4991,7 @@ static int submit_io(int opcode, char *command, const char *desc, struct nvme_id_ns ns; __u8 lba_index, ms = 0; + const char *namespace_id = "desired namespace"; const char *start_block = "64-bit addr of first block to access"; const char *block_count = "number of blocks (zeroes based) on device to access"; const char *data_size = "size of data in bytes"; @@ -4728,8 +5010,13 @@ static int submit_io(int opcode, char *command, const char *desc, const char *dtype = "directive type (for write-only)"; const char *dspec = "directive specific (for write-only)"; const char *dsm = "dataset management attributes (lower 16 bits)"; + const char *storage_tag_check = "This bit specifies the Storage Tag field shall be " \ + "checked as part of end-to-end data protection processing"; + const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ + "(for end to end PI)"; struct config { + __u32 namespace_id; __u64 start_block; __u16 block_count; __u64 data_size; @@ -4743,27 +5030,33 @@ static int submit_io(int opcode, char *command, const char *desc, __u16 dsmgmt; __u16 app_tag_mask; __u16 app_tag; + __u64 storage_tag; int limited_retry; int force_unit_access; + int storage_tag_check; int show; int dry_run; int latency; }; struct config cfg = { - .start_block = 0, - .block_count = 0, - .data_size = 0, - .metadata_size = 0, - .ref_tag = 0, - .data = "", - .metadata = "", - .prinfo = 0, - .app_tag_mask = 0, - .app_tag = 0, + .namespace_id = 0, + .start_block = 0, + .block_count = 0, + .data_size = 0, + .metadata_size = 0, + .ref_tag = 0, + .data = "", + .metadata = "", + .prinfo = 0, + .app_tag_mask = 0, + .app_tag = 0, + .storage_tag_check = 0, + .storage_tag = 0, }; OPT_ARGS(opts) = { + OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block), OPT_SHRT("block-count", 'c', &cfg.block_count, block_count), OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size), @@ -4774,8 +5067,10 @@ static int submit_io(int opcode, char *command, const char *desc, OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), + OPT_SUFFIX("storage-tag", 'g', &cfg.storage_tag, storage_tag), OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry), OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype), OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec), OPT_SHRT("dsm", 'D', &cfg.dsmgmt, dsm), @@ -4789,9 +5084,18 @@ static int submit_io(int opcode, char *command, const char *desc, if (fd < 0) goto ret; + if (!cfg.namespace_id) { + err = cfg.namespace_id = nvme_get_nsid(fd); + if (err < 0) { + perror("get-namespace-id"); + goto close_fd; + } + } + dfd = mfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO; if (cfg.prinfo > 0xf) { - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -4801,11 +5105,14 @@ static int submit_io(int opcode, char *command, const char *desc, control |= NVME_RW_LR; if (cfg.force_unit_access) control |= NVME_RW_FUA; + if (cfg.storage_tag_check) + control |= NVME_RW_STORAGE_TAG_CHECK; if (cfg.dtype) { if (cfg.dtype > 0xf) { fprintf(stderr, "Invalid directive type, %x\n", cfg.dtype); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } control |= cfg.dtype << 4; @@ -4816,7 +5123,8 @@ static int submit_io(int opcode, char *command, const char *desc, dfd = open(cfg.data, flags, mode); if (dfd < 0) { perror(cfg.data); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } mfd = dfd; @@ -4825,19 +5133,26 @@ static int submit_io(int opcode, char *command, const char *desc, mfd = open(cfg.metadata, flags, mode); if (mfd < 0) { perror(cfg.metadata); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_dfd; } } if (!cfg.data_size) { fprintf(stderr, "data size not provided\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_mfd; } - if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) - goto close_mfd; + if (is_ns_chardev()) { + logical_block_size = + nvme_logical_block_size_from_ns_char(devicename); + } else { + if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) + goto close_mfd; + } buffer_size = (cfg.block_count + 1) * logical_block_size; if (cfg.data_size < buffer_size) { @@ -4850,7 +5165,8 @@ static int submit_io(int opcode, char *command, const char *desc, buffer = nvme_alloc(buffer_size, &huge); if (!buffer) { perror("can not allocate io payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_mfd; } @@ -4880,7 +5196,8 @@ static int submit_io(int opcode, char *command, const char *desc, mbuffer = malloc(mbuffer_size); if (!mbuffer) { perror("can not allocate buf for io metadata payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto free_buffer; } memset(mbuffer, 0, mbuffer_size); @@ -4907,24 +5224,27 @@ static int submit_io(int opcode, char *command, const char *desc, } if (cfg.show) { - printf("opcode : %02x\n", opcode); - printf("flags : %02x\n", 0); - printf("control : %04x\n", control); - printf("nblocks : %04x\n", cfg.block_count); - printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer); - printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer); - printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block); - printf("dsmgmt : %08x\n", dsmgmt); - printf("reftag : %08x\n", cfg.ref_tag); - printf("apptag : %04x\n", cfg.app_tag); - printf("appmask : %04x\n", cfg.app_tag_mask); + printf("opcode : %02x\n", opcode); + printf("nsid : %02x\n", cfg.namespace_id); + printf("control : %04x\n", control); + printf("nblocks : %04x\n", cfg.block_count); + printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer); + printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer); + printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block); + printf("dsmgmt : %08x\n", dsmgmt); + printf("reftag : %08x\n", cfg.ref_tag); + printf("apptag : %04x\n", cfg.app_tag); + printf("appmask : %04x\n", cfg.app_tag_mask); + printf("storagetagcheck : %04x\n", cfg.storage_tag_check); + printf("storagetag : %"PRIx64"\n", (uint64_t)cfg.storage_tag); } if (cfg.dry_run) goto free_mbuffer; gettimeofday(&start_time, NULL); - err = nvme_io(fd, opcode, cfg.start_block, cfg.block_count, control, dsmgmt, - cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, buffer, mbuffer); + err = nvme_io(fd, opcode, cfg.namespace_id, cfg.start_block, cfg.block_count, + control, dsmgmt, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, + cfg.storage_tag, buffer, mbuffer); gettimeofday(&end_time, NULL); if (cfg.latency) printf(" latency: %s: %llu us\n", @@ -4937,12 +5257,14 @@ static int submit_io(int opcode, char *command, const char *desc, if (!(opcode & 1) && write(dfd, (void *)buffer, cfg.data_size) < 0) { fprintf(stderr, "write: %s: failed to write buffer to output file\n", strerror(errno)); - err = -EINVAL; + errno = EINVAL; + err = -1; } else if (!(opcode & 1) && cfg.metadata_size && write(mfd, (void *)mbuffer, mbuffer_size) < 0) { fprintf(stderr, "write: %s: failed to write meta-data buffer to output file\n", strerror(errno)); - err = -EINVAL; + errno = EINVAL; + err = -1; } else fprintf(stderr, "%s: Success\n", command); } @@ -4987,7 +5309,7 @@ static int write_cmd(int argc, char **argv, struct command *cmd, struct plugin * static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - int err, fd; + int err = -1, fd; __u16 control = 0; const char *desc = "Verify specified logical blocks on the given device."; const char *namespace_id = "desired namespace"; @@ -4999,6 +5321,10 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin const char *ref_tag = "reference tag (for end to end PI)"; const char *app_tag_mask = "app tag mask (for end to end PI)"; const char *app_tag = "app tag (for end to end PI)"; + const char *storage_tag = "storage tag, CDW2 and CDW3 (00:47) bits "\ + "(for end to end PI)"; + const char *storage_tag_check = "This bit specifies the Storage Tag field shall "\ + "be checked as part of Verify operation"; struct config { __u64 start_block; @@ -5008,6 +5334,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin __u16 app_tag_mask; __u16 block_count; __u8 prinfo; + __u64 storage_tag; + int storage_tag_check; int limited_retry; int force_unit_access; }; @@ -5022,6 +5350,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin .app_tag_mask = 0, .limited_retry = 0, .force_unit_access = 0, + .storage_tag = 0, + .storage_tag_check = 0, }; OPT_ARGS(opts) = { @@ -5034,15 +5364,19 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag), OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag), OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask), + OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag), + OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check), OPT_END() }; err = fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) - goto err; + goto ret; if (cfg.prinfo > 0xf) { - err = EINVAL; + fprintf(stderr, "invalid 'prinfo' param:%u\n", cfg.prinfo); + errno = EINVAL; + err = -1; goto close_fd; } @@ -5051,6 +5385,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin control |= NVME_RW_LR; if (cfg.force_unit_access) control |= NVME_RW_FUA; + if (cfg.storage_tag_check) + control |= NVME_RW_STORAGE_TAG_CHECK; if (!cfg.namespace_id) { err = cfg.namespace_id = nvme_get_nsid(fd); @@ -5061,7 +5397,7 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin } err = nvme_verify(fd, cfg.namespace_id, cfg.start_block, cfg.block_count, - control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask); + control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, cfg.storage_tag); if (err < 0) perror("verify"); else if (err != 0) @@ -5071,8 +5407,8 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin close_fd: close(fd); -err: - return err; +ret: + return nvme_status_to_errno(err, false);; } static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin) @@ -5090,7 +5426,7 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p const char *raw = "dump output in binary format"; const char *namespace_id = "desired namespace"; const char *nssf = "NVMe Security Specific Field"; - int err, fd; + int err = -1, fd; void *sec_buf = NULL; struct config { @@ -5129,7 +5465,8 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p if (posix_memalign(&sec_buf, getpagesize(), cfg.size)) { fprintf(stderr, "No memory for security size:%d\n", cfg.size); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } } @@ -5165,7 +5502,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, " logical block addressed by this command"; const char *mndw = "Maximum Number of Dwords(MNDW) specifies maximum"\ " number of dwords to return"; - const char *atype = "Action Type(ATYPE) specifies the mechanism the"\ + const char *atype = "Action Type(ATYPE) specifies the mechanism"\ " the controller uses in determining the LBA"\ " Status Descriptors to return."; const char *rl = "Range Length(RL) specifies the length of the range"\ @@ -5174,7 +5511,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, enum nvme_print_flags flags; unsigned long buf_len; - int err, fd; + int err = -1, fd; void *buf; struct config { @@ -5218,7 +5555,8 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, if (!cfg.atype) { fprintf(stderr, "action type (--action) has to be given\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } @@ -5226,7 +5564,8 @@ static int get_lba_status(int argc, char **argv, struct command *cmd, buf = calloc(1, buf_len); if (!buf) { perror("could not alloc memory for get lba status"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } @@ -5245,6 +5584,75 @@ err: return nvme_status_to_errno(err, false); } +static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Host software uses the Capacity Management command to "\ + "configure Endurance Groups and NVM Sets in an NVM subsystem by either " \ + "selecting one of a set of supported configurations or by specifying the "\ + "capacity of the Endurance Group or NVM Set to be created"; + const char *operation = "Operation to be performed by the controller"; + const char *element_id = "Value specific to the value of the Operation field."; + const char *cap_lower = "Least significant 32 bits of the capacity in bytes of the "\ + "Endurance Group or NVM Set to be created"; + const char *cap_upper = "Most significant 32 bits of the capacity in bytes of the "\ + "Endurance Group or NVM Set to be created"; + + int err = -1, fd; + __u32 result; + + struct config { + __u8 operation; + __u16 element_id; + __u32 dw11; + __u32 dw12; + }; + + struct config cfg = { + .operation = 0xff, + .element_id = 0xffff, + .dw11 = 0, + .dw12 = 0, + }; + + OPT_ARGS(opts) = { + OPT_BYTE("operation", 'o', &cfg.operation, operation), + OPT_SHRT("element-id", 'i', &cfg.element_id, element_id), + OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower), + OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper), + OPT_END() + }; + + err = fd = parse_and_open(argc, argv, desc, opts); + if (fd < 0) + goto ret; + + if (cfg.operation > 0xf) { + fprintf(stderr, "invalid operation field: %u\n", cfg.operation); + errno = EINVAL; + err = -1; + goto close_fd; + } + + err = nvme_cap_mgmt(fd, cfg.operation, cfg.element_id, cfg.dw11, + cfg.dw12, &result); + if (!err) { + printf("Capacity Management Command is Success\n"); + if (cfg.operation == 1) { + printf("Created Element Identifier for Endurance Group is: %u\n", result); + } else if (cfg.operation == 3) { + printf("Created Element Identifier for NVM Set is: %u\n", result); + } + } else if (err > 0) + nvme_show_status(err); + else if (err < 0) + perror("capacity management"); + +close_fd: + close(fd); +ret: + return nvme_status_to_errno(err, false); +} + static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Read directive parameters of the "\ @@ -5259,7 +5667,7 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin const char *human_readable = "show directive in readable format"; enum nvme_print_flags flags = NORMAL; - int err, fd; + int err = -1, fd; __u32 result; __u32 dw12 = 0; void *buf = NULL; @@ -5314,7 +5722,8 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin break; default: fprintf(stderr, "invalid directive operations for Identify Directives\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } break; @@ -5333,19 +5742,22 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin break; default: fprintf(stderr, "invalid directive operations for Streams Directives\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } break; default: fprintf(stderr, "invalid directive type\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } if (cfg.data_len) { if (posix_memalign(&buf, getpagesize(), cfg.data_len)) { - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_fd; } memset(buf, 0, cfg.data_len); @@ -5401,11 +5813,14 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, const char *re = "set dataflow direction to receive"; const char *wr = "set dataflow direction to send"; const char *prefill = "prefill buffers with known byte-value, default 0"; + const char *latency = "output latency statistics"; + void *data = NULL, *metadata = NULL; - int err = 0, wfd = STDIN_FILENO, fd; + int err = -1, wfd = STDIN_FILENO, fd; __u32 result; bool huge; const char *cmd_name = NULL; + struct timeval start_time, end_time; struct config { __u8 opcode; @@ -5430,6 +5845,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, int read; int write; __u8 prefill; + int latency; }; struct config cfg = { @@ -5475,6 +5891,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, OPT_FLAG("dry-run", 'd', &cfg.dry_run, dry), OPT_FLAG("read", 'r', &cfg.read, re), OPT_FLAG("write", 'w', &cfg.write, wr), + OPT_FLAG("latency", 'T', &cfg.latency, latency), OPT_END() }; @@ -5487,7 +5904,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, S_IRUSR | S_IRGRP | S_IROTH); if (wfd < 0) { perror(cfg.input_file); - err = -EINVAL; + errno = EINVAL; + err = -1; goto close_fd; } } @@ -5496,7 +5914,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, metadata = malloc(cfg.metadata_len); if (!metadata) { perror("can not allocate metadata payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto close_wfd; } memset(metadata, cfg.prefill, cfg.metadata_len); @@ -5505,7 +5924,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, data = nvme_alloc(cfg.data_len, &huge); if (!data) { perror("can not allocate data payload\n"); - err = -ENOMEM; + errno = ENOMEM; + err = -1; goto free_metadata; } @@ -5520,7 +5940,8 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, memset(data, cfg.prefill, cfg.data_len); if (!cfg.read && !cfg.write) { fprintf(stderr, "data direction not given\n"); - err = -EINVAL; + errno = EINVAL; + err = -1; goto free_data; } else if (cfg.write) { if (read(wfd, data, cfg.data_len) < 0) { @@ -5554,17 +5975,27 @@ static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type, if (cfg.dry_run) goto free_data; + gettimeofday(&start_time, NULL); + err = nvme_passthru(fd, ioctl_cmd, cfg.opcode, cfg.flags, cfg.rsvd, cfg.namespace_id, cfg.cdw2, cfg.cdw3, cfg.cdw10, cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, cfg.cdw15, cfg.data_len, data, cfg.metadata_len, metadata, cfg.timeout, &result); + + gettimeofday(&end_time, NULL); + cmd_name = nvme_cmd_to_string(cmd_type, cfg.opcode); + if (cfg.latency) + printf("%s Command %s latency: %llu us\n", + cmd_type ? "Admin": "IO", + strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific", + elapsed_utime(start_time, end_time)); + if (err < 0) perror("passthru"); else if (err) nvme_show_status(err); else { - cmd_name = nvme_cmd_to_string(cmd_type, cfg.opcode); fprintf(stderr, "%s Command %s is Success and result: 0x%08x\n", cmd_type ? "Admin": "IO", strcmp(cmd_name, "Unknown") ? cmd_name: "Vendor Specific", diff --git a/nvme.h b/nvme.h index e33094d..5150c8d 100644 --- a/nvme.h +++ b/nvme.h @@ -82,6 +82,7 @@ struct nvme_ctrl { char *traddr; char *trsvcid; char *host_traddr; + char *host_iface; char *hostnqn; char *hostid; @@ -120,6 +121,7 @@ enum nvme_print_flags validate_output_format(const char *format); int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root)); char *nvme_char_from_block(char *block); +int nvme_logical_block_size_from_ns_char(const char *dev); void *mmap_registers(const char *dev); extern int current_index; @@ -144,4 +146,11 @@ int uuid_from_systemd(char *uuid); unsigned long long elapsed_utime(struct timeval start_time, struct timeval end_time); + +static inline void nvme_strip_spaces(char *s, int l) +{ + while (l && (s[l] == '\0' || s[l] == ' ')) + s[l--] = '\0'; +} + #endif /* _NVME_H */ diff --git a/nvmf-autoconnect/systemd/nvmf-autoconnect.service b/nvmf-autoconnect/systemd/nvmf-autoconnect.service index 2690467..b1be272 100644 --- a/nvmf-autoconnect/systemd/nvmf-autoconnect.service +++ b/nvmf-autoconnect/systemd/nvmf-autoconnect.service @@ -1,11 +1,12 @@ [Unit] Description=Connect NVMe-oF subsystems automatically during boot ConditionPathExists=/etc/nvme/discovery.conf -After=network.target +After=network-online.target Before=remote-fs-pre.target [Service] Type=oneshot +ExecStartPre=/sbin/modprobe nvme-fabrics ExecStart=/usr/sbin/nvme connect-all [Install] diff --git a/plugin.c b/plugin.c index c7d6b2e..78f03ab 100644 --- a/plugin.c +++ b/plugin.c @@ -11,7 +11,7 @@ static int version(struct plugin *plugin) struct program *prog = plugin->parent; if (plugin->name) - printf("%s %s version %s\n", prog->name, plugin->name, prog->version); + printf("%s %s version %s\n", prog->name, plugin->name, plugin->version); else printf("%s version %s\n", prog->name, prog->version); return 0; diff --git a/plugin.h b/plugin.h index 91079fb..7a8ed09 100644 --- a/plugin.h +++ b/plugin.h @@ -16,6 +16,7 @@ struct program { struct plugin { const char *name; const char *desc; + const char *version; struct command **commands; struct program *parent; struct plugin *next; diff --git a/plugins/amzn/amzn-nvme.h b/plugins/amzn/amzn-nvme.h index 9b8d797..f969c0e 100644 --- a/plugins/amzn/amzn-nvme.h +++ b/plugins/amzn/amzn-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("amzn", "Amazon vendor specific extensions"), +PLUGIN(NAME("amzn", "Amazon vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ) diff --git a/plugins/dera/dera-nvme.h b/plugins/dera/dera-nvme.h index dc54fab..d3a8b0b 100644 --- a/plugins/dera/dera-nvme.h +++ b/plugins/dera/dera-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("dera", "Dera vendor specific extensions"), +PLUGIN(NAME("dera", "Dera vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Dera SMART Log, show it", get_status, "stat") ) diff --git a/plugins/huawei/huawei-nvme.h b/plugins/huawei/huawei-nvme.h index 7aac90c..175ddd5 100644 --- a/plugins/huawei/huawei-nvme.h +++ b/plugins/huawei/huawei-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("huawei", "Huawei vendor specific extensions"), +PLUGIN(NAME("huawei", "Huawei vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("list", "List all Huawei NVMe devices and namespaces on machine", huawei_list) ENTRY("id-ctrl", "Huawei identify controller", huawei_id_ctrl) diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c index 27b065d..aaa40ad 100644 --- a/plugins/intel/intel-nvme.c +++ b/plugins/intel/intel-nvme.c @@ -454,7 +454,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct struct intel_temp_stats stats; int err, fd; - const char *desc = "Get Intel Marketing Name log and show it."; + const char *desc = "Get Temperature Statistics log and show it."; const char *raw = "dump output in binary format"; struct config { int raw_binary; @@ -1065,7 +1065,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct __u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0}; __u32 result; - err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0, + err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0, 0, sizeof(thresholds), thresholds, &result); if (err) { fprintf(stderr, "Quering thresholds failed. NVMe Status:%s(%x)\n", @@ -1542,7 +1542,7 @@ static int enable_lat_stats_tracking(int argc, char **argv, return fd; switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf, + err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, &result); if (!err) { printf( @@ -1555,7 +1555,7 @@ static int enable_lat_stats_tracking(int argc, char **argv, break; case True: case False: - err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, + err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, data_len, buf, &result); if (err > 0) { fprintf(stderr, "NVMe Status:%s(%x)\n", @@ -1636,7 +1636,7 @@ static int set_lat_stats_thresholds(int argc, char **argv, } err = nvme_set_feature(fd, nsid, fid, cfg.write ? 0x1 : 0x0, - cdw12, save, OPTANE_V1000_BUCKET_LEN, + cdw12, save, 0, OPTANE_V1000_BUCKET_LEN, thresholds, &result); if (err > 0) { diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h index b119004..af1231a 100644 --- a/plugins/intel/intel-nvme.h +++ b/plugins/intel/intel-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("intel", "Intel vendor specific extensions"), +PLUGIN(NAME("intel", "Intel vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ENTRY("internal-log", "Retrieve Intel internal firmware log, save it", get_internal_log) diff --git a/plugins/lnvm/lnvm-nvme.h b/plugins/lnvm/lnvm-nvme.h index 45b3cf0..18dffe1 100644 --- a/plugins/lnvm/lnvm-nvme.h +++ b/plugins/lnvm/lnvm-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" -PLUGIN(NAME("lnvm", "LightNVM specific extensions"), +PLUGIN(NAME("lnvm", "LightNVM specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("list", "List available LightNVM devices", lnvm_list) ENTRY("info", "List general information and available target engines", lnvm_info) diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c index d330835..e3807f1 100644 --- a/plugins/memblaze/memblaze-nvme.c +++ b/plugins/memblaze/memblaze-nvme.c @@ -503,7 +503,7 @@ static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; - err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, NULL, &result); + err = nvme_get_feature(fd, 0, feature_id, 0, 0, 0, 0, NULL, &result); if (err < 0) { perror("get-feature"); } @@ -545,7 +545,7 @@ static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -602,7 +602,7 @@ static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, s } cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2; - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -1038,7 +1038,7 @@ static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, - err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, NULL, &result); + err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, cfg.save, 0, 0, NULL, &result); if (err < 0) { perror("set-feature"); } @@ -1115,7 +1115,7 @@ static int mb_set_lat_stats(int argc, char **argv, return fd; switch (option) { case None: - err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf, + err = nvme_get_feature(fd, nsid, fid, sel, cdw11, 0, data_len, buf, &result); if (!err) { printf( @@ -1128,7 +1128,7 @@ static int mb_set_lat_stats(int argc, char **argv, break; case True: case False: - err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, + err = nvme_set_feature(fd, nsid, fid, option, cdw12, save, 0, data_len, buf, &result); if (err > 0) { fprintf(stderr, "NVMe Status:%s(%x)\n", diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h index 043d0a8..6f10bd7 100644 --- a/plugins/memblaze/memblaze-nvme.h +++ b/plugins/memblaze/memblaze-nvme.h @@ -12,7 +12,7 @@ #include #include -PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"), +PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", mb_get_additional_smart_log) ENTRY("get-pm-status", "Get Memblaze Power Manager Status", mb_get_powermanager_status) diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index f76c015..840682d 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -11,6 +11,7 @@ #include #include "nvme.h" #include "nvme-print.h" +#include "nvme-status.h" #include "nvme-ioctl.h" #include #include @@ -38,7 +39,7 @@ /* Plugin version major_number.minor_number.patch */ static const char *__version_major = "1"; static const char *__version_minor = "0"; -static const char *__version_patch = "5"; +static const char *__version_patch = "6"; /* supported models of micron plugin; new models should be added at the end * before UNKNOWN_MODEL. Make sure M5410 is first in the list ! @@ -626,7 +627,7 @@ static int micron_smbus_option(int argc, char **argv, if (!strcmp(opt.option, "enable")) { cdw11 = opt.value << 1 | 1; - err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, &result); + err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); if (err == 0) { printf("successfully enabled SMBus on drive\n"); } else { @@ -635,7 +636,7 @@ static int micron_smbus_option(int argc, char **argv, } else if (!strcmp(opt.option, "status")) { cdw10 = opt.value; - err = nvme_get_feature(fd, 1, fid, cdw10, 0, 0, 0, &result); + err = nvme_get_feature(fd, 1, fid, cdw10, 0, 0, 0, 0, &result); if (err == 0) { printf("SMBus status on the drive: %s (returns %s temperature) \n", (result & 1) ? "enabled" : "disabled", @@ -646,7 +647,7 @@ static int micron_smbus_option(int argc, char **argv, } else if (!strcmp(opt.option, "disable")) { cdw11 = opt.value << 1 | 0; - err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, &result); + err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, 0, &result); if (err == 0) { printf("Successfully disabled SMBus on drive\n"); } else { @@ -932,9 +933,11 @@ static int micron_clear_pcie_correctable_errors(int argc, char **argv, /* For M51CX models, PCIe errors are cleared using 0xC3 feature */ if (model == M51CX) { - err = nvme_set_feature(fd, 0, fid, (1 << 31), 0, 0, 0, 0, &result); + err = nvme_set_feature(fd, 0, fid, (1 << 31), 0, 0, 0, 0, 0, &result); if (err == 0 && (err = (int)result) == 0) printf("Device correctable errors cleared!\n"); + else if (err > 0) + nvme_show_status(err); else printf("Error clearing Device correctable errors = 0x%x\n", err); goto out; @@ -1056,11 +1059,12 @@ static void init_d0_log_page(__u8 *buf, __u8 nsze) /* OCP and Vendor specific log data format */ struct micron_vs_logpage { char *field; - int size; + int size; /* FB client spec version 1.0 sizes - M5410 models */ + int size2; /* FB client spec version 0.7 sizes - M5407 models */ } -/* Smart Health Log information as per OCP spec */ +/* Smart Health Log information as per OCP spec M51CX models */ ocp_c0_log_page[] = { - { "Physical Media Units Written", 16 }, + { "Physical Media Units Written", 16}, { "Physical Media Units Read", 16 }, { "Raw Bad User NAND Block Count", 6}, { "Normalized Bad User NAND Block Count", 2}, @@ -1096,43 +1100,56 @@ ocp_c0_log_page[] = { }, /* Vendor Specific Health Log information */ fb_log_page[] = { - { "Physical Media Units Written - TLC", 16 }, - { "Physical Media Units Written - SLC", 16 }, - { "Normalized Bad User NAND Block Count", 2}, - { "Raw Bad User NAND Block Count", 6}, - { "XOR Recovery Count", 8}, - { "Uncorrectable Read Error Count", 8}, - { "SSD End to End Corrected Errors", 8}, - { "SSD End to End Detected Counts", 4}, - { "SSD End to End Uncorrected Counts", 4}, - { "System data % life-used", 1}, - { "Minimum User Data Erase Count - TLC", 8}, - { "Maximum User Data Erase Count - TLC", 8}, - { "Minimum User Data Erase Count - SLC", 8}, - { "Maximum User Data Erase Count - SLC", 8}, - { "Normalized Program Fail Count", 2}, - { "Raw Program Fail Count", 6}, - { "Normalized Erase Fail Count", 2}, - { "Raw Erase Fail Count", 6}, - { "Pcie Correctable Error Count", 8}, - { "% Free Blocks (User)", 1}, - { "Security Version Number", 8}, - { "% Free Blocks (System)", 1}, - { "Dataset Management (Deallocate) Commands", 16}, - { "Incomplete TRIM Data", 8}, - { "% Age of Completed TRIM", 1}, - { "Background Back-Pressure Gauge", 1}, - { "Soft ECC Error Count", 8}, - { "Refresh Count", 8}, - { "Normalized Bad System NAND Block Count", 2}, - { "Raw Bad System NAND Block Count", 6}, - { "Endurance Estimate", 16}, - { "Thermal Throttling Count", 1}, - { "Thermal Throttling Status", 1}, - { "Unaligned I/O", 8}, - { "Physical Media Units Read", 16}, - { "Reserved", 279}, - { "Log Page Version", 2} + { "Physical Media Units Written - TLC", 16, 16 }, + { "Physical Media Units Written - SLC", 16, 16 }, + { "Normalized Bad User NAND Block Count", 2, 2}, + { "Raw Bad User NAND Block Count", 6, 6}, + { "XOR Recovery Count", 8, 8}, + { "Uncorrectable Read Error Count", 8, 8}, + { "SSD End to End Corrected Errors", 8, 8}, + { "SSD End to End Detected Counts", 4, 8}, + { "SSD End to End Uncorrected Counts", 4, 8}, + { "System data % life-used", 1, 1}, + { "Reserved", 0, 3}, + { "Minimum User Data Erase Count - TLC", 8, 8}, + { "Maximum User Data Erase Count - TLC", 8, 8}, + { "Average User Data Erase Count - TLC", 0, 8}, + { "Minimum User Data Erase Count - SLC", 8, 8}, + { "Maximum User Data Erase Count - SLC", 8, 8}, + { "Average User Data Erase Count - SLC", 0, 8}, + { "Normalized Program Fail Count", 2, 2}, + { "Raw Program Fail Count", 6, 6}, + { "Normalized Erase Fail Count", 2, 2}, + { "Raw Erase Fail Count", 6, 6}, + { "Pcie Correctable Error Count", 8, 8}, + { "% Free Blocks (User)", 1, 1}, + { "Reserved", 0, 3}, + { "Security Version Number", 8, 8}, + { "% Free Blocks (System)", 1, 1}, + { "Reserved", 0, 3}, + { "Dataset Management (Deallocate) Commands", 16, 16}, + { "Incomplete TRIM Data", 8, 8}, + { "% Age of Completed TRIM", 1, 2}, + { "Background Back-Pressure Gauge", 1, 1}, + { "Reserved", 0, 3}, + { "Soft ECC Error Count", 8, 8}, + { "Refresh Count", 8, 8}, + { "Normalized Bad System NAND Block Count", 2, 2}, + { "Raw Bad System NAND Block Count", 6, 6}, + { "Endurance Estimate", 16, 16}, + { "Thermal Throttling Count", 1, 1}, + { "Thermal Throttling Status", 1, 1}, + { "Unaligned I/O", 8, 8}, + { "Physical Media Units Read", 16, 16}, + { "Reserved", 279, 0}, + { "Log Page Version", 2, 0}, + { "READ CMDs exceeding threshold", 0, 4}, + { "WRITE CMDs exceeding threshold", 0, 4}, + { "TRIMs CMDs exceeding threshold", 0, 4}, + { "Reserved", 0, 4}, + { "Reserved", 0, 210}, + { "Log Page Version", 0, 2}, + { "Log Page GUID", 0, 16}, }; /* Common function to print Micron VS log pages */ @@ -1140,66 +1157,70 @@ static void print_micron_vs_logs( __u8 *buf, /* raw log data */ struct micron_vs_logpage *log_page, /* format of the data */ int field_count, /* log field count */ - struct json_object *stats /* json object to add fields */ + struct json_object *stats, /* json object to add fields */ + __u8 spec /* ocp spec index */ ) { __u64 lval_lo, lval_hi; __u32 ival; __u16 sval; __u8 cval, lval[8] = { 0 }; - int field, guid_index; + int field; int offset = 0; for (field = 0; field < field_count; field++) { char datastr[1024] = { 0 }; - if (log_page[field].size == 16) { - if (strstr(log_page[field].field, "GUID")) { - char *tmpstr = datastr; - tmpstr += sprintf(datastr, "0x"); - for(guid_index = 0; guid_index < 16; guid_index++) - tmpstr += sprintf(tmpstr, "%01X", buf[offset + guid_index]); + char *sfield = NULL; + int size = (spec == 0) ? log_page[field].size : log_page[field].size2; + if (size == 0) continue; + sfield = log_page[field].field; + if (size == 16) { + if (strstr(sfield, "GUID")) { + sprintf(datastr, "0x%"PRIx64"%"PRIx64"", + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])), + (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset]))); } else { lval_lo = *((__u64 *)(&buf[offset])); lval_hi = *((__u64 *)(&buf[offset + 8])); if (lval_hi) - sprintf(datastr, "0x%"PRIx64"_%"PRIx64"", + sprintf(datastr, "0x%"PRIx64"%016"PRIx64"", le64_to_cpu(lval_hi), le64_to_cpu(lval_lo)); else sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); } - } else if (log_page[field].size == 8) { + } else if (size == 8) { lval_lo = *((__u64 *)(&buf[offset])); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 7) { + } else if (size == 7) { /* 7 bytes will be in little-endian format, with last byte as MSB */ memcpy(&lval[0], &buf[offset], 7); memcpy((void *)&lval_lo, lval, 8); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 6) { + } else if (size == 6) { ival = *((__u32 *)(&buf[offset])); sval = *((__u16 *)(&buf[offset + 4])); lval_lo = (((__u64)sval << 32) | ival); sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); - } else if (log_page[field].size == 4) { + } else if (size == 4) { ival = *((__u32 *)(&buf[offset])); sprintf(datastr, "0x%x", le32_to_cpu(ival)); - } else if (log_page[field].size == 2) { + } else if (size == 2) { sval = *((__u16 *)(&buf[offset])); sprintf(datastr, "0x%04x", le16_to_cpu(sval)); - } else if (log_page[field].size == 1) { + } else if (size == 1) { cval = buf[offset]; sprintf(datastr, "0x%02x", cval); } else { sprintf(datastr, "0"); } - offset += log_page[field].size; + offset += size; /* do not print reserved values */ - if (strstr(log_page[field].field, "Reserved")) + if (strstr(sfield, "Reserved")) continue; if (stats != NULL) { - json_object_add_value_string(stats, log_page[field].field, datastr); + json_object_add_value_string(stats, sfield, datastr); } else { - printf("%-40s : %-4s\n", log_page[field].field, datastr); + printf("%-40s : %-4s\n", sfield, datastr); } } } @@ -1219,7 +1240,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json) logPages); } - print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats); + print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats, 0); if (is_json) { json_array_add_value_object(logPages, stats); @@ -1229,7 +1250,7 @@ static void print_smart_cloud_health_log(__u8 *buf, bool is_json) } } -static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json) +static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, __u8 spec) { struct json_object *root; struct json_object *logPages; @@ -1244,20 +1265,22 @@ static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json) logPages); } - print_micron_vs_logs(buf, fb_log_page, field_count, stats); + print_micron_vs_logs(buf, fb_log_page, field_count, stats, spec); /* print last three entries from D0 log page */ - init_d0_log_page(buf2, nsze); + if (buf2 != NULL) { + init_d0_log_page(buf2, nsze); - if (is_json) { - for (int i = 4; i < 7; i++) { - json_object_add_value_string(stats, - d0_log_page[i].field, - d0_log_page[i].datastr); - } - } else { - for (int i = 4; i < 7; i++) { - printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + if (is_json) { + for (int i = 0; i < 7; i++) { + json_object_add_value_string(stats, + d0_log_page[i].field, + d0_log_page[i].datastr); + } + } else { + for (int i = 0; i < 7; i++) { + printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr); + } } } @@ -1337,14 +1360,16 @@ static int micron_nand_stats(int argc, char **argv, is_json = false; err = nvme_identify_ctrl(fd, &ctrl); - if (err) + if (err) { + printf("Error %d retrieving controller identification data\n", err); goto out; + } /* pull log details based on the model name */ sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { printf ("Unsupported drive model for vs-nand-stats command\n"); - close(fd); + err = -1; goto out; } @@ -1353,27 +1378,29 @@ static int micron_nand_stats(int argc, char **argv, has_d0_log = (0 == err); /* should check for firmware version if this log is supported or not */ - if (eModel == M5407 || eModel == M5410) { + if (eModel != M5407 && eModel != M5410) { err = nvme_get_log(fd, NVME_NSID_ALL, 0xFB, false, NVME_NO_LOG_LSP, FB_log_size, logFB); has_fb_log = (0 == err); } nsze = (ctrl.vs[987] == 0x12); + if (nsze == 0 && nsze_from_oacs) nsze = ((ctrl.oacs >> 3) & 0x1); - err = 0; - if (has_fb_log) - print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json); - else if (has_d0_log) + + if (has_fb_log) { + __u8 spec = (eModel == M5410) ? 0 : 1; /* FB spec version */ + print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec); + } else if (has_d0_log) { print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json); - else { - printf("Unable to retrieve extended smart log for the drive\n"); - err = -ENOTTY; + err = 0; } out: close(fd); - return err; + if (err > 0) + nvme_show_status(err); + return nvme_status_to_errno(err, false); } @@ -1483,6 +1510,62 @@ static void GetErrorlogData(int fd, int entries, const char *dir) free(error_log); } +static void GetGenericLogs(int fd, const char *dir) +{ + struct nvme_self_test_log self_test_log; + struct nvme_firmware_log_page fw_log; + struct nvme_effects_log_page effects; + struct nvme_persistent_event_log_head pevent_log_head; + void *pevent_log_info = NULL; + __u32 log_len = 0; + int err = 0 ; + bool huge = false; + + /* get self test log */ + if (nvme_self_test_log(fd, sizeof(self_test_log), &self_test_log) == 0) { + WriteData((__u8*)&self_test_log, sizeof(self_test_log), dir, + "drive_self_test.bin", "self test log"); + } + + /* get fw slot info log */ + if (nvme_fw_log(fd, &fw_log) == 0) { + WriteData((__u8*)&fw_log, sizeof(fw_log), dir, + "firmware_slot_info_log.bin", "firmware log"); + } + + /* get effects log */ + if (nvme_effects_log(fd, &effects) == 0) { + WriteData((__u8*)&effects, sizeof(effects), dir, + "command_effects_log.bin", "effects log"); + } + + /* get persistent event log */ + (void)nvme_persistent_event_log(fd, NVME_PEVENT_LOG_RELEASE_CTX, + sizeof(pevent_log_head), &pevent_log_head); + memset(&pevent_log_head, 0, sizeof(pevent_log_head)); + err = nvme_persistent_event_log(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ, + sizeof(pevent_log_head), &pevent_log_head); + if (err) { + fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n"); + return; + } + + log_len = le64_to_cpu(pevent_log_head.tll); + pevent_log_info = nvme_alloc(log_len, &huge); + if (!pevent_log_info) { + perror("could not alloc buffer for persistent event log page (ignored)!\n"); + return; + } + err = nvme_persistent_event_log(fd, NVME_PEVENT_LOG_READ, + log_len, pevent_log_info); + if (err == 0) { + WriteData((__u8*)pevent_log_info, log_len, dir, + "persistent_event_log.bin", "persistent event log"); + } + nvme_free(pevent_log_info, huge); + return; +} + static void GetNSIDDInfo(int fd, const char *dir, int nsid) { char file[PATH_MAX] = { 0 }; @@ -1537,14 +1620,14 @@ static void GetOSConfig(const char *strOSDirName) static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, int *logSize, int da) { - int err; + int err, bs = 512, offset = bs; unsigned short data_area[4]; unsigned char ctrl_init = (type == 0x8); - __u8 *buffer = (unsigned char *)calloc(512, 1); + __u8 *buffer = (unsigned char *)calloc(bs, 1); if (buffer == NULL) return -1; - err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, 512, 0); + err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, bs, 0); if (err != 0) { fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type); if (buffer != NULL) { @@ -1553,10 +1636,10 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, return err; } - // compute size of the log - data_area[1] = buffer[9] << 16 | buffer[8]; - data_area[2] = buffer[11] << 16 | buffer[10]; - data_area[3] = buffer[13] << 16 | buffer[12]; + /* compute size of the log */ + data_area[1] = buffer[9] << 8 | buffer[8]; + data_area[2] = buffer[11] << 8 | buffer[10]; + data_area[3] = buffer[13] << 8 | buffer[12]; data_area[0] = data_area[1] > data_area[2] ? data_area[1] : data_area[2]; data_area[0] = data_area[3] > data_area[0] ? data_area[3] : data_area[0]; @@ -1569,9 +1652,14 @@ static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data, return -1; } - *logSize = data_area[da] * 512; + *logSize = data_area[da] * bs; + offset = bs; + err = 0; if ((buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize))) != NULL) { - err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, *logSize, 0); + while (err == 0 && offset != *logSize) { + err = nvme_get_telemetry_log(fd, buffer + offset, gen, ctrl_init, bs, offset); + offset += bs; + } } if (err == 0 && buffer != NULL) { @@ -1594,12 +1682,13 @@ static int GetTelemetryData(int fd, const char *dir) __u8 log; char *file; } tmap[] = { - {0x07, "nvme_host_telemetry.bin"}, - {0x08, "nvme_cntrl_telemetry.bin"}, + {0x07, "nvmetelemetrylog.bin"}, + {0x08, "nvmetelemetrylog.bin"}, }; for(i = 0; i < (int)(sizeof(tmap)/sizeof(tmap[0])); i++) { - err = micron_telemetry_log(fd, 0, tmap[i].log, &buffer, &logSize, 0); + err = micron_telemetry_log(fd, (tmap[i].log == 0x07), + tmap[i].log, &buffer, &logSize, 0); if (err == 0 && logSize > 0 && buffer != NULL) { sprintf(msg, "telemetry log: 0x%X", tmap[i].log); WriteData(buffer, logSize, dir, tmap[i].file, msg); @@ -1646,7 +1735,7 @@ static int GetFeatureSettings(int fd, const char *dir) bufp = NULL; } - err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, len, bufp, &attrVal); + err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, 0, len, bufp, &attrVal); if (err == 0) { sprintf(msg, "feature: 0x%X", fmap[i].id); WriteData((__u8*)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg); @@ -1654,7 +1743,8 @@ static int GetFeatureSettings(int fd, const char *dir) WriteData(bufp, len, dir, fmap[i].file, msg); } } else { - printf("Failed to retrieve feature 0x%x data !\n", fmap[i].id); + fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n", + fmap[i].id, err); errcnt++; } } @@ -1667,20 +1757,98 @@ static int micron_drive_info(int argc, char **argv, struct command *cmd, const char *desc = "Get drive HW information"; int fd, err = 0; struct nvme_id_ctrl ctrl = { 0 }; + struct nvme_admin_cmd admin_cmd = { 0 }; + struct fb_drive_info { + unsigned char hw_ver_major; + unsigned char hw_ver_minor; + unsigned char ftl_unit_size; + unsigned char bs_ver_major; + unsigned char bs_ver_minor; + } dinfo = { 0 }; + eDriveModel model = UNKNOWN_MODEL; + bool is_json = false; + struct json_object *root, *driveInfo; + struct format { + char *fmt; + }; + + const char *fmt = "output format normal"; + struct format cfg = { + .fmt = "normal", + }; + OPT_ARGS(opts) = { + OPT_FMT("format", 'f', &cfg.fmt, fmt), OPT_END() }; - if ((fd = micron_parse_options(argc, argv, desc, opts, NULL)) < 0) + if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) return err; - err = nvme_identify_ctrl(fd, &ctrl); - if (err) { - fprintf(stderr, "ERROR : nvme_identify_ctrl() failed with 0x%x\n", err); + if (model == UNKNOWN_MODEL) { + fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd"); return -1; } - printf("%u.%u\n", ctrl.vs[820], ctrl.vs[821]); + if (strcmp(cfg.fmt, "json") == 0) + is_json = true; + + if (model == M5407) { + admin_cmd.opcode = 0xDA, + admin_cmd.addr = (__u64) (uintptr_t) &dinfo; + admin_cmd.data_len = (__u32)sizeof(dinfo); + admin_cmd.cdw12 = 3; + err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &admin_cmd); + if (err) { + fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err); + return -1; + } + } else { + err = nvme_identify_ctrl(fd, &ctrl); + if (err) { + fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err); + return -1; + } + dinfo.hw_ver_major = ctrl.vs[820]; + dinfo.hw_ver_minor = ctrl.vs[821]; + } + + if (is_json) { + struct json_object *pinfo = json_create_object(); + char tempstr[64] = { 0 }; + root = json_create_object(); + driveInfo = json_create_array(); + json_object_add_value_array(root, "Micron Drive HW Information", driveInfo); + sprintf(tempstr, "%hhu.%hhu", dinfo.hw_ver_major, dinfo.hw_ver_minor); + json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr); + + if (dinfo.ftl_unit_size) { + sprintf(tempstr, "%hhu KB", dinfo.ftl_unit_size); + json_object_add_value_string(pinfo, "FTL_unit_size", tempstr); + } + + if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { + sprintf(tempstr, "%hhu.%hhu", dinfo.bs_ver_major, dinfo.bs_ver_minor); + json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr); + } + + json_array_add_value_object(driveInfo, pinfo); + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); + } else { + printf("Drive Hardware Version: %hhu.%hhu\n", + dinfo.hw_ver_major, dinfo.hw_ver_minor); + + if (dinfo.ftl_unit_size) + printf("FTL_unit_size: %hhu KB\n", dinfo.ftl_unit_size); + + if (dinfo.bs_ver_major != 0 || dinfo.bs_ver_minor != 0) { + printf("Boot Spec.Version: %hhu.%hhu\n", + dinfo.bs_ver_major, dinfo.bs_ver_minor); + } + } + return 0; } @@ -1825,8 +1993,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c int count = 0; unsigned int logC2[C2_log_size/sizeof(int)] = { 0 }; eDriveModel eModel = UNKNOWN_MODEL; - struct nvme_id_ctrl ctrl; - int fd, err, ctrlIdx; + int fd, err; struct format { char *fmt; }; @@ -1841,9 +2008,7 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c OPT_END() }; - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) { - printf("\nDevice not found \n");; + if ((fd = micron_parse_options(argc, argv, desc, opts, &eModel)) < 0) { return -1; } @@ -1853,16 +2018,8 @@ static int micron_fw_activation_history(int argc, char **argv, struct command *c return -1; } - err = nvme_identify_ctrl(fd, &ctrl); - if (err) { - fprintf(stderr, "failed get device identification data, error: %x\n", err); - goto out; - } - /* check if product supports fw_history log */ err = -EINVAL; - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - eModel = GetDriveModel(ctrlIdx); if (eModel != M51CX) { fprintf(stderr, "Unsupported drive model for vs-fw-activate-history command\n"); goto out; @@ -1916,18 +2073,19 @@ static int micron_error_reason(int argc, char **argv, struct command *cmd, static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *cmd, struct plugin *plugin) { - const char *desc = "Retrieve Micron OCP Smart Health log for the given device "; + const char *desc = "Retrieve Smart or Extended Smart Health log for the given device "; unsigned int logC0[C0_log_size/sizeof(int)] = { 0 }; - eDriveModel eModel = UNKNOWN_MODEL; + unsigned int logFB[FB_log_size/sizeof(int)] = { 0 }; struct nvme_id_ctrl ctrl; - int fd, err, ctrlIdx; - bool is_json = false; + eDriveModel eModel = UNKNOWN_MODEL; + int fd, err = 0; + bool is_json = true; struct format { char *fmt; }; const char *fmt = "output format normal|json"; struct format cfg = { - .fmt = "normal", + .fmt = "json", }; OPT_ARGS(opts) = { @@ -1935,41 +2093,53 @@ static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *c OPT_END() }; - fd = parse_and_open(argc, argv, desc, opts); - if (fd < 0) { - printf("\nDevice not found \n");; + if ((fd = micron_parse_options(argc, argv, desc, opts, &eModel)) < 0) { return -1; } - if (strcmp(cfg.fmt, "json") == 0) - is_json = true; + if (strcmp(cfg.fmt, "normal") == 0) + is_json = false; - err = nvme_identify_ctrl(fd, &ctrl); - if (err) + /* For M5410 and M5407, this option prints 0xFB log page */ + if (eModel == M5410 || eModel == M5407) { + __u8 spec = (eModel == M5410) ? 0 : 1; + __u8 nsze; + + if ((err = nvme_identify_ctrl(fd, &ctrl)) == 0) + err = nvme_get_log(fd, NVME_NSID_ALL, 0xFB, false, NVME_NO_LOG_LSP, + FB_log_size, logFB); + if (err) { + if (err < 0) + printf("Unable to retrieve smart log 0xFB for the drive\n"); + goto out; + } + + nsze = (ctrl.vs[987] == 0x12); + if (nsze == 0 && nsze_from_oacs) + nsze = ((ctrl.oacs >> 3) & 0x1); + print_nand_stats_fb((__u8 *)logFB, NULL, nsze, is_json, spec); goto out; + } - /* pull log details based on the model name */ - sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx); - if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) { + /* check for models that support 0xC0 log */ + if (eModel != M51CX) { printf ("Unsupported drive model for vs-smart-add-log commmand\n"); - close(fd); + err = -1; goto out; } - /* should check for firmware version if this log is supported or not */ - if (eModel == M5407 || eModel == M5410) { - err = nvme_get_log(fd, NVME_NSID_ALL, 0xC0, false, NVME_NO_LOG_LSP, - C0_log_size, logC0); - } - if (err < 0) { - printf("Unable to retrieve extended smart log for the drive\n"); - err = -ENOTTY; - } else { + err = nvme_get_log(fd, NVME_NSID_ALL, 0xC0, false, NVME_NO_LOG_LSP, + C0_log_size, logC0); + if (err == 0) { print_smart_cloud_health_log((__u8 *)logC0, is_json); + } else if (err < 0) { + printf("Unable to retrieve extended smart log 0xC0 for the drive\n"); } out: close(fd); - return err; + if (err > 0) + nvme_show_status(err); + return nvme_status_to_errno(err, false); } static int micron_clr_fw_activation_history(int argc, char **argv, @@ -1994,7 +2164,7 @@ static int micron_clr_fw_activation_history(int argc, char **argv, } //err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, &result); - err = nvme_set_feature(fd, 1, fid, 0, 0, 0, 0, 0, &result); + err = nvme_set_feature(fd, 1, fid, 0, 0, 0, 0, 0, 0, &result); if (err == 0) err = (int)result; return err; } @@ -2040,14 +2210,14 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, } if (!strcmp(opt.option, "enable")) { - err = nvme_set_feature(fd, 1, fid, 1, 0, (opt.select & 0x1), 0, 0, &result); + err = nvme_set_feature(fd, 1, fid, 1, 0, (opt.select & 0x1), 0, 0, 0, &result); if (err == 0) { printf("successfully set controller telemetry option\n"); } else { printf("Failed to set controller telemetry option\n"); } } else if (!strcmp(opt.option, "disable")) { - err = nvme_set_feature(fd, 1, fid, 0, 0, (opt.select & 0x1), 0, 0, &result); + err = nvme_set_feature(fd, 1, fid, 0, 0, (opt.select & 0x1), 0, 0, 0, &result); if (err == 0) { printf("successfully disabled controller telemetry option\n"); } else { @@ -2055,7 +2225,7 @@ static int micron_telemetry_cntrl_option(int argc, char **argv, } } else if (!strcmp(opt.option, "status")) { opt.select &= 0x3; - err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, &result); + err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, 0, &result); if (err == 0) { printf("Controller telemetry option : %s\n", (result) ? "enabled" : "disabled"); @@ -2249,6 +2419,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, GetSmartlogData(fd, strCtrlDirName); GetErrorlogData(fd, ctrl.elpe, strCtrlDirName); + GetGenericLogs(fd, strCtrlDirName); // pull if telemetry log data is supported if ((ctrl.lpa & 0x8) == 0x8) @@ -2256,7 +2427,7 @@ static int micron_internal_logs(int argc, char **argv, struct command *cmd, GetFeatureSettings(fd, strCtrlDirName); - if (eModel != M5410) { + if (eModel != M5410 && eModel != M5407) { memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs)); if (eModel == M51AX) memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs)); diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h index 118f8cd..be80544 100644 --- a/plugins/micron/micron-nvme.h +++ b/plugins/micron/micron-nvme.h @@ -6,8 +6,9 @@ #include "cmd.h" -PLUGIN(NAME("micron", "Micron vendor specific extensions"), - COMMAND_LIST(ENTRY("select-download", "Selective Firmware Download", micron_selective_download) +PLUGIN(NAME("micron", "Micron vendor specific extensions", NVME_VERSION), + COMMAND_LIST( + ENTRY("select-download", "Selective Firmware Download", micron_selective_download) ENTRY("vs-temperature-stats", "Retrieve Micron temperature statistics ", micron_temp_stats) ENTRY("vs-pcie-stats", "Retrieve Micron PCIe error stats", micron_pcie_stats) ENTRY("clear-pcie-correctable-errors", "Clear correctable PCIe errors", micron_clear_pcie_correctable_errors) diff --git a/plugins/netapp/netapp-nvme.h b/plugins/netapp/netapp-nvme.h index d4eebd6..2599db0 100644 --- a/plugins/netapp/netapp-nvme.h +++ b/plugins/netapp/netapp-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("netapp", "NetApp vendor specific extensions"), +PLUGIN(NAME("netapp", "NetApp vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smdevices", "NetApp SMdevices", netapp_smdevices) ENTRY("ontapdevices", "NetApp ONTAPdevices", netapp_ontapdevices) diff --git a/plugins/nvidia/nvidia-nvme.h b/plugins/nvidia/nvidia-nvme.h index bf562b9..74a20b8 100644 --- a/plugins/nvidia/nvidia-nvme.h +++ b/plugins/nvidia/nvidia-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions"), +PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl) ) diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h index 8f14501..fde5ba3 100644 --- a/plugins/scaleflux/sfx-nvme.h +++ b/plugins/scaleflux/sfx-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions"), +PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve ScaleFlux SMART Log, show it", get_additional_smart_log) ENTRY("lat-stats", "Retrieve ScaleFlux IO Latency Statistics log, show it", get_lat_stats_log) diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c index d5ef32b..9512cda 100644 --- a/plugins/seagate/seagate-nvme.c +++ b/plugins/seagate/seagate-nvme.c @@ -1051,7 +1051,7 @@ static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *c fd = parse_and_open(argc, argv, desc, opts); - err = nvme_set_feature(fd, 0, 0xE1, 0xCB, 0, cfg.save, 0, buf, &result); + err = nvme_set_feature(fd, 0, 0xE1, 0xCB, 0, cfg.save, 0, 0, buf, &result); if (err < 0) { perror("set-feature"); diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h index f570697..a4989f1 100644 --- a/plugins/seagate/seagate-nvme.h +++ b/plugins/seagate/seagate-nvme.h @@ -27,7 +27,7 @@ #include "cmd.h" -PLUGIN(NAME("seagate", "Seagate vendor specific extensions"), +PLUGIN(NAME("seagate", "Seagate vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("vs-temperature-stats", "Retrieve Seagate temperature statistics ", temp_stats) ENTRY("vs-log-page-sup", "Retrieve Seagate Supported Log-pages Information ", log_pages_supp) diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c index 588f4f3..1909e45 100644 --- a/plugins/shannon/shannon-nvme.c +++ b/plugins/shannon/shannon-nvme.c @@ -231,7 +231,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st memset(buf, 0, cfg.data_len); } - err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11, + err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11, 0, cfg.data_len, buf, &result); if (!err) { printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id, @@ -344,7 +344,7 @@ static int set_additional_feature(int argc, char **argv, struct command *cmd, st } err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value, - 0, cfg.save, cfg.data_len, buf, &result); + 0, cfg.save, 0, cfg.data_len, buf, &result); if (err < 0) { perror("set-feature"); goto free; diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h index d40732e..db25828 100644 --- a/plugins/shannon/shannon-nvme.h +++ b/plugins/shannon/shannon-nvme.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("shannon", "Shannon vendor specific extensions"), +PLUGIN(NAME("shannon", "Shannon vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Shannon SMART Log, show it", get_additional_smart_log) ENTRY("get-feature-add", "Get Shannon feature and show the resulting value", get_additional_feature) diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c index 53d54bc..cba1af8 100644 --- a/plugins/toshiba/toshiba-nvme.c +++ b/plugins/toshiba/toshiba-nvme.c @@ -551,7 +551,7 @@ static int clear_correctable_errors(int argc, char **argv, struct command *cmd, goto end; err = nvme_set_feature(fd, namespace_id, feature_id, value, cdw12, save, - 0, NULL, &result); + 0, 0, NULL, &result); if (err) fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n", __func__); diff --git a/plugins/toshiba/toshiba-nvme.h b/plugins/toshiba/toshiba-nvme.h index c405e78..ebd7575 100644 --- a/plugins/toshiba/toshiba-nvme.h +++ b/plugins/toshiba/toshiba-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" #include "plugin.h" -PLUGIN(NAME("toshiba", "Toshiba NVME plugin"), +PLUGIN(NAME("toshiba", "Toshiba NVME plugin", NVME_VERSION), COMMAND_LIST( ENTRY("vs-smart-add-log", "Extended SMART information", vendor_log) ENTRY("vs-internal-log", "Get Internal Log", internal_log) diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h index 14d62ec..317793a 100644 --- a/plugins/transcend/transcend-nvme.h +++ b/plugins/transcend/transcend-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" -PLUGIN(NAME("transcend", "Transcend vendor specific extensions"), +PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("healthvalue", "NVME health percentage", getHealthValue) ENTRY("badblock", "Get NVME bad block number", getBadblock) diff --git a/plugins/virtium/virtium-nvme.h b/plugins/virtium/virtium-nvme.h index b95c910..124ab18 100644 --- a/plugins/virtium/virtium-nvme.h +++ b/plugins/virtium/virtium-nvme.h @@ -7,7 +7,7 @@ #include "cmd.h" #include "plugin.h" -PLUGIN(NAME("virtium", "Virtium vendor specific extensions"), +PLUGIN(NAME("virtium", "Virtium vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("save-smart-to-vtview-log", "Periodically save smart attributes into a log file.\n\ The data in this log file can be analyzed using excel or using Virtium’s vtView.\n\ diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c index f7a5b31..4468344 100644 --- a/plugins/wdc/wdc-nvme.c +++ b/plugins/wdc/wdc-nvme.c @@ -79,6 +79,8 @@ #define WDC_NVME_SN650_DEV_ID_1 0x2701 #define WDC_NVME_SN650_DEV_ID_2 0x2702 #define WDC_NVME_SN650_DEV_ID_3 0x2720 +#define WDC_NVME_SN450_DEV_ID_1 0x2712 +#define WDC_NVME_SN450_DEV_ID_2 0x2713 #define WDC_NVME_SXSLCL_DEV_ID 0x2001 #define WDC_NVME_SN520_DEV_ID 0x5003 #define WDC_NVME_SN520_DEV_ID_1 0x5004 @@ -125,6 +127,7 @@ #define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000 #define WDC_SN730B_CAP_VUC_LOG 0x0000000400000000 #define WDC_DRIVE_CAP_DUI 0x0000000800000000 +#define WDC_DRIVE_CAP_PURGE 0x0000001000000000 #define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C0_LOG_PAGE | WDC_DRIVE_CAP_C1_LOG_PAGE | \ WDC_DRIVE_CAP_CA_LOG_PAGE | WDC_DRIVE_CAP_D0_LOG_PAGE) #define WDC_DRIVE_CAP_CLEAR_PCIE_MASK (WDC_DRIVE_CAP_CLEAR_PCIE | \ @@ -954,7 +957,7 @@ struct __attribute__((__packed__)) wdc_fw_act_history_log_format_c2 { __u8 log_identifier; __u8 reserved[3]; __le32 num_entries; - struct wdc_fw_act_history_log_entry_c2 entry[20]; + struct wdc_fw_act_history_log_entry_c2 entry[WDC_MAX_NUM_ACT_HIST_ENTRIES]; __u8 reserved2[2790]; __le16 log_page_version; __u8 log_page_guid[WDC_C2_GUID_LENGTH]; @@ -1181,11 +1184,13 @@ static __u64 wdc_get_drive_capabilities(int fd) { switch (read_device_id) { case WDC_NVME_SN100_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_C1_LOG_PAGE | - WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); + WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | + WDC_DRIVE_CAP_PURGE); break; case WDC_NVME_SN200_DEV_ID: capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE | - WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP); + WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP | + WDC_DRIVE_CAP_PURGE); /* verify the 0xCA log page is supported */ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true) @@ -1287,6 +1292,8 @@ static __u64 wdc_get_drive_capabilities(int fd) { case WDC_NVME_SN650_DEV_ID_1: case WDC_NVME_SN650_DEV_ID_2: case WDC_NVME_SN650_DEV_ID_3: + case WDC_NVME_SN450_DEV_ID_1: + case WDC_NVME_SN450_DEV_ID_2: /* verify the 0xC0 log page is supported */ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE) == true) { capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE; @@ -1614,7 +1621,7 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) memset(data, 0, sizeof (__u8) * WDC_C2_LOG_BUF_LEN); /* get the log page length */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, WDC_C2_LOG_BUF_LEN, data); + ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, WDC_C2_LOG_BUF_LEN, data); if (ret) { fprintf(stderr, "ERROR : WDC : Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret); goto end; @@ -1633,7 +1640,7 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) } /* get the log page data */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, le32_to_cpu(hdr_ptr->length), data); + ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, le32_to_cpu(hdr_ptr->length), data); if (ret) { fprintf(stderr, "ERROR : WDC : Unable to read 0x%x Log Page data, ret = 0x%x\n", lid, ret); goto end; @@ -1652,7 +1659,7 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data) /* not found with uuid = 1 try with uuid = 0 */ uuid_ix = 0; /* get the log page data */ - ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, le32_to_cpu(hdr_ptr->length), data); + ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, 0, false, le32_to_cpu(hdr_ptr->length), data); hdr_ptr = (struct wdc_c2_log_page_header *)data; sph = (struct wdc_c2_log_subpage_header *)(data + length); found = wdc_get_dev_mng_log_entry(hdr_ptr->length, log_id, hdr_ptr, &sph); @@ -1980,7 +1987,7 @@ static int wdc_do_cap_telemetry_log(int fd, char *file, __u32 bs, int type, int } else if (type == WDC_TELEMETRY_TYPE_CONTROLLER) { /* Verify the Controller Initiated Option is enabled */ err = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, - 4, buf, &result); + 0, 4, buf, &result); if (err == 0) { if (result == 0) { /* enabled */ @@ -3263,15 +3270,12 @@ static int wdc_purge(int argc, char **argv, char *err_str; int fd, ret; struct nvme_passthru_cmd admin_cmd; + __u64 capabilities = 0; OPT_ARGS(opts) = { OPT_END() }; - err_str = ""; - memset(&admin_cmd, 0, sizeof (admin_cmd)); - admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; - fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; @@ -3279,23 +3283,33 @@ static int wdc_purge(int argc, char **argv, if (!wdc_check_device(fd)) return -1; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - if (ret > 0) { - switch (ret) { - case WDC_NVME_PURGE_CMD_SEQ_ERR: - err_str = "ERROR : WDC : Cannot execute purge, " - "Purge operation is in progress.\n"; - break; - case WDC_NVME_PURGE_INT_DEV_ERR: - err_str = "ERROR : WDC : Internal Device Error.\n"; - break; - default: - err_str = "ERROR : WDC\n"; + capabilities = wdc_get_drive_capabilities(fd); + if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { + ret = -1; + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + } else { + err_str = ""; + memset(&admin_cmd, 0, sizeof (admin_cmd)); + admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE; + + ret = nvme_submit_admin_passthru(fd, &admin_cmd); + if (ret > 0) { + switch (ret) { + case WDC_NVME_PURGE_CMD_SEQ_ERR: + err_str = "ERROR : WDC : Cannot execute purge, " + "Purge operation is in progress.\n"; + break; + case WDC_NVME_PURGE_INT_DEV_ERR: + err_str = "ERROR : WDC : Internal Device Error.\n"; + break; + default: + err_str = "ERROR : WDC\n"; + } } - } - fprintf(stderr, "%s", err_str); - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + fprintf(stderr, "%s", err_str); + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + } return ret; } @@ -3308,19 +3322,12 @@ static int wdc_purge_monitor(int argc, char **argv, double progress_percent; struct nvme_passthru_cmd admin_cmd; struct wdc_nvme_purge_monitor_data *mon; + __u64 capabilities = 0; OPT_ARGS(opts) = { OPT_END() }; - memset(output, 0, sizeof (output)); - memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); - admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE; - admin_cmd.addr = (__u64)(uintptr_t)output; - admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN; - admin_cmd.cdw10 = WDC_NVME_PURGE_MONITOR_CMD_CDW10; - admin_cmd.timeout_ms = WDC_NVME_PURGE_MONITOR_TIMEOUT; - fd = parse_and_open(argc, argv, desc, opts); if (fd < 0) return fd; @@ -3328,20 +3335,34 @@ static int wdc_purge_monitor(int argc, char **argv, if (!wdc_check_device(fd)) return -1; - ret = nvme_submit_admin_passthru(fd, &admin_cmd); - if (ret == 0) { - mon = (struct wdc_nvme_purge_monitor_data *) output; - printf("Purge state = 0x%0x\n", admin_cmd.result); - printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result)); - if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) { - progress_percent = - ((double)le32_to_cpu(mon->entire_progress_current) * 100) / - le32_to_cpu(mon->entire_progress_total); - printf("Purge Progress = %f%%\n", progress_percent); + capabilities = wdc_get_drive_capabilities(fd); + if((capabilities & WDC_DRIVE_CAP_PURGE) == 0) { + ret = -1; + fprintf(stderr, "ERROR : WDC: unsupported device for this command\n"); + } else { + memset(output, 0, sizeof (output)); + memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd)); + admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE; + admin_cmd.addr = (__u64)(uintptr_t)output; + admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN; + admin_cmd.cdw10 = WDC_NVME_PURGE_MONITOR_CMD_CDW10; + admin_cmd.timeout_ms = WDC_NVME_PURGE_MONITOR_TIMEOUT; + + ret = nvme_submit_admin_passthru(fd, &admin_cmd); + if (ret == 0) { + mon = (struct wdc_nvme_purge_monitor_data *) output; + printf("Purge state = 0x%0x\n", admin_cmd.result); + printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result)); + if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) { + progress_percent = + ((double)le32_to_cpu(mon->entire_progress_current) * 100) / + le32_to_cpu(mon->entire_progress_total); + printf("Purge Progress = %f%%\n", progress_percent); + } } - } - fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); + } return ret; } @@ -4006,9 +4027,9 @@ static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin) } -static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id) +static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) { - int i; + int i, j; char previous_fw[9]; char new_fw[9]; char commit_action_bin[8]; @@ -4019,7 +4040,7 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u if (data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) { printf(" Firmware Activate History Log \n"); - if (cust_id == WDC_CUSTOMER_ID_0x1005) { + if (cust_id == WDC_CUSTOMER_ID_0x1005 || vendor_id == WDC_NVME_SNDK_VID) { printf(" Power on Hour Power Cycle Previous New \n"); printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); @@ -4028,14 +4049,16 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf(" Entry Timestamp Count Firmware Firmware Slot Action Result \n"); printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n"); } + struct wdc_fw_act_history_log_format_c2 *fw_act_history_entry = (struct wdc_fw_act_history_log_format_c2 *)(data); if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { + j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) > - le16_to_cpu(fw_act_history_entry->entry[i+1].fw_act_hist_entries)) { - oldestEntryIdx = i+1; + le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; break; } } @@ -4066,6 +4089,14 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u printf("%s", time_str); printf(" "); + } else if(vendor_id == WDC_NVME_SNDK_VID) { + printf(" "); + uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + memset((void *)time_str, 0, 9); + sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), + (int)((timestamp/1000)%60)); + printf("%s", time_str); + printf(" "); } else { printf(" "); uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); @@ -4161,10 +4192,10 @@ static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u } } -static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id) +static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id, __u32 vendor_id) { struct json_object *root; - int i; + int i, j; char previous_fw[9]; char new_fw[9]; char commit_action_bin[8]; @@ -4186,9 +4217,10 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) { /* find lowest/oldest entry */ for (i = 0; i < num_entries; i++) { + j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1; if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) > - le16_to_cpu(fw_act_history_entry->entry[i+1].fw_act_hist_entries)) { - oldestEntryIdx = i+1; + le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) { + oldestEntryIdx = j; break; } } @@ -4215,6 +4247,11 @@ static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 json_object_add_value_string(root, "Power on Hour", time_str); + } else if (vendor_id == WDC_NVME_SNDK_VID) { + uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); + sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60), + (int)((timestamp/1000)%60)); + json_object_add_value_string(root, "Power on Hour", time_str); } else { uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)); json_object_add_value_int(root, "Timestamp", timestamp); @@ -4369,7 +4406,7 @@ static void wdc_print_smart_cloud_attr_C0_normal(void *data) smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]); printf(" Log page version %"PRIu16"\n",smart_log_ver); printf(" Log page GUID 0x"); - printf("%lX%lX\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + printf("0x%"PRIx64"%"PRIx64"\n",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); if(smart_log_ver > 2) { printf(" Errata Version Field %d\n", @@ -4451,9 +4488,8 @@ static void wdc_print_smart_cloud_attr_C0_json(void *data) json_object_add_value_uint(root, "Log page version", smart_log_ver); char guid[40]; memset((void*)guid, 0, 40); - sprintf((char*)guid, "0x%lX%lX",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), + sprintf((char*)guid, "0x%"PRIx64"%"PRIx64"",(uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]), (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG])); - printf("GUID string:%s", guid); json_object_add_value_string(root, "Log page GUID", guid); if(smart_log_ver > 2){ json_object_add_value_uint(root, "Errata Version Field", @@ -4605,7 +4641,7 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index) /* Get the 0xC0 log data */ ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); @@ -4652,7 +4688,7 @@ static int wdc_get_c0_log_page(int fd, char *format, int uuid_index) /* Get the 0xC0 log data */ ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, WDC_NVME_EOL_STATUS_LOG_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_EOL_STATUS_LOG_LEN, data); if (strcmp(format, "json")) fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); @@ -4783,7 +4819,7 @@ static int wdc_print_d0_log(struct wdc_ssd_d0_smart_log *perf, int fmt) return 0; } -static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id) +static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id, __u32 vendor_id) { if (!data) { fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n"); @@ -4792,10 +4828,10 @@ static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __ switch (fmt) { case NORMAL: - wdc_print_fw_act_history_log_normal(data, num_entries, cust_id); + wdc_print_fw_act_history_log_normal(data, num_entries, cust_id, vendor_id); break; case JSON: - wdc_print_fw_act_history_log_json(data, num_entries, cust_id); + wdc_print_fw_act_history_log_json(data, num_entries, cust_id, vendor_id); break; } return 0; @@ -5200,7 +5236,7 @@ static int wdc_do_clear_pcie_correctable_errors_fid(int fd) __u32 value = 1 << 31; /* Bit 31 - clear PCIe correctable count */ ret = nvme_set_feature(fd, 0, WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID, value, - 0, 0, 0, NULL, &result); + 0, 0, 0, 0, NULL, &result); fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); return ret; @@ -5448,7 +5484,7 @@ static int wdc_get_fw_act_history(int fd, char *format) fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data); if ((fw_act_history_hdr->num_entries > 0) && (fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) - ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt, 0); + ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries, fmt, 0, 0); else if (fw_act_history_hdr->num_entries == 0) { fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); ret = 0; @@ -5473,7 +5509,8 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) __u8 *data; __u32 *cust_id; struct wdc_fw_act_history_log_format_c2 *fw_act_history_log; - __u32 num_entries = 0; + __u32 tot_entries = 0, num_entries = 0; + __u32 vendor_id = 0, device_id = 0; if (!wdc_check_device(fd)) return -1; @@ -5483,6 +5520,7 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) fprintf(stderr, "ERROR : WDC : invalid output format\n"); return fmt; } + ret = wdc_get_pci_ids(&device_id, &vendor_id); if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) { fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno)); @@ -5500,25 +5538,22 @@ static int wdc_get_fw_act_history_C2(int fd, char *format) if (ret == 0) { /* parse the data */ fw_act_history_log = (struct wdc_fw_act_history_log_format_c2*)(data); - num_entries = le32_to_cpu(fw_act_history_log->num_entries); + tot_entries = le32_to_cpu(fw_act_history_log->num_entries); - if ((num_entries > 0) && (num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) { + if (tot_entries > 0) { /* get the FW customer id */ if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&cust_id)) { fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID); ret = -1; goto freeData; } - - ret = wdc_print_fw_act_history_log(data, num_entries, fmt, *cust_id); - } else if (num_entries == 0) { + num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries : + WDC_MAX_NUM_ACT_HIST_ENTRIES; + ret = wdc_print_fw_act_history_log(data, num_entries, fmt, *cust_id, vendor_id); + } else { fprintf(stderr, "INFO : WDC : No FW Activate History entries found.\n"); ret = 0; } - else { - fprintf(stderr, "ERROR : WDC : Invalid number entries found in FW Activate History Log Page - %d\n", num_entries); - ret = -1; - } } else { fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n"); ret = -1; @@ -5578,7 +5613,7 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com /* Get the 0xC0 log data */ ret = nvme_get_log14(fd, 0xFFFFFFFF, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE, - NVME_NO_LOG_LSP, 0, 0, false, uuid_index, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); + NVME_NO_LOG_LSP, 0, 0, false, uuid_index, 0, false, WDC_NVME_SMART_CLOUD_ATTR_LEN, data); if (ret == 0) { /* Verify GUID matches */ @@ -5634,7 +5669,7 @@ static int wdc_do_clear_fw_activate_history_fid(int fd) __u32 value = 1 << 31; /* Bit 31 - Clear Firmware Update History Log */ ret = nvme_set_feature(fd, 0, WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID, value, - 0, 0, 0, NULL, &result); + 0, 0, 0, 0, NULL, &result); fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret); return ret; @@ -5728,18 +5763,18 @@ static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct comm if (cfg.disable) { ret = nvme_set_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 1, - 0, 0, 0, buf, &result); + 0, 0, 0, 0, buf, &result); wdc_clear_reason_id(fd); } else { if (cfg.enable) { ret = nvme_set_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, - 0, 0, 0, buf, &result); + 0, 0, 0, 0, buf, &result); } else if (cfg.status) { ret = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0, - 4, buf, &result); + 0, 4, buf, &result); if (ret == 0) { if (result) fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n"); @@ -6363,7 +6398,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key) if (deFeatureIdList[listIdx].featureId == FID_LBA_RANGE_TYPE) continue; ret = nvme_get_feature(fd, WDC_DE_GLOBAL_NSID, deFeatureIdList[listIdx].featureId, FS_CURRENT, 0, - sizeof(featureIdBuff), &featureIdBuff, &result); + 0, sizeof(featureIdBuff), &featureIdBuff, &result); if (ret) { fprintf(stderr, "ERROR : WDC : nvme_get_feature id 0x%x failed, ret = %d\n", @@ -7713,7 +7748,7 @@ static int wdc_vs_temperature_stats(int argc, char **argv, temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273; /* retrieve HCTM Thermal Management Temperatures */ - nvme_get_feature(fd, 0, 0x10, 0, 0, 0, 0, &hctm_tmt); + nvme_get_feature(fd, 0, 0x10, 0, 0, 0, 0, 0, &hctm_tmt); temp_tmt1 = ((hctm_tmt >> 16) & 0xffff) ? ((hctm_tmt >> 16) & 0xffff) - 273 : 0; temp_tmt2 = (hctm_tmt & 0xffff) ? (hctm_tmt & 0xffff) - 273 : 0; @@ -7800,8 +7835,10 @@ static int wdc_capabilities(int argc, char **argv, printf("get-pfail-dump : %s\n", capabilities & WDC_DRIVE_CAP_PFAIL_DUMP ? "Supported" : "Not Supported"); printf("id-ctrl : Supported\n"); - printf("purge : Supported\n"); - printf("purge-monitor : Supported\n"); + printf("purge : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); + printf("purge-monitor : %s\n", + capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported"); printf("vs-internal-log : %s\n", capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported"); printf("vs-nand-stats : %s\n", diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h index de6affa..29ff6a0 100644 --- a/plugins/wdc/wdc-nvme.h +++ b/plugins/wdc/wdc-nvme.h @@ -4,9 +4,10 @@ #if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ) #define WDC_NVME +#define WDC_PLUGIN_VERSION "1.14.1" #include "cmd.h" -PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"), +PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION), COMMAND_LIST( ENTRY("cap-diag", "WDC Capture-Diagnostics", wdc_cap_diag) ENTRY("drive-log", "WDC Drive Log", wdc_drive_log) diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c index 2740181..52c427b 100644 --- a/plugins/wdc/wdc-utils.c +++ b/plugins/wdc/wdc-utils.c @@ -77,7 +77,11 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo) timeInfo->second = currTimeInfo.tm_sec; timeInfo->msecs = 0; timeInfo->isDST = currTimeInfo.tm_isdst; +#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__) timeInfo->zone = -currTimeInfo.tm_gmtoff / 60; +#else + timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN); +#endif return WDC_STATUS_SUCCESS; } diff --git a/plugins/ymtc/ymtc-nvme.h b/plugins/ymtc/ymtc-nvme.h index 739fd37..c1ebc11 100644 --- a/plugins/ymtc/ymtc-nvme.h +++ b/plugins/ymtc/ymtc-nvme.h @@ -12,7 +12,7 @@ #include #include -PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions"), +PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions", NVME_VERSION), COMMAND_LIST( ENTRY("smart-log-add", "Retrieve Ymtc SMART Log, show it", get_additional_smart_log) ) diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c index 7f6f52e..e558317 100644 --- a/plugins/zns/zns.c +++ b/plugins/zns/zns.c @@ -130,12 +130,13 @@ close_fd: return nvme_status_to_errno(err, false); } -static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba, - bool select_all, enum nvme_zns_send_action zsa, __u32 data_len, void *buf) +static int __zns_mgmt_send(int fd, __u32 namespace_id, __u64 zslba, + bool select_all, __u32 timeout, enum nvme_zns_send_action zsa, + __u32 data_len, void *buf) { int err; - err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, zsa, + err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, timeout, zsa, data_len, buf); close(fd); return err; @@ -146,6 +147,7 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug { const char *zslba = "starting LBA of the zone for this command"; const char *select_all = "send command to all zones"; + const char *timeout = "timeout value, in milliseconds"; int err, fd; char *command; @@ -154,15 +156,16 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug __u64 zslba; __u32 namespace_id; bool select_all; + __u32 timeout; }; - struct config cfg = { - }; + struct config cfg = {}; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -183,7 +186,7 @@ static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plug } err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, - cfg.select_all, zsa, 0, NULL); + cfg.select_all, cfg.timeout, zsa, 0, NULL); if (!err) printf("%s: Success, action:%d zone:%"PRIx64" all:%d nsid:%d\n", command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all, @@ -207,23 +210,21 @@ static int get_zdes_bytes(int fd, __u32 nsid) int err; err = nvme_identify_ns(fd, nsid, false, &id_ns); - if (err > 0){ + if (err > 0) { nvme_show_status(err); - return err; - } - else if (err < 0){ + return -1; + } else if (err < 0) { perror("identify namespace"); - return err; + return -1; } err = nvme_zns_identify_ns(fd, nsid, &ns); - if (err > 0){ + if (err > 0) { nvme_show_status(err); - return err; - } - else if (err < 0){ + return -1; + } else if (err < 0) { perror("zns identify namespace"); - return err; + return -1; } lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK; @@ -238,6 +239,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu const char *zsa = "zone send action"; const char *data_len = "buffer length if data required"; const char *data = "optional file for data (default stdin)"; + const char *timeout = "timeout value, in milliseconds"; int fd, ffd = STDIN_FILENO, err = -1; void *buf = NULL; @@ -247,20 +249,21 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu __u32 namespace_id; bool select_all; __u8 zsa; - int data_len; + int data_len; char *file; + __u32 timeout; }; - struct config cfg = { - }; + struct config cfg = {}; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), OPT_FLAG("select-all", 'a', &cfg.select_all, select_all), OPT_BYTE("zsa", 'z', &cfg.zsa, zsa), - OPT_UINT("data-len", 'l', &cfg.data_len, data_len), - OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("data-len", 'l', &cfg.data_len, data_len), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -285,9 +288,9 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) { if(!cfg.data_len) { cfg.data_len = get_zdes_bytes(fd, cfg.namespace_id); - if (cfg.data_len == 0) { + if (!cfg.data_len || cfg.data_len < 0) { fprintf(stderr, - "Zone Descriptor Extensions are not supported\n"); + "Zone Descriptor Extensions are not supported\n"); goto close_fd; } else if (cfg.data_len < 0) { err = cfg.data_len; @@ -323,7 +326,7 @@ static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plu } err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, cfg.select_all, - cfg.zsa, cfg.data_len, buf); + cfg.timeout, cfg.zsa, cfg.data_len, buf); if (!err) printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" " "all:%d nsid:%d\n", @@ -384,6 +387,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug const char *desc = "Set Zone Descriptor Extension\n"; const char *zslba = "starting LBA of the zone for this command"; const char *data = "optional file for zone extention data (default stdin)"; + const char *timeout = "timeout value, in milliseconds"; int fd, ffd = STDIN_FILENO, err; void *buf = NULL; @@ -393,15 +397,16 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug __u64 zslba; __u32 namespace_id; char *file; + __u32 timeout; }; - struct config cfg = { - }; + struct config cfg = {}; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba), - OPT_FILE("data", 'd', &cfg.file, data), + OPT_FILE("data", 'd', &cfg.file, data), + OPT_UINT("timeout", 't', &cfg.timeout, timeout), OPT_END() }; @@ -419,7 +424,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug data_len = get_zdes_bytes(fd, cfg.namespace_id); - if (!data_len) { + if (!data_len || data_len < 0) { fprintf(stderr, "zone format does not provide descriptor extention\n"); errno = EINVAL; @@ -449,7 +454,7 @@ static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plug goto close_ffd; } - err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0, + err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0, cfg.timeout, NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf); if (!err) printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n", @@ -708,8 +713,7 @@ static int zone_append(int argc, char **argv, struct command *cmd, struct plugin int latency; }; - struct config cfg = { - }; + struct config cfg = {}; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h index a92de69..61063f7 100644 --- a/plugins/zns/zns.h +++ b/plugins/zns/zns.h @@ -6,7 +6,7 @@ #include "cmd.h" -PLUGIN(NAME("zns", "Zoned Namespace Command Set"), +PLUGIN(NAME("zns", "Zoned Namespace Command Set", NVME_VERSION), COMMAND_LIST( ENTRY("id-ctrl", "Retrieve ZNS controller identification", id_ctrl) ENTRY("id-ns", "Retrieve ZNS namespace identification", id_ns) diff --git a/scripts/gen-hostnqn.sh b/scripts/gen-hostnqn.sh index 5138f0c..563aa60 100644 --- a/scripts/gen-hostnqn.sh +++ b/scripts/gen-hostnqn.sh @@ -23,24 +23,6 @@ if ! [[ $UUID =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ exit 2 fi -# HEURISTIC: -# (1) if any one given character occurs more than 50% of the time, it is likely -# that the UUID is fake. -# (2) if the first or the last group consists of mostly the same character, it -# is likely that the UUID is fake. -FIRST_GROUP="$(echo $UUID | cut -d'-' -f1)" -LAST_GROUP="$(echo $UUID | cut -d'-' -f5)" -for i in {{0..9},{a..f}} ; do - COUNT_TOTAL="${UUID//[^$i]}" - COUNT_FIRST="${FIRST_GROUP//[^$i]}" - COUNT_LAST="${LAST_GROUP//[^$i]}" - if [ ${#COUNT_TOTAL} -ge 16 ] || [ ${#COUNT_FIRST} -ge 7 ] || [ ${#COUNT_LAST} -ge 11 ] ; then - >&2 echo "UUID is too repetitive. This may be a false alert." - >&2 echo "Repetitive UUID: ${UUID}" - exit 3 - fi -done - HOSTNQN="nqn.2014-08.org.nvmexpress:uuid:${UUID}" echo $HOSTNQN -- cgit v1.2.3