summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:49:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:49:35 +0000
commitf2c543b4ccad3b9f8871d952cddf66b3b438595b (patch)
treec3c363d1cc72514221685c42a79a19b320114acc
parentAdding debian version 1.12-8. (diff)
downloadnvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.tar.xz
nvme-cli-f2c543b4ccad3b9f8871d952cddf66b3b438595b.zip
Merging upstream version 1.14.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.github/workflows/c-cpp.yml18
-rw-r--r--.gitignore3
-rw-r--r--Documentation/cmds-main.txt35
-rw-r--r--Documentation/nvme-admin-passthru.14
-rw-r--r--Documentation/nvme-ana-log.14
-rw-r--r--Documentation/nvme-attach-ns.14
-rw-r--r--Documentation/nvme-changed-ns-list-log.14
-rw-r--r--Documentation/nvme-compare.14
-rw-r--r--Documentation/nvme-connect-all.114
-rw-r--r--Documentation/nvme-connect-all.html10
-rw-r--r--Documentation/nvme-connect-all.txt5
-rw-r--r--Documentation/nvme-connect.110
-rw-r--r--Documentation/nvme-connect.html8
-rw-r--r--Documentation/nvme-connect.txt1
-rw-r--r--Documentation/nvme-copy.1141
-rw-r--r--Documentation/nvme-copy.html989
-rw-r--r--Documentation/nvme-copy.txt111
-rw-r--r--Documentation/nvme-create-ns.110
-rw-r--r--Documentation/nvme-create-ns.html27
-rw-r--r--Documentation/nvme-create-ns.txt6
-rw-r--r--Documentation/nvme-delete-ns.14
-rw-r--r--Documentation/nvme-dera-stat.14
-rw-r--r--Documentation/nvme-detach-ns.14
-rw-r--r--Documentation/nvme-device-self-test.14
-rw-r--r--Documentation/nvme-dir-receive.14
-rw-r--r--Documentation/nvme-dir-send.14
-rw-r--r--Documentation/nvme-disconnect-all.14
-rw-r--r--Documentation/nvme-disconnect.14
-rw-r--r--Documentation/nvme-discover.110
-rw-r--r--Documentation/nvme-discover.html8
-rw-r--r--Documentation/nvme-discover.txt13
-rw-r--r--Documentation/nvme-dsm.14
-rw-r--r--Documentation/nvme-effects-log.14
-rw-r--r--Documentation/nvme-endurance-event-agg-log.1112
-rw-r--r--Documentation/nvme-endurance-event-agg-log.html858
-rw-r--r--Documentation/nvme-endurance-event-agg-log.txt66
-rw-r--r--Documentation/nvme-endurance-log.14
-rw-r--r--Documentation/nvme-endurance-log.html2
-rw-r--r--Documentation/nvme-error-log.14
-rw-r--r--Documentation/nvme-flush.14
-rw-r--r--Documentation/nvme-format.14
-rw-r--r--Documentation/nvme-fw-commit.14
-rw-r--r--Documentation/nvme-fw-download.14
-rw-r--r--Documentation/nvme-fw-log.14
-rw-r--r--Documentation/nvme-gen-hostnqn.14
-rw-r--r--Documentation/nvme-get-feature.14
-rw-r--r--Documentation/nvme-get-log.14
-rw-r--r--Documentation/nvme-get-ns-id.14
-rw-r--r--Documentation/nvme-get-ns-id.html14
-rw-r--r--Documentation/nvme-get-property.14
-rw-r--r--Documentation/nvme-help.14
-rw-r--r--Documentation/nvme-huawei-id-ctrl.14
-rw-r--r--Documentation/nvme-huawei-list.14
-rw-r--r--Documentation/nvme-id-ctrl.14
-rw-r--r--Documentation/nvme-id-iocs.172
-rw-r--r--Documentation/nvme-id-iocs.html817
-rw-r--r--Documentation/nvme-id-iocs.txt39
-rw-r--r--Documentation/nvme-id-ns.14
-rw-r--r--Documentation/nvme-id-nvmset.14
-rw-r--r--Documentation/nvme-intel-id-ctrl.14
-rw-r--r--Documentation/nvme-intel-internal-log.14
-rw-r--r--Documentation/nvme-intel-lat-stats.14
-rw-r--r--Documentation/nvme-intel-market-name.14
-rw-r--r--Documentation/nvme-intel-smart-log-add.14
-rw-r--r--Documentation/nvme-intel-temp-stats.14
-rw-r--r--Documentation/nvme-intel-temp-stats.html14
-rw-r--r--Documentation/nvme-io-passthru.14
-rw-r--r--Documentation/nvme-lba-status-log.1105
-rw-r--r--Documentation/nvme-lba-status-log.html838
-rw-r--r--Documentation/nvme-lba-status-log.txt54
-rw-r--r--Documentation/nvme-list-ctrl.14
-rw-r--r--Documentation/nvme-list-ns.110
-rw-r--r--Documentation/nvme-list-ns.html20
-rw-r--r--Documentation/nvme-list-ns.txt6
-rw-r--r--Documentation/nvme-list-subsys.14
-rw-r--r--Documentation/nvme-list.14
-rw-r--r--Documentation/nvme-lnvm-create.14
-rw-r--r--Documentation/nvme-lnvm-diag-bbtbl.14
-rw-r--r--Documentation/nvme-lnvm-diag-set-bbtbl.14
-rw-r--r--Documentation/nvme-lnvm-factory.14
-rw-r--r--Documentation/nvme-lnvm-id-ns.14
-rw-r--r--Documentation/nvme-lnvm-info.14
-rw-r--r--Documentation/nvme-lnvm-init.14
-rw-r--r--Documentation/nvme-lnvm-list.14
-rw-r--r--Documentation/nvme-lnvm-remove.14
-rw-r--r--Documentation/nvme-micron-clear-pcie-errors.171
-rw-r--r--Documentation/nvme-micron-clear-pcie-errors.html803
-rw-r--r--Documentation/nvme-micron-clear-pcie-errors.txt39
-rw-r--r--Documentation/nvme-micron-internal-log.174
-rw-r--r--Documentation/nvme-micron-internal-log.html818
-rw-r--r--Documentation/nvme-micron-internal-log.txt43
-rw-r--r--Documentation/nvme-micron-nand-stats.171
-rw-r--r--Documentation/nvme-micron-nand-stats.html804
-rw-r--r--Documentation/nvme-micron-nand-stats.txt40
-rw-r--r--Documentation/nvme-micron-pcie-stats.171
-rw-r--r--Documentation/nvme-micron-pcie-stats.html804
-rw-r--r--Documentation/nvme-micron-pcie-stats.txt40
-rw-r--r--Documentation/nvme-micron-selective-download.1139
-rw-r--r--Documentation/nvme-micron-selective-download.html874
-rw-r--r--Documentation/nvme-micron-selective-download.txt63
-rw-r--r--Documentation/nvme-micron-temperature-stats.171
-rw-r--r--Documentation/nvme-micron-temperature-stats.html804
-rw-r--r--Documentation/nvme-micron-temperature-stats.txt40
-rw-r--r--Documentation/nvme-netapp-ontapdevices.14
-rw-r--r--Documentation/nvme-netapp-smdevices.14
-rw-r--r--Documentation/nvme-ns-descs.14
-rw-r--r--Documentation/nvme-ns-rescan.14
-rw-r--r--Documentation/nvme-ns-rescan.html1256
-rw-r--r--Documentation/nvme-nvm-id-ctrl.198
-rw-r--r--Documentation/nvme-nvm-id-ctrl.html828
-rw-r--r--Documentation/nvme-nvm-id-ctrl.txt49
-rw-r--r--Documentation/nvme-persistent-event-log.1118
-rw-r--r--Documentation/nvme-persistent-event-log.html874
-rw-r--r--Documentation/nvme-persistent-event-log.txt76
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.1117
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.html870
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.txt72
-rw-r--r--Documentation/nvme-predictable-lat-log.1112
-rw-r--r--Documentation/nvme-predictable-lat-log.html857
-rw-r--r--Documentation/nvme-predictable-lat-log.txt66
-rw-r--r--Documentation/nvme-read.14
-rw-r--r--Documentation/nvme-reset.14
-rw-r--r--Documentation/nvme-resv-acquire.16
-rw-r--r--Documentation/nvme-resv-acquire.html2
-rw-r--r--Documentation/nvme-resv-acquire.txt2
-rw-r--r--Documentation/nvme-resv-notif-log.198
-rw-r--r--Documentation/nvme-resv-notif-log.html829
-rw-r--r--Documentation/nvme-resv-notif-log.txt51
-rw-r--r--Documentation/nvme-resv-register.14
-rw-r--r--Documentation/nvme-resv-release.16
-rw-r--r--Documentation/nvme-resv-release.html2
-rw-r--r--Documentation/nvme-resv-release.txt2
-rw-r--r--Documentation/nvme-resv-report.14
-rw-r--r--Documentation/nvme-resv-report.html7
-rw-r--r--Documentation/nvme-rpmb.1326
-rw-r--r--Documentation/nvme-rpmb.html1008
-rw-r--r--Documentation/nvme-rpmb.txt150
-rw-r--r--Documentation/nvme-sanitize-log.115
-rw-r--r--Documentation/nvme-sanitize-log.html15
-rw-r--r--Documentation/nvme-sanitize-log.txt6
-rw-r--r--Documentation/nvme-sanitize.14
-rw-r--r--Documentation/nvme-security-recv.14
-rw-r--r--Documentation/nvme-security-send.14
-rw-r--r--Documentation/nvme-self-test-log.116
-rw-r--r--Documentation/nvme-self-test-log.html30
-rw-r--r--Documentation/nvme-self-test-log.txt9
-rw-r--r--Documentation/nvme-set-feature.14
-rw-r--r--Documentation/nvme-set-property.14
-rw-r--r--Documentation/nvme-show-hostnqn.14
-rw-r--r--Documentation/nvme-show-regs.14
-rw-r--r--Documentation/nvme-smart-log.14
-rw-r--r--Documentation/nvme-smart-log.html14
-rw-r--r--Documentation/nvme-subsystem-reset.14
-rw-r--r--Documentation/nvme-telemetry-log.14
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.14
-rw-r--r--Documentation/nvme-toshiba-vs-internal-log.14
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.14
-rw-r--r--Documentation/nvme-transcend-badblock.14
-rw-r--r--Documentation/nvme-transcend-healthvalue.14
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.14
-rw-r--r--Documentation/nvme-virtium-show-identify.14
-rw-r--r--Documentation/nvme-wdc-cap-diag.14
-rw-r--r--Documentation/nvme-wdc-capabilities.168
-rw-r--r--Documentation/nvme-wdc-capabilities.html796
-rw-r--r--Documentation/nvme-wdc-capabilities.txt32
-rw-r--r--Documentation/nvme-wdc-clear-assert-dump.14
-rw-r--r--Documentation/nvme-wdc-clear-fw-activate-history.14
-rw-r--r--Documentation/nvme-wdc-clear-pcie-correctable-errors.14
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.168
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.html793
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.txt33
-rw-r--r--Documentation/nvme-wdc-drive-essentials.14
-rw-r--r--Documentation/nvme-wdc-drive-log.14
-rw-r--r--Documentation/nvme-wdc-drive-resize.14
-rw-r--r--Documentation/nvme-wdc-enc-get-log.1104
-rw-r--r--Documentation/nvme-wdc-enc-get-log.html839
-rw-r--r--Documentation/nvme-wdc-enc-get-log.txt54
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.14
-rw-r--r--Documentation/nvme-wdc-get-drive-status.14
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.14
-rw-r--r--Documentation/nvme-wdc-id-ctrl.14
-rw-r--r--Documentation/nvme-wdc-log-page-directory.14
-rw-r--r--Documentation/nvme-wdc-namespace-resize.14
-rw-r--r--Documentation/nvme-wdc-purge-monitor.14
-rw-r--r--Documentation/nvme-wdc-purge.14
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.14
-rw-r--r--Documentation/nvme-wdc-vs-error-reason-identifier.14
-rw-r--r--Documentation/nvme-wdc-vs-fw-activate-history.14
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.16
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.html8
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.txt30
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.14
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.html12
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.1421
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.html335
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.txt226
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.14
-rw-r--r--Documentation/nvme-wdc-vs-temperature-stats.1179
-rw-r--r--Documentation/nvme-wdc-vs-temperature-stats.html864
-rw-r--r--Documentation/nvme-wdc-vs-temperature-stats.txt78
-rw-r--r--Documentation/nvme-write-uncor.14
-rw-r--r--Documentation/nvme-write-zeroes.14
-rw-r--r--Documentation/nvme-write.14
-rw-r--r--Documentation/nvme-zns-changed-zone-list.1105
-rw-r--r--Documentation/nvme-zns-changed-zone-list.html840
-rw-r--r--Documentation/nvme-zns-changed-zone-list.txt54
-rw-r--r--Documentation/nvme-zns-close-zone.184
-rw-r--r--Documentation/nvme-zns-close-zone.html841
-rw-r--r--Documentation/nvme-zns-close-zone.txt49
-rw-r--r--Documentation/nvme-zns-finish-zone.184
-rw-r--r--Documentation/nvme-zns-finish-zone.html842
-rw-r--r--Documentation/nvme-zns-finish-zone.txt50
-rw-r--r--Documentation/nvme-zns-id-ctrl.198
-rw-r--r--Documentation/nvme-zns-id-ctrl.html828
-rw-r--r--Documentation/nvme-zns-id-ctrl.txt50
-rw-r--r--Documentation/nvme-zns-id-ns.1110
-rw-r--r--Documentation/nvme-zns-id-ns.html854
-rw-r--r--Documentation/nvme-zns-id-ns.txt62
-rw-r--r--Documentation/nvme-zns-offline-zone.184
-rw-r--r--Documentation/nvme-zns-offline-zone.html841
-rw-r--r--Documentation/nvme-zns-offline-zone.txt49
-rw-r--r--Documentation/nvme-zns-open-zone.184
-rw-r--r--Documentation/nvme-zns-open-zone.html841
-rw-r--r--Documentation/nvme-zns-open-zone.txt49
-rw-r--r--Documentation/nvme-zns-report-zones.1198
-rw-r--r--Documentation/nvme-zns-report-zones.html964
-rw-r--r--Documentation/nvme-zns-report-zones.txt102
-rw-r--r--Documentation/nvme-zns-reset-zone.184
-rw-r--r--Documentation/nvme-zns-reset-zone.html842
-rw-r--r--Documentation/nvme-zns-reset-zone.txt50
-rw-r--r--Documentation/nvme-zns-set-zone-desc.182
-rw-r--r--Documentation/nvme-zns-set-zone-desc.html842
-rw-r--r--Documentation/nvme-zns-set-zone-desc.txt50
-rw-r--r--Documentation/nvme-zns-zone-append.1133
-rw-r--r--Documentation/nvme-zns-zone-append.html947
-rw-r--r--Documentation/nvme-zns-zone-append.txt96
-rw-r--r--Documentation/nvme-zns-zone-mgmt-recv.1121
-rw-r--r--Documentation/nvme-zns-zone-mgmt-recv.html889
-rw-r--r--Documentation/nvme-zns-zone-mgmt-recv.txt78
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.1126
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.html899
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.txt77
-rw-r--r--Documentation/nvme.163
-rw-r--r--Documentation/nvme.html92
-rw-r--r--Makefile33
-rwxr-xr-xNVME-VERSION-GEN2
-rw-r--r--README.md7
-rw-r--r--common.h3
-rw-r--r--completions/_nvme149
-rw-r--r--completions/bash-nvme-completion.sh54
-rw-r--r--fabrics.c744
-rw-r--r--fabrics.h42
-rw-r--r--linux/nvme.h509
-rw-r--r--nvme-builtin.h11
-rw-r--r--nvme-filters.c16
-rw-r--r--nvme-ioctl.c314
-rw-r--r--nvme-ioctl.h74
-rwxr-xr-x[-rw-r--r--]nvme-print.c1802
-rw-r--r--nvme-print.h56
-rw-r--r--nvme-rpmb.c1001
-rw-r--r--nvme-status.c37
-rw-r--r--nvme-topology.c259
-rw-r--r--nvme.c1427
-rw-r--r--nvme.h43
-rw-r--r--nvme.spec.in4
-rw-r--r--nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in2
-rw-r--r--plugins/amzn/amzn-nvme.c59
-rw-r--r--plugins/amzn/amzn-nvme.h17
-rw-r--r--plugins/dera/dera-nvme.c3
-rw-r--r--plugins/huawei/huawei-nvme.c3
-rw-r--r--plugins/intel/intel-nvme.c513
-rw-r--r--plugins/intel/intel-nvme.h1
-rw-r--r--plugins/memblaze/memblaze-nvme.c781
-rw-r--r--plugins/memblaze/memblaze-nvme.h13
-rw-r--r--plugins/memblaze/memblaze-utils.h63
-rw-r--r--plugins/micron/micron-nvme.c3293
-rw-r--r--plugins/micron/micron-nvme.h10
-rw-r--r--plugins/netapp/netapp-nvme.c13
-rw-r--r--plugins/nvidia/nvidia-nvme.c58
-rw-r--r--plugins/nvidia/nvidia-nvme.h17
-rw-r--r--plugins/scaleflux/sfx-nvme.c377
-rw-r--r--plugins/scaleflux/sfx-nvme.h4
-rw-r--r--plugins/seagate/seagate-nvme.c33
-rw-r--r--plugins/shannon/shannon-nvme.c7
-rw-r--r--plugins/toshiba/toshiba-nvme.c2
-rw-r--r--plugins/virtium/virtium-nvme.c6
-rw-r--r--plugins/wdc/wdc-nvme.c3187
-rw-r--r--plugins/wdc/wdc-nvme.h5
-rw-r--r--plugins/wdc/wdc-utils.c15
-rw-r--r--plugins/wdc/wdc-utils.h1
-rw-r--r--plugins/ymtc/ymtc-nvme.c148
-rw-r--r--plugins/ymtc/ymtc-nvme.h24
-rw-r--r--plugins/ymtc/ymtc-utils.h80
-rw-r--r--plugins/zns/zns.c923
-rw-r--r--plugins/zns/zns.h30
-rw-r--r--scripts/gen-hostnqn.sh6
-rw-r--r--tests/nvme_get_features_test.py7
-rw-r--r--util/argconfig.c31
-rw-r--r--util/argconfig.h4
-rw-r--r--util/cleanup.c4
-rw-r--r--util/cleanup.h18
-rw-r--r--util/json.c26
-rw-r--r--util/json.h17
-rw-r--r--util/log.c90
-rw-r--r--util/log.h34
305 files changed, 49168 insertions, 4426 deletions
diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
new file mode 100644
index 0000000..d2f94e9
--- /dev/null
+++ b/.github/workflows/c-cpp.yml
@@ -0,0 +1,18 @@
+name: C/C++ CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: make
+ run: sudo apt-get install gcc-10-powerpc* && make clean && make && make clean && make LD=powerpc64le-linux-gnu-ld CC=powerpc64le-linux-gnu-gcc-10 CFLAGS='-O2 -g -Wall -Wformat-security -Werror -m64 -mcpu=power8 -mtune=power8 -I -I/usr/powerpc64-linux-gnu/include/'
+
diff --git a/.gitignore b/.gitignore
index b0efd0b..8e5ae00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,9 @@ a.out
*~
*.swp
NVME-VERSION-FILE
+nvme.spec
+nvme-*.tar.gz
+version
cscope.*
diff --git a/Documentation/cmds-main.txt b/Documentation/cmds-main.txt
index 824ca69..46df03d 100644
--- a/Documentation/cmds-main.txt
+++ b/Documentation/cmds-main.txt
@@ -17,7 +17,10 @@ linknvme:nvme-format[1]::
Format namespace(s)
linknvme:nvme-fw-activate[1]::
- F/W Activate
+ F/W Activate (in old version < 1.2)
+
+linknvme:nvme-fw-commit[1]::
+ F/W Commit (in > 1.2)
linknvme:nvme-fw-download[1]::
F/W Download
@@ -34,15 +37,24 @@ linknvme:nvme-get-log[1]::
linknvme:nvme-telemetry-log[1]::
Telemetry Host-Initiated Log
+linknvme:nvme-changed-ns-list-log[1]::
+ Retrieve Changed Namespace List Log
+
linknvme:nvme-smart-log[1]::
Retrieve Smart Log
+linknvme:nvme-ana-log[1]::
+ Retreive ANA(Asymmetric Namespace Access) Log
+
linknvme:nvme-endurance-log[1]::
Retrieve endurance Log
linknvme:nvme-effects-log[1]::
Retrieve effects Log
+linknvme:nvme-self-test-log[1]::
+ Retrieve Device Self-test Log
+
linknvme:nvme-get-ns-id[1]::
Retrieve namespace identifier
@@ -55,6 +67,12 @@ linknvme:nvme-id-ctrl[1]::
linknvme:nvme-id-ns[1]::
Identify Namespace
+linknvme:nvme-id-nvmset[1]::
+ Identify NVM Set List
+
+linknvme:nvme-id-iocs[1]::
+ Identify I/O Command Set
+
linknvme:nvme-create-ns[1]::
Create a new namespace
@@ -82,6 +100,15 @@ linknvme:nvme-list[1]::
linknvme:nvme-list-ctrl[1]::
List controller in NVMe subsystem
+linknvme:nvme-list-subsys[1]::
+ List NVMe subsystems
+
+linknvme:nvme-reset[1]::
+ Reset a NVMe controller
+
+linknvme:nvme-device-self-test[1]::
+ Issue Device Self-test Command
+
linknvme:nvme-read[1]::
Issue IO Read Command
@@ -112,6 +139,12 @@ linknvme:nvme-security-recv[1]::
linknvme:nvme-security-send[1]::
Security Send
+linknvme:nvme-dsm[1]::
+ Issue Data Set Management Command
+
+linknvme:nvme-copy[1]::
+ Issue Simple Copy Command
+
linknvme:nvme-set-feature[1]::
Set Feature
diff --git a/Documentation/nvme-admin-passthru.1 b/Documentation/nvme-admin-passthru.1
index f6d247f..286709f 100644
--- a/Documentation/nvme-admin-passthru.1
+++ b/Documentation/nvme-admin-passthru.1
@@ -2,12 +2,12 @@
.\" Title: nvme-admin-passthru
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ADMIN\-PASSTHR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ADMIN\-PASSTHR" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-ana-log.1 b/Documentation/nvme-ana-log.1
index 862f42d..5ba4cc3 100644
--- a/Documentation/nvme-ana-log.1
+++ b/Documentation/nvme-ana-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-ana-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ANA\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ANA\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-attach-ns.1 b/Documentation/nvme-attach-ns.1
index 0af22ae..37f63a8 100644
--- a/Documentation/nvme-attach-ns.1
+++ b/Documentation/nvme-attach-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-attach-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ATTACH\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ATTACH\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-changed-ns-list-log.1 b/Documentation/nvme-changed-ns-list-log.1
index 13dda55..97372fd 100644
--- a/Documentation/nvme-changed-ns-list-log.1
+++ b/Documentation/nvme-changed-ns-list-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-changed-ns-list-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-CHANGED\-NS\-L" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-CHANGED\-NS\-L" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-compare.1 b/Documentation/nvme-compare.1
index 0f1c6ff..0638190 100644
--- a/Documentation/nvme-compare.1
+++ b/Documentation/nvme-compare.1
@@ -2,12 +2,12 @@
.\" Title: nvme-compare
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-COMPARE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-COMPARE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-connect-all.1 b/Documentation/nvme-connect-all.1
index f829935..a53a017 100644
--- a/Documentation/nvme-connect-all.1
+++ b/Documentation/nvme-connect-all.1
@@ -2,12 +2,12 @@
.\" Title: nvme-connect-all
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/29/2020
+.\" Date: 01/20/2021
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-CONNECT\-ALL" "1" "04/29/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-CONNECT\-ALL" "1" "01/20/2021" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -51,7 +51,7 @@ nvme-connect-all \- Discover and Connect to Fabrics controllers\&.
[\-\-queue\-size=<#> | \-Q <#>]
[\-\-matching | \-m]
[\-\-persistent | \-p]
- [\-\-quiet | \-q]
+ [\-\-quiet | \-S]
.fi
.SH "DESCRIPTION"
.sp
@@ -72,6 +72,7 @@ allbox tab(:);
lt lt
lt lt
lt lt
+lt lt
lt lt.
T{
Value
@@ -90,6 +91,11 @@ T}:T{
The network fabric is a Fibre Channel network\&.
T}
T{
+tcp
+T}:T{
+The network fabric is a TCP/IP network\&.
+T}
+T{
loop
T}:T{
Connect to a NVMe over Fabrics target on the local host
@@ -187,7 +193,7 @@ If a traddr was specified on the command line or in the configuration file, only
Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
.RE
.PP
-\-q, \-\-quiet
+\-S, \-\-quiet
.RS 4
Suppress error messages\&.
.RE
diff --git a/Documentation/nvme-connect-all.html b/Documentation/nvme-connect-all.html
index b5f22f7..f779c7b 100644
--- a/Documentation/nvme-connect-all.html
+++ b/Documentation/nvme-connect-all.html
@@ -768,7 +768,7 @@ nvme-connect-all(1) Manual Page
[--queue-size=&lt;#&gt; | -Q &lt;#&gt;]
[--matching | -m]
[--persistent | -p]
- [--quiet | -q]</pre>
+ [--quiet | -S]</pre>
<div class="attribution">
</div></div>
</div>
@@ -825,6 +825,10 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><strong>WIP</strong> The network fabric is a Fibre Channel network.</p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table">tcp</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is a TCP/IP network.</p></td>
+</tr>
+<tr>
<td align="left" valign="top"><p class="table">loop</p></td>
<td align="left" valign="top"><p class="table">Connect to a NVMe over Fabrics target on the local host</p></td>
</tr>
@@ -1044,7 +1048,7 @@ cellspacing="0" cellpadding="4">
</p>
</dd>
<dt class="hdlist1">
--q
+-S
</dt>
<dt class="hdlist1">
--quiet
@@ -1111,7 +1115,7 @@ nvme-connect(1)</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2020-04-29 22:28:00 CEST
+ 2021-01-20 23:40:57 CET
</div>
</div>
</body>
diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt
index 63d3c8f..820dd6c 100644
--- a/Documentation/nvme-connect-all.txt
+++ b/Documentation/nvme-connect-all.txt
@@ -27,7 +27,7 @@ SYNOPSIS
[--queue-size=<#> | -Q <#>]
[--matching | -m]
[--persistent | -p]
- [--quiet | -q]
+ [--quiet | -S]
DESCRIPTION
-----------
@@ -58,6 +58,7 @@ OPTIONS
|Value|Definition
|rdma|The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
|fc |*WIP* The network fabric is a Fibre Channel network.
+|tcp |The network fabric is a TCP/IP network.
|loop|Connect to a NVMe over Fabrics target on the local host
|=================
@@ -153,7 +154,7 @@ OPTIONS
Don't remove the discovery controller after retrieving the discovery
log page.
--q::
+-S::
--quiet::
Suppress error messages.
diff --git a/Documentation/nvme-connect.1 b/Documentation/nvme-connect.1
index 9170d01..64d18bb 100644
--- a/Documentation/nvme-connect.1
+++ b/Documentation/nvme-connect.1
@@ -2,12 +2,12 @@
.\" Title: nvme-connect
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-CONNECT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-CONNECT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -65,6 +65,7 @@ allbox tab(:);
lt lt
lt lt
lt lt
+lt lt
lt lt.
T{
Value
@@ -83,6 +84,11 @@ T}:T{
The network fabric is a Fibre Channel network\&.
T}
T{
+tcp
+T}:T{
+The network fabric is a TCP/IP network\&.
+T}
+T{
loop
T}:T{
Connect to a NVMe over Fabrics target on the local host
diff --git a/Documentation/nvme-connect.html b/Documentation/nvme-connect.html
index 3387333..1f523dc 100644
--- a/Documentation/nvme-connect.html
+++ b/Documentation/nvme-connect.html
@@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.10" />
+<meta name="generator" content="AsciiDoc" />
<title>nvme-connect(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -816,6 +816,10 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><strong>WIP</strong> The network fabric is a Fibre Channel network.</p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table">tcp</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is a TCP/IP network.</p></td>
+</tr>
+<tr>
<td align="left" valign="top"><p class="table">loop</p></td>
<td align="left" valign="top"><p class="table">Connect to a NVMe over Fabrics target on the local host</p></td>
</tr>
@@ -1070,7 +1074,7 @@ and <a href="mailto:hch@lst.de">Christoph Hellwig</a></p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2020-02-15 08:33:28 JST
+ 2020-07-14 17:50:40 -03
</div>
</div>
</body>
diff --git a/Documentation/nvme-connect.txt b/Documentation/nvme-connect.txt
index 3f12ec0..757e3d0 100644
--- a/Documentation/nvme-connect.txt
+++ b/Documentation/nvme-connect.txt
@@ -46,6 +46,7 @@ OPTIONS
|Value|Definition
|rdma|The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
|fc |*WIP* The network fabric is a Fibre Channel network.
+|tcp |The network fabric is a TCP/IP network.
|loop|Connect to a NVMe over Fabrics target on the local host
|=================
diff --git a/Documentation/nvme-copy.1 b/Documentation/nvme-copy.1
new file mode 100644
index 0000000..766c65e
--- /dev/null
+++ b/Documentation/nvme-copy.1
@@ -0,0 +1,141 @@
+'\" t
+.\" Title: nvme-copy
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-COPY" "1" "10/20/2020" "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-copy \- Send an NVMe Simple Copy command, provide results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-copy\fR <device> [\-\-sdlba=<sdlba> | \-d <sdlba>]
+ [\-\-blocks=<nlb\-list,> | \-b <nlb\-list,>]
+ [\-\-slbs=<slbas,> | \-s <slbas,>]
+ [\-\-limited\-retry | \-l]
+ [\-\-force\-unit\-access | \-f]
+ [\-\-prinfow=<prinfow> | \-p <prinfow>]
+ [\-\-prinfor=<prinfor> | \-P <prinfor>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-expected\-ref\-tags=<reftag,> | \-R <reftag,>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>]
+ [\-\-expected\-app\-tags=<apptag,> | \-A <apptag,>]
+ [\-\-app\-mask=<appmask> | \-m <appmask>]
+ [\-\-expected\-app\-masks=<appmask,> | \-M <appmask,>]
+ [\-\-dir\-type=<type> | \-T <type>]
+ [\-\-dir\-spec=<spec> | \-S <spec>]
+ [\-\-format=<entry\-format> | \-F <entry\-format>]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Copy command is used by the host to copy data from one or more source logical block ranges to a single consecutive destination logical block range\&.
+.SH "OPTIONS"
+.PP
+\-\-sdlba=<sdlba>, \-d <sdlba>
+.RS 4
+64\-bit addr of first destination logical block
+.RE
+.PP
+\-\-blocks=<nlb\-list,>, \-b <nlb\-list,>
+.RS 4
+Comma separated list of the number of blocks in each range
+.RE
+.PP
+\-\-slbs=<slbas,>, \-s <slbas,>
+.RS 4
+Comma separated list of the starting blocks in each range
+.RE
+.PP
+\-\-limited\-retry, \-l
+.RS 4
+Sets the limited retry flag\&.
+.RE
+.PP
+\-\-force\-unit\-access, \-f
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-\-prinfow=<prinfow>, \-p <prinfow>
+.RS 4
+Protection Information field write definition\&.
+.RE
+.PP
+\-\-prinfor=<prinfor>, \-P <prinfor>
+.RS 4
+Protection Information field read definition\&.
+.RE
+.PP
+\-\-ref\-tag=<reftag>, \-r <reftag>
+.RS 4
+initial lba reference tag\&.
+.RE
+.PP
+\-\-expected\-ref\-tags=<reftag,>, \-R <reftag,>
+.RS 4
+expected lba reference tags (comma\-separated list)\&.
+.RE
+.PP
+\-\-app\-tag=<apptag>, \-a <apptag>
+.RS 4
+lba app tag
+.RE
+.PP
+\-\-expected\-app\-tags=<apptag,>, \-A <apptag,>
+.RS 4
+expected lba app tags (comma\-separated list)
+.RE
+.PP
+\-\-app\-mask=<appmask>, \-m <appmask>
+.RS 4
+lba tag mask
+.RE
+.PP
+\-\-expected\-app\-masks=<appmask,>, \-M <appmask,>
+.RS 4
+expected lba tag masks (comma\-separated list)
+.RE
+.PP
+\-\-dir\-type=<type>, \-T <type>
+.RS 4
+Optional directive type\&. The nvme\-cli only enforces the value be in the defined range for the directive type, though the NVMe specifcation (1\&.3a) defines only one directive, 01h, for write stream idenfiers\&.
+.RE
+.PP
+\-\-dir\-spec=<spec>, \-S <spec>
+.RS 4
+Optional field for directive specifics\&. When used with write streams, this value is defined to be the write stream identifier\&. The nvme\-cli will not validate the stream requested is within the controller\(cqs capabilities\&.
+.RE
+.PP
+\-\-format=<entry\-format>, \-F <entry\-format>
+.RS 4
+source range entry format
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-copy.html b/Documentation/nvme-copy.html
new file mode 100644
index 0000000..96acd03
--- /dev/null
+++ b/Documentation/nvme-copy.html
@@ -0,0 +1,989 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-copy(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-copy(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-copy -
+ Send an NVMe Simple Copy command, provide results
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme-copy</em> &lt;device&gt; [--sdlba=&lt;sdlba&gt; | -d &lt;sdlba&gt;]
+ [--blocks=&lt;nlb-list,&gt; | -b &lt;nlb-list,&gt;]
+ [--slbs=&lt;slbas,&gt; | -s &lt;slbas,&gt;]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--prinfow=&lt;prinfow&gt; | -p &lt;prinfow&gt;]
+ [--prinfor=&lt;prinfor&gt; | -P &lt;prinfor&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--expected-ref-tags=&lt;reftag,&gt; | -R &lt;reftag,&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]
+ [--expected-app-tags=&lt;apptag,&gt; | -A &lt;apptag,&gt;]
+ [--app-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--expected-app-masks=&lt;appmask,&gt; | -M &lt;appmask,&gt;]
+ [--dir-type=&lt;type&gt; | -T &lt;type&gt;]
+ [--dir-spec=&lt;spec&gt; | -S &lt;spec&gt;]
+ [--format=&lt;entry-format&gt; | -F &lt;entry-format&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Copy command is used by the host to copy data from one or more source
+logical block ranges to a single consecutive destination logical block range.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--sdlba=&lt;sdlba&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;sdlba&gt;
+</dt>
+<dd>
+<p>
+ 64-bit addr of first destination logical block
+</p>
+</dd>
+<dt class="hdlist1">
+--blocks=&lt;nlb-list,&gt;
+</dt>
+<dt class="hdlist1">
+-b &lt;nlb-list,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the number of blocks in each range
+</p>
+</dd>
+<dt class="hdlist1">
+--slbs=&lt;slbas,&gt;
+</dt>
+<dt class="hdlist1">
+-s &lt;slbas,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the starting blocks in each range
+</p>
+</dd>
+<dt class="hdlist1">
+--limited-retry
+</dt>
+<dt class="hdlist1">
+-l
+</dt>
+<dd>
+<p>
+ Sets the limited retry flag.
+</p>
+</dd>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dt class="hdlist1">
+-f
+</dt>
+<dd>
+<p>
+ Set the force-unit access flag.
+</p>
+</dd>
+<dt class="hdlist1">
+--prinfow=&lt;prinfow&gt;
+</dt>
+<dt class="hdlist1">
+-p &lt;prinfow&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field write definition.
+</p>
+</dd>
+<dt class="hdlist1">
+--prinfor=&lt;prinfor&gt;
+</dt>
+<dt class="hdlist1">
+-P &lt;prinfor&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field read definition.
+</p>
+</dd>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ initial lba reference tag.
+</p>
+</dd>
+<dt class="hdlist1">
+--expected-ref-tags=&lt;reftag,&gt;
+</dt>
+<dt class="hdlist1">
+-R &lt;reftag,&gt;
+</dt>
+<dd>
+<p>
+ expected lba reference tags (comma-separated list).
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ lba app tag
+</p>
+</dd>
+<dt class="hdlist1">
+--expected-app-tags=&lt;apptag,&gt;
+</dt>
+<dt class="hdlist1">
+-A &lt;apptag,&gt;
+</dt>
+<dd>
+<p>
+ expected lba app tags (comma-separated list)
+</p>
+</dd>
+<dt class="hdlist1">
+--app-mask=&lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ lba tag mask
+</p>
+</dd>
+<dt class="hdlist1">
+--expected-app-masks=&lt;appmask,&gt;
+</dt>
+<dt class="hdlist1">
+-M &lt;appmask,&gt;
+</dt>
+<dd>
+<p>
+ expected lba tag masks (comma-separated list)
+</p>
+</dd>
+<dt class="hdlist1">
+--dir-type=&lt;type&gt;
+</dt>
+<dt class="hdlist1">
+-T &lt;type&gt;
+</dt>
+<dd>
+<p>
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+</p>
+</dd>
+<dt class="hdlist1">
+--dir-spec=&lt;spec&gt;
+</dt>
+<dt class="hdlist1">
+-S &lt;spec&gt;
+</dt>
+<dd>
+<p>
+ Optional field for directive specifics. When used with
+ write streams, this value is defined to be the write stream
+ identifier. The nvme-cli will not validate the stream requested
+ is within the controller&#8217;s capabilities.
+</p>
+</dd>
+<dt class="hdlist1">
+--format=&lt;entry-format&gt;
+</dt>
+<dt class="hdlist1">
+-F &lt;entry-format&gt;
+</dt>
+<dd>
+<p>
+ source range entry format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No examples yet.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-05-06 10:35:20 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-copy.txt b/Documentation/nvme-copy.txt
new file mode 100644
index 0000000..d6452ec
--- /dev/null
+++ b/Documentation/nvme-copy.txt
@@ -0,0 +1,111 @@
+nvme-copy(1)
+============
+
+NAME
+----
+nvme-copy - Send an NVMe Simple Copy command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-copy' <device> [--sdlba=<sdlba> | -d <sdlba>]
+ [--blocks=<nlb-list,> | -b <nlb-list,>]
+ [--slbs=<slbas,> | -s <slbas,>]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--prinfow=<prinfow> | -p <prinfow>]
+ [--prinfor=<prinfor> | -P <prinfor>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--expected-ref-tags=<reftag,> | -R <reftag,>]
+ [--app-tag=<apptag> | -a <apptag>]
+ [--expected-app-tags=<apptag,> | -A <apptag,>]
+ [--app-mask=<appmask> | -m <appmask>]
+ [--expected-app-masks=<appmask,> | -M <appmask,>]
+ [--dir-type=<type> | -T <type>]
+ [--dir-spec=<spec> | -S <spec>]
+ [--format=<entry-format> | -F <entry-format>]
+
+DESCRIPTION
+-----------
+The Copy command is used by the host to copy data from one or more source
+logical block ranges to a single consecutive destination logical block range.
+
+OPTIONS
+-------
+--sdlba=<sdlba>::
+-d <sdlba>::
+ 64-bit addr of first destination logical block
+
+--blocks=<nlb-list,>::
+-b <nlb-list,>::
+ Comma separated list of the number of blocks in each range
+
+--slbs=<slbas,>::
+-s <slbas,>::
+ Comma separated list of the starting blocks in each range
+
+--limited-retry::
+-l::
+ Sets the limited retry flag.
+
+--force-unit-access::
+-f::
+ Set the force-unit access flag.
+
+--prinfow=<prinfow>::
+-p <prinfow>::
+ Protection Information field write definition.
+
+--prinfor=<prinfor>::
+-P <prinfor>::
+ Protection Information field read definition.
+
+--ref-tag=<reftag>::
+-r <reftag>::
+ initial lba reference tag.
+
+--expected-ref-tags=<reftag,>::
+-R <reftag,>::
+ expected lba reference tags (comma-separated list).
+
+--app-tag=<apptag>::
+-a <apptag>::
+ lba app tag
+
+--expected-app-tags=<apptag,>::
+-A <apptag,>::
+ expected lba app tags (comma-separated list)
+
+--app-mask=<appmask>::
+-m <appmask>::
+ lba tag mask
+
+--expected-app-masks=<appmask,>::
+-M <appmask,>::
+ expected lba tag masks (comma-separated list)
+
+--dir-type=<type>::
+-T <type>::
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+
+--dir-spec=<spec>::
+-S <spec>::
+ Optional field for directive specifics. When used with
+ write streams, this value is defined to be the write stream
+ identifier. The nvme-cli will not validate the stream requested
+ is within the controller's capabilities.
+
+--format=<entry-format>::
+-F <entry-format>::
+ source range entry format
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-create-ns.1 b/Documentation/nvme-create-ns.1
index 7f358c1..7a61f79 100644
--- a/Documentation/nvme-create-ns.1
+++ b/Documentation/nvme-create-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-create-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-CREATE\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-CREATE\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -39,6 +39,7 @@ nvme-create-ns \- Send NVMe Namespace management command to create namespace, re
[\-\-nmic=<nmic> | \-m <nmic>]
[\-\-anagrp\-id=<anagrpid> | \-a <anagrpid>]
[\-\-nvmset\-id=<nvmsetid> | \-i <nvmsetid>]
+ [\-\-csi=<command_set_identifier> | \-y <command_set_identifier>]
[\-\-block\-size=<block\-size> | \-b <block\-size>]
[\-\-timeout=<timeout> | \-t <timeout>]
DESCRIPTION
@@ -90,6 +91,11 @@ ANA Gorup Identifier\&. If this value is 0h specifies that the controller determ
This field specifies the identifier of the NVM Set\&.
.RE
.PP
+\-y <command_set_identifier>, \-\-csi=<command_set_identifier>
+.RS 4
+This field specifies the identifier of command set\&. if not issued, NVM Command Set will be selected\&.
+.RE
+.PP
\-b, \-\-block\-size
.RS 4
Target block size the new namespace should be formatted as\&. Potential FLBAS values will be values will be scanned and the lowest numbered will be selected for the create\-ns operation\&. Conflicts with \-\-flbas argument\&.
diff --git a/Documentation/nvme-create-ns.html b/Documentation/nvme-create-ns.html
index 1ecc66e..6d31241 100644
--- a/Documentation/nvme-create-ns.html
+++ b/Documentation/nvme-create-ns.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-create-ns(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -753,6 +756,7 @@ nvme-create-ns(1) Manual Page
[--nmic=&lt;nmic&gt; | -m &lt;nmic&gt;]
[--anagrp-id=&lt;anagrpid&gt; | -a &lt;anagrpid&gt;]
[--nvmset-id=&lt;nvmsetid&gt; | -i &lt;nvmsetid&gt;]
+ [--csi=&lt;command_set_identifier&gt; | -y &lt;command_set_identifier&gt;]
[--block-size=&lt;block-size&gt; | -b &lt;block-size&gt;]
[--timeout=&lt;timeout&gt; | -t &lt;timeout&gt;]
DESCRIPTION</pre>
@@ -842,7 +846,7 @@ OPTIONS</code></pre>
-i &lt;nvmsetid&gt;
</dt>
<dt class="hdlist1">
---nvmset_id=&lt;nvmsetid&gt;
+--nvmset-id=&lt;nvmsetid&gt;
</dt>
<dd>
<p>
@@ -850,6 +854,18 @@ OPTIONS</code></pre>
</p>
</dd>
<dt class="hdlist1">
+-y &lt;command_set_identifier&gt;
+</dt>
+<dt class="hdlist1">
+--csi=&lt;command_set_identifier&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the identifier of command set.
+ if not issued, NVM Command Set will be selected.
+</p>
+</dd>
+<dt class="hdlist1">
-b
</dt>
<dt class="hdlist1">
@@ -881,7 +897,8 @@ OPTIONS</code></pre>
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2019-11-16 14:07:32 KST
+Last updated
+ 2020-05-06 10:35:44 CEST
</div>
</div>
</body>
diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt
index 661b01b..09c0c78 100644
--- a/Documentation/nvme-create-ns.txt
+++ b/Documentation/nvme-create-ns.txt
@@ -15,6 +15,7 @@ SYNOPSIS
[--nmic=<nmic> | -m <nmic>]
[--anagrp-id=<anagrpid> | -a <anagrpid>]
[--nvmset-id=<nvmsetid> | -i <nvmsetid>]
+ [--csi=<command_set_identifier> | -y <command_set_identifier>]
[--block-size=<block-size> | -b <block-size>]
[--timeout=<timeout> | -t <timeout>]
DESCRIPTION
@@ -58,6 +59,11 @@ OPTIONS
--nvmset-id=<nvmsetid>::
This field specifies the identifier of the NVM Set.
+-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.
+
-b::
--block-size::
Target block size the new namespace should be formatted as. Potential FLBAS
diff --git a/Documentation/nvme-delete-ns.1 b/Documentation/nvme-delete-ns.1
index c186a86..1e6908f 100644
--- a/Documentation/nvme-delete-ns.1
+++ b/Documentation/nvme-delete-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-dera-stat.1 b/Documentation/nvme-dera-stat.1
index bf2ec27..c50fd72 100644
--- a/Documentation/nvme-dera-stat.1
+++ b/Documentation/nvme-dera-stat.1
@@ -2,12 +2,12 @@
.\" Title: nvme-dera-stat
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DERA\-STAT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DERA\-STAT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-detach-ns.1 b/Documentation/nvme-detach-ns.1
index 5765c85..c7b2b66 100644
--- a/Documentation/nvme-detach-ns.1
+++ b/Documentation/nvme-detach-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-detach-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DETACH\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DETACH\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-device-self-test.1 b/Documentation/nvme-device-self-test.1
index 699c178..1fba6ce 100644
--- a/Documentation/nvme-device-self-test.1
+++ b/Documentation/nvme-device-self-test.1
@@ -2,12 +2,12 @@
.\" Title: nvme-device-self-test
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DEVICE\-SELF\-" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DEVICE\-SELF\-" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-dir-receive.1 b/Documentation/nvme-dir-receive.1
index 44e8a2a..005cd73 100644
--- a/Documentation/nvme-dir-receive.1
+++ b/Documentation/nvme-dir-receive.1
@@ -2,12 +2,12 @@
.\" Title: nvme-dir-receive
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DIR\-RECEIVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DIR\-RECEIVE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-dir-send.1 b/Documentation/nvme-dir-send.1
index 77f9120..ebe17b3 100644
--- a/Documentation/nvme-dir-send.1
+++ b/Documentation/nvme-dir-send.1
@@ -2,12 +2,12 @@
.\" Title: nvme-dir-send
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DIR\-SEND" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DIR\-SEND" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-disconnect-all.1 b/Documentation/nvme-disconnect-all.1
index 04aec10..2a9f033 100644
--- a/Documentation/nvme-disconnect-all.1
+++ b/Documentation/nvme-disconnect-all.1
@@ -2,12 +2,12 @@
.\" Title: nvme-disconnect-all
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DISCONNECT\-AL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DISCONNECT\-AL" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-disconnect.1 b/Documentation/nvme-disconnect.1
index 23e1af7..456d937 100644
--- a/Documentation/nvme-disconnect.1
+++ b/Documentation/nvme-disconnect.1
@@ -2,12 +2,12 @@
.\" Title: nvme-disconnect
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DISCONNECT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DISCONNECT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-discover.1 b/Documentation/nvme-discover.1
index f354560..80b8a47 100644
--- a/Documentation/nvme-discover.1
+++ b/Documentation/nvme-discover.1
@@ -2,12 +2,12 @@
.\" Title: nvme-discover
.\" Author: [see the "AUTHORS" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DISCOVER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DISCOVER" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -76,6 +76,7 @@ allbox tab(:);
lt lt
lt lt
lt lt
+lt lt
lt lt.
T{
Value
@@ -94,6 +95,11 @@ T}:T{
The network fabric is a Fibre Channel network\&.
T}
T{
+tcp
+T}:T{
+The network fabric is a TCP/IP network\&.
+T}
+T{
loop
T}:T{
Connect to a NVMe over Fabrics target on the local host
diff --git a/Documentation/nvme-discover.html b/Documentation/nvme-discover.html
index dc6c7a1..e03361d 100644
--- a/Documentation/nvme-discover.html
+++ b/Documentation/nvme-discover.html
@@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.10" />
+<meta name="generator" content="AsciiDoc" />
<title>nvme-discover(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -846,6 +846,10 @@ cellspacing="0" cellpadding="4">
<td align="left" valign="top"><p class="table"><strong>WIP</strong> The network fabric is a Fibre Channel network.</p></td>
</tr>
<tr>
+<td align="left" valign="top"><p class="table">tcp</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is a TCP/IP network.</p></td>
+</tr>
+<tr>
<td align="left" valign="top"><p class="table">loop</p></td>
<td align="left" valign="top"><p class="table">Connect to a NVMe over Fabrics target on the local host</p></td>
</tr>
@@ -1122,7 +1126,7 @@ nvme-connect-all(1)</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2019-11-08 08:22:36 JST
+ 2020-07-14 17:46:53 -03
</div>
</div>
</body>
diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt
index f006639..74add74 100644
--- a/Documentation/nvme-discover.txt
+++ b/Documentation/nvme-discover.txt
@@ -16,6 +16,7 @@ SYNOPSIS
[--hostnqn=<hostnqn> | -q <hostnqn>]
[--hostid=<hostid> | -I <hostid>]
[--raw=<filename> | -r <filename>]
+ [--device=<device> | -d <device>]
[--keep-alive-tmo=<sec> | -k <sec>]
[--reconnect-delay=<#> | -c <#>]
[--ctrl-loss-tmo=<#> | -l <#>]
@@ -27,6 +28,7 @@ SYNOPSIS
[--queue-size=<#> | -Q <#>]
[--persistent | -p]
[--quiet | -S]
+ [--output-format=<fmt> | -o <fmt>]
DESCRIPTION
-----------
@@ -78,6 +80,7 @@ OPTIONS
|Value|Definition
|rdma|The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
|fc |*WIP* The network fabric is a Fibre Channel network.
+|tcp |The network fabric is a TCP/IP network.
|loop|Connect to a NVMe over Fabrics target on the local host
|=================
@@ -116,6 +119,11 @@ OPTIONS
and dump it to a raw binary file. By default 'nvme discover' will
dump the output to stdout.
+-d <device>::
+--device=<device>::
+ This field takes a device as input. Device is in the format of nvme*,
+ eg. nvme0, nvme1
+
-k <#>::
--keep-alive-tmo=<#>::
Overrides the default dealy (in seconds) for keep alive.
@@ -168,6 +176,11 @@ OPTIONS
--quiet::
Suppress already connected errors.
+-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
--------
* Query the Discover Controller with IP4 address 192.168.1.3 for all
diff --git a/Documentation/nvme-dsm.1 b/Documentation/nvme-dsm.1
index 899a6a6..727bab3 100644
--- a/Documentation/nvme-dsm.1
+++ b/Documentation/nvme-dsm.1
@@ -2,12 +2,12 @@
.\" Title: nvme-dsm
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-DSM" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-DSM" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-effects-log.1 b/Documentation/nvme-effects-log.1
index 72b22fb..0929ece 100644
--- a/Documentation/nvme-effects-log.1
+++ b/Documentation/nvme-effects-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-effects-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-EFFECTS\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-EFFECTS\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-endurance-event-agg-log.1 b/Documentation/nvme-endurance-event-agg-log.1
new file mode 100644
index 0000000..b8f3acc
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" Title: nvme-endurance-event-agg-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 02/20/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ENDURANCE\-EVE" "1" "02/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-endurance-event-agg-log \- Send NVMe Endurance log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme endurance\-event\-agg\-log\fR <device> [\-\-log\-entries=<log_entries> | \-e <log_entries>]
+ [\-\-rae | \-r] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Endurance Event Aggregate log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned endurance event agg log 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, the raw buffer may be printed to stdout for another program to parse, or reported in json format\&.
+.SH "OPTIONS"
+.PP
+\-e <log_entries>, \-\-log\-entries=<log_entries>
+.RS 4
+Retrieve the Endurance Group Event Aggregate Log pending entries\&. This argument is mandatory and its success may depend on the device\(cqs statistics to provide this log For More details see NVM Express 1\&.4 Spec\&. Section 5\&.14\&.1\&.15\&. The maximum number of log entries supported is 2044 for the device\&.
+.RE
+.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Endurance log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme endurance\-event\-agg\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the raw Endurance log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme endurance\-event\-agg\-log /dev/nvme0 \-\-output=binary > endurance_event_agg_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-endurance-event-agg-log.html b/Documentation/nvme-endurance-event-agg-log.html
new file mode 100644
index 0000000..cf7d32a
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.html
@@ -0,0 +1,858 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-endurance-event-agg-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-endurance-event-agg-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-endurance-event-agg-log -
+ Send NVMe Endurance log page request, returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme endurance-event-agg-log</em> &lt;device&gt; [--log-entries=&lt;log_entries&gt; | -e &lt;log_entries&gt;]
+ [--rae | -r] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe Endurance Event Aggregate log page from an NVMe device and
+provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned endurance event agg log 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, the raw buffer may be
+printed to stdout for another program to parse, or reported in json format.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;log_entries&gt;
+</dt>
+<dt class="hdlist1">
+--log-entries=&lt;log_entries&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the Endurance Group Event Aggregate Log pending entries.
+ This argument is mandatory and its success may depend on the device&#8217;s
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.15. The maximum number of log entries supported is 2044
+ for the device.
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the Endurance log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme endurance-event-agg-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw Endurance log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme endurance-event-agg-log /dev/nvme0 --output=binary &gt; endurance_event_agg_log.raw</code></pre>
+</div></div>
+<div class="paragraph"><p>It is probably a bad idea to not redirect stdout when using this mode.</p></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-02-20 21:58:13 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-endurance-event-agg-log.txt b/Documentation/nvme-endurance-event-agg-log.txt
new file mode 100644
index 0000000..69701e3
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.txt
@@ -0,0 +1,66 @@
+nvme-endurance-event-agg-log(1)
+===============================
+
+NAME
+----
+nvme-endurance-event-agg-log - Send NVMe Endurance log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme endurance-event-agg-log' <device> [--log-entries=<log_entries> | -e <log_entries>]
+ [--rae | -r] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Endurance Event Aggregate log page from an NVMe device and
+provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned endurance event agg log 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, the raw buffer may be
+printed to stdout for another program to parse, or reported in json format.
+
+OPTIONS
+-------
+-e <log_entries>::
+--log-entries=<log_entries>::
+ Retrieve the Endurance Group Event Aggregate Log pending entries.
+ This argument is mandatory and its success may depend on the device's
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.15. The maximum number of log entries supported is 2044
+ for the device.
+
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the Endurance log page in a human readable format:
++
+------------
+# nvme endurance-event-agg-log /dev/nvme0
+------------
++
+
+* Print the raw Endurance log to a file:
++
+------------
+# nvme endurance-event-agg-log /dev/nvme0 --output=binary > endurance_event_agg_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-endurance-log.1 b/Documentation/nvme-endurance-log.1
index 067a7a3..5e3170d 100644
--- a/Documentation/nvme-endurance-log.1
+++ b/Documentation/nvme-endurance-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-endurance-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ENDURANCE\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ENDURANCE\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-endurance-log.html b/Documentation/nvme-endurance-log.html
index 42fe267..809edee 100644
--- a/Documentation/nvme-endurance-log.html
+++ b/Documentation/nvme-endurance-log.html
@@ -834,7 +834,7 @@ Print the raw Endurance log to a file:
<div id="footer">
<div id="footer-text">
Last updated
- 2019-11-08 02:18:28 JST
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-error-log.1 b/Documentation/nvme-error-log.1
index e116ad4..4428aee 100644
--- a/Documentation/nvme-error-log.1
+++ b/Documentation/nvme-error-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-error-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ERROR\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ERROR\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-flush.1 b/Documentation/nvme-flush.1
index 3c4ddeb..1ee4223 100644
--- a/Documentation/nvme-flush.1
+++ b/Documentation/nvme-flush.1
@@ -2,12 +2,12 @@
.\" Title: nvme-flush
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-FLUSH" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-FLUSH" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-format.1 b/Documentation/nvme-format.1
index b47c53e..dad63a6 100644
--- a/Documentation/nvme-format.1
+++ b/Documentation/nvme-format.1
@@ -2,12 +2,12 @@
.\" Title: nvme-format
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-FORMAT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-FORMAT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-fw-commit.1 b/Documentation/nvme-fw-commit.1
index 2a965a7..178e546 100644
--- a/Documentation/nvme-fw-commit.1
+++ b/Documentation/nvme-fw-commit.1
@@ -2,12 +2,12 @@
.\" Title: nvme-fw-commit
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-FW\-COMMIT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-FW\-COMMIT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-fw-download.1 b/Documentation/nvme-fw-download.1
index 0fd360b..d1126da 100644
--- a/Documentation/nvme-fw-download.1
+++ b/Documentation/nvme-fw-download.1
@@ -2,12 +2,12 @@
.\" Title: nvme-fw-download
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-FW\-DOWNLOAD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-FW\-DOWNLOAD" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-fw-log.1 b/Documentation/nvme-fw-log.1
index f96bcdc..1d1da08 100644
--- a/Documentation/nvme-fw-log.1
+++ b/Documentation/nvme-fw-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-fw-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-FW\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-FW\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-gen-hostnqn.1 b/Documentation/nvme-gen-hostnqn.1
index 255dcca..9074dcb 100644
--- a/Documentation/nvme-gen-hostnqn.1
+++ b/Documentation/nvme-gen-hostnqn.1
@@ -2,12 +2,12 @@
.\" Title: nvme-gen-hostnqn
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-GEN\-HOSTNQN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-GEN\-HOSTNQN" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-get-feature.1 b/Documentation/nvme-get-feature.1
index 1bc451f..399d1d2 100644
--- a/Documentation/nvme-get-feature.1
+++ b/Documentation/nvme-get-feature.1
@@ -2,12 +2,12 @@
.\" Title: nvme-get-feature
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-GET\-FEATURE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-GET\-FEATURE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-get-log.1 b/Documentation/nvme-get-log.1
index 742a791..98f81a8 100644
--- a/Documentation/nvme-get-log.1
+++ b/Documentation/nvme-get-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-get-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-GET\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-GET\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-get-ns-id.1 b/Documentation/nvme-get-ns-id.1
index f7e69e4..6987f3f 100644
--- a/Documentation/nvme-get-ns-id.1
+++ b/Documentation/nvme-get-ns-id.1
@@ -2,12 +2,12 @@
.\" Title: nvme-get-ns-id
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-GET\-NS\-ID" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-GET\-NS\-ID" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-get-ns-id.html b/Documentation/nvme-get-ns-id.html
index bd02929..6fd2329 100644
--- a/Documentation/nvme-get-ns-id.html
+++ b/Documentation/nvme-get-ns-id.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-get-ns-id(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -433,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -790,7 +793,8 @@ Shows the namespace id for the given block device:
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2016-05-16 12:47:42 EDT
+Last updated
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-get-property.1 b/Documentation/nvme-get-property.1
index 116c338..6703f6c 100644
--- a/Documentation/nvme-get-property.1
+++ b/Documentation/nvme-get-property.1
@@ -2,12 +2,12 @@
.\" Title: nvme-get-property
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-GET\-PROPERTY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-GET\-PROPERTY" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-help.1 b/Documentation/nvme-help.1
index fc49411..75fdb75 100644
--- a/Documentation/nvme-help.1
+++ b/Documentation/nvme-help.1
@@ -2,12 +2,12 @@
.\" Title: nvme-help
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-HELP" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-HELP" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-huawei-id-ctrl.1 b/Documentation/nvme-huawei-id-ctrl.1
index b4dbb69..903b507 100644
--- a/Documentation/nvme-huawei-id-ctrl.1
+++ b/Documentation/nvme-huawei-id-ctrl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-huawei-id-ctrl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-HUAWEI\-ID\-CT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-HUAWEI\-ID\-CT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-huawei-list.1 b/Documentation/nvme-huawei-list.1
index 3cbe6f4..94a5b60 100644
--- a/Documentation/nvme-huawei-list.1
+++ b/Documentation/nvme-huawei-list.1
@@ -2,12 +2,12 @@
.\" Title: nvme-list
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LIST" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-id-ctrl.1 b/Documentation/nvme-id-ctrl.1
index 258188a..d077c03 100644
--- a/Documentation/nvme-id-ctrl.1
+++ b/Documentation/nvme-id-ctrl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ctrl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-CTRL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-CTRL" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-id-iocs.1 b/Documentation/nvme-id-iocs.1
new file mode 100644
index 0000000..f79b4de
--- /dev/null
+++ b/Documentation/nvme-id-iocs.1
@@ -0,0 +1,72 @@
+'\" t
+.\" Title: nvme-id-iocs
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-IOCS" "1" "10/20/2020" "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-iocs \- Send NVMe Identify I/O Command Set, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-iocs\fR <device> [\-\-controller\-id=<cntid> | \-c <cntid>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an identify command and return the Identify I/O Command Set data structure\&.
+.sp
+The <device> 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
+\-c <cntid>, \-\-controller\-id=<cntid>
+.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
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program interpret the returned buffer and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-iocs /dev/nvme0
+.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
new file mode 100644
index 0000000..6bc983f
--- /dev/null
+++ b/Documentation/nvme-id-iocs.html
@@ -0,0 +1,817 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-id-iocs(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-id-iocs(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-iocs -
+ Send NVMe Identify I/O Command Set, return result and structure
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme id-iocs</em> &lt;device&gt; [--controller-id=&lt;cntid&gt; | -c &lt;cntid&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, send an identify command and return the Identify I/O
+Command Set data structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-c &lt;cntid&gt;
+</dt>
+<dt class="hdlist1">
+--controller-id=&lt;cntid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify I/O Command set data structure for the given
+ cntid. If this value is not given, cntid will be 0xffff.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Have the program interpret the returned buffer and display the known
+fields in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-iocs /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-05-06 10:39:59 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-iocs.txt b/Documentation/nvme-id-iocs.txt
new file mode 100644
index 0000000..9e53207
--- /dev/null
+++ b/Documentation/nvme-id-iocs.txt
@@ -0,0 +1,39 @@
+nvme-id-iocs(1)
+===============
+
+NAME
+----
+nvme-id-iocs - Send NVMe Identify I/O Command Set, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-iocs' <device> [--controller-id=<cntid> | -c <cntid>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an identify command and return the Identify I/O
+Command Set 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
+-------
+-c <cntid>::
+--controller-id=<cntid>::
+ Retrieve the identify I/O Command set data structure for the given
+ cntid. If this value is not given, cntid will be 0xffff.
+
+EXAMPLES
+--------
+* Have the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme id-iocs /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-ns.1 b/Documentation/nvme-id-ns.1
index 55094c9..de73c08 100644
--- a/Documentation/nvme-id-ns.1
+++ b/Documentation/nvme-id-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-id-nvmset.1 b/Documentation/nvme-id-nvmset.1
index bcec988..f29f45a 100644
--- a/Documentation/nvme-id-nvmset.1
+++ b/Documentation/nvme-id-nvmset.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-nvmset
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NVMSET" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NVMSET" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-id-ctrl.1 b/Documentation/nvme-intel-id-ctrl.1
index 9e90231..4605de0 100644
--- a/Documentation/nvme-intel-id-ctrl.1
+++ b/Documentation/nvme-intel-id-ctrl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-id-ctrl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-ID\-CTR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-ID\-CTR" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-internal-log.1 b/Documentation/nvme-intel-internal-log.1
index fdefc66..22e193d 100644
--- a/Documentation/nvme-intel-internal-log.1
+++ b/Documentation/nvme-intel-internal-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-internal-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-INTERNA" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-INTERNA" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-lat-stats.1 b/Documentation/nvme-intel-lat-stats.1
index a936e9a..577c625 100644
--- a/Documentation/nvme-intel-lat-stats.1
+++ b/Documentation/nvme-intel-lat-stats.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-lat-stats
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-LAT\-ST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-LAT\-ST" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-market-name.1 b/Documentation/nvme-intel-market-name.1
index a19a844..92e2d3e 100644
--- a/Documentation/nvme-intel-market-name.1
+++ b/Documentation/nvme-intel-market-name.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-market-name
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-MARKET\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-MARKET\" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-smart-log-add.1 b/Documentation/nvme-intel-smart-log-add.1
index 94eac80..de28a8e 100644
--- a/Documentation/nvme-intel-smart-log-add.1
+++ b/Documentation/nvme-intel-smart-log-add.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-smart-log-add
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-SMART\-" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-SMART\-" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-temp-stats.1 b/Documentation/nvme-intel-temp-stats.1
index aaab8fa..90cb356 100644
--- a/Documentation/nvme-intel-temp-stats.1
+++ b/Documentation/nvme-intel-temp-stats.1
@@ -2,12 +2,12 @@
.\" Title: nvme-intel-temp-stats
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-INTEL\-TEMP\-S" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-INTEL\-TEMP\-S" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-intel-temp-stats.html b/Documentation/nvme-intel-temp-stats.html
index 2005af0..b97b8b4 100644
--- a/Documentation/nvme-intel-temp-stats.html
+++ b/Documentation/nvme-intel-temp-stats.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-intel-temp-stats(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -433,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -818,7 +821,8 @@ Print the raw SMART log to a file:
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2017-02-27 10:11:58 EST
+Last updated
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-io-passthru.1 b/Documentation/nvme-io-passthru.1
index 0f6c9be..b5e4322 100644
--- a/Documentation/nvme-io-passthru.1
+++ b/Documentation/nvme-io-passthru.1
@@ -2,12 +2,12 @@
.\" Title: nvme-io-passthru
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-IO\-PASSTHRU" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-IO\-PASSTHRU" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lba-status-log.1 b/Documentation/nvme-lba-status-log.1
new file mode 100644
index 0000000..6903a3e
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.1
@@ -0,0 +1,105 @@
+'\" t
+.\" Title: nvme-lba-status-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 02/24/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LBA\-STATUS\-L" "1" "02/24/2021" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lba-status-log \- Send LBA Status Log Page request returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lba\-status\-log\fR <device> [\-\-rae | \-r] [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe LBA Status Log Page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned LBA Status Log Page structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the LBA Status Log page in a normal readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lba\-status\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lba\-status\-log /dev/nvme0 \-o json
++
+
+NVME
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lba-status-log.html b/Documentation/nvme-lba-status-log.html
new file mode 100644
index 0000000..64cb938
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.html
@@ -0,0 +1,838 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-lba-status-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-lba-status-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lba-status-log -
+ Send LBA Status Log Page request returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme lba-status-log</em> &lt;device&gt; [--rae | -r] [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe LBA Status Log Page from an NVMe device and provides
+the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned LBA Status Log Page structure may be returned
+in one of several ways depending on the option flags; the structure may
+parsed by the program and printed in a readable format or the raw buffer
+may be printed to stdout for another program to parse.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or <em>binary</em>.
+ Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the LBA Status Log page in a normal readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lba-status-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lba-status-log /dev/nvme0 -o json
++
+
+NVME</code></pre>
+</div></div>
+</li>
+</ul></div>
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-02-23 23:41:13 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lba-status-log.txt b/Documentation/nvme-lba-status-log.txt
new file mode 100644
index 0000000..0d888f7
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.txt
@@ -0,0 +1,54 @@
+nvme-lba-status-log(1)
+======================
+
+NAME
+----
+nvme-lba-status-log - Send LBA Status Log Page request returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme lba-status-log' <device> [--rae | -r] [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe LBA Status Log Page from an NVMe device and provides
+the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned LBA Status Log Page structure may be returned
+in one of several ways depending on the option flags; the structure may
+parsed by the program and printed in a readable format or the raw buffer
+may be printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or 'binary'.
+ Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the LBA Status Log page in a normal readable format:
++
+------------
+# nvme lba-status-log /dev/nvme0
+------------
++
+
+* Show the output in json format
++
+------------
+# nvme lba-status-log /dev/nvme0 -o json
++
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-list-ctrl.1 b/Documentation/nvme-list-ctrl.1
index 516f1e8..ce64471 100644
--- a/Documentation/nvme-list-ctrl.1
+++ b/Documentation/nvme-list-ctrl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-list-ns.1 b/Documentation/nvme-list-ns.1
index 3297d39..084eb3e 100644
--- a/Documentation/nvme-list-ns.1
+++ b/Documentation/nvme-list-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -33,6 +33,7 @@ nvme-list-ns \- Send NVMe Identify List Namespaces, return result and structure
.sp
.nf
\fInvme list\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-csi=<command_set_identifier> | \-y <command_set_identifier>]
[\-\-all | \-a]
.fi
.SH "DESCRIPTION"
@@ -49,6 +50,11 @@ On success, the namespace array is printed for each index and nsid for a valid n
Retrieve the identify list structure starting with the given nsid\&.
.RE
.PP
+\-y <command_set_identifier>, \-\-csi=<command_set_identifier>
+.RS 4
+If this value is given, retrieve the identify list structure associated with the speicified I/O command set\&.
+.RE
+.PP
\-a, \-\-all
.RS 4
Retrieve the identify list structure for all namespaces in the subsystem, whether attached or inactive\&.
diff --git a/Documentation/nvme-list-ns.html b/Documentation/nvme-list-ns.html
index 45737bb..f88f3e8 100644
--- a/Documentation/nvme-list-ns.html
+++ b/Documentation/nvme-list-ns.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.9" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-id-ns(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -435,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -749,6 +750,7 @@ nvme-id-ns(1) Manual Page
<div class="sectionbody">
<div class="verseblock">
<pre class="content"><em>nvme list-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--csi=&lt;command_set_identifier&gt; | -y &lt;command_set_identifier&gt;]
[--all | -a]</pre>
<div class="attribution">
</div></div>
@@ -783,6 +785,18 @@ a valid nsid.</p></div>
</p>
</dd>
<dt class="hdlist1">
+-y &lt;command_set_identifier&gt;
+</dt>
+<dt class="hdlist1">
+--csi=&lt;command_set_identifier&gt;
+</dt>
+<dd>
+<p>
+ If this value is given, retrieve the identify list structure associated
+ with the speicified I/O command set.
+</p>
+</dd>
+<dt class="hdlist1">
-a
</dt>
<dt class="hdlist1">
@@ -814,7 +828,7 @@ a valid nsid.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2018-01-30 19:28:39 KST
+ 2020-05-06 10:35:44 CEST
</div>
</div>
</body>
diff --git a/Documentation/nvme-list-ns.txt b/Documentation/nvme-list-ns.txt
index 7cc90d8..6d7c1f4 100644
--- a/Documentation/nvme-list-ns.txt
+++ b/Documentation/nvme-list-ns.txt
@@ -9,6 +9,7 @@ SYNOPSIS
--------
[verse]
'nvme list-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--csi=<command_set_identifier> | -y <command_set_identifier>]
[--all | -a]
DESCRIPTION
@@ -30,6 +31,11 @@ OPTIONS
--namespace-id=<nsid>::
Retrieve the identify list structure starting with the given nsid.
+-y <command_set_identifier>::
+--csi=<command_set_identifier>::
+ If this value is given, retrieve the identify list structure associated
+ with the speicified I/O command set.
+
-a::
--all::
Retrieve the identify list structure for all namespaces in the
diff --git a/Documentation/nvme-list-subsys.1 b/Documentation/nvme-list-subsys.1
index a120021..500e7ea 100644
--- a/Documentation/nvme-list-subsys.1
+++ b/Documentation/nvme-list-subsys.1
@@ -2,12 +2,12 @@
.\" Title: nvme-list-subsys
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LIST\-SUBSYS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LIST\-SUBSYS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-list.1 b/Documentation/nvme-list.1
index da23dad..a83e9e8 100644
--- a/Documentation/nvme-list.1
+++ b/Documentation/nvme-list.1
@@ -2,12 +2,12 @@
.\" Title: nvme-list
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LIST" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-create.1 b/Documentation/nvme-lnvm-create.1
index 68a3a6f..6080207 100644
--- a/Documentation/nvme-lnvm-create.1
+++ b/Documentation/nvme-lnvm-create.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-create
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-CREATE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-CREATE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-diag-bbtbl.1 b/Documentation/nvme-lnvm-diag-bbtbl.1
index 3d80de0..398dc80 100644
--- a/Documentation/nvme-lnvm-diag-bbtbl.1
+++ b/Documentation/nvme-lnvm-diag-bbtbl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-diag-bbtbl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-DIAG\-BB" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-DIAG\-BB" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-diag-set-bbtbl.1 b/Documentation/nvme-lnvm-diag-set-bbtbl.1
index 1d67328..6d3b5a7 100644
--- a/Documentation/nvme-lnvm-diag-set-bbtbl.1
+++ b/Documentation/nvme-lnvm-diag-set-bbtbl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-diag-set-bbtbl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-DIAG\-SE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-DIAG\-SE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-factory.1 b/Documentation/nvme-lnvm-factory.1
index fb0a70b..0f713c2 100644
--- a/Documentation/nvme-lnvm-factory.1
+++ b/Documentation/nvme-lnvm-factory.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-factory
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-FACTORY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-FACTORY" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-id-ns.1 b/Documentation/nvme-lnvm-id-ns.1
index 22efa51..4156729 100644
--- a/Documentation/nvme-lnvm-id-ns.1
+++ b/Documentation/nvme-lnvm-id-ns.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-info.1 b/Documentation/nvme-lnvm-info.1
index e1f9c97..eff7406 100644
--- a/Documentation/nvme-lnvm-info.1
+++ b/Documentation/nvme-lnvm-info.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-info
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-INFO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-INFO" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-init.1 b/Documentation/nvme-lnvm-init.1
index b21a5c7..369b1af 100644
--- a/Documentation/nvme-lnvm-init.1
+++ b/Documentation/nvme-lnvm-init.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-init
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-INIT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-INIT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-list.1 b/Documentation/nvme-lnvm-list.1
index 65eb085..08ecc6d 100644
--- a/Documentation/nvme-lnvm-list.1
+++ b/Documentation/nvme-lnvm-list.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-list
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-LIST" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-lnvm-remove.1 b/Documentation/nvme-lnvm-remove.1
index 3dc3140..d6a8aa2 100644
--- a/Documentation/nvme-lnvm-remove.1
+++ b/Documentation/nvme-lnvm-remove.1
@@ -2,12 +2,12 @@
.\" Title: nvme-lnvm-remove
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-LNVM\-REMOVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-LNVM\-REMOVE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-micron-clear-pcie-errors.1 b/Documentation/nvme-micron-clear-pcie-errors.1
new file mode 100644
index 0000000..9fd417e
--- /dev/null
+++ b/Documentation/nvme-micron-clear-pcie-errors.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-micron-clear-pcie-errors
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-CLEAR\" "1" "10/20/2020" "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-micron-clear-pcie-errors \- Clears correctable PCIe correctable errors of given Micron device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron clear\-pcie\-correctable\-errors\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command clears corretable pcie errors for the specified Micron device\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model numbers 54XX\&. Support for new devices may be added subsequently\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve NAND statistics information
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron clear\-pcie\-correctable\-errors /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-clear-pcie-errors.html b/Documentation/nvme-micron-clear-pcie-errors.html
new file mode 100644
index 0000000..2c442bd
--- /dev/null
+++ b/Documentation/nvme-micron-clear-pcie-errors.html
@@ -0,0 +1,803 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-clear-pcie-errors(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-clear-pcie-errors(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-clear-pcie-errors - Clears correctable PCIe correctable errors of given Micron device</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron clear-pcie-correctable-errors</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This command clears corretable pcie errors for the specified Micron device.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 54XX. Support for new
+devices may be added subsequently.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve NAND statistics information
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron clear-pcie-correctable-errors /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 21:48:50 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-clear-pcie-errors.txt b/Documentation/nvme-micron-clear-pcie-errors.txt
new file mode 100644
index 0000000..d3afccf
--- /dev/null
+++ b/Documentation/nvme-micron-clear-pcie-errors.txt
@@ -0,0 +1,39 @@
+nvme-micron-clear-pcie-errors(1)
+===============================
+
+NAME
+----
+nvme-micron-clear-pcie-errors - Clears correctable PCIe correctable errors of given Micron device
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron clear-pcie-correctable-errors' <device>
+
+DESCRIPTION
+-----------
+This command clears corretable pcie errors for the specified Micron device.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model numbers 54XX. Support for new
+devices may be added subsequently.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Retrieve NAND statistics information
++
+------------
+# nvme micron clear-pcie-correctable-errors /dev/nvme0
+
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-internal-log.1 b/Documentation/nvme-micron-internal-log.1
new file mode 100644
index 0000000..4fb909d
--- /dev/null
+++ b/Documentation/nvme-micron-internal-log.1
@@ -0,0 +1,74 @@
+'\" t
+.\" Title: nvme-micron-internal-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-INTERN" "1" "10/20/2020" "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-micron-internal-log \- Retrieve Micron device\*(Aqs internal logs and save to given zip file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron vs\-internal\-log\fR <device> [\-\-package=<FILE>, \-p <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the given NVMe device, sends the Micron vendor specific device commands to retrieve various logs (in binary format) and compresses them and saves into speficied zip file\&. These vendor unique logs can be analysed with Micron Technical support team for any device specific issues
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model numbers 9200 and 54XX\&. Support for new devices may be added subsequently\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.PP
+\-l <FILE>, \-\-package=<FILE>
+.RS 4
+name of the file (with \&.zip extension) to save the device logs
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the logs from the device and saves to micron_logs\&.zip file
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron vs\-internal\-log /dev/nvme0 \-\-package=micron_logs\&.zip
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-internal-log.html b/Documentation/nvme-micron-internal-log.html
new file mode 100644
index 0000000..324092d
--- /dev/null
+++ b/Documentation/nvme-micron-internal-log.html
@@ -0,0 +1,818 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-internal-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-internal-log(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-internal-log - Retrieve Micron device&#8217;s internal logs and save to given zip file.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron vs-internal-log</em> &lt;device&gt; [--package=&lt;FILE&gt;, -p &lt;FILE&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the given NVMe device, sends the Micron vendor specific device commands to retrieve
+various logs (in binary format) and compresses them and saves into speficied zip file.
+These vendor unique logs can be analysed with Micron Technical support team for any device
+specific issues</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 9200 and 54XX. Support
+for new devices may be added subsequently. Results for any other device are undefined.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-l &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--package=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ name of the file (with .zip extension) to save the device logs
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Gets the logs from the device and saves to micron_logs.zip file
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron vs-internal-log /dev/nvme0 --package=micron_logs.zip</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 22:14:44 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-internal-log.txt b/Documentation/nvme-micron-internal-log.txt
new file mode 100644
index 0000000..66fb90f
--- /dev/null
+++ b/Documentation/nvme-micron-internal-log.txt
@@ -0,0 +1,43 @@
+nvme-micron-internal-log(1)
+==========================
+
+NAME
+----
+nvme-micron-internal-log - Retrieve Micron device's internal logs and save to given zip file.
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron vs-internal-log' <device> [--package=<FILE>, -p <FILE>]
+
+DESCRIPTION
+-----------
+For the given NVMe device, sends the Micron vendor specific device commands to retrieve
+various logs (in binary format) and compresses them and saves into speficied zip file.
+These vendor unique logs can be analysed with Micron Technical support team for any device
+specific issues
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model numbers 9200 and 54XX. Support
+for new devices may be added subsequently. Results for any other device are undefined.
+
+OPTIONS
+-------
+-l <FILE>::
+--package=<FILE>::
+ name of the file (with .zip extension) to save the device logs
+
+EXAMPLES
+--------
+* Gets the logs from the device and saves to micron_logs.zip file
++
+------------
+# nvme micron vs-internal-log /dev/nvme0 --package=micron_logs.zip
+
+------------
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-nand-stats.1 b/Documentation/nvme-micron-nand-stats.1
new file mode 100644
index 0000000..313e7d2
--- /dev/null
+++ b/Documentation/nvme-micron-nand-stats.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-micron-nand-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-NAND\-" "1" "10/20/2020" "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-micron-nand-stats \- Retrieves NAND statistics of given micron device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron vs\-nand\-stats\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command prints NAND information (Total bytes written, Bad block count and Erase failures etc) for the given micron device\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model numbers 54XX\&. Support for new devices may be added subsequently\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve NAND statistics information
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron vs\-nand\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-nand-stats.html b/Documentation/nvme-micron-nand-stats.html
new file mode 100644
index 0000000..175dfd3
--- /dev/null
+++ b/Documentation/nvme-micron-nand-stats.html
@@ -0,0 +1,804 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-nand-stats(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-nand-stats(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-nand-stats - Retrieves NAND statistics of given micron device</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron vs-nand-stats</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This command prints NAND information (Total bytes written, Bad block count and
+Erase failures etc) for the given micron device.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 54XX. Support for
+new devices may be added subsequently.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve NAND statistics information
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron vs-nand-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 22:31:51 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-nand-stats.txt b/Documentation/nvme-micron-nand-stats.txt
new file mode 100644
index 0000000..68e211e
--- /dev/null
+++ b/Documentation/nvme-micron-nand-stats.txt
@@ -0,0 +1,40 @@
+nvme-micron-nand-stats(1)
+=========================
+
+NAME
+----
+nvme-micron-nand-stats - Retrieves NAND statistics of given micron device
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron vs-nand-stats' <device>
+
+DESCRIPTION
+-----------
+This command prints NAND information (Total bytes written, Bad block count and
+Erase failures etc) for the given micron device.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model numbers 54XX. Support for
+new devices may be added subsequently.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Retrieve NAND statistics information
++
+------------
+# nvme micron vs-nand-stats /dev/nvme0
+
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-pcie-stats.1 b/Documentation/nvme-micron-pcie-stats.1
new file mode 100644
index 0000000..3070c7e
--- /dev/null
+++ b/Documentation/nvme-micron-pcie-stats.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-micron-pcie-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-PCIE\-" "1" "10/20/2020" "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-micron-pcie-stats \- Retrieves pcie error statistics for given micron device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron vs\-pcie\-stats\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command prints pcie correctable and uncorrectable error information for the given micron device\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model numbers 54XX\&. Support for new devices may be added subsequently\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve PCIe error information
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron vs\-pcie\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-pcie-stats.html b/Documentation/nvme-micron-pcie-stats.html
new file mode 100644
index 0000000..c27f4bb
--- /dev/null
+++ b/Documentation/nvme-micron-pcie-stats.html
@@ -0,0 +1,804 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-pcie-stats(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-pcie-stats(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-pcie-stats - Retrieves pcie error statistics for given micron device</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron vs-pcie-stats</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This command prints pcie correctable and uncorrectable error information for the
+given micron device.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 54XX. Support for
+new devices may be added subsequently.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve PCIe error information
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron vs-pcie-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 22:25:46 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-pcie-stats.txt b/Documentation/nvme-micron-pcie-stats.txt
new file mode 100644
index 0000000..f58257a
--- /dev/null
+++ b/Documentation/nvme-micron-pcie-stats.txt
@@ -0,0 +1,40 @@
+nvme-micron-pcie-stats(1)
+=========================
+
+NAME
+----
+nvme-micron-pcie-stats - Retrieves pcie error statistics for given micron device
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron vs-pcie-stats' <device>
+
+DESCRIPTION
+-----------
+This command prints pcie correctable and uncorrectable error information for the
+given micron device.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model numbers 54XX. Support for
+new devices may be added subsequently.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Retrieve PCIe error information
++
+------------
+# nvme micron vs-pcie-stats /dev/nvme0
+
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-selective-download.1 b/Documentation/nvme-micron-selective-download.1
new file mode 100644
index 0000000..fd521b5
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.1
@@ -0,0 +1,139 @@
+'\" t
+.\" Title: nvme-micron-selective-download
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-SELECT" "1" "10/20/2020" "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-micron-selective-download \- Performs selective firmware download that allows user to select which firmware binary to update for 9200 devices\&. This requires power cycle once the update completes\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron selective\-download\fR <device> [\-\-fw=<FILE>, \-f <FILE>] [\-\-select=<flag>, \-s <flag>]
+.fi
+.SH "DESCRIPTION"
+.sp
+This command uses micron vendor specific nvme commands to download given firmware image to the specified 9200 device to update selected or all portions of firmware image\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model number 9200\&. Support for new devices may be added subsequently\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.PP
+\-f <FILE>, \-\-fw=<FILE>
+.RS 4
+name of the firmware image file
+.RE
+.PP
+\-s <flag>, \-\-select=<flag>
+.RS 4
+flag that has following values
+.RE
+.PP
+OOB
+.RS 4
+This updates the OOB and main firmware\en"
+.RE
+.PP
+EEP
+.RS 4
+This updates the eeprom and main firmware\en"
+.RE
+.PP
+ALL
+.RS 4
+This updates the eeprom, OOB, and main firmware";
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Update OOB and main firmware
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron selective\-download /dev/nvme0 \-\-fw=firmware_bin \-\-select=OOB
+# nvme micron selective\-download /dev/nvme0 \-f firmware_bin \-s OOB
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Update OOB and main firmware
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron selective\-download /dev/nvme0 \-\-fw=firmware_bin \-\-select=EEP
+# nvme micron selective\-download /dev/nvme0 \-f firmware_bin \-\-s EEP
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Update eeprom, OOB and main firmware
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron selective\-download /dev/nvme0 \-\-fw=firmware_bin \-\-select=ALL
+# nvme micron selective\-download /dev/nvme0 \-f firmware_bin \-\-s ALL
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-selective-download.html b/Documentation/nvme-micron-selective-download.html
new file mode 100644
index 0000000..7281f48
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.html
@@ -0,0 +1,874 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-selective-download(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-selective-download(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-selective-download - Performs selective firmware download that allows user
+to select which firmware binary to update for 9200 devices. This requires power cycle
+once the update completes.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron selective-download</em> &lt;device&gt; [--fw=&lt;FILE&gt;, -f &lt;FILE&gt;] [--select=&lt;flag&gt;, -s &lt;flag&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This command uses micron vendor specific nvme commands to download given firmware image to the
+specified 9200 device to update selected or all portions of firmware image.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model number 9200. Support for new devices
+may be added subsequently. Results for any other device are undefined.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-f &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--fw=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ name of the firmware image file
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;flag&gt;
+</dt>
+<dt class="hdlist1">
+--select=&lt;flag&gt;
+</dt>
+<dd>
+<p>
+ flag that has following values
+</p>
+</dd>
+<dt class="hdlist1">
+OOB
+</dt>
+<dd>
+<p>
+This updates the OOB and main firmware\n"
+</p>
+</dd>
+<dt class="hdlist1">
+EEP
+</dt>
+<dd>
+<p>
+This updates the eeprom and main firmware\n"
+</p>
+</dd>
+<dt class="hdlist1">
+ALL
+</dt>
+<dd>
+<p>
+This updates the eeprom, OOB, and main firmware";
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Update OOB and main firmware
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=OOB
+# nvme micron selective-download /dev/nvme0 -f firmware_bin -s OOB</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Update OOB and main firmware
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=EEP
+# nvme micron selective-download /dev/nvme0 -f firmware_bin --s EEP</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Update eeprom, OOB and main firmware
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=ALL
+# nvme micron selective-download /dev/nvme0 -f firmware_bin --s ALL</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 21:49:53 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-selective-download.txt b/Documentation/nvme-micron-selective-download.txt
new file mode 100644
index 0000000..5fb11d7
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.txt
@@ -0,0 +1,63 @@
+nvme-micron-selective-download(1)
+=================================
+
+NAME
+----
+nvme-micron-selective-download - Performs selective firmware download that allows user
+to select which firmware binary to update for 9200 devices. This requires power cycle
+once the update completes.
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron selective-download' <device> [--fw=<FILE>, -f <FILE>] [--select=<flag>, -s <flag>]
+
+DESCRIPTION
+-----------
+This command uses micron vendor specific nvme commands to download given firmware image to the
+specified 9200 device to update selected or all portions of firmware image.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model number 9200. Support for new devices
+may be added subsequently. Results for any other device are undefined.
+
+OPTIONS
+-------
+-f <FILE>::
+--fw=<FILE>::
+ name of the firmware image file
+-s <flag>::
+--select=<flag>::
+ flag that has following values
+ OOB:: This updates the OOB and main firmware\n"
+ EEP:: This updates the eeprom and main firmware\n"
+ ALL:: This updates the eeprom, OOB, and main firmware";
+
+EXAMPLES
+--------
+* Update OOB and main firmware
++
+------------
+# nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=OOB
+# nvme micron selective-download /dev/nvme0 -f firmware_bin -s OOB
+
+------------
+* Update OOB and main firmware
++
+------------
+# nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=EEP
+# nvme micron selective-download /dev/nvme0 -f firmware_bin --s EEP
+------------
+* Update eeprom, OOB and main firmware
++
+------------
+# nvme micron selective-download /dev/nvme0 --fw=firmware_bin --select=ALL
+# nvme micron selective-download /dev/nvme0 -f firmware_bin --s ALL
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-temperature-stats.1 b/Documentation/nvme-micron-temperature-stats.1
new file mode 100644
index 0000000..71297d1
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-micron-temperarature-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-TEMPER" "1" "10/20/2020" "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-micron-temperature-stats \- Retrieves temperature information of given micron device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron vs\-temperature\-stats\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command prints temperature information (composite temperature and number of active temperature sensors) for the given micron device\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on Micron devices devices of model numbers 54XX\&. Support for new devices may be added subsequently\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve temperature information
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron vs\-temperature\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-temperature-stats.html b/Documentation/nvme-micron-temperature-stats.html
new file mode 100644
index 0000000..6701cc2
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.html
@@ -0,0 +1,804 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-micron-temperarature-stats(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>nvme-micron-temperarature-stats(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-micron-temperature-stats - Retrieves temperature information of given micron device</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme micron vs-temperature-stats</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This command prints temperature information (composite temperature and number of active
+temperature sensors) for the given micron device.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 54XX. Support for new
+devices may be added subsequently.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve temperature information
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron vs-temperature-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2019-12-19 22:32:11 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-temperature-stats.txt b/Documentation/nvme-micron-temperature-stats.txt
new file mode 100644
index 0000000..43061c0
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.txt
@@ -0,0 +1,40 @@
+nvme-micron-temperarature-stats(1)
+==================================
+
+NAME
+----
+nvme-micron-temperature-stats - Retrieves temperature information of given micron device
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron vs-temperature-stats' <device>
+
+DESCRIPTION
+-----------
+This command prints temperature information (composite temperature and number of active
+temperature sensors) for the given micron device.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+This will only work on Micron devices devices of model numbers 54XX. Support for new
+devices may be added subsequently.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Retrieve temperature information
++
+------------
+# nvme micron vs-temperature-stats /dev/nvme0
+
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-netapp-ontapdevices.1 b/Documentation/nvme-netapp-ontapdevices.1
index 83bc5cb..7a0fdc0 100644
--- a/Documentation/nvme-netapp-ontapdevices.1
+++ b/Documentation/nvme-netapp-ontapdevices.1
@@ -2,12 +2,12 @@
.\" Title: nvme-netapp-ontapdevices
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-NETAPP\-ONTAPD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-NETAPP\-ONTAPD" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-netapp-smdevices.1 b/Documentation/nvme-netapp-smdevices.1
index 78622ea..b0d052a 100644
--- a/Documentation/nvme-netapp-smdevices.1
+++ b/Documentation/nvme-netapp-smdevices.1
@@ -2,12 +2,12 @@
.\" Title: nvme-netapp-smdevices
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-NETAPP\-SMDEVI" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-NETAPP\-SMDEVI" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-ns-descs.1 b/Documentation/nvme-ns-descs.1
index cddc126..907a081 100644
--- a/Documentation/nvme-ns-descs.1
+++ b/Documentation/nvme-ns-descs.1
@@ -2,12 +2,12 @@
.\" Title: nvme-ns-descs
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-NS\-DESCS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-NS\-DESCS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-ns-rescan.1 b/Documentation/nvme-ns-rescan.1
index 5fcf6e8..8be4772 100644
--- a/Documentation/nvme-ns-rescan.1
+++ b/Documentation/nvme-ns-rescan.1
@@ -2,12 +2,12 @@
.\" Title: nvme-ns-rescan
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-NS\-RESCAN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-NS\-RESCAN" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-ns-rescan.html b/Documentation/nvme-ns-rescan.html
index f4b0346..5e94762 100644
--- a/Documentation/nvme-ns-rescan.html
+++ b/Documentation/nvme-ns-rescan.html
@@ -1,455 +1,801 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
- "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.4.5" />
-<title>nvme-ns-rescan(1)</title>
-<style type="text/css">
-/* Debug borders */
-p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
-/*
- border: 1px solid red;
-*/
-}
-
-body {
- margin: 1em 5% 1em 5%;
-}
-
-a {
- color: blue;
- text-decoration: underline;
-}
-a:visited {
- color: fuchsia;
-}
-
-em {
- font-style: italic;
- color: navy;
-}
-
-strong {
- font-weight: bold;
- color: #083194;
-}
-
-tt {
- color: navy;
-}
-
-h1, h2, h3, h4, h5, h6 {
- color: #527bbd;
- font-family: sans-serif;
- margin-top: 1.2em;
- margin-bottom: 0.5em;
- line-height: 1.3;
-}
-
-h1, h2, h3 {
- border-bottom: 2px solid silver;
-}
-h2 {
- padding-top: 0.5em;
-}
-h3 {
- float: left;
-}
-h3 + * {
- clear: left;
-}
-
-div.sectionbody {
- font-family: serif;
- margin-left: 0;
-}
-
-hr {
- border: 1px solid silver;
-}
-
-p {
- margin-top: 0.5em;
- margin-bottom: 0.5em;
-}
-
-ul, ol, li > p {
- margin-top: 0;
-}
-
-pre {
- padding: 0;
- margin: 0;
-}
-
-span#author {
- color: #527bbd;
- font-family: sans-serif;
- font-weight: bold;
- font-size: 1.1em;
-}
-span#email {
-}
-span#revnumber, span#revdate, span#revremark {
- font-family: sans-serif;
-}
-
-div#footer {
- font-family: sans-serif;
- font-size: small;
- border-top: 2px solid silver;
- padding-top: 0.5em;
- margin-top: 4.0em;
-}
-div#footer-text {
- float: left;
- padding-bottom: 0.5em;
-}
-div#footer-badges {
- float: right;
- padding-bottom: 0.5em;
-}
-
-div#preamble {
- margin-top: 1.5em;
- margin-bottom: 1.5em;
-}
-div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
-div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
-div.admonitionblock {
- margin-top: 1.5em;
- margin-bottom: 1.5em;
-}
-div.admonitionblock {
- margin-top: 2.5em;
- margin-bottom: 2.5em;
-}
-
-div.content { /* Block element content. */
- padding: 0;
-}
-
-/* Block element titles. */
-div.title, caption.title {
- color: #527bbd;
- font-family: sans-serif;
- font-weight: bold;
- text-align: left;
- margin-top: 1.0em;
- margin-bottom: 0.5em;
-}
-div.title + * {
- margin-top: 0;
-}
-
-td div.title:first-child {
- margin-top: 0.0em;
-}
-div.content div.title:first-child {
- margin-top: 0.0em;
-}
-div.content + div.title {
- margin-top: 0.0em;
-}
-
-div.sidebarblock > div.content {
- background: #ffffee;
- border: 1px solid silver;
- padding: 0.5em;
-}
-
-div.listingblock > div.content {
- border: 1px solid silver;
- background: #f4f4f4;
- padding: 0.5em;
-}
-
-div.quoteblock {
- padding-left: 2.0em;
- margin-right: 10%;
-}
-div.quoteblock > div.attribution {
- padding-top: 0.5em;
- text-align: right;
-}
-
-div.verseblock {
- padding-left: 2.0em;
- margin-right: 10%;
-}
-div.verseblock > div.content {
- white-space: pre;
-}
-div.verseblock > div.attribution {
- padding-top: 0.75em;
- text-align: left;
-}
-/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
-div.verseblock + div.attribution {
- text-align: left;
-}
-
-div.admonitionblock .icon {
- vertical-align: top;
- font-size: 1.1em;
- font-weight: bold;
- text-decoration: underline;
- color: #527bbd;
- padding-right: 0.5em;
-}
-div.admonitionblock td.content {
- padding-left: 0.5em;
- border-left: 2px solid silver;
-}
-
-div.exampleblock > div.content {
- border-left: 2px solid silver;
- padding: 0.5em;
-}
-
-div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
-a.image:visited { color: white; }
-
-dl {
- margin-top: 0.8em;
- margin-bottom: 0.8em;
-}
-dt {
- margin-top: 0.5em;
- margin-bottom: 0;
- font-style: normal;
- color: navy;
-}
-dd > *:first-child {
- margin-top: 0.1em;
-}
-
-ul, ol {
- list-style-position: outside;
-}
-ol.arabic {
- list-style-type: decimal;
-}
-ol.loweralpha {
- list-style-type: lower-alpha;
-}
-ol.upperalpha {
- list-style-type: upper-alpha;
-}
-ol.lowerroman {
- list-style-type: lower-roman;
-}
-ol.upperroman {
- list-style-type: upper-roman;
-}
-
-div.compact ul, div.compact ol,
-div.compact p, div.compact p,
-div.compact div, div.compact div {
- margin-top: 0.1em;
- margin-bottom: 0.1em;
-}
-
-div.tableblock > table {
- border: 3px solid #527bbd;
-}
-thead {
- font-family: sans-serif;
- font-weight: bold;
-}
-tfoot {
- font-weight: bold;
-}
-td > div.verse {
- white-space: pre;
-}
-p.table {
- margin-top: 0;
-}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
-div.tableblock > table[frame="void"] {
- border-style: none;
-}
-div.tableblock > table[frame="hsides"] {
- border-left-style: none;
- border-right-style: none;
-}
-div.tableblock > table[frame="vsides"] {
- border-top-style: none;
- border-bottom-style: none;
-}
-
-
-div.hdlist {
- margin-top: 0.8em;
- margin-bottom: 0.8em;
-}
-div.hdlist tr {
- padding-bottom: 15px;
-}
-dt.hdlist1.strong, td.hdlist1.strong {
- font-weight: bold;
-}
-td.hdlist1 {
- vertical-align: top;
- font-style: normal;
- padding-right: 0.8em;
- color: navy;
-}
-td.hdlist2 {
- vertical-align: top;
-}
-div.hdlist.compact tr {
- margin: 0;
- padding-bottom: 0;
-}
-
-.comment {
- background: yellow;
-}
-
-@media print {
- div#footer-badges { display: none; }
-}
-
-div#toctitle {
- color: #527bbd;
- font-family: sans-serif;
- font-size: 1.1em;
- font-weight: bold;
- margin-top: 1.0em;
- margin-bottom: 0.1em;
-}
-
-div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
- margin-top: 0;
- margin-bottom: 0;
-}
-div.toclevel2 {
- margin-left: 2em;
- font-size: 0.9em;
-}
-div.toclevel3 {
- margin-left: 4em;
- font-size: 0.9em;
-}
-div.toclevel4 {
- margin-left: 6em;
- font-size: 0.9em;
-}
-/* Overrides for manpage documents */
-h1 {
- padding-top: 0.5em;
- padding-bottom: 0.5em;
- border-top: 2px solid silver;
- border-bottom: 2px solid silver;
-}
-h2 {
- border-style: none;
-}
-div.sectionbody {
- margin-left: 5%;
-}
-
-@media print {
- div#toc { display: none; }
-}
-
-/* Workarounds for IE6's broken and incomplete CSS2. */
-
-div.sidebar-content {
- background: #ffffee;
- border: 1px solid silver;
- padding: 0.5em;
-}
-div.sidebar-title, div.image-title {
- color: #527bbd;
- font-family: sans-serif;
- font-weight: bold;
- margin-top: 0.0em;
- margin-bottom: 0.5em;
-}
-
-div.listingblock div.content {
- border: 1px solid silver;
- background: #f4f4f4;
- padding: 0.5em;
-}
-
-div.quoteblock-attribution {
- padding-top: 0.5em;
- text-align: right;
-}
-
-div.verseblock-content {
- white-space: pre;
-}
-div.verseblock-attribution {
- padding-top: 0.75em;
- text-align: left;
-}
-
-div.exampleblock-content {
- border-left: 2px solid silver;
- padding-left: 0.5em;
-}
-
-/* IE6 sets dynamically generated links as visited. */
-div#toc a:visited { color: blue; }
-</style>
-</head>
-<body>
-<div id="header">
-<h1>
-nvme-ns-rescan(1) Manual Page
-</h1>
-<h2>NAME</h2>
-<div class="sectionbody">
-<p>nvme-ns-rescan -
- Rescans the nvme namespaces.
-</p>
-</div>
-</div>
-<h2 id="_synopsis">SYNOPSIS</h2>
-<div class="sectionbody">
-<div class="verseblock">
-<div class="verseblock-content"><em>nvme ns-rescan</em> &lt;device&gt;</div>
-<div class="verseblock-attribution">
-</div></div>
-</div>
-<h2 id="_description">DESCRIPTION</h2>
-<div class="sectionbody">
-<div class="paragraph"><p>Requests NVMe controller rescans the namespaces. The &lt;device&gt; param is mandatory and must
-be an NVMe character device (ex: /dev/nvme0).</p></div>
-</div>
-<h2 id="_options">OPTIONS</h2>
-<div class="sectionbody">
-<div class="paragraph"><p>None</p></div>
-</div>
-<h2 id="_examples">EXAMPLES</h2>
-<div class="sectionbody">
-<div class="ulist"><ul>
-<li>
-<p>
-Rescans the nvme namespaces.
-</p>
-<div class="listingblock">
-<div class="content">
-<pre><tt># nvme ns-rescan /dev/nvme0</tt></pre>
-</div></div>
-</li>
-</ul></div>
-</div>
-<h2 id="_nvme">NVME</h2>
-<div class="sectionbody">
-<div class="paragraph"><p>Part of the nvme-user suite</p></div>
-</div>
-<div id="footer">
-<div id="footer-text">
-Last updated 2017-09-22 16:31:43 CDT
-</div>
-</div>
-</body>
-</html>
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-ns-rescan(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-ns-rescan(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ns-rescan -
+ Rescans the nvme namespaces.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme ns-rescan</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Requests NVMe controller rescans the namespaces. The &lt;device&gt; param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Rescans the nvme namespaces.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ns-rescan /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-08 08:31:26 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvm-id-ctrl.1 b/Documentation/nvme-nvm-id-ctrl.1
new file mode 100644
index 0000000..4d1c634
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.1
@@ -0,0 +1,98 @@
+'\" t
+.\" Title: nvme-nvm-id-ctrl
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 02/18/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVM\-ID\-CTRL" "1" "02/18/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-nvm-id-ctrl \- Send NVMe Identify Controller, return NVM command set structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme nvm\-id\-ctrl\fR <device> [\-o <fmt> | \-\-output\-format=<fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the NVM command set\(cqs identify controller command and provides the result and returned structure\&.
+.sp
+The <device> 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 data structure returned by the device will be decoded and displayed in one of several ways\&.
+.SH "OPTIONS"
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program interpret the returned buffer and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvm\-id\-ctrl /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvm\-id\-ctrl /dev/nvme0 \-o json
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-nvm-id-ctrl.html b/Documentation/nvme-nvm-id-ctrl.html
new file mode 100644
index 0000000..fa08be0
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.html
@@ -0,0 +1,828 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-nvm-id-ctrl(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-nvm-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-nvm-id-ctrl -
+ Send NVMe Identify Controller, return NVM command set structure
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme nvm-id-ctrl</em> &lt;device&gt; [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends the NVM command set&#8217;s identify controller
+command and provides the result and returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the data structure returned by the device will be decoded and
+displayed in one of several ways.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program interpret the returned buffer and display the known
+fields in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvm-id-ctrl /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvm-id-ctrl /dev/nvme0 -o json</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-02-18 15:56:16 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvm-id-ctrl.txt b/Documentation/nvme-nvm-id-ctrl.txt
new file mode 100644
index 0000000..fb4a237
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.txt
@@ -0,0 +1,49 @@
+nvme-nvm-id-ctrl(1)
+===================
+
+NAME
+----
+nvme-nvm-id-ctrl - Send NVMe Identify Controller, return NVM command set structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme nvm-id-ctrl' <device> [-o <fmt> | --output-format=<fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the NVM command set's identify controller
+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 data structure returned by the device will be decoded and
+displayed in one of several ways.
+
+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.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme nvm-id-ctrl /dev/nvme0
+------------
++
+
+* Show the output in json format
++
+------------
+# nvme nvm-id-ctrl /dev/nvme0 -o json
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-persistent-event-log.1 b/Documentation/nvme-persistent-event-log.1
new file mode 100644
index 0000000..5d74346
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" Title: persistent-event-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 01/11/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "PERSISTENT\-EVENT\-L" "1" "01/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-persistent-event-log \- Send NVMe persistent event log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme persistent\-event\-log\fR <device> [\-\-action=<action> | \-a <action>]
+ [\-\-log\-len=<log\-len> | \-l <log\-len>]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe persistent event log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned persistent event log structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-a <action>, \-\-action=<action>
+.RS 4
+While try to retrieve this log action the controller shall take during processing this persistent log page command\&. This mandatory field, based on the value issued it may Read Log Data, Establish Context and Read Log Data or Release Context can occur\&. For More details see NVM Express 1\&.4 Spec\&. Section 5\&.14\&.1\&.13 Persistent Event Log (Log Identifier 0Dh)
+.RE
+.PP
+\-l <log\-len>, \-\-log\-len=<log\-len>
+.RS 4
+Allocates a buffer of <log\-len> bytes size and requests this many bytes be returned in the constructed NVMe command\&. This param is mandatory\&. If <log\-len> given is 0 and action is 0, it will read the Total Log Length(TLL) of the page\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw persistent event log buffer to stdout\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the persistent event log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme persistent\-event\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the raw persistent event log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme persistent\-event\-log /dev/nvme0 \-\-raw\-binary > persistent_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-persistent-event-log.html b/Documentation/nvme-persistent-event-log.html
new file mode 100644
index 0000000..44a6499
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.html
@@ -0,0 +1,874 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>persistent-event-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+persistent-event-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-persistent-event-log -
+ Send NVMe persistent event log page request, returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme persistent-event-log</em> &lt;device&gt; [--action=&lt;action&gt; | -a &lt;action&gt;]
+ [--log-len=&lt;log-len&gt; | -l &lt;log-len&gt;]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe persistent event log page from an NVMe device
+and provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned persistent event log 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.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-a &lt;action&gt;
+</dt>
+<dt class="hdlist1">
+--action=&lt;action&gt;
+</dt>
+<dd>
+<p>
+ While try to retrieve this log action the controller shall take
+ during processing this persistent log page command. This mandatory
+ field, based on the value issued it may Read Log Data, Establish
+ Context and Read Log Data or Release Context can occur. For More
+ details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent
+ Event Log (Log Identifier 0Dh)
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;log-len&gt;
+</dt>
+<dt class="hdlist1">
+--log-len=&lt;log-len&gt;
+</dt>
+<dd>
+<p>
+ Allocates a buffer of &lt;log-len&gt; bytes size and requests this
+ many bytes be returned in the constructed NVMe command. This
+ param is mandatory. If &lt;log-len&gt; given is 0 and action is 0,
+ it will read the Total Log Length(TLL) of the page.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw persistent event log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or <em>binary</em>.
+ Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the persistent event log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme persistent-event-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw persistent event log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme persistent-event-log /dev/nvme0 --raw-binary &gt; persistent_log.raw</code></pre>
+</div></div>
+<div class="paragraph"><p>It is probably a bad idea to not redirect stdout when using this mode.</p></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-01-11 17:07:01 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-persistent-event-log.txt b/Documentation/nvme-persistent-event-log.txt
new file mode 100644
index 0000000..833491f
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.txt
@@ -0,0 +1,76 @@
+persistent-event-log(1)
+=======================
+
+NAME
+----
+nvme-persistent-event-log - Send NVMe persistent event log page request,
+returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme persistent-event-log' <device> [--action=<action> | -a <action>]
+ [--log-len=<log-len> | -l <log-len>]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe persistent event log page from an NVMe device
+and provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned persistent event log 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
+-------
+-a <action>::
+--action=<action>::
+ While try to retrieve this log action the controller shall take
+ during processing this persistent log page command. This mandatory
+ field, based on the value issued it may Read Log Data, Establish
+ Context and Read Log Data or Release Context can occur. For More
+ details see NVM Express 1.4 Spec. Section 5.14.1.13 Persistent
+ Event Log (Log Identifier 0Dh)
+
+-l <log-len>::
+--log-len=<log-len>::
+ Allocates a buffer of <log-len> bytes size and requests this
+ many bytes be returned in the constructed NVMe command. This
+ param is mandatory. If <log-len> given is 0 and action is 0,
+ it will read the Total Log Length(TLL) of the page.
+
+-b::
+--raw-binary::
+ Print the raw persistent event log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or 'binary'.
+ Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the persistent event log page in a human readable format:
++
+------------
+# nvme persistent-event-log /dev/nvme0
+------------
++
+
+* Print the raw persistent event log to a file:
++
+------------
+# nvme persistent-event-log /dev/nvme0 --raw-binary > persistent_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-pred-lat-event-agg-log.1 b/Documentation/nvme-pred-lat-event-agg-log.1
new file mode 100644
index 0000000..69785cb
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.1
@@ -0,0 +1,117 @@
+'\" t
+.\" Title: nvme-pred-lat-event-agg-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 01/12/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-PRED\-LAT\-EVE" "1" "01/12/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-pred-lat-event-agg-log \- Send Predictable Latency Event Aggregate Log Page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme pred\-lat\-event\-agg\-log\fR <device> [\-\-log\-entries=<log_entries> | \-e <log_entries>]
+ [\-\-rae | \-r] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Predictable Latency Event Aggregate Log Page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned Predictable Latency Event Aggregate Log Page structure may be returned in one ofseveral ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-e <log_entries>, \-\-log\-entries=<log_entries>
+.RS 4
+Retrieve the Predictable Latency Event Aggregate Log pending entries\&. This argument is mandatory and its success may depend on the device\(cqs statistics to provide this log For More details see NVM Express 1\&.4 Spec\&. Section 5\&.14\&.1\&.11\&. The maximum number of log entries supported is 2044 for the device\&.
+.RE
+.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw Predectible Latency Event Aggregate log buffer to stdout\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Predictable Latency Event Aggregate Log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme pred\-lat\-event\-agg\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the raw Predectible Latency Event Aggregate log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme pred\-lat\-event\-agg\-log /dev/nvme0 \-\-raw\-binary > pred_lat_agg_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-pred-lat-event-agg-log.html b/Documentation/nvme-pred-lat-event-agg-log.html
new file mode 100644
index 0000000..42c370f
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.html
@@ -0,0 +1,870 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-pred-lat-event-agg-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-pred-lat-event-agg-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-pred-lat-event-agg-log -
+ Send Predictable Latency Event Aggregate Log Page request, returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme pred-lat-event-agg-log</em> &lt;device&gt; [--log-entries=&lt;log_entries&gt; | -e &lt;log_entries&gt;]
+ [--rae | -r] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe Predictable Latency Event Aggregate Log Page from an
+NVMe device and provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned Predictable Latency Event Aggregate Log
+Page structure may be returned in one ofseveral 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.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;log_entries&gt;
+</dt>
+<dt class="hdlist1">
+--log-entries=&lt;log_entries&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the Predictable Latency Event Aggregate Log pending entries.
+ This argument is mandatory and its success may depend on the device&#8217;s
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.11. The maximum number of log entries supported is 2044
+ for the device.
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw Predectible Latency Event Aggregate log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or <em>binary</em>.
+ Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the Predictable Latency Event Aggregate Log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme pred-lat-event-agg-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw Predectible Latency Event Aggregate log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme pred-lat-event-agg-log /dev/nvme0 --raw-binary &gt; pred_lat_agg_log.raw</code></pre>
+</div></div>
+<div class="paragraph"><p>It is probably a bad idea to not redirect stdout when using this mode.</p></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-01-12 00:04:13 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-pred-lat-event-agg-log.txt b/Documentation/nvme-pred-lat-event-agg-log.txt
new file mode 100644
index 0000000..d7d998b
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.txt
@@ -0,0 +1,72 @@
+nvme-pred-lat-event-agg-log(1)
+==============================
+
+NAME
+----
+nvme-pred-lat-event-agg-log - Send Predictable Latency Event Aggregate Log
+Page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme pred-lat-event-agg-log' <device> [--log-entries=<log_entries> | -e <log_entries>]
+ [--rae | -r] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Predictable Latency Event Aggregate Log Page from an
+NVMe device and provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned Predictable Latency Event Aggregate Log
+Page structure may be returned in one ofseveral 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
+-------
+-e <log_entries>::
+--log-entries=<log_entries>::
+ Retrieve the Predictable Latency Event Aggregate Log pending entries.
+ This argument is mandatory and its success may depend on the device's
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.11. The maximum number of log entries supported is 2044
+ for the device.
+
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+-b::
+--raw-binary::
+ Print the raw Predectible Latency Event Aggregate log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or 'binary'.
+ Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the Predictable Latency Event Aggregate Log page in a human readable format:
++
+------------
+# nvme pred-lat-event-agg-log /dev/nvme0
+------------
++
+
+* Print the raw Predectible Latency Event Aggregate log to a file:
++
+------------
+# nvme pred-lat-event-agg-log /dev/nvme0 --raw-binary > pred_lat_agg_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-predictable-lat-log.1 b/Documentation/nvme-predictable-lat-log.1
new file mode 100644
index 0000000..41dd16c
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" Title: nvme-predictable-lat-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 01/13/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-PREDICTABLE\-L" "1" "01/13/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-predictable-lat-log \- Send Predectible latency per NVM set log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme predictable\-lat\-log\fR <device> [\-\-nvmset\-id=<nvmset_id> | \-i <nvmset_id>]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned Predectible latency per NVM set log structure may be returned in one ofseveral ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-i <nvmset_id>, \-\-nvmset\-id=<nvmset_id>
+.RS 4
+Retrieve the Predectible latency per NVM set log for the given nvmset id\&. This argument is mandatory and its success may depend on the device\(cqs statistics to provide this log For More details see NVM Express 1\&.4 Spec\&. Section 5\&.14\&.1\&.10\&. The default nvmset id to use is 1 for the device\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw Predectible latency per NVM set log buffer to stdout\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Predectible latency per NVM set log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme predictable\-lat\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the raw Predectible latency per NVM set log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme predictable\-lat\-log /dev/nvme0 \-\-raw\-binary > nvmset_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-predictable-lat-log.html b/Documentation/nvme-predictable-lat-log.html
new file mode 100644
index 0000000..42dfda8
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.html
@@ -0,0 +1,857 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-predictable-lat-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-predictable-lat-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-predictable-lat-log -
+ Send Predectible latency per NVM set log page request, returns result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme predictable-lat-log</em> &lt;device&gt; [--nvmset-id=&lt;nvmset_id&gt; | -i &lt;nvmset_id&gt;]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device
+and provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned Predectible latency per NVM set log structure
+may be returned in one ofseveral 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.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-i &lt;nvmset_id&gt;
+</dt>
+<dt class="hdlist1">
+--nvmset-id=&lt;nvmset_id&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the Predectible latency per NVM set log for the given nvmset id.
+ This argument is mandatory and its success may depend on the device&#8217;s
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.10. The default nvmset id to use is 1 for the device.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw Predectible latency per NVM set log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the Predectible latency per NVM set log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme predictable-lat-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw Predectible latency per NVM set log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme predictable-lat-log /dev/nvme0 --raw-binary &gt; nvmset_log.raw</code></pre>
+</div></div>
+<div class="paragraph"><p>It is probably a bad idea to not redirect stdout when using this mode.</p></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-01-13 21:53:55 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-predictable-lat-log.txt b/Documentation/nvme-predictable-lat-log.txt
new file mode 100644
index 0000000..b4d7335
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.txt
@@ -0,0 +1,66 @@
+nvme-predictable-lat-log(1)
+===========================
+
+NAME
+----
+nvme-predictable-lat-log - Send Predectible latency per NVM set log page request,
+returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme predictable-lat-log' <device> [--nvmset-id=<nvmset_id> | -i <nvmset_id>]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Predectible latency per NVM set log page from an NVMe device
+and provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned Predectible latency per NVM set log structure
+may be returned in one ofseveral 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
+-------
+-i <nvmset_id>::
+--nvmset-id=<nvmset_id>::
+ Retrieve the Predectible latency per NVM set log for the given nvmset id.
+ This argument is mandatory and its success may depend on the device's
+ statistics to provide this log For More details see NVM Express 1.4 Spec.
+ Section 5.14.1.10. The default nvmset id to use is 1 for the device.
+
+-b::
+--raw-binary::
+ Print the raw Predectible latency per NVM set log buffer to stdout.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the Predectible latency per NVM set log page in a human readable format:
++
+------------
+# nvme predictable-lat-log /dev/nvme0
+------------
++
+
+* Print the raw Predectible latency per NVM set log to a file:
++
+------------
+# nvme predictable-lat-log /dev/nvme0 --raw-binary > nvmset_log.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-read.1 b/Documentation/nvme-read.1
index ae7faf6..7ba8d6a 100644
--- a/Documentation/nvme-read.1
+++ b/Documentation/nvme-read.1
@@ -2,12 +2,12 @@
.\" Title: nvme-read
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-READ" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-READ" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-reset.1 b/Documentation/nvme-reset.1
index 7b8f3de..3d153e2 100644
--- a/Documentation/nvme-reset.1
+++ b/Documentation/nvme-reset.1
@@ -2,12 +2,12 @@
.\" Title: nvme-reset
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-RESET" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-RESET" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-resv-acquire.1 b/Documentation/nvme-resv-acquire.1
index f96d127..1088479 100644
--- a/Documentation/nvme-resv-acquire.1
+++ b/Documentation/nvme-resv-acquire.1
@@ -2,12 +2,12 @@
.\" Title: nvme-resv-acquire
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-RESV\-ACQUIRE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-RESV\-ACQUIRE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -59,7 +59,7 @@ Current Reservation Key: The field specifies the current reservation key associa
Preempt Reservation Key: If the Reservation Acquire Action is set to 001b (i\&.e\&., Preempt) or 010b (i\&.e\&., Preempt and Abort), then this field specifies the reservation key to be unregistered from the namespace\&. For all other Reservation Acquire Action values, this field is reserved\&.
.RE
.PP
-\-t <rtype>, \-\-rtyep=<rtype>
+\-t <rtype>, \-\-rtype=<rtype>
.RS 4
Reservation Type: This field specifies the type of reservation to be created\&.
.TS
diff --git a/Documentation/nvme-resv-acquire.html b/Documentation/nvme-resv-acquire.html
index 17b3d94..fabd8fd 100644
--- a/Documentation/nvme-resv-acquire.html
+++ b/Documentation/nvme-resv-acquire.html
@@ -815,7 +815,7 @@ reservation held on a namespace.</p></div>
-t &lt;rtype&gt;
</dt>
<dt class="hdlist1">
---rtyep=&lt;rtype&gt;
+--rtype=&lt;rtype&gt;
</dt>
<dd>
<p>
diff --git a/Documentation/nvme-resv-acquire.txt b/Documentation/nvme-resv-acquire.txt
index 41cbf8f..1b6e110 100644
--- a/Documentation/nvme-resv-acquire.txt
+++ b/Documentation/nvme-resv-acquire.txt
@@ -44,7 +44,7 @@ OPTIONS
this field is reserved.
-t <rtype>::
---rtyep=<rtype>::
+--rtype=<rtype>::
Reservation Type: This field specifies the type of reservation
to be created.
+
diff --git a/Documentation/nvme-resv-notif-log.1 b/Documentation/nvme-resv-notif-log.1
new file mode 100644
index 0000000..ec0aca2
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.1
@@ -0,0 +1,98 @@
+'\" t
+.\" Title: nvme-resv-notif-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 03/09/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-NOTIF\-L" "1" "03/09/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-resv-notif-log \- Send NVMe Reservation Notification log page request, return result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme resv\-notif\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves NVMe Reservation Notification log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned Reservation Notification log structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the Reservation Notification log and print it in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme resv\-notif\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the output in json format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme resv\-notif\-log /dev/nvme0 \-o json
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-resv-notif-log.html b/Documentation/nvme-resv-notif-log.html
new file mode 100644
index 0000000..ebac7e1
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.html
@@ -0,0 +1,829 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-resv-notif-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-resv-notif-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-resv-notif-log -
+ Send NVMe Reservation Notification log page request, return result and log
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme resv-notif-log</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves NVMe Reservation Notification log page from an NVMe device and
+provides the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned Reservation Notification log 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.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get the Reservation Notification log and print it in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme resv-notif-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the output in json format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme resv-notif-log /dev/nvme0 -o json</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2021-03-09 23:51:52 IST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-notif-log.txt b/Documentation/nvme-resv-notif-log.txt
new file mode 100644
index 0000000..a9c5cdd
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.txt
@@ -0,0 +1,51 @@
+nvme-resv-notif-log(1)
+======================
+
+NAME
+----
+nvme-resv-notif-log - Send NVMe Reservation Notification log page request,
+ return result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme resv-notif-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Retrieves NVMe Reservation Notification log page from an NVMe device and
+provides the returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned Reservation Notification log 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
+-------
+-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 Reservation Notification log and print it in a human readable format:
++
+------------
+# nvme resv-notif-log /dev/nvme0
+------------
++
+
+* Print the output in json format:
++
+------------
+# nvme resv-notif-log /dev/nvme0 -o json
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-resv-register.1 b/Documentation/nvme-resv-register.1
index 4a50513..48b391f 100644
--- a/Documentation/nvme-resv-register.1
+++ b/Documentation/nvme-resv-register.1
@@ -2,12 +2,12 @@
.\" Title: nvme-resv-register
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-RESV\-REGISTER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-RESV\-REGISTER" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-resv-release.1 b/Documentation/nvme-resv-release.1
index 1817e51..5ade7f5 100644
--- a/Documentation/nvme-resv-release.1
+++ b/Documentation/nvme-resv-release.1
@@ -2,12 +2,12 @@
.\" Title: nvme-resv-release
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-RESV\-RELEASE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-RESV\-RELEASE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -53,7 +53,7 @@ Override the nsid field\&. If using the admin character device, this parameter i
Current Reservation Key: If the Reservation Register Action is 001b (i\&.e\&., Unregister Reservation Key) or 010b (i\&.e\&., Replace Reservation Key), then this field contains the current reservation key associated with the host\&. For all other Reservation Register Action values, this field is reserved\&. The controller ignores the value of this field when the Ignore Existing Key (IEKEY) bit is set to \(oq1\(cq\&.
.RE
.PP
-\-t <rtype>, \-\-rtyep=<rtype>
+\-t <rtype>, \-\-rtype=<rtype>
.RS 4
Reservation Type: This field specifies the type of reservation to be created\&.
.TS
diff --git a/Documentation/nvme-resv-release.html b/Documentation/nvme-resv-release.html
index 884dc78..094c89a 100644
--- a/Documentation/nvme-resv-release.html
+++ b/Documentation/nvme-resv-release.html
@@ -802,7 +802,7 @@ held on a namespace.</p></div>
-t &lt;rtype&gt;
</dt>
<dt class="hdlist1">
---rtyep=&lt;rtype&gt;
+--rtype=&lt;rtype&gt;
</dt>
<dd>
<p>
diff --git a/Documentation/nvme-resv-release.txt b/Documentation/nvme-resv-release.txt
index a6a895e..6eb0b43 100644
--- a/Documentation/nvme-resv-release.txt
+++ b/Documentation/nvme-resv-release.txt
@@ -37,7 +37,7 @@ OPTIONS
bit is set to ‘1’.
-t <rtype>::
---rtyep=<rtype>::
+--rtype=<rtype>::
Reservation Type: This field specifies the type of reservation
to be created.
+
diff --git a/Documentation/nvme-resv-report.1 b/Documentation/nvme-resv-report.1
index 7242f3a..f9f1fa8 100644
--- a/Documentation/nvme-resv-report.1
+++ b/Documentation/nvme-resv-report.1
@@ -2,12 +2,12 @@
.\" Title: nvme-resv-report
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-RESV\-REPORT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-RESV\-REPORT" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-resv-report.html b/Documentation/nvme-resv-report.html
index d34e6da..83655ae 100644
--- a/Documentation/nvme-resv-report.html
+++ b/Documentation/nvme-resv-report.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.9" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-resv-report(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -435,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -854,7 +855,7 @@ Controller data structure for each such controller).</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2018-01-30 19:28:39 KST
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-rpmb.1 b/Documentation/nvme-rpmb.1
new file mode 100644
index 0000000..7449243
--- /dev/null
+++ b/Documentation/nvme-rpmb.1
@@ -0,0 +1,326 @@
+'\" t
+.\" Title: nvme-rpmb
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 08/04/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RPMB" "1" "08/04/2020" "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-rpmb \- Send RPMB commands to an NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme rpmb\fR <device> [\-\-cmd=<command> | \-c <command>]
+ [\-\-msgfile=<data\-file> | \-f <data\-file>]
+ [\-\-keyfile=<key\-file> | \-g <key\-file>]
+ [\-\-key=<key> | \-k <key>]
+ [\-\-msg=<data> | \-d <data>]
+ [\-\-address=<offset> | \-o <offset>]
+ [\-\-blocks=<512 byte sectors> | \-b <sectors> ]
+ [\-\-target=<target\-id> | \-t <id> ]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an nvme rpmb command and provide the results\&.
+.sp
+The <device> parameter is mandatory and NVMe character device (ex: /dev/nvme0) must be specified\&. If the given device supports RPMB targets, command given with \-\-cmd or \-c option shall be sent to the controller\&. If given NVMe device doesn\(cqt support RPMB targets, a message indicating the same shall be printed along with controller register values related RPMB\&.
+.SH "OPTIONS"
+.PP
+\-c <command>, \-\-cmd=<command>
+.RS 4
+RPMB command to be sent to the device\&. It can be one of the following
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+info \- print information regarding supported RPMB targets and
+ access and total sizes\&. No further arguments are required
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+program\-key \- program \*(Aqkey\*(Aq specified with \-k option or key read from
+ file specified with \-\-keyfile option to the specified
+ RPMB target given with \-\-target or \-t options\&. As per
+ spec, this is one time action which can\*(Aqt be undone\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+read\-couter \- Read \*(Aqwrite counter\*(Aq of specified RPMB target\&. The
+ counter value read is printed onto STDOUT
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+read\-config \- Read 512 bytes of device configuration block data of
+ specified RPMB target of the NVMe device\&. The data read
+ is written to input file specified with \-\-msgfile or \-f
+ option\&.
+write\-config \- Write 512 byes of device configuration block data
+ from file specified by \-\-msgfile or \-f options to the
+ RPMB target specified with \-\-target or \-t options\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+read\-data \- Supports authenticated data reading from specified
+ RPMB target (\-\-target or \-t option) at given offset
+ specified with \-\-address or \-o option, using key
+ specified using \-\-keyfile or \-k options\&. \-\-blocks or
+ \-o option should be given to read the amount of data
+ to be read in 512 byte blocks\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+write\-data \- Supports authenticated data writting to specified RPMB
+ target (\-\-target or \-t option) at given offset
+ specified with \-\-address or \-o option, using key
+ specified using \-\-keyfile or \-k options\&. \-\-blocks or
+ \-o option should be given to indicate amount of data
+ to be written in 512 byte blocks\&.
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+For data transfer (read/write) commands, if the specified size is not
+within the total size supported by a target, the request is failed
+nvme\-rpmb without sending it to device\&. RPMB target 0 is used as the
+default target if \-\-target or \-t is not specified\&. 0x0 is used as the
+default address if no \-address or \-o option is specified,
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.PP
+\-t <target>, \-\-target=<target>
+.RS 4
+RPMB target id\&. This should be one of the supported RPMB targets as reported by
+\fIinfo\fR
+command\&. If nothing is given, default of 0 is used as RPMB target\&.
+.RE
+.PP
+\-k <key>, \-\-key=<key>, \-g <key\-file>, \-\-keyfile=<key\-file>
+.RS 4
+Authentication key to be used for read/write commands\&. This should have been already programmed by
+\fIprogram\-key\fR
+command for given target\&. Key can be specified on command line using \-\-key or \-k options\&. Key can also be specified using file argument specified with \-\-keyfile or \-g options\&.
+.RE
+.PP
+\-f <data\-file>, \-\-msgfile=<data\-file>
+.RS 4
+Name of the file to be used for data transfer commands (read or write)\&. For read command, if an existing file is specified, it will be appended\&.
+.RE
+.PP
+\-d <data>, \-\-msg=<data>
+.RS 4
+These options provide the data on the command line itself\&.
+.RE
+.PP
+\-o <offset>, \-\-address=<offset>
+.RS 4
+The address (in 512 byte sector offset from 0) to be used for data trasnfer commands (read or write) for a specified RPMB target\&.
+.RE
+.PP
+\-b, \-\-blocks=<sectors>
+.RS 4
+The size in 512 byte sectors to be used for data trasnfer commands (read or write) for a specified RPMB target\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print RPMB support information of an NVMe device
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-\-cmd=info
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Program
+\fISecreteKey\fR
+as authentication key for target 1
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-\-cmd=program\-key \-key=\*(AqSecretKey\*(Aq \-\-target=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Read current write counter of RPMB target 0
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-\-cmd=read\-counter \-\-target=0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Read configuration data block of target 2 into config\&.bin file
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-\-cmd=read\-config \-\-target=2 \-f config\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Write 200 blocks of (512 bytes) from input\&.bin onto target 0
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-c write\-data \-t 0 \-f input\&.bin \-b 200 \-k \*(AqSecreteKey\*(Aq
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Read 200 blocks of (512 bytes) from target 2, at offset 0x100 and save the
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+data onto output\&.bin
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme rpmb /dev/nvme0 \-c read\-data \-t 2 \-f out\&.bin \-b 200 \-o 0x100
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-rpmb.html b/Documentation/nvme-rpmb.html
new file mode 100644
index 0000000..d98ca07
--- /dev/null
+++ b/Documentation/nvme-rpmb.html
@@ -0,0 +1,1008 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-rpmb(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-rpmb(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-rpmb -
+ Send RPMB commands to an NVMe device
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme rpmb</em> &lt;device&gt; [--cmd=&lt;command&gt; | -c &lt;command&gt;]
+ [--msgfile=&lt;data-file&gt; | -f &lt;data-file&gt;]
+ [--keyfile=&lt;key-file&gt; | -g &lt;key-file&gt;]
+ [--key=&lt;key&gt; | -k &lt;key&gt;]
+ [--msg=&lt;data&gt; | -d &lt;data&gt;]
+ [--address=&lt;offset&gt; | -o &lt;offset&gt;]
+ [--blocks=&lt;512 byte sectors&gt; | -b &lt;sectors&gt; ]
+ [--target=&lt;target-id&gt; | -t &lt;id&gt; ]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, send an nvme rpmb command and provide the results.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and NVMe character device (ex: /dev/nvme0)
+must be specified. If the given device supports RPMB targets, command given
+with --cmd or -c option shall be sent to the controller. If given NVMe device
+doesn&#8217;t support RPMB targets, a message indicating the same shall be printed
+along with controller register values related RPMB.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-c &lt;command&gt;
+</dt>
+<dt class="hdlist1">
+--cmd=&lt;command&gt;
+</dt>
+<dd>
+<p>
+ RPMB command to be sent to the device. It can be one of the following
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>info - print information regarding supported RPMB targets and
+ access and total sizes. No further arguments are required</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>program-key - program 'key' specified with -k option or key read from
+ file specified with --keyfile option to the specified
+ RPMB target given with --target or -t options. As per
+ spec, this is one time action which can't be undone.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>read-couter - Read 'write counter' of specified RPMB target. The
+ counter value read is printed onto STDOUT</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>read-config - Read 512 bytes of device configuration block data of
+ specified RPMB target of the NVMe device. The data read
+ is written to input file specified with --msgfile or -f
+ option.
+write-config - Write 512 byes of device configuration block data
+ from file specified by --msgfile or -f options to the
+ RPMB target specified with --target or -t options.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>read-data - Supports authenticated data reading from specified
+ RPMB target (--target or -t option) at given offset
+ specified with --address or -o option, using key
+ specified using --keyfile or -k options. --blocks or
+ -o option should be given to read the amount of data
+ to be read in 512 byte blocks.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>write-data - Supports authenticated data writting to specified RPMB
+ target (--target or -t option) at given offset
+ specified with --address or -o option, using key
+ specified using --keyfile or -k options. --blocks or
+ -o option should be given to indicate amount of data
+ to be written in 512 byte blocks.</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code>For data transfer (read/write) commands, if the specified size is not
+within the total size supported by a target, the request is failed
+nvme-rpmb without sending it to device. RPMB target 0 is used as the
+default target if --target or -t is not specified. 0x0 is used as the
+default address if no -address or -o option is specified,</code></pre>
+</div></div>
+</dd>
+<dt class="hdlist1">
+-t &lt;target&gt;
+</dt>
+<dt class="hdlist1">
+--target=&lt;target&gt;
+</dt>
+<dd>
+<p>
+ RPMB target id. This should be one of the supported RPMB targets as
+ reported by <em>info</em> command. If nothing is given, default of 0 is used
+ as RPMB target.
+</p>
+</dd>
+<dt class="hdlist1">
+-k &lt;key&gt;
+</dt>
+<dt class="hdlist1">
+--key=&lt;key&gt;
+</dt>
+<dt class="hdlist1">
+-g &lt;key-file&gt;
+</dt>
+<dt class="hdlist1">
+--keyfile=&lt;key-file&gt;
+</dt>
+<dd>
+<p>
+ Authentication key to be used for read/write commands. This should have
+ been already programmed by <em>program-key</em> command for given target. Key
+ can be specified on command line using --key or -k options. Key can
+ also be specified using file argument specified with --keyfile or -g
+ options.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+--msgfile=&lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Name of the file to be used for data transfer commands (read or write).
+ For read command, if an existing file is specified, it will be appended.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;data&gt;
+</dt>
+<dt class="hdlist1">
+--msg=&lt;data&gt;
+</dt>
+<dd>
+<p>
+ These options provide the data on the command line itself.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;offset&gt;
+</dt>
+<dt class="hdlist1">
+--address=&lt;offset&gt;
+</dt>
+<dd>
+<p>
+ The address (in 512 byte sector offset from 0) to be used for data
+ trasnfer commands (read or write) for a specified RPMB target.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--blocks=&lt;sectors&gt;
+</dt>
+<dd>
+<p>
+ The size in 512 byte sectors to be used for data trasnfer commands
+ (read or write) for a specified RPMB target.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print RPMB support information of an NVMe device
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 --cmd=info</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Program <em>SecreteKey</em> as authentication key for target 1
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 --cmd=program-key -key='SecretKey' --target=1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Read current write counter of RPMB target 0
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 --cmd=read-counter --target=0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Read configuration data block of target 2 into config.bin file
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 --cmd=read-config --target=2 -f config.bin</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Write 200 blocks of (512 bytes) from input.bin onto target 0
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 -c write-data -t 0 -f input.bin -b 200 -k 'SecreteKey'</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Read 200 blocks of (512 bytes) from target 2, at offset 0x100 and save the
+</p>
+</li>
+<li>
+<p>
+data onto output.bin
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme rpmb /dev/nvme0 -c read-data -t 2 -f out.bin -b 200 -o 0x100</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-08-04 15:06:40 DST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-rpmb.txt b/Documentation/nvme-rpmb.txt
new file mode 100644
index 0000000..f9b371a
--- /dev/null
+++ b/Documentation/nvme-rpmb.txt
@@ -0,0 +1,150 @@
+nvme-rpmb(1)
+==============
+
+NAME
+----
+nvme-rpmb - Send RPMB commands to an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme rpmb' <device> [--cmd=<command> | -c <command>]
+ [--msgfile=<data-file> | -f <data-file>]
+ [--keyfile=<key-file> | -g <key-file>]
+ [--key=<key> | -k <key>]
+ [--msg=<data> | -d <data>]
+ [--address=<offset> | -o <offset>]
+ [--blocks=<512 byte sectors> | -b <sectors> ]
+ [--target=<target-id> | -t <id> ]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an nvme rpmb command and provide the results.
+
+The <device> parameter is mandatory and NVMe character device (ex: /dev/nvme0)
+must be specified. If the given device supports RPMB targets, command given
+with --cmd or -c option shall be sent to the controller. If given NVMe device
+doesn't support RPMB targets, a message indicating the same shall be printed
+along with controller register values related RPMB.
+
+OPTIONS
+-------
+-c <command>::
+--cmd=<command>::
+ RPMB command to be sent to the device. It can be one of the following
+
+ info - print information regarding supported RPMB targets and
+ access and total sizes. No further arguments are required
+
+ program-key - program 'key' specified with -k option or key read from
+ file specified with --keyfile option to the specified
+ RPMB target given with --target or -t options. As per
+ spec, this is one time action which can't be undone.
+
+ read-couter - Read 'write counter' of specified RPMB target. The
+ counter value read is printed onto STDOUT
+
+ read-config - Read 512 bytes of device configuration block data of
+ specified RPMB target of the NVMe device. The data read
+ is written to input file specified with --msgfile or -f
+ option.
+ write-config - Write 512 byes of device configuration block data
+ from file specified by --msgfile or -f options to the
+ RPMB target specified with --target or -t options.
+
+ read-data - Supports authenticated data reading from specified
+ RPMB target (--target or -t option) at given offset
+ specified with --address or -o option, using key
+ specified using --keyfile or -k options. --blocks or
+ -o option should be given to read the amount of data
+ to be read in 512 byte blocks.
+
+ write-data - Supports authenticated data writting to specified RPMB
+ target (--target or -t option) at given offset
+ specified with --address or -o option, using key
+ specified using --keyfile or -k options. --blocks or
+ -o option should be given to indicate amount of data
+ to be written in 512 byte blocks.
+
+ For data transfer (read/write) commands, if the specified size is not
+ within the total size supported by a target, the request is failed
+ nvme-rpmb without sending it to device. RPMB target 0 is used as the
+ default target if --target or -t is not specified. 0x0 is used as the
+ default address if no -address or -o option is specified,
+
+-t <target>::
+--target=<target>::
+ RPMB target id. This should be one of the supported RPMB targets as
+ reported by 'info' command. If nothing is given, default of 0 is used
+ as RPMB target.
+
+-k <key>::
+--key=<key>::
+-g <key-file>::
+--keyfile=<key-file>::
+ Authentication key to be used for read/write commands. This should have
+ been already programmed by 'program-key' command for given target. Key
+ can be specified on command line using --key or -k options. Key can
+ also be specified using file argument specified with --keyfile or -g
+ options.
+
+-f <data-file>::
+--msgfile=<data-file>::
+ Name of the file to be used for data transfer commands (read or write).
+ For read command, if an existing file is specified, it will be appended.
+
+-d <data>::
+--msg=<data>::
+ These options provide the data on the command line itself.
+-o <offset>::
+--address=<offset>::
+ The address (in 512 byte sector offset from 0) to be used for data
+ trasnfer commands (read or write) for a specified RPMB target.
+-b::
+--blocks=<sectors>::
+ The size in 512 byte sectors to be used for data trasnfer commands
+ (read or write) for a specified RPMB target.
+
+EXAMPLES
+--------
+* Print RPMB support information of an NVMe device
++
+-----------
+# nvme rpmb /dev/nvme0 --cmd=info
+-----------
++
+* Program 'SecreteKey' as authentication key for target 1
++
+------------
+# nvme rpmb /dev/nvme0 --cmd=program-key -key='SecretKey' --target=1
+------------
++
+* Read current write counter of RPMB target 0
++
+------------
+# nvme rpmb /dev/nvme0 --cmd=read-counter --target=0
+------------
++
+* Read configuration data block of target 2 into config.bin file
++
+------------
+# nvme rpmb /dev/nvme0 --cmd=read-config --target=2 -f config.bin
+------------
++
+* Write 200 blocks of (512 bytes) from input.bin onto target 0
++
+------------
+# nvme rpmb /dev/nvme0 -c write-data -t 0 -f input.bin -b 200 -k 'SecreteKey'
+------------
++
+* Read 200 blocks of (512 bytes) from target 2, at offset 0x100 and save the
+* data onto output.bin
++
+------------
+# nvme rpmb /dev/nvme0 -c read-data -t 2 -f out.bin -b 200 -o 0x100
+------------
+
+NVME
+----
+Part of the nvme-user suite
+
diff --git a/Documentation/nvme-sanitize-log.1 b/Documentation/nvme-sanitize-log.1
index 72787c7..1163e2d 100644
--- a/Documentation/nvme-sanitize-log.1
+++ b/Documentation/nvme-sanitize-log.1
@@ -1,13 +1,13 @@
'\" t
.\" Title: nvme-sanitize-log
-.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
-.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 04/05/2021
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SANITIZE\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SANITIZE\-LOG" "1" "04/05/2021" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -32,7 +32,7 @@ nvme-sanitize-log \- Send NVMe sanitize\-log Command, return result
.SH "SYNOPSIS"
.sp
.nf
-\fInvme sanitize\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+\fInvme sanitize\-log\fR <device> [\-\-rae | \-r] [\-\-output\-format=<fmt> | \-o <fmt>]
[\-\-human\-readable | \-H]
[\-\-raw\-binary | \-b]
.fi
@@ -100,6 +100,11 @@ Sanitize Progress \- percentage complete
On success it returns 0, error code otherwise\&.
.SH "OPTIONS"
.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.PP
\-o <format>, \-\-output\-format=<format>
.RS 4
Set the reporting format to
diff --git a/Documentation/nvme-sanitize-log.html b/Documentation/nvme-sanitize-log.html
index d369a10..63c8db6 100644
--- a/Documentation/nvme-sanitize-log.html
+++ b/Documentation/nvme-sanitize-log.html
@@ -749,7 +749,7 @@ nvme-sanitize-log(1) Manual Page
<h2 id="_synopsis">SYNOPSIS</h2>
<div class="sectionbody">
<div class="verseblock">
-<pre class="content"><em>nvme sanitize-log</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
+<pre class="content"><em>nvme sanitize-log</em> &lt;device&gt; [--rae | -r] [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
[--human-readable | -H]
[--raw-binary | -b]</pre>
<div class="attribution">
@@ -816,6 +816,17 @@ If cleared to 0, then non-volatile storage in the NVM subsystem has been written
<div class="sectionbody">
<div class="dlist"><dl>
<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+<dt class="hdlist1">
-o &lt;format&gt;
</dt>
<dt class="hdlist1">
@@ -881,7 +892,7 @@ Has the program issue Sanitize-log Command :
<div id="footer">
<div id="footer-text">
Last updated
- 2019-11-08 02:18:28 JST
+ 2021-04-05 15:38:33 IST
</div>
</div>
</body>
diff --git a/Documentation/nvme-sanitize-log.txt b/Documentation/nvme-sanitize-log.txt
index 3c3b73e..3c2d43e 100644
--- a/Documentation/nvme-sanitize-log.txt
+++ b/Documentation/nvme-sanitize-log.txt
@@ -8,7 +8,7 @@ nvme-sanitize-log - Send NVMe sanitize-log Command, return result
SYNOPSIS
--------
[verse]
-'nvme sanitize-log' <device> [--output-format=<fmt> | -o <fmt>]
+'nvme sanitize-log' <device> [--rae | -r] [--output-format=<fmt> | -o <fmt>]
[--human-readable | -H]
[--raw-binary | -b]
@@ -54,6 +54,10 @@ On success it returns 0, error code otherwise.
OPTIONS
-------
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
-o <format>::
--output-format=<format>::
Set the reporting format to 'normal', 'json', or
diff --git a/Documentation/nvme-sanitize.1 b/Documentation/nvme-sanitize.1
index 85d2bd4..709992e 100644
--- a/Documentation/nvme-sanitize.1
+++ b/Documentation/nvme-sanitize.1
@@ -2,12 +2,12 @@
.\" Title: nvme-sanitize
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SANITIZE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SANITIZE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-security-recv.1 b/Documentation/nvme-security-recv.1
index df47abb..eef260a 100644
--- a/Documentation/nvme-security-recv.1
+++ b/Documentation/nvme-security-recv.1
@@ -2,12 +2,12 @@
.\" Title: nvme-security-recv
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SECURITY\-RECV" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SECURITY\-RECV" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-security-send.1 b/Documentation/nvme-security-send.1
index 919464c..81e4854 100644
--- a/Documentation/nvme-security-send.1
+++ b/Documentation/nvme-security-send.1
@@ -2,12 +2,12 @@
.\" Title: nvme-security-send
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SECURITY\-SEND" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SECURITY\-SEND" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-self-test-log.1 b/Documentation/nvme-self-test-log.1
index caff6ff..e00e289 100644
--- a/Documentation/nvme-self-test-log.1
+++ b/Documentation/nvme-self-test-log.1
@@ -1,13 +1,13 @@
'\" t
.\" Title: nvme-self-test-log
-.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
-.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 01/23/2021
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SELF\-TEST\-LO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SELF\-TEST\-LO" "1" "01/23/2021" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -32,7 +32,8 @@ nvme-self-test-log \- Retrieve the log information initited by device\-self\-tes
.SH "SYNOPSIS"
.sp
.nf
-\fInvme self\-test\fR\-log <device> [\-\-output\-format=<FMT> | \-o <FMT>]
+\fInvme self\-test\fR\-log <device> [\-\-log\-entries=<entries> | \-e <entries>]
+ [\-\-output\-format=<FMT> | \-o <FMT>]
.fi
.SH "DESCRIPTION"
.sp
@@ -45,6 +46,11 @@ On success, the returned log structure may be returned in one of several ways de
By default the log is printed out in the normal readable format\&.
.SH "OPTION"
.PP
+\-e <entries>, \-\-log\-entries=<entries>
+.RS 4
+Specifies how many DST log entries the program should request from the device\&. This must be at least one, and shouldn\(cqt exceed the 20 entries\&. Defaults to 20 DST log entries\&.
+.RE
+.PP
\-o <format>, \-\-output\-format=<format>
.RS 4
Set the reporting format to
diff --git a/Documentation/nvme-self-test-log.html b/Documentation/nvme-self-test-log.html
index 7f02a76..3b24a26 100644
--- a/Documentation/nvme-self-test-log.html
+++ b/Documentation/nvme-self-test-log.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-self-test-log(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -433,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -746,7 +749,8 @@ nvme-self-test-log(1) Manual Page
<h2 id="_synopsis">SYNOPSIS</h2>
<div class="sectionbody">
<div class="verseblock">
-<pre class="content"><em>nvme self-test</em>-log &lt;device&gt; [--output-format=&lt;FMT&gt; | -o &lt;FMT&gt;]</pre>
+<pre class="content"><em>nvme self-test</em>-log &lt;device&gt; [--log-entries=&lt;entries&gt; | -e &lt;entries&gt;]
+ [--output-format=&lt;FMT&gt; | -o &lt;FMT&gt;]</pre>
<div class="attribution">
</div></div>
</div>
@@ -771,6 +775,19 @@ json format.</p></div>
<div class="sectionbody">
<div class="dlist"><dl>
<dt class="hdlist1">
+-e &lt;entries&gt;
+</dt>
+<dt class="hdlist1">
+--log-entries=&lt;entries&gt;
+</dt>
+<dd>
+<p>
+ Specifies how many DST log entries the program should request from
+ the device. This must be at least one, and shouldn&#8217;t exceed the
+ 20 entries. Defaults to 20 DST log entries.
+</p>
+</dd>
+<dt class="hdlist1">
-o &lt;format&gt;
</dt>
<dt class="hdlist1">
@@ -829,7 +846,8 @@ Get the self-test-log and print it in a json format:
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2018-06-15 13:12:28 MDT
+Last updated
+ 2021-01-23 16:07:45 IST
</div>
</div>
</body>
diff --git a/Documentation/nvme-self-test-log.txt b/Documentation/nvme-self-test-log.txt
index 78798d9..a801cb0 100644
--- a/Documentation/nvme-self-test-log.txt
+++ b/Documentation/nvme-self-test-log.txt
@@ -8,7 +8,8 @@ nvme-self-test-log - Retrieve the log information initited by device-self-test a
SYNOPSIS
--------
[verse]
-'nvme self-test'-log <device> [--output-format=<FMT> | -o <FMT>]
+'nvme self-test'-log <device> [--log-entries=<entries> | -e <entries>]
+ [--output-format=<FMT> | -o <FMT>]
DESCRIPTION
-----------
@@ -28,6 +29,12 @@ By default the log is printed out in the normal readable format.
OPTION
-------
+-e <entries>::
+--log-entries=<entries>::
+ Specifies how many DST log entries the program should request from
+ the device. This must be at least one, and shouldn't exceed the
+ 20 entries. Defaults to 20 DST log entries.
+
-o <format>::
--output-format=<format>::
Set the reporting format to 'normal', 'json', or
diff --git a/Documentation/nvme-set-feature.1 b/Documentation/nvme-set-feature.1
index a39755e..913df38 100644
--- a/Documentation/nvme-set-feature.1
+++ b/Documentation/nvme-set-feature.1
@@ -2,12 +2,12 @@
.\" Title: nvme-set-feature
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SET\-FEATURE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SET\-FEATURE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-set-property.1 b/Documentation/nvme-set-property.1
index d87efd4..276c101 100644
--- a/Documentation/nvme-set-property.1
+++ b/Documentation/nvme-set-property.1
@@ -2,12 +2,12 @@
.\" Title: nvme-set-property
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SET\-PROPERTY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SET\-PROPERTY" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-show-hostnqn.1 b/Documentation/nvme-show-hostnqn.1
index 8f901aa..944d170 100644
--- a/Documentation/nvme-show-hostnqn.1
+++ b/Documentation/nvme-show-hostnqn.1
@@ -2,12 +2,12 @@
.\" Title: nvme-show-hostnqn
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SHOW\-HOSTNQN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SHOW\-HOSTNQN" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-show-regs.1 b/Documentation/nvme-show-regs.1
index b29271d..3e8a76f 100644
--- a/Documentation/nvme-show-regs.1
+++ b/Documentation/nvme-show-regs.1
@@ -2,12 +2,12 @@
.\" Title: nvme-id-ns
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ID\-NS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-smart-log.1 b/Documentation/nvme-smart-log.1
index 95fbb70..85ca8b9 100644
--- a/Documentation/nvme-smart-log.1
+++ b/Documentation/nvme-smart-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-smart-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SMART\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SMART\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-smart-log.html b/Documentation/nvme-smart-log.html
index 465cb91..f1eae8a 100644
--- a/Documentation/nvme-smart-log.html
+++ b/Documentation/nvme-smart-log.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-smart-log(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -433,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overridden by CSS in most browsers. */
+/* Because the table frame attribute is overriden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -846,7 +849,8 @@ Print the raw SMART log to a file:
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2017-06-26 15:57:42 EDT
+Last updated
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-subsystem-reset.1 b/Documentation/nvme-subsystem-reset.1
index abf7d0d..83db99f 100644
--- a/Documentation/nvme-subsystem-reset.1
+++ b/Documentation/nvme-subsystem-reset.1
@@ -2,12 +2,12 @@
.\" Title: nvme-subsystem-reset
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-SUBSYSTEM\-RES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-SUBSYSTEM\-RES" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-telemetry-log.1 b/Documentation/nvme-telemetry-log.1
index e978e83..11f9e87 100644
--- a/Documentation/nvme-telemetry-log.1
+++ b/Documentation/nvme-telemetry-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-telemetry-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TELEMETRY\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TELEMETRY\-LOG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1
index fd92c33..cb45341 100644
--- a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1
@@ -2,12 +2,12 @@
.\" Title: nvme-toshiba-clear-pcie-correctable-errors
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TOSHIBA\-CLEAR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TOSHIBA\-CLEAR" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-toshiba-vs-internal-log.1 b/Documentation/nvme-toshiba-vs-internal-log.1
index 325ebbd..2a57da2 100644
--- a/Documentation/nvme-toshiba-vs-internal-log.1
+++ b/Documentation/nvme-toshiba-vs-internal-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-toshiba-vs-internal-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TOSHIBA\-VS\-I" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TOSHIBA\-VS\-I" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.1 b/Documentation/nvme-toshiba-vs-smart-add-log.1
index 7463a72..1506716 100644
--- a/Documentation/nvme-toshiba-vs-smart-add-log.1
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-toshiba-vs-smart-add-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TOSHIBA\-VS\-S" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TOSHIBA\-VS\-S" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-transcend-badblock.1 b/Documentation/nvme-transcend-badblock.1
index 4986df0..345a6e2 100644
--- a/Documentation/nvme-transcend-badblock.1
+++ b/Documentation/nvme-transcend-badblock.1
@@ -2,12 +2,12 @@
.\" Title: nvme-transcend-badblock
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TRANSCEND\-BAD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TRANSCEND\-BAD" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-transcend-healthvalue.1 b/Documentation/nvme-transcend-healthvalue.1
index 47e16a9..f8eb7e4 100644
--- a/Documentation/nvme-transcend-healthvalue.1
+++ b/Documentation/nvme-transcend-healthvalue.1
@@ -2,12 +2,12 @@
.\" Title: nvme-transcend-healthvalue
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-TRANSCEND\-HEA" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-TRANSCEND\-HEA" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.1 b/Documentation/nvme-virtium-save-smart-to-vtview-log.1
index 7f70ccf..76de601 100644
--- a/Documentation/nvme-virtium-save-smart-to-vtview-log.1
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-virtium-save-smart-to-vtview-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-VIRTIUM\-SAVE\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-VIRTIUM\-SAVE\" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-virtium-show-identify.1 b/Documentation/nvme-virtium-show-identify.1
index 0d778f6..bde7398 100644
--- a/Documentation/nvme-virtium-show-identify.1
+++ b/Documentation/nvme-virtium-show-identify.1
@@ -2,12 +2,12 @@
.\" Title: nvme-virtium-show-identify
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-VIRTIUM\-SHOW\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-VIRTIUM\-SHOW\" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-cap-diag.1 b/Documentation/nvme-wdc-cap-diag.1
index 3d47e7c..f0f5cb5 100644
--- a/Documentation/nvme-wdc-cap-diag.1
+++ b/Documentation/nvme-wdc-cap-diag.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-cap-diag
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-CAP\-DIAG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-CAP\-DIAG" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-capabilities.1 b/Documentation/nvme-wdc-capabilities.1
new file mode 100644
index 0000000..3397935
--- /dev/null
+++ b/Documentation/nvme-wdc-capabilities.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-wdc-capabilities
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CAPABILIT" "1" "10/20/2020" "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-wdc-capabilities \- Display WDC plugin command capabilities
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc capabilities\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, displays list of commands and support status\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Displays the capabilities for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc capabilities /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-capabilities.html b/Documentation/nvme-wdc-capabilities.html
new file mode 100644
index 0000000..d6d52c5
--- /dev/null
+++ b/Documentation/nvme-wdc-capabilities.html
@@ -0,0 +1,796 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 9.0.0rc1" />
+<title>nvme-wdc-capabilities(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-capabilities(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-capabilities -
+ Display WDC plugin command capabilities
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme wdc capabilities</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, displays list of commands and support status.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory NVMe character device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success it returns 0, error code otherwise.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Displays the capabilities for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc capabilities /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-07-13 10:08:56 CDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-capabilities.txt b/Documentation/nvme-wdc-capabilities.txt
new file mode 100644
index 0000000..859bb5f
--- /dev/null
+++ b/Documentation/nvme-wdc-capabilities.txt
@@ -0,0 +1,32 @@
+nvme-wdc-capabilities(1)
+========================
+
+NAME
+----
+nvme-wdc-capabilities - Display WDC plugin command capabilities
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc capabilities' <device>
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, displays list of commands and support status.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+On success it returns 0, error code otherwise.
+
+EXAMPLES
+--------
+* Displays the capabilities for the device:
++
+------------
+# nvme wdc capabilities /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-clear-assert-dump.1 b/Documentation/nvme-wdc-clear-assert-dump.1
index 1f1569e..85e7dca 100644
--- a/Documentation/nvme-wdc-clear-assert-dump.1
+++ b/Documentation/nvme-wdc-clear-assert-dump.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-clear-assert-dump
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-CLEAR\-AS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-CLEAR\-AS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.1 b/Documentation/nvme-wdc-clear-fw-activate-history.1
index 0a0a999..3dd36b2 100644
--- a/Documentation/nvme-wdc-clear-fw-activate-history.1
+++ b/Documentation/nvme-wdc-clear-fw-activate-history.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-clear-fw-activate-history
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-CLEAR\-FW" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-CLEAR\-FW" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1
index 1f45364..f819679 100644
--- a/Documentation/nvme-wdc-clear-pcie-correctable-errors.1
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-clear-pcie-correctable-errors
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-CLEAR\-PC" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-CLEAR\-PC" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-cloud-SSD-plugin-version.1 b/Documentation/nvme-wdc-cloud-SSD-plugin-version.1
new file mode 100644
index 0000000..3ac3bc1
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-wdc-cloud-SSD-plugin-version
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 03/01/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLOUD\-SS" "1" "03/01/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-wdc-cloud-SSD-plugin-version \- Display WDC plugin Cloud SSD Plugin Version
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc cloud\-SSD\-plugin\-version\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, this command displays the current Cloud SSD Plugin Version (if supported by the device)\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Displays the cloud ssd plugin version for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cloud\-SSD\-plugin\-version /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-cloud-SSD-plugin-version.html b/Documentation/nvme-wdc-cloud-SSD-plugin-version.html
new file mode 100644
index 0000000..dd686f8
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.html
@@ -0,0 +1,793 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-cloud-SSD-plugin-version(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-cloud-SSD-plugin-version(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-cloud-SSD-plugin-version -
+ Display WDC plugin Cloud SSD Plugin Version
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme wdc cloud-SSD-plugin-version</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, this command displays the current Cloud SSD
+Plugin Version (if supported by the device).</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory NVMe character device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success it returns 0, error code otherwise.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Displays the cloud ssd plugin version for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cloud-SSD-plugin-version /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2021-03-01 15:37:25 CST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-cloud-SSD-plugin-version.txt b/Documentation/nvme-wdc-cloud-SSD-plugin-version.txt
new file mode 100644
index 0000000..3fed5cd
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.txt
@@ -0,0 +1,33 @@
+nvme-wdc-cloud-SSD-plugin-version(1)
+====================================
+
+NAME
+----
+nvme-wdc-cloud-SSD-plugin-version - Display WDC plugin Cloud SSD Plugin Version
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc cloud-SSD-plugin-version' <device>
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, this command displays the current Cloud SSD
+Plugin Version (if supported by the device).
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+On success it returns 0, error code otherwise.
+
+EXAMPLES
+--------
+* Displays the cloud ssd plugin version for the device:
++
+------------
+# nvme wdc cloud-SSD-plugin-version /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-drive-essentials.1 b/Documentation/nvme-wdc-drive-essentials.1
index e0a2902..e6e1b57 100644
--- a/Documentation/nvme-wdc-drive-essentials.1
+++ b/Documentation/nvme-wdc-drive-essentials.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-drive-essentials
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-DRIVE\-ES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-DRIVE\-ES" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-drive-log.1 b/Documentation/nvme-wdc-drive-log.1
index 4ce6955..5ed478b 100644
--- a/Documentation/nvme-wdc-drive-log.1
+++ b/Documentation/nvme-wdc-drive-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-drive-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-DRIVE\-LO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-DRIVE\-LO" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-drive-resize.1 b/Documentation/nvme-wdc-drive-resize.1
index 0949d70..6bd64f4 100644
--- a/Documentation/nvme-wdc-drive-resize.1
+++ b/Documentation/nvme-wdc-drive-resize.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-drive-resize
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-DRIVE\-RE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-DRIVE\-RE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-enc-get-log.1 b/Documentation/nvme-wdc-enc-get-log.1
new file mode 100644
index 0000000..69a4f3e
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.1
@@ -0,0 +1,104 @@
+'\" t
+.\" Title: nvme-wdc-enc-get-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-ENC\-GET\" "1" "10/20/2020" "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-wdc-enc-get-log \- Send NVMe WDC enc\-get\-log Vendor Unique Command, return result\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc enc\-get\-log\fR <device> [\-\-log\-id=<NUM>, \-l <NUM>] [\-\-output\-file=<FILE>, \-o <FILE>] [\-\-transfer\-size=<SIZE>, \-s <SIZE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC enc\-get\-log command and output the Enclosure logs\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+The \-\-log\-id=<NUM>, \-l <NUM> parameter is mandatory and may be either 0xd1, 0xd2, 0xd3, 0xd4, 0xe2 and 0xe4\&.
+.sp
+This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns the enclosure log data, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file pathname
+.RE
+.PP
+\-s <SIZE>, \-\-transfer\-size=<NUM>
+.RS 4
+Data retrieval transfer size, maximum transfer size should be 0x2000 (decimal 8192)
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the enclosure log from the device based on the log id(0xd1) with transfer size(0x2000) and saves to defined file in current directory:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc enc\-get\-log /dev/nvme0 \-l 0xd1 \-o d1_log\&.bin \-s 0x2000
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the enclosure log from the device based on the log id(0xd2) with default transfer size(0x1000) and saves to defined file in current directory:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc enc\-get\-log /dev/nvme0 \-l 0xd2 \-o d1_log\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-enc-get-log.html b/Documentation/nvme-wdc-enc-get-log.html
new file mode 100644
index 0000000..b806f3a
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.html
@@ -0,0 +1,839 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-wdc-enc-get-log(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-enc-get-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-enc-get-log -
+ Send NVMe WDC enc-get-log Vendor Unique Command, return result.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme wdc enc-get-log</em> &lt;device&gt; [--log-id=&lt;NUM&gt;, -l &lt;NUM&gt;] [--output-file=&lt;FILE&gt;, -o &lt;FILE&gt;] [--transfer-size=&lt;SIZE&gt;, -s &lt;SIZE&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, send a Vendor Unique WDC enc-get-log command and
+output the Enclosure logs.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>The --log-id=&lt;NUM&gt;, -l &lt;NUM&gt; parameter is mandatory and may be either 0xd1, 0xd2, 0xd3, 0xd4, 0xe2 and 0xe4.</p></div>
+<div class="paragraph"><p>This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns the enclosure log data, error code otherwise.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output file pathname
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;SIZE&gt;
+</dt>
+<dt class="hdlist1">
+--transfer-size=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Data retrieval transfer size, maximum transfer size should be 0x2000 (decimal 8192)
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Gets the enclosure log from the device based on the log id(0xd1) with transfer size(0x2000) and saves to defined file in current directory:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc enc-get-log /dev/nvme0 -l 0xd1 -o d1_log.bin -s 0x2000</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the enclosure log from the device based on the log id(0xd2) with default transfer size(0x1000) and saves to defined file in current directory:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc enc-get-log /dev/nvme0 -l 0xd2 -o d1_log.bin</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-10-20 16:47:21 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-enc-get-log.txt b/Documentation/nvme-wdc-enc-get-log.txt
new file mode 100644
index 0000000..ae93a7a
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.txt
@@ -0,0 +1,54 @@
+nvme-wdc-enc-get-log(1)
+=======================
+
+NAME
+----
+nvme-wdc-enc-get-log - Send NVMe WDC enc-get-log Vendor Unique Command, return result.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc enc-get-log' <device> [--log-id=<NUM>, -l <NUM>] [--output-file=<FILE>, -o <FILE>] [--transfer-size=<SIZE>, -s <SIZE>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, send a Vendor Unique WDC enc-get-log command and
+output the Enclosure logs.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+The --log-id=<NUM>, -l <NUM> parameter is mandatory and may be either 0xd1, 0xd2, 0xd3, 0xd4, 0xe2 and 0xe4.
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns the enclosure log data, error code otherwise.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file pathname
+
+-s <SIZE>::
+--transfer-size=<NUM>::
+ Data retrieval transfer size, maximum transfer size should be 0x2000 (decimal 8192)
+
+EXAMPLES
+--------
+* Gets the enclosure log from the device based on the log id(0xd1) with transfer size(0x2000) and saves to defined file in current directory:
++
+------------
+# nvme wdc enc-get-log /dev/nvme0 -l 0xd1 -o d1_log.bin -s 0x2000
+------------
+* Gets the enclosure log from the device based on the log id(0xd2) with default transfer size(0x1000) and saves to defined file in current directory:
++
+------------
+# nvme wdc enc-get-log /dev/nvme0 -l 0xd2 -o d1_log.bin
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-get-crash-dump.1 b/Documentation/nvme-wdc-get-crash-dump.1
index 152643f..8e6a880 100644
--- a/Documentation/nvme-wdc-get-crash-dump.1
+++ b/Documentation/nvme-wdc-get-crash-dump.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-get-crash-dump
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-GET\-CRAS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-GET\-CRAS" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-get-drive-status.1 b/Documentation/nvme-wdc-get-drive-status.1
index b19520d..f360e85 100644
--- a/Documentation/nvme-wdc-get-drive-status.1
+++ b/Documentation/nvme-wdc-get-drive-status.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-get-drive-status
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-GET\-DRIV" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-GET\-DRIV" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-get-pfail-dump.1 b/Documentation/nvme-wdc-get-pfail-dump.1
index 230ce79..a96febd 100644
--- a/Documentation/nvme-wdc-get-pfail-dump.1
+++ b/Documentation/nvme-wdc-get-pfail-dump.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-get-pfail-dump
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-GET\-PFAI" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-GET\-PFAI" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-id-ctrl.1 b/Documentation/nvme-wdc-id-ctrl.1
index 220d953..71aaa71 100644
--- a/Documentation/nvme-wdc-id-ctrl.1
+++ b/Documentation/nvme-wdc-id-ctrl.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-id-ctrl
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-ID\-CTRL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-ID\-CTRL" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-log-page-directory.1 b/Documentation/nvme-wdc-log-page-directory.1
index 0d407ba..611f65e 100644
--- a/Documentation/nvme-wdc-log-page-directory.1
+++ b/Documentation/nvme-wdc-log-page-directory.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-log-page-directory
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-LOG\-PAGE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-LOG\-PAGE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-namespace-resize.1 b/Documentation/nvme-wdc-namespace-resize.1
index ea0235a..c159d2b 100644
--- a/Documentation/nvme-wdc-namespace-resize.1
+++ b/Documentation/nvme-wdc-namespace-resize.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-namespace-resize
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-NAMESPACE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-NAMESPACE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-purge-monitor.1 b/Documentation/nvme-wdc-purge-monitor.1
index 3df192a..ffb7fd8 100644
--- a/Documentation/nvme-wdc-purge-monitor.1
+++ b/Documentation/nvme-wdc-purge-monitor.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-purge-monitor
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-PURGE\-MO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-PURGE\-MO" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-purge.1 b/Documentation/nvme-wdc-purge.1
index 748f78d..506714a 100644
--- a/Documentation/nvme-wdc-purge.1
+++ b/Documentation/nvme-wdc-purge.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-purge
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-PURGE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-PURGE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-drive-info.1 b/Documentation/nvme-wdc-vs-drive-info.1
index 4f5dd1c..9ca8396 100644
--- a/Documentation/nvme-wdc-vs-drive-info.1
+++ b/Documentation/nvme-wdc-vs-drive-info.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-drive-info
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-DRIVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-DRIVE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.1 b/Documentation/nvme-wdc-vs-error-reason-identifier.1
index 2770ce3..e8779bf 100644
--- a/Documentation/nvme-wdc-vs-error-reason-identifier.1
+++ b/Documentation/nvme-wdc-vs-error-reason-identifier.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-error-reason-identifier
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-ERROR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-ERROR" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.1 b/Documentation/nvme-wdc-vs-fw-activate-history.1
index 25ce40a..696acf8 100644
--- a/Documentation/nvme-wdc-vs-fw-activate-history.1
+++ b/Documentation/nvme-wdc-vs-fw-activate-history.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-fw-activate-history
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-FW\-A" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-FW\-A" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-internal-log.1 b/Documentation/nvme-wdc-vs-internal-log.1
index abb6e94..441777d 100644
--- a/Documentation/nvme-wdc-vs-internal-log.1
+++ b/Documentation/nvme-wdc-vs-internal-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-internal-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-INTER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-INTER" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -57,7 +57,7 @@ Transfer size; defaults to 0x10000 (65536 decimal) bytes
.PP
\-d <DATA AREA>, \-\-data\-area=<DATA AREA>
.RS 4
-DUI data area to retrieve\&. The DUI data areas from 1 to <DATA AREA> will be retrieved\&. This parameter is currently only supported on the SN340, SN640, and SN840 devices\&.
+DUI data area to retrieve\&. The DUI data areas from 1 to <DATA AREA> will be retrieved\&. This parameter is currently only supported on the SN340, SN640, SN730, and SN840 devices\&.
.RE
.PP
\-f <FILE SIZE>, \-\-file\-size=<FILE SIZE>
diff --git a/Documentation/nvme-wdc-vs-internal-log.html b/Documentation/nvme-wdc-vs-internal-log.html
index d07be0e..8919541 100644
--- a/Documentation/nvme-wdc-vs-internal-log.html
+++ b/Documentation/nvme-wdc-vs-internal-log.html
@@ -4,7 +4,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.10" />
+<meta name="generator" content="AsciiDoc 9.0.0rc1" />
<title>nvme-wdc-vs-internal-log(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -436,7 +436,7 @@ thead, p.table.header {
p.table {
margin-top: 0;
}
-/* Because the table frame attribute is overriden by CSS in most browsers. */
+/* Because the table frame attribute is overridden by CSS in most browsers. */
div.tableblock > table[frame="void"] {
border-style: none;
}
@@ -801,7 +801,7 @@ Results for any other device are undefined.</p></div>
<dd>
<p>
DUI data area to retrieve. The DUI data areas from 1 to &lt;DATA AREA&gt; will be retrieved. This parameter
- is currently only supported on the SN340, SN640, and SN840 devices.
+ is currently only supported on the SN340, SN640, SN730, and SN840 devices.
</p>
</dd>
<dt class="hdlist1">
@@ -950,7 +950,7 @@ Gets the controller telemetry log page to data area 3 from the device and stores
<div id="footer">
<div id="footer-text">
Last updated
- 2019-12-19 04:03:07 JST
+ 2020-09-02 11:35:55 CDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-wdc-vs-internal-log.txt b/Documentation/nvme-wdc-vs-internal-log.txt
index eaeb21e..4fbde38 100644
--- a/Documentation/nvme-wdc-vs-internal-log.txt
+++ b/Documentation/nvme-wdc-vs-internal-log.txt
@@ -8,7 +8,7 @@ nvme-wdc-vs-internal-log - Retrieve WDC device's internal firmware log and save
SYNOPSIS
--------
[verse]
-'nvme wdc vs-internal-log' <device> [--output-file=<FILE>, -o <FILE>] [--transfer-size=<SIZE>, -s <SIZE>]
+'nvme wdc vs-internal-log' <device> [--output-file=<FILE>, -o <FILE>] [--transfer-size=<SIZE>, -s <SIZE>]
[--data-area=<DATA AREA>, -d <DATA_AREA>] [--file-size=<FILE SIZE>, -f <FILE SIZE>] [--offset=<OFFSET>, -e <OFFSET>]
[--type=<TYPE>, -t <type>] [--verbose, -v]
@@ -35,31 +35,31 @@ OPTIONS
-d <DATA AREA>::
--data-area=<DATA AREA>::
- DUI data area to retrieve. The DUI data areas from 1 to <DATA AREA> will be retrieved. This parameter
- is currently only supported on the SN340, SN640, and SN840 devices.
-
+ DUI data area to retrieve. The DUI data areas from 1 to <DATA AREA> will be retrieved. This parameter
+ is currently only supported on the SN340, SN640, SN730, and SN840 devices.
+
-f <FILE SIZE>::
--file-size=<FILE SIZE>::
- Specifies the desired size of the data file starting at the passed in offset. This allows the user to
- retrieve the data in several smaller files of the passed in size. This parameter is currently only
- supported on the SN340 device.
+ Specifies the desired size of the data file starting at the passed in offset. This allows the user to
+ retrieve the data in several smaller files of the passed in size. This parameter is currently only
+ supported on the SN340 device.
-e <OFFSET>::
---offset=<OFFSET>::
+--offset=<OFFSET>::
Specifies the data offset at which to start retrieving the data. This parameter is used in combination
- with the file size parameter to retrieve the data in several smaller files. This parameter is currently
- only supported on the SN340 device.
+ with the file size parameter to retrieve the data in several smaller files. This parameter is currently
+ only supported on the SN340 device.
-t <TYPE>::
---type=<TYPE>::
+--type=<TYPE>::
Specifies the telemetry type - NONE, HOST, or CONTROLLER. This parameter is used to get either the host
generated or controller initiated telemetry log page. If not specified or none is specified, the command
will return the default E6 log data. This parameter is currently only supported on the SN640 and SN840
- devices.
+ devices.
-v <VERBOSE>::
---verbose=<VERBOSE>::
- Provides additional debug messages for certain drives.
+--verbose=<VERBOSE>::
+ Provides additional debug messages for certain drives.
EXAMPLES
--------
@@ -100,7 +100,7 @@ EXAMPLES
------------
# nvme wdc vs-internal-log /dev/nvme1 -t host -o host-telem-log-da3.bin -d 3
------------
-* Gets the controller telemetry log page to data area 3 from the device and stores it in file ctlr-telem-log-da3.bin:
+* Gets the controller telemetry log page to data area 3 from the device and stores it in file ctlr-telem-log-da3.bin:
+
------------
# nvme wdc vs-internal-log /dev/nvme1 -t controller -o ctlr-telem-log-da3.bin -d 3
diff --git a/Documentation/nvme-wdc-vs-nand-stats.1 b/Documentation/nvme-wdc-vs-nand-stats.1
index ec93cf0..ed8a97f 100644
--- a/Documentation/nvme-wdc-vs-nand-stats.1
+++ b/Documentation/nvme-wdc-vs-nand-stats.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-nand-stats
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-NAND\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-NAND\" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-nand-stats.html b/Documentation/nvme-wdc-vs-nand-stats.html
index 97c436d..dc04e6f 100644
--- a/Documentation/nvme-wdc-vs-nand-stats.html
+++ b/Documentation/nvme-wdc-vs-nand-stats.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-wdc-vs-nand-stats(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -810,7 +813,8 @@ Has the program issue WDC vs-nand-stats Vendor Unique Command :
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2019-02-27 08:37:46 MST
+Last updated
+ 2020-06-08 08:31:26 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.1 b/Documentation/nvme-wdc-vs-smart-add-log.1
index 5b3f8ec..4e9c186 100644
--- a/Documentation/nvme-wdc-vs-smart-add-log.1
+++ b/Documentation/nvme-wdc-vs-smart-add-log.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-smart-add-log
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-SMART" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-SMART" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -33,12 +33,13 @@ nvme-wdc-vs-smart-add-log \- Send NVMe WDC vs\-smart\-add\-log Vendor Unique Com
.sp
.nf
\fInvme wdc vs\-smart\-add\-log\fR <device> [\-\-interval=<NUM>, \-i <NUM>] [\-\-output\-format=<normal|json> \-o <normal|json>]
+ [\-\-log\-page\-version=<NUM>, \-l <NUM>] [\-\-log\-page\-mask=<LIST>, \-p <LIST>]
.fi
.SH "DESCRIPTION"
.sp
-For the NVMe device given, send a Vendor Unique WDC vs\-smart\-add\-log command and provide the additional smart log\&. The \-\-interval option will return performance statistics from the specified reporting interval\&.
+For the NVMe device given, send a Vendor Unique WDC vs\-smart\-add\-log command and provide the additional smart log\&.
.sp
-The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0)\&.
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&.
.sp
This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&.
.sp
@@ -47,7 +48,7 @@ On success it returns 0, error code otherwise\&.
.PP
\-i <NUM>, \-\-interval=<NUM>
.RS 4
-Return the statistics from specific interval, defaults to 14
+Return the statistics from specific interval, defaults to 14\&. This parameter is only valid for the 0xC1 log page and ignored for all other log pages\&.
.RE
.PP
\-o <format>, \-\-output\-format=<format>
@@ -56,6 +57,16 @@ Set the reporting format to
\fInormal\fR, or
\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
.RE
+.PP
+\-l <NUM>, \-\-log\-page\-version=<NUM>
+.RS 4
+Log Page Version: 0 = vendor, 1 = WDC\&. This parameter is only valid for the 0xC0 log page and ignored for all other log pages\&.
+.RE
+.PP
+\-p <LIST>, \-\-log\-page\-mask=<LIST>
+.RS 4
+Supply a comma separated list of desired log pages to display\&. The possible values are 0xc0, 0xc1, 0xca, 0xd0\&. Note: Not all pages are supported on all drives\&. The default is to display all supported log pages\&.
+.RE
.sp
Valid Interval values and description :\-
.TS
@@ -109,367 +120,49 @@ The statistical set accumulated during the entire lifetime of the device\&.
T}
.TE
.sp 1
-.SH "CA LOG PAGE DATA OUTPUT EXPLANATION"
-.TS
-allbox tab(:);
-ltB ltB.
-T{
-Field
-T}:T{
-Description
-T}
-.T&
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt.
-T{
-.sp
-\fBPhysical NAND bytes written\&.\fR
-T}:T{
-.sp
-The number of bytes written to NAND\&. 16 bytes \- hi/lo
-T}
-T{
-.sp
-\fBPhysical NAND bytes read\fR
-T}:T{
-.sp
-The number of bytes read from NAND\&. 16 bytes \- hi/lo
-T}
-T{
-.sp
-\fBBad NAND Block Count\fR
-T}:T{
-.sp
-Raw and normalized count of the number of NAND blocks that have been retired after the drives manufacturing tests (i\&.e\&. grown back blocks)\&. 2 bytes normalized, 6 bytes raw count
-T}
-T{
-.sp
-\fBUncorrectable Read Error Count\fR
-T}:T{
-.sp
-Total count of NAND reads that were not correctable by read retries, all levels of ECC, or XOR (as applicable)\&. 8 bytes
-T}
-T{
-.sp
-\fBSoft ECC Error Count\fR
-T}:T{
-.sp
-Total count of NAND reads that were not correctable by read retries, or first\-level ECC\&. 8 bytes
-T}
-T{
-.sp
-\fBSSD End to End Detection Count\fR
-T}:T{
-.sp
-A count of the detected errors by the SSD end to end error correction which includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not NAND ECC)\&. 4 bytes
-T}
-T{
-.sp
-\fBSSD End to End Correction Count\fR
-T}:T{
-.sp
-A count of the corrected errors by the SSD end to end error correction which includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not NAND ECC)\&. 4 bytes
-T}
-T{
-.sp
-\fBSystem Data % Used\fR
-T}:T{
-.sp
-A normalized cumulative count of the number of erase cycles per block since leaving the factory for the system (FW and metadata) area\&. Starts at 0 and increments\&. 100 indicates that the estimated endurance has been consumed\&.
-T}
-T{
-.sp
-\fBUser Data Max Erase Count\fR
-T}:T{
-.sp
-The maximum erase count across all NAND blocks in the drive\&. 4 bytes
-T}
-T{
-.sp
-\fBUser Data Min Erase Count\fR
-T}:T{
-.sp
-The minimum erase count across all NAND blocks in the drive\&. 4 bytes
-T}
-T{
-.sp
-\fBRefresh Count\fR
-T}:T{
-.sp
-A count of the number of blocks that have been re\-allocated due to background operations only\&. 8 bytes
-T}
-T{
-.sp
-\fBProgram Fail Count\fR
-T}:T{
-.sp
-Raw and normalized count of total program failures\&. Normalized count starts at 100 and shows the percent of remaining allowable failures\&. 2 bytes normalized, 6 bytes raw count
-T}
-T{
-.sp
-\fBUser Data Erase Fail Count\fR
-T}:T{
-.sp
-Raw and normalized count of total erase failures in the user area\&. Normalized count starts at 100 and shows the percent of remaining allowable failures\&. 2 bytes normalized, 6 bytes raw count
-T}
-T{
-.sp
-\fBSystem Area Erase Fail Count\fR
-T}:T{
-.sp
-Raw and normalized count of total erase failures in the system area\&. Normalized count starts at 100 and shows the percent of remaining allowable failures\&. 2 bytes normalized, 6 bytes raw count
-T}
-T{
-.sp
-\fBThermal Throttling Status\fR
-T}:T{
-.sp
-The current status of thermal throttling (enabled or disabled)\&. 2 bytes
-T}
-T{
-.sp
-\fBThermal Throttling Count\fR
-T}:T{
-.sp
-A count of the number of thermal throttling events\&. 2 bytes
-T}
-T{
-.sp
-\fBPCIe Correctable Error Count\fR
-T}:T{
-.sp
-Summation counter of all PCIe correctable errors (Bad TLP, Bad DLLP, Receiver error, Replay timeouts, Replay rollovers)\&. 8 bytes
-T}
-.TE
-.sp 1
-.SH "C1 LOG PAGE DATA OUTPUT EXPLANATION"
-.TS
-allbox tab(:);
-ltB ltB.
-T{
-Field
-T}:T{
-Description
-T}
-.T&
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt
-lt lt.
-T{
-.sp
-\fBHost Read Commands\fR
-T}:T{
-.sp
-Number of host read commands received during the reporting period\&.
-T}
-T{
-.sp
-\fBHost Read Blocks\fR
-T}:T{
-.sp
-Number of 512\-byte blocks requested during the reporting period\&.
-T}
-T{
-.sp
-\fBAverage Read Size\fR
-T}:T{
-.sp
-Average Read size is calculated using (Host Read Blocks/Host Read Commands)\&.
-T}
-T{
-.sp
-\fBHost Read Cache Hit Commands\fR
-T}:T{
-.sp
-Number of host read commands that serviced entirely from the on\-board read cache during the reporting period\&. No access to the NAND flash memory was required\&. This count is only updated if the entire command was serviced from the cache memory\&.
-T}
-T{
-.sp
-\fBHost Read Cache Hit Percentage\fR
-T}:T{
-.sp
-Percentage of host read commands satisfied from the cache\&.
-T}
-T{
-.sp
-\fBHost Read Cache Hit Blocks\fR
-T}:T{
-.sp
-Number of 512\-byte blocks of data that have been returned for Host Read Cache Hit Commands during the reporting period\&. This count is only updated with the blocks returned for host read commands that were serviced entirely from cache memory\&.
-T}
-T{
-.sp
-\fBAverage Read Cache Hit Size\fR
-T}:T{
-.sp
-Average size of read commands satisfied from the cache\&.
-T}
-T{
-.sp
-\fBHost Read Commands Stalled\fR
-T}:T{
-.sp
-Number of host read commands that were stalled due to a lack of resources within the SSD during the reporting period (NAND flash command queue full, low cache page count, cache page contention, etc\&.)\&. Commands are not considered stalled if the only reason for the delay was waiting for the data to be physically read from the NAND flash\&. It is normal to expect this count to equal zero on heavily utilized systems\&.
-T}
-T{
-.sp
-\fBHost Read Commands Stalled Percentage\fR
-T}:T{
-.sp
-Percentage of read commands that were stalled\&. If the figure is consistently high, then consideration should be given to spreading the data across multiple SSDs\&.
-T}
-T{
-.sp
-\fBHost Write Commands\fR
-T}:T{
-.sp
-Number of host write commands received during the reporting period\&.
-T}
-T{
-.sp
-\fBHost Write Blocks\fR
-T}:T{
-.sp
-Number of 512\-byte blocks written during the reporting period\&.
-T}
-T{
-.sp
-\fBAverage Write Size\fR
-T}:T{
-.sp
-Average Write size calculated using (Host Write Blocks/Host Write Commands)\&.
-T}
-T{
-.sp
-\fBHost Write Odd Start Commands\fR
-T}:T{
-.sp
-Number of host write commands that started on a non\-aligned boundary during the reporting period\&. The size of the boundary alignment is normally 4K; therefore this returns the number of commands that started on a non\-4K aligned boundary\&. The SSD requires slightly more time to process non\-aligned write commands than it does to process aligned write commands\&.
-T}
-T{
-.sp
-\fBHost Write Odd Start Commands Percentage\fR
-T}:T{
-.sp
-Percentage of host write commands that started on a non\-aligned boundary\&. If this figure is equal to or near 100%, and the NAND Read Before Write value is also high, then the user should investigate the possibility of offsetting the file system\&. For Microsoft Windows systems, the user can use Diskpart\&. For Unix\-based operating systems, there is normally a method whereby file system partitions can be placed where required\&.
-T}
-T{
-.sp
-\fBHost Write Odd End Commands\fR
-T}:T{
-.sp
-Number of host write commands that ended on a non\-aligned boundary during the reporting period\&. The size of the boundary alignment is normally 4K; therefore this returns the number of commands that ended on a non\-4K aligned boundary\&.
-T}
-T{
-.sp
-\fBHost Write Odd End Commands Percentage\fR
-T}:T{
-.sp
-Percentage of host write commands that ended on a non\-aligned boundary\&.
-T}
-T{
-.sp
-\fBHost Write Commands Stalled\fR
-T}:T{
-.sp
-Number of host write commands that were stalled due to a lack of resources within the SSD during the reporting period\&. The most likely cause is that the write data was being received faster than it could be saved to the NAND flash memory\&. If there was a large volume of read commands being processed simultaneously, then other causes might include the NAND flash command queue being full, low cache page count, or cache page contention, etc\&. It is normal to expect this count to be non\-zero on heavily utilized systems\&.
-T}
-T{
-.sp
-\fBHost Write Commands Stalled Percentage\fR
-T}:T{
-.sp
-Percentage of write commands that were stalled\&. If the figure is consistently high, then consideration should be given to spreading the data across multiple SSDs\&.
-T}
-T{
-.sp
-\fBNAND Read Commands\fR
-T}:T{
-.sp
-Number of read commands issued to the NAND devices during the reporting period\&. This figure will normally be much higher than the host read commands figure, as the data needed to satisfy a single host read command may be spread across several NAND flash devices\&.
-T}
-T{
-.sp
-\fBNAND Read Blocks\fR
-T}:T{
-.sp
-Number of 512\-byte blocks requested from NAND flash devices during the reporting period\&. This figure would normally be about the same as the host read blocks figure
-T}
-T{
-.sp
-\fBAverage NAND Read Size\fR
-T}:T{
-.sp
-Average size of NAND read commands\&.
-T}
-T{
-.sp
-\fBNAND Write Commands\fR
-T}:T{
-.sp
-Number of write commands issued to the NAND devices during the reporting period\&. There is no real correlation between the number of host write commands issued and the number of NAND Write Commands\&.
-T}
-T{
-.sp
-\fBNAND Write Blocks\fR
-T}:T{
-.sp
-Number of 512\-byte blocks written to the NAND flash devices during the reporting period\&. This figure would normally be about the same as the host write blocks figure\&.
-T}
-T{
+.SH "EXAMPLES"
.sp
-\fBAverage NAND Write Size\fR
-T}:T{
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-smart\-add\-log Vendor Unique Command with default interval (14) :
.sp
-Average size of NAND write commands\&. This figure should never be greater than 128K, as this is the maximum size write that is ever issued to a NAND device\&.
-T}
-T{
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-smart\-add\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
.sp
-\fBNAND Read Before Write\fR
-T}:T{
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-smart\-add\-log Vendor Unique Command for just the 0xCA log page :
.sp
-This is the number of read before write operations that were required to process non\-aligned host write commands during the reporting period\&. See Host Write Odd Start Commands and Host Write Odd End Commands\&. NAND Read Before Write operations have a detrimental effect on the overall performance of the device\&.
-T}
-.TE
-.sp 1
-.SH "EXAMPLES"
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-smart\-add\-log /dev/nvme0 \-p 0xCA
+.fi
+.if n \{\
+.RE
+.\}
+.RE
.sp
.RS 4
.ie n \{\
@@ -479,13 +172,13 @@ T}
.sp -1
.IP \(bu 2.3
.\}
-Has the program issue WDC vs\-smart\-add\-log Vendor Unique Command with default interval (14) :
+Has the program issue WDC vs\-smart\-add\-log Vendor Unique Command for 0xC0 and 0xCA log pages :
.sp
.if n \{\
.RS 4
.\}
.nf
-# nvme wdc vs\-smart\-add\-log /dev/nvme0
+# nvme wdc vs\-smart\-add\-log /dev/nvme0 \-p 0xCA,0xC0
.fi
.if n \{\
.RE
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.html b/Documentation/nvme-wdc-vs-smart-add-log.html
index 182b9c2..29cf0fa 100644
--- a/Documentation/nvme-wdc-vs-smart-add-log.html
+++ b/Documentation/nvme-wdc-vs-smart-add-log.html
@@ -1,9 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
-<meta name="generator" content="AsciiDoc 8.6.8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
<title>nvme-wdc-vs-smart-add-log(1)</title>
<style type="text/css">
/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
@@ -94,7 +95,9 @@ ul > li > * { color: black; }
padding: 0;
margin: 0;
}
-
+pre {
+ white-space: pre-wrap;
+}
#author {
color: #527bbd;
@@ -223,7 +226,7 @@ div.exampleblock > div.content {
}
div.imageblock div.content { padding-left: 0; }
-span.image img { border-style: none; }
+span.image img { border-style: none; vertical-align: text-bottom; }
a.image:visited { color: white; }
dl {
@@ -746,7 +749,8 @@ nvme-wdc-vs-smart-add-log(1) Manual Page
<h2 id="_synopsis">SYNOPSIS</h2>
<div class="sectionbody">
<div class="verseblock">
-<pre class="content"><em>nvme wdc vs-smart-add-log</em> &lt;device&gt; [--interval=&lt;NUM&gt;, -i &lt;NUM&gt;] [--output-format=&lt;normal|json&gt; -o &lt;normal|json&gt;]</pre>
+<pre class="content"><em>nvme wdc vs-smart-add-log</em> &lt;device&gt; [--interval=&lt;NUM&gt;, -i &lt;NUM&gt;] [--output-format=&lt;normal|json&gt; -o &lt;normal|json&gt;]
+ [--log-page-version=&lt;NUM&gt;, -l &lt;NUM&gt;] [--log-page-mask=&lt;LIST&gt;, -p &lt;LIST&gt;]</pre>
<div class="attribution">
</div></div>
</div>
@@ -755,10 +759,9 @@ nvme-wdc-vs-smart-add-log(1) Manual Page
<h2 id="_description">DESCRIPTION</h2>
<div class="sectionbody">
<div class="paragraph"><p>For the NVMe device given, send a Vendor Unique WDC vs-smart-add-log command and
-provide the additional smart log. The --interval option will return performance
-statistics from the specified reporting interval.</p></div>
+provide the additional smart log.</p></div>
<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
-device (ex: /dev/nvme0).</p></div>
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).</p></div>
<div class="paragraph"><p>This will only work on WDC devices supporting this feature.
Results for any other device are undefined.</p></div>
<div class="paragraph"><p>On success it returns 0, error code otherwise.</p></div>
@@ -776,7 +779,8 @@ Results for any other device are undefined.</p></div>
</dt>
<dd>
<p>
- Return the statistics from specific interval, defaults to 14
+ Return the statistics from specific interval, defaults to 14. This parameter is only valid for the 0xC1 log page
+ and ignored for all other log pages.
</p>
</dd>
<dt class="hdlist1">
@@ -792,6 +796,32 @@ Results for any other device are undefined.</p></div>
Default is normal.
</p>
</dd>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--log-page-version=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for the 0xC0 log page and ignored for all
+ other log pages.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;LIST&gt;
+</dt>
+<dt class="hdlist1">
+--log-page-mask=&lt;LIST&gt;
+</dt>
+<dd>
+<p>
+ Supply a comma separated list of desired log pages to display.
+ The possible values are 0xc0, 0xc1, 0xca, 0xd0.
+ Note: Not all pages are supported on all drives.
+ The default is to display all supported log pages.
+</p>
+</dd>
</dl></div>
<div class="paragraph"><p>Valid Interval values and description :-</p></div>
<div class="tableblock">
@@ -836,274 +866,6 @@ accumulated statistics.</p></td>
</div>
</div>
<div class="sect1">
-<h2 id="_ca_log_page_data_output_explanation">CA Log Page Data Output Explanation</h2>
-<div class="sectionbody">
-<div class="tableblock">
-<table rules="all"
-style="margin-left:auto; margin-right:auto;"
-width="100%"
-frame="hsides"
-cellspacing="0" cellpadding="4">
-<col width="50%" />
-<col width="50%" />
-<thead>
-<tr>
-<th align="left" valign="top">Field </th>
-<th align="left" valign="top">Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Physical NAND bytes written.</strong></p></td>
-<td align="left" valign="top"><p class="table">The number of bytes written to NAND. 16 bytes - hi/lo</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Physical NAND bytes read</strong></p></td>
-<td align="left" valign="top"><p class="table">The number of bytes read from NAND. 16 bytes - hi/lo</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Bad NAND Block Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Raw and normalized count of the number of NAND blocks that have been
-retired after the drives manufacturing tests (i.e. grown back blocks).
-2 bytes normalized, 6 bytes raw count</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Uncorrectable Read Error Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Total count of NAND reads that were not correctable by read retries, all
-levels of ECC, or XOR (as applicable). 8 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Soft ECC Error Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Total count of NAND reads that were not correctable by read retries, or
-first-level ECC. 8 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>SSD End to End Detection Count</strong></p></td>
-<td align="left" valign="top"><p class="table">A count of the detected errors by the SSD end to end error correction which
-includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
-NAND ECC). 4 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>SSD End to End Correction Count</strong></p></td>
-<td align="left" valign="top"><p class="table">A count of the corrected errors by the SSD end to end error correction which
-includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
-NAND ECC). 4 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>System Data % Used</strong></p></td>
-<td align="left" valign="top"><p class="table">A normalized cumulative count of the number of erase cycles per block since
-leaving the factory for the system (FW and metadata) area. Starts at 0 and
-increments. 100 indicates that the estimated endurance has been consumed.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>User Data Max Erase Count</strong></p></td>
-<td align="left" valign="top"><p class="table">The maximum erase count across all NAND blocks in the drive. 4 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>User Data Min Erase Count</strong></p></td>
-<td align="left" valign="top"><p class="table">The minimum erase count across all NAND blocks in the drive. 4 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Refresh Count</strong></p></td>
-<td align="left" valign="top"><p class="table">A count of the number of blocks that have been re-allocated due to
-background operations only. 8 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Program Fail Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Raw and normalized count of total program failures. Normalized count
-starts at 100 and shows the percent of remaining allowable failures.
-2 bytes normalized, 6 bytes raw count</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>User Data Erase Fail Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Raw and normalized count of total erase failures in the user area.
-Normalized count starts at 100 and shows the percent of remaining
-allowable failures. 2 bytes normalized, 6 bytes raw count</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>System Area Erase Fail Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Raw and normalized count of total erase failures in the system area.
-Normalized count starts at 100 and shows the percent of remaining
-allowable failures. 2 bytes normalized, 6 bytes raw count</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Thermal Throttling Status</strong></p></td>
-<td align="left" valign="top"><p class="table">The current status of thermal throttling (enabled or disabled).
-2 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Thermal Throttling Count</strong></p></td>
-<td align="left" valign="top"><p class="table">A count of the number of thermal throttling events. 2 bytes</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>PCIe Correctable Error Count</strong></p></td>
-<td align="left" valign="top"><p class="table">Summation counter of all PCIe correctable errors (Bad TLP, Bad
-DLLP, Receiver error, Replay timeouts, Replay rollovers). 8 bytes</p></td>
-</tr>
-</tbody>
-</table>
-</div>
-</div>
-</div>
-<div class="sect1">
-<h2 id="_c1_log_page_data_output_explanation">C1 Log Page Data Output Explanation</h2>
-<div class="sectionbody">
-<div class="tableblock">
-<table rules="all"
-style="margin-left:auto; margin-right:auto;"
-width="100%"
-frame="hsides"
-cellspacing="0" cellpadding="4">
-<col width="50%" />
-<col width="50%" />
-<thead>
-<tr>
-<th align="left" valign="top">Field </th>
-<th align="left" valign="top">Description</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host read commands received during the reporting period.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Blocks</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of 512-byte blocks requested during the reporting period.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Average Read Size</strong></p></td>
-<td align="left" valign="top"><p class="table">Average Read size is calculated using (Host Read Blocks/Host Read Commands).</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Cache Hit Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host read commands that serviced entirely from the on-board read
-cache during the reporting period. No access to the NAND flash memory was required.
-This count is only updated if the entire command was serviced from the cache memory.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Cache Hit Percentage</strong></p></td>
-<td align="left" valign="top"><p class="table">Percentage of host read commands satisfied from the cache.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Cache Hit Blocks</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of 512-byte blocks of data that have been returned for Host Read Cache Hit
-Commands during the reporting period. This count is only updated with the blocks
-returned for host read commands that were serviced entirely from cache memory.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Average Read Cache Hit Size</strong></p></td>
-<td align="left" valign="top"><p class="table">Average size of read commands satisfied from the cache.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Commands Stalled</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host read commands that were stalled due to a lack of resources within
-the SSD during the reporting period (NAND flash command queue full, low cache page count,
-cache page contention, etc.). Commands are not considered stalled if the only reason for
-the delay was waiting for the data to be physically read from the NAND flash. It is normal
-to expect this count to equal zero on heavily utilized systems.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Read Commands Stalled Percentage</strong></p></td>
-<td align="left" valign="top"><p class="table">Percentage of read commands that were stalled. If the figure is consistently high,
-then consideration should be given to spreading the data across multiple SSDs.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host write commands received during the reporting period.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Blocks</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of 512-byte blocks written during the reporting period.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Average Write Size</strong></p></td>
-<td align="left" valign="top"><p class="table">Average Write size calculated using (Host Write Blocks/Host Write Commands).</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Odd Start Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host write commands that started on a non-aligned boundary during
-the reporting period. The size of the boundary alignment is normally 4K; therefore
-this returns the number of commands that started on a non-4K aligned boundary.
-The SSD requires slightly more time to process non-aligned write commands than it
-does to process aligned write commands.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Odd Start Commands Percentage</strong></p></td>
-<td align="left" valign="top"><p class="table">Percentage of host write commands that started on a non-aligned boundary. If this
-figure is equal to or near 100%, and the NAND Read Before Write value is also high,
-then the user should investigate the possibility of offsetting the file system. For
-Microsoft Windows systems, the user can use Diskpart. For Unix-based operating systems,
-there is normally a method whereby file system partitions can be placed where required.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Odd End Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host write commands that ended on a non-aligned boundary during the
-reporting period. The size of the boundary alignment is normally 4K; therefore this
-returns the number of commands that ended on a non-4K aligned boundary.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Odd End Commands Percentage</strong></p></td>
-<td align="left" valign="top"><p class="table">Percentage of host write commands that ended on a non-aligned boundary.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Commands Stalled</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of host write commands that were stalled due to a lack of resources within the
-SSD during the reporting period. The most likely cause is that the write data was being
-received faster than it could be saved to the NAND flash memory. If there was a large
-volume of read commands being processed simultaneously, then other causes might include
-the NAND flash command queue being full, low cache page count, or cache page contention, etc.
-It is normal to expect this count to be non-zero on heavily utilized systems.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Host Write Commands Stalled Percentage</strong></p></td>
-<td align="left" valign="top"><p class="table">Percentage of write commands that were stalled. If the figure is consistently high, then
-consideration should be given to spreading the data across multiple SSDs.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>NAND Read Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of read commands issued to the NAND devices during the reporting period.
-This figure will normally be much higher than the host read commands figure, as the data
-needed to satisfy a single host read command may be spread across several NAND flash devices.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>NAND Read Blocks</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of 512-byte blocks requested from NAND flash devices during the reporting period.
-This figure would normally be about the same as the host read blocks figure</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Average NAND Read Size</strong></p></td>
-<td align="left" valign="top"><p class="table">Average size of NAND read commands.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>NAND Write Commands</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of write commands issued to the NAND devices during the reporting period.
-There is no real correlation between the number of host write commands issued and the
-number of NAND Write Commands.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>NAND Write Blocks</strong></p></td>
-<td align="left" valign="top"><p class="table">Number of 512-byte blocks written to the NAND flash devices during the reporting period.
-This figure would normally be about the same as the host write blocks figure.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>Average NAND Write Size</strong></p></td>
-<td align="left" valign="top"><p class="table">Average size of NAND write commands. This figure should never be greater than 128K, as
-this is the maximum size write that is ever issued to a NAND device.</p></td>
-</tr>
-<tr>
-<td align="left" valign="top"><p class="table"><strong>NAND Read Before Write</strong></p></td>
-<td align="left" valign="top"><p class="table">This is the number of read before write operations that were required to process
-non-aligned host write commands during the reporting period. See Host Write Odd Start
-Commands and Host Write Odd End Commands. NAND Read Before Write operations have
-a detrimental effect on the overall performance of the device.</p></td>
-</tr>
-</tbody>
-</table>
-</div>
-</div>
-</div>
-<div class="sect1">
<h2 id="_examples">EXAMPLES</h2>
<div class="sectionbody">
<div class="ulist"><ul>
@@ -1116,6 +878,24 @@ Has the program issue WDC vs-smart-add-log Vendor Unique Command with default in
<pre><code># nvme wdc vs-smart-add-log /dev/nvme0</code></pre>
</div></div>
</li>
+<li>
+<p>
+Has the program issue WDC vs-smart-add-log Vendor Unique Command for just the 0xCA log page :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-smart-add-log /dev/nvme0 -p 0xCA</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Has the program issue WDC vs-smart-add-log Vendor Unique Command for 0xC0 and 0xCA log pages :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-smart-add-log /dev/nvme0 -p 0xCA,0xC0</code></pre>
+</div></div>
+</li>
</ul></div>
</div>
</div>
@@ -1129,7 +909,8 @@ Has the program issue WDC vs-smart-add-log Vendor Unique Command with default in
<div id="footnotes"><hr /></div>
<div id="footer">
<div id="footer-text">
-Last updated 2019-01-11 13:56:35 MST
+Last updated
+ 2020-08-06 15:54:37 PDT
</div>
</div>
</body>
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.txt b/Documentation/nvme-wdc-vs-smart-add-log.txt
index a9c4ead..96b55c5 100644
--- a/Documentation/nvme-wdc-vs-smart-add-log.txt
+++ b/Documentation/nvme-wdc-vs-smart-add-log.txt
@@ -9,15 +9,15 @@ SYNOPSIS
--------
[verse]
'nvme wdc vs-smart-add-log' <device> [--interval=<NUM>, -i <NUM>] [--output-format=<normal|json> -o <normal|json>]
+ [--log-page-version=<NUM>, -l <NUM>] [--log-page-mask=<LIST>, -p <LIST>]
DESCRIPTION
-----------
For the NVMe device given, send a Vendor Unique WDC vs-smart-add-log command and
-provide the additional smart log. The --interval option will return performance
-statistics from the specified reporting interval.
+provide the additional smart log.
The <device> parameter is mandatory and may be either the NVMe character
-device (ex: /dev/nvme0).
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
This will only work on WDC devices supporting this feature.
Results for any other device are undefined.
@@ -28,7 +28,8 @@ OPTIONS
-------
-i <NUM>::
--interval=<NUM>::
- Return the statistics from specific interval, defaults to 14
+ Return the statistics from specific interval, defaults to 14. This parameter is only valid for the 0xC1 log page
+ and ignored for all other log pages.
-o <format>::
--output-format=<format>::
@@ -36,6 +37,18 @@ OPTIONS
'json'. Only one output format can be used at a time.
Default is normal.
+-l <NUM>::
+--log-page-version=<NUM>::
+ Log Page Version: 0 = vendor, 1 = WDC. This parameter is only valid for the 0xC0 log page and ignored for all
+ other log pages.
+
+-p <LIST>::
+--log-page-mask=<LIST>::
+ Supply a comma separated list of desired log pages to display.
+ The possible values are 0xc0, 0xc1, 0xca, 0xd0.
+ Note: Not all pages are supported on all drives.
+ The default is to display all supported log pages.
+
Valid Interval values and description :-
[cols="2*", frame="topbot", align="center", options="header"]
@@ -59,201 +72,6 @@ accumulated statistics.
|The statistical set accumulated during the entire lifetime of the device.
|===
-CA Log Page Data Output Explanation
------------------------------------
-[cols="2*", frame="topbot", align="center", options="header"]
-|===
-|Field |Description
-
-|*Physical NAND bytes written.*
-|The number of bytes written to NAND. 16 bytes - hi/lo
-
-|*Physical NAND bytes read*
-|The number of bytes read from NAND. 16 bytes - hi/lo
-
-|*Bad NAND Block Count*
-|Raw and normalized count of the number of NAND blocks that have been
-retired after the drives manufacturing tests (i.e. grown back blocks).
-2 bytes normalized, 6 bytes raw count
-
-|*Uncorrectable Read Error Count*
-|Total count of NAND reads that were not correctable by read retries, all
-levels of ECC, or XOR (as applicable). 8 bytes
-
-|*Soft ECC Error Count*
-|Total count of NAND reads that were not correctable by read retries, or
-first-level ECC. 8 bytes
-
-|*SSD End to End Detection Count*
-|A count of the detected errors by the SSD end to end error correction which
-includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
-NAND ECC). 4 bytes
-
-|*SSD End to End Correction Count*
-|A count of the corrected errors by the SSD end to end error correction which
-includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
-NAND ECC). 4 bytes
-
-|*System Data % Used*
-|A normalized cumulative count of the number of erase cycles per block since
-leaving the factory for the system (FW and metadata) area. Starts at 0 and
-increments. 100 indicates that the estimated endurance has been consumed.
-
-|*User Data Max Erase Count*
-|The maximum erase count across all NAND blocks in the drive. 4 bytes
-
-|*User Data Min Erase Count*
-|The minimum erase count across all NAND blocks in the drive. 4 bytes
-
-|*Refresh Count*
-|A count of the number of blocks that have been re-allocated due to
-background operations only. 8 bytes
-
-|*Program Fail Count*
-|Raw and normalized count of total program failures. Normalized count
-starts at 100 and shows the percent of remaining allowable failures.
-2 bytes normalized, 6 bytes raw count
-
-|*User Data Erase Fail Count*
-|Raw and normalized count of total erase failures in the user area.
-Normalized count starts at 100 and shows the percent of remaining
-allowable failures. 2 bytes normalized, 6 bytes raw count
-
-|*System Area Erase Fail Count*
-|Raw and normalized count of total erase failures in the system area.
-Normalized count starts at 100 and shows the percent of remaining
-allowable failures. 2 bytes normalized, 6 bytes raw count
-
-|*Thermal Throttling Status*
-|The current status of thermal throttling (enabled or disabled).
-2 bytes
-
-|*Thermal Throttling Count*
-|A count of the number of thermal throttling events. 2 bytes
-
-|*PCIe Correctable Error Count*
-|Summation counter of all PCIe correctable errors (Bad TLP, Bad
-DLLP, Receiver error, Replay timeouts, Replay rollovers). 8 bytes
-|===
-
-
-C1 Log Page Data Output Explanation
------------------------------------
-[cols="2*", frame="topbot", align="center", options="header"]
-|===
-|Field |Description
-
-|*Host Read Commands*
-|Number of host read commands received during the reporting period.
-
-|*Host Read Blocks*
-|Number of 512-byte blocks requested during the reporting period.
-
-|*Average Read Size*
-|Average Read size is calculated using (Host Read Blocks/Host Read Commands).
-
-|*Host Read Cache Hit Commands*
-|Number of host read commands that serviced entirely from the on-board read
-cache during the reporting period. No access to the NAND flash memory was required.
-This count is only updated if the entire command was serviced from the cache memory.
-
-|*Host Read Cache Hit Percentage*
-|Percentage of host read commands satisfied from the cache.
-
-|*Host Read Cache Hit Blocks*
-|Number of 512-byte blocks of data that have been returned for Host Read Cache Hit
-Commands during the reporting period. This count is only updated with the blocks
-returned for host read commands that were serviced entirely from cache memory.
-
-|*Average Read Cache Hit Size*
-|Average size of read commands satisfied from the cache.
-
-|*Host Read Commands Stalled*
-|Number of host read commands that were stalled due to a lack of resources within
-the SSD during the reporting period (NAND flash command queue full, low cache page count,
-cache page contention, etc.). Commands are not considered stalled if the only reason for
-the delay was waiting for the data to be physically read from the NAND flash. It is normal
-to expect this count to equal zero on heavily utilized systems.
-
-|*Host Read Commands Stalled Percentage*
-|Percentage of read commands that were stalled. If the figure is consistently high,
-then consideration should be given to spreading the data across multiple SSDs.
-
-|*Host Write Commands*
-|Number of host write commands received during the reporting period.
-
-|*Host Write Blocks*
-|Number of 512-byte blocks written during the reporting period.
-
-|*Average Write Size*
-|Average Write size calculated using (Host Write Blocks/Host Write Commands).
-
-|*Host Write Odd Start Commands*
-|Number of host write commands that started on a non-aligned boundary during
-the reporting period. The size of the boundary alignment is normally 4K; therefore
-this returns the number of commands that started on a non-4K aligned boundary.
-The SSD requires slightly more time to process non-aligned write commands than it
-does to process aligned write commands.
-
-|*Host Write Odd Start Commands Percentage*
-|Percentage of host write commands that started on a non-aligned boundary. If this
-figure is equal to or near 100%, and the NAND Read Before Write value is also high,
-then the user should investigate the possibility of offsetting the file system. For
-Microsoft Windows systems, the user can use Diskpart. For Unix-based operating systems,
-there is normally a method whereby file system partitions can be placed where required.
-
-|*Host Write Odd End Commands*
-|Number of host write commands that ended on a non-aligned boundary during the
-reporting period. The size of the boundary alignment is normally 4K; therefore this
-returns the number of commands that ended on a non-4K aligned boundary.
-
-|*Host Write Odd End Commands Percentage*
-|Percentage of host write commands that ended on a non-aligned boundary.
-
-|*Host Write Commands Stalled*
-|Number of host write commands that were stalled due to a lack of resources within the
-SSD during the reporting period. The most likely cause is that the write data was being
-received faster than it could be saved to the NAND flash memory. If there was a large
-volume of read commands being processed simultaneously, then other causes might include
-the NAND flash command queue being full, low cache page count, or cache page contention, etc.
-It is normal to expect this count to be non-zero on heavily utilized systems.
-
-|*Host Write Commands Stalled Percentage*
-|Percentage of write commands that were stalled. If the figure is consistently high, then
-consideration should be given to spreading the data across multiple SSDs.
-
-|*NAND Read Commands*
-|Number of read commands issued to the NAND devices during the reporting period.
-This figure will normally be much higher than the host read commands figure, as the data
-needed to satisfy a single host read command may be spread across several NAND flash devices.
-
-|*NAND Read Blocks*
-|Number of 512-byte blocks requested from NAND flash devices during the reporting period.
-This figure would normally be about the same as the host read blocks figure
-
-|*Average NAND Read Size*
-|Average size of NAND read commands.
-
-|*NAND Write Commands*
-|Number of write commands issued to the NAND devices during the reporting period.
-There is no real correlation between the number of host write commands issued and the
-number of NAND Write Commands.
-
-|*NAND Write Blocks*
-|Number of 512-byte blocks written to the NAND flash devices during the reporting period.
-This figure would normally be about the same as the host write blocks figure.
-
-|*Average NAND Write Size*
-|Average size of NAND write commands. This figure should never be greater than 128K, as
-this is the maximum size write that is ever issued to a NAND device.
-
-|*NAND Read Before Write*
-|This is the number of read before write operations that were required to process
-non-aligned host write commands during the reporting period. See Host Write Odd Start
-Commands and Host Write Odd End Commands. NAND Read Before Write operations have
-a detrimental effect on the overall performance of the device.
-|===
-
EXAMPLES
--------
@@ -262,6 +80,16 @@ EXAMPLES
------------
# nvme wdc vs-smart-add-log /dev/nvme0
------------
+* Has the program issue WDC vs-smart-add-log Vendor Unique Command for just the 0xCA log page :
++
+------------
+# nvme wdc vs-smart-add-log /dev/nvme0 -p 0xCA
+------------
+* Has the program issue WDC vs-smart-add-log Vendor Unique Command for 0xC0 and 0xCA log pages :
++
+------------
+# nvme wdc vs-smart-add-log /dev/nvme0 -p 0xCA,0xC0
+------------
NVME
----
diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.1 b/Documentation/nvme-wdc-vs-telemetry-controller-option.1
index 0359a0b..1c6397f 100644
--- a/Documentation/nvme-wdc-vs-telemetry-controller-option.1
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.1
@@ -2,12 +2,12 @@
.\" Title: nvme-wdc-vs-telemetry-controller-option
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WDC\-VS\-TELEM" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WDC\-VS\-TELEM" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-wdc-vs-temperature-stats.1 b/Documentation/nvme-wdc-vs-temperature-stats.1
new file mode 100644
index 0000000..9f5c92b
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-temperature-stats.1
@@ -0,0 +1,179 @@
+'\" t
+.\" Title: nvme-wdc-vs-temperature-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-TEMPE" "1" "10/20/2020" "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-wdc-vs-temperature-stats \- Display temperature\-related statistics
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-temperature\-stats\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, displays temperature statistics\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+Expected status and description :\-
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Statistic
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+The current composite temperature
+T}:T{
+.sp
+device temperature
+T}
+T{
+.sp
+Warning Composite TEMPerature threshold
+T}:T{
+.sp
+temp of overheating
+T}
+T{
+.sp
+Critical Composite TEMPerature threshold
+T}:T{
+.sp
+temp of critical overheating
+T}
+T{
+.sp
+Device Initiated Thermal Throttling support status
+T}:T{
+.sp
+0 = unsupported, 1 = supported
+T}
+T{
+.sp
+Host Controlled Thermal Management support
+T}:T{
+.sp
+0 = unsupported, 1 = supported
+T}
+T{
+.sp
+Thermal Management Temperature 1 (Light throttle)
+T}:T{
+.sp
+temp to start light throttle
+T}
+T{
+.sp
+Thermal Management Temperature 1 Transition Counter
+T}:T{
+.sp
+# times switched into light throttle
+T}
+T{
+.sp
+Thermal Management Temperature 1 Total Time
+T}:T{
+.sp
+# seconds spent in light throttle
+T}
+T{
+.sp
+Thermal Management Temperature 2 (Heavy throttle)
+T}:T{
+.sp
+temp to start heavy throttle
+T}
+T{
+.sp
+Thermal Management Temperature 2 Transition Counter
+T}:T{
+.sp
+# times switched into heavy throttle
+T}
+T{
+.sp
+Thermal Management Temperature 2 Total Time
+T}:T{
+.sp
+# seconds spent in heavy throttle
+T}
+T{
+.sp
+Thermal Shutdown Threshold
+T}:T{
+.sp
+temp of device shutdown
+T}
+.TE
+.sp 1
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Displays the temperature stats for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-temperature\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-temperature-stats.html b/Documentation/nvme-wdc-vs-temperature-stats.html
new file mode 100644
index 0000000..3280131
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-temperature-stats.html
@@ -0,0 +1,864 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 9.0.0rc1" />
+<title>nvme-wdc-vs-temperature-stats(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-vs-temperature-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-temperature-stats -
+ Display temperature-related statistics
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme wdc vs-temperature-stats</em> &lt;device&gt;</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, displays temperature statistics.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory NVMe character device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>Expected status and description :-</p></div>
+<div class="tableblock">
+<table rules="all"
+width="100%"
+frame="border"
+cellspacing="0" cellpadding="4">
+<col width="50%" />
+<col width="50%" />
+<thead>
+<tr>
+<th align="left" valign="top">Statistic </th>
+<th align="left" valign="top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table">The current composite temperature</p></td>
+<td align="left" valign="top"><p class="table">device temperature</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Warning Composite TEMPerature threshold</p></td>
+<td align="left" valign="top"><p class="table">temp of overheating</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Critical Composite TEMPerature threshold</p></td>
+<td align="left" valign="top"><p class="table">temp of critical overheating</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Device Initiated Thermal Throttling support status</p></td>
+<td align="left" valign="top"><p class="table">0 = unsupported, 1 = supported</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Host Controlled Thermal Management support</p></td>
+<td align="left" valign="top"><p class="table">0 = unsupported, 1 = supported</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 1 (Light throttle)</p></td>
+<td align="left" valign="top"><p class="table">temp to start light throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 1 Transition Counter</p></td>
+<td align="left" valign="top"><p class="table"># times switched into light throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 1 Total Time</p></td>
+<td align="left" valign="top"><p class="table"># seconds spent in light throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 2 (Heavy throttle)</p></td>
+<td align="left" valign="top"><p class="table">temp to start heavy throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 2 Transition Counter</p></td>
+<td align="left" valign="top"><p class="table"># times switched into heavy throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Management Temperature 2 Total Time</p></td>
+<td align="left" valign="top"><p class="table"># seconds spent in heavy throttle</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">Thermal Shutdown Threshold</p></td>
+<td align="left" valign="top"><p class="table">temp of device shutdown</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="paragraph"><p>On success it returns 0, error code otherwise.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Displays the temperature stats for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-temperature-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-24 08:15:01 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-temperature-stats.txt b/Documentation/nvme-wdc-vs-temperature-stats.txt
new file mode 100644
index 0000000..1d000e3
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-temperature-stats.txt
@@ -0,0 +1,78 @@
+nvme-wdc-vs-temperature-stats(1)
+================================
+
+NAME
+----
+nvme-wdc-vs-temperature-stats - Display temperature-related statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-temperature-stats' <device>
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, displays temperature statistics.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+Expected status and description :-
+
+[cols="2*", options="header"]
+|===
+|Statistic |Description
+
+|The current composite temperature
+|device temperature
+
+|Warning Composite TEMPerature threshold
+|temp of overheating
+
+|Critical Composite TEMPerature threshold
+|temp of critical overheating
+
+|Device Initiated Thermal Throttling support status
+|0 = unsupported, 1 = supported
+
+|Host Controlled Thermal Management support
+|0 = unsupported, 1 = supported
+
+|Thermal Management Temperature 1 (Light throttle)
+|temp to start light throttle
+
+|Thermal Management Temperature 1 Transition Counter
+|# times switched into light throttle
+
+|Thermal Management Temperature 1 Total Time
+|# seconds spent in light throttle
+
+|Thermal Management Temperature 2 (Heavy throttle)
+|temp to start heavy throttle
+
+|Thermal Management Temperature 2 Transition Counter
+|# times switched into heavy throttle
+
+|Thermal Management Temperature 2 Total Time
+|# seconds spent in heavy throttle
+
+|Thermal Shutdown Threshold
+|temp of device shutdown
+|===
+
+On success it returns 0, error code otherwise.
+
+EXAMPLES
+--------
+* Displays the temperature stats for the device:
++
+------------
+# nvme wdc vs-temperature-stats /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-write-uncor.1 b/Documentation/nvme-write-uncor.1
index 2cc5c88..93e7511 100644
--- a/Documentation/nvme-write-uncor.1
+++ b/Documentation/nvme-write-uncor.1
@@ -2,12 +2,12 @@
.\" Title: nvme-uncor
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-UNCOR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-UNCOR" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-write-zeroes.1 b/Documentation/nvme-write-zeroes.1
index c1a5b52..d32e3ca 100644
--- a/Documentation/nvme-write-zeroes.1
+++ b/Documentation/nvme-write-zeroes.1
@@ -2,12 +2,12 @@
.\" Title: nvme-zeroes
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-ZEROES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-ZEROES" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-write.1 b/Documentation/nvme-write.1
index 5e9101a..727ac03 100644
--- a/Documentation/nvme-write.1
+++ b/Documentation/nvme-write.1
@@ -2,12 +2,12 @@
.\" Title: nvme-write
.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Date: 10/20/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME\-WRITE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME\-WRITE" "1" "10/20/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/Documentation/nvme-zns-changed-zone-list.1 b/Documentation/nvme-zns-changed-zone-list.1
new file mode 100644
index 0000000..c4a96ba
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.1
@@ -0,0 +1,105 @@
+'\" t
+.\" Title: nvme-zns-changed-zone-list
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-CHANGED\-" "1" "10/20/2020" "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-zns-changed-zone-list \- Retrieve Changed Zone log for the given device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns changed\-zone\-list\fR <device> [\-o <fmt> | \-\-output\-format=<fmt>]
+ [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-rae | \-r]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, requests the namespace\(cqs changed zoned list log and provides the result and returned structure\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1)\&.
+.sp
+On success, the returned list may be decoded and displayed in one of several ways\&.
+.SH "OPTIONS"
+.PP
+\-o <format>, \-\-output\-format=<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
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the changed zone list log for namespace 1
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns changed\-zone\-list /dev/nvme0 \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns changed\-zone\-list /dev/nvme0 \-o json \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-changed-zone-list.html b/Documentation/nvme-zns-changed-zone-list.html
new file mode 100644
index 0000000..977c1d6
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.html
@@ -0,0 +1,840 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-changed-zone-list(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-changed-zone-list(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-changed-zone-list -
+ Retrieve Changed Zone log for the given device
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns changed-zone-list</em> &lt;device&gt; [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]
+ [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--rae | -r]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, requests the namespace&#8217;s changed zoned list log
+and provides the result and returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the returned list may be decoded and displayed in one of several
+ways.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get the changed zone list log for namespace 1
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns changed-zone-list /dev/nvme0 -n 1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns changed-zone-list /dev/nvme0 -o json -n 1</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-changed-zone-list.txt b/Documentation/nvme-zns-changed-zone-list.txt
new file mode 100644
index 0000000..9626c05
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.txt
@@ -0,0 +1,54 @@
+nvme-zns-changed-zone-list(1)
+=============================
+
+NAME
+----
+nvme-zns-changed-zone-list - Retrieve Changed Zone log for the given device
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns changed-zone-list' <device> [-o <fmt> | --output-format=<fmt>]
+ [--namespace-id=<NUM> | -n <NUM>]
+ [--rae | -r]
+
+DESCRIPTION
+-----------
+For the NVMe device given, requests the namespace's changed zoned list log
+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 returned list may be decoded and displayed in one of several
+ways.
+
+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.
+
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+EXAMPLES
+--------
+* Get the changed zone list log for namespace 1
++
+------------
+# nvme zns changed-zone-list /dev/nvme0 -n 1
+------------
++
+
+* Show the output in json format
++
+------------
+# nvme zns changed-zone-list /dev/nvme0 -o json -n 1
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-close-zone.1 b/Documentation/nvme-zns-close-zone.1
new file mode 100644
index 0000000..d9624c1
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-close-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-CLOSE\-ZO" "1" "10/20/2020" "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-zns-close-zone \- Closes one or all zones
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns close\-zone nvme zns id\-ctrl\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "Close Zone" action\&. This will transition the zone to the closed state\&.
+.sp
+The <device> 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
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to close\&.
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Close all zones on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns close\-zone /dev/nvme0 \-a \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-close-zone.html b/Documentation/nvme-zns-close-zone.html
new file mode 100644
index 0000000..d2e297a
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.html
@@ -0,0 +1,841 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-close-zone(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-close-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-close-zone -
+ Closes one or all zones
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns close-zone nvme zns id-ctrl</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--select-all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+"Close Zone" action. This will transition the zone to the closed state.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to close.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Close all zones on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns close-zone /dev/nvme0 -a -n 1</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-close-zone.txt b/Documentation/nvme-zns-close-zone.txt
new file mode 100644
index 0000000..7b47bf0
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.txt
@@ -0,0 +1,49 @@
+nvme-zns-close-zone(1)
+======================
+
+NAME
+----
+nvme-zns-close-zone - Closes one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns close-zone nvme zns id-ctrl' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"Close Zone" action. This will transition the zone to the closed state.
+
+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
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to close.
+
+-a::
+--select-all::
+ Select all zones for this action
+
+EXAMPLES
+--------
+* Close all zones on namespace 1:
++
+------------
+# nvme zns close-zone /dev/nvme0 -a -n 1
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-finish-zone.1 b/Documentation/nvme-zns-finish-zone.1
new file mode 100644
index 0000000..764c683
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-finish-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-FINISH\-Z" "1" "10/20/2020" "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-zns-finish-zone \- Finishes one or all zones
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns finish\-zone nvme zns id\-ctrl\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "Finish Zone" action\&. This will transition the zone to the full state on success\&.
+.sp
+The <device> 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
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to finish\&.
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Finish all zones on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns finish\-zone /dev/nvme0 \-a \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-finish-zone.html b/Documentation/nvme-zns-finish-zone.html
new file mode 100644
index 0000000..36b833f
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.html
@@ -0,0 +1,842 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-finish-zone(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-finish-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-finish-zone -
+ Finishes one or all zones
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns finish-zone nvme zns id-ctrl</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--select-all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+"Finish Zone" action. This will transition the zone to the full state on
+success.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to finish.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Finish all zones on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns finish-zone /dev/nvme0 -a -n 1</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-finish-zone.txt b/Documentation/nvme-zns-finish-zone.txt
new file mode 100644
index 0000000..9a9a2f0
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.txt
@@ -0,0 +1,50 @@
+nvme-zns-finish-zone(1)
+=======================
+
+NAME
+----
+nvme-zns-finish-zone - Finishes one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns finish-zone nvme zns id-ctrl' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"Finish Zone" action. This will transition the zone to the full state on
+success.
+
+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
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to finish.
+
+-a::
+--select-all::
+ Select all zones for this action.
+
+EXAMPLES
+--------
+* Finish all zones on namespace 1:
++
+------------
+# nvme zns finish-zone /dev/nvme0 -a -n 1
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-id-ctrl.1 b/Documentation/nvme-zns-id-ctrl.1
new file mode 100644
index 0000000..7b444c5
--- /dev/null
+++ b/Documentation/nvme-zns-id-ctrl.1
@@ -0,0 +1,98 @@
+'\" t
+.\" Title: nvme-zns-id-ctrl
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ID\-CTRL" "1" "10/20/2020" "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-zns-id-ctrl \- Send NVMe Zoned Command Set Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns id\-ctrl\fR <device> [\-o <fmt> | \-\-output\-format=<fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the zoned command set\(cqs identify controller command and provides the result and returned structure\&.
+.sp
+The <device> 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 data structure returned by the device will be decoded and displayed in one of several ways\&.
+.SH "OPTIONS"
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program interpret the returned buffer and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns id\-ctrl /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns id\-ctrl /dev/nvme0 \-o json
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-id-ctrl.html b/Documentation/nvme-zns-id-ctrl.html
new file mode 100644
index 0000000..cc892a5
--- /dev/null
+++ b/Documentation/nvme-zns-id-ctrl.html
@@ -0,0 +1,828 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-id-ctrl(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-id-ctrl -
+ Send NVMe Zoned Command Set Identify Controller, return result and structure
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns id-ctrl</em> &lt;device&gt; [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends the zoned command set&#8217;s identify controller
+command and provides the result and returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the data structure returned by the device will be decoded and
+displayed in one of several ways.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program interpret the returned buffer and display the known
+fields in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns id-ctrl /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns id-ctrl /dev/nvme0 -o json</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-id-ctrl.txt b/Documentation/nvme-zns-id-ctrl.txt
new file mode 100644
index 0000000..e7bd5ba
--- /dev/null
+++ b/Documentation/nvme-zns-id-ctrl.txt
@@ -0,0 +1,50 @@
+nvme-zns-id-ctrl(1)
+===================
+
+NAME
+----
+nvme-zns-id-ctrl - Send NVMe Zoned Command Set Identify Controller, return
+ result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns id-ctrl' <device> [-o <fmt> | --output-format=<fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the zoned command set's identify controller
+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 data structure returned by the device will be decoded and
+displayed in one of several ways.
+
+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.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme zns id-ctrl /dev/nvme0
+------------
++
+
+* Show the output in json format
++
+------------
+# nvme zns id-ctrl /dev/nvme0 -o json
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-id-ns.1 b/Documentation/nvme-zns-id-ns.1
new file mode 100644
index 0000000..979bea5
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.1
@@ -0,0 +1,110 @@
+'\" t
+.\" Title: nvme-zns-id-ns
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ID\-NS" "1" "10/20/2020" "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-zns-id-ns \- Send NVMe Zoned Command Set Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns id\-ns\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-o <fmt> | \-\-output\-format=<fmt>]
+ [\-v | \-\-verbose]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the zoned command set\(cqs identify namepsace command and provides the result and returned structure\&.
+.sp
+The <device> 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 data structure returned by the device will be decoded and displayed in one of several ways\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program interpret the returned buffer and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns id\-ns /dev/nvme0 \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format with extra details
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns id\-ns /dev/nvme0 \-o json \-v
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-id-ns.html b/Documentation/nvme-zns-id-ns.html
new file mode 100644
index 0000000..45393db
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.html
@@ -0,0 +1,854 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-id-ctrl(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-id-ctrl -
+ Send NVMe Zoned Command Set Identify Controller, return result and structure
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns id-ctrl</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]
+ [-v | --verbose]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends the zoned command set&#8217;s identify namepsace
+command and provides the result and returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the data structure returned by the device will be decoded and
+displayed in one of several ways.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program interpret the returned buffer and display the known
+fields in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns id-ns /dev/nvme0 -n 1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format with extra details
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns id-ctrl /dev/nvme0 -o json -v</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-id-ns.txt b/Documentation/nvme-zns-id-ns.txt
new file mode 100644
index 0000000..a95d975
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.txt
@@ -0,0 +1,62 @@
+nvme-zns-id-ns(1)
+=================
+
+NAME
+----
+nvme-zns-id-ns - Send NVMe Zoned Command Set Identify Controller, return
+ result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns id-ns' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [-o <fmt> | --output-format=<fmt>]
+ [-v | --verbose]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the zoned command set's identify namepsace
+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 data structure returned by the device will be decoded and
+displayed in one of several ways.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme zns id-ns /dev/nvme0 -n 1
+------------
++
+
+* Show the output in json format with extra details
++
+------------
+# nvme zns id-ns /dev/nvme0 -o json -v
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-offline-zone.1 b/Documentation/nvme-zns-offline-zone.1
new file mode 100644
index 0000000..9d2d083
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-offline-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-OFFLINE\-" "1" "10/20/2020" "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-zns-offline-zone \- Offlines one or all zones
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns offline\-zone nvme zns id\-ctrl\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "Offline Zone" action\&. This will transition the zone to the offlined state\&.
+.sp
+The <device> 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
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to offline\&.
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Offline all zones on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns offline\-zone /dev/nvme0 \-a \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-offline-zone.html b/Documentation/nvme-zns-offline-zone.html
new file mode 100644
index 0000000..ae2da7f
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.html
@@ -0,0 +1,841 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-offline-zone(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-offline-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-offline-zone -
+ Offlines one or all zones
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns offline-zone nvme zns id-ctrl</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--select-all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+"Offline Zone" action. This will transition the zone to the offlined state.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to offline.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Offline all zones on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns offline-zone /dev/nvme0 -a -n 1</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-offline-zone.txt b/Documentation/nvme-zns-offline-zone.txt
new file mode 100644
index 0000000..0a35235
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.txt
@@ -0,0 +1,49 @@
+nvme-zns-offline-zone(1)
+========================
+
+NAME
+----
+nvme-zns-offline-zone - Offlines one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns offline-zone nvme zns id-ctrl' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"Offline Zone" action. This will transition the zone to the offlined state.
+
+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
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to offline.
+
+-a::
+--select-all::
+ Select all zones for this action
+
+EXAMPLES
+--------
+* Offline all zones on namespace 1:
++
+------------
+# nvme zns offline-zone /dev/nvme0 -a -n 1
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-open-zone.1 b/Documentation/nvme-zns-open-zone.1
new file mode 100644
index 0000000..8ea78f2
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-open-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-OPEN\-ZON" "1" "10/20/2020" "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-zns-open-zone \- Opens one or all zones
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns open\-zone nvme zns id\-ctrl\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "Open Zone" action\&. This will transition the zone to the opened state\&.
+.sp
+The <device> 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
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to open\&.
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Open the first zone on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns open\-zone /dev/nvme0 \-n 1 \-s 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-open-zone.html b/Documentation/nvme-zns-open-zone.html
new file mode 100644
index 0000000..5a648b2
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.html
@@ -0,0 +1,841 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-open-zone(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-open-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-open-zone -
+ Opens one or all zones
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns open-zone nvme zns id-ctrl</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--select-all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+"Open Zone" action. This will transition the zone to the opened state.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to open.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Open the first zone on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns open-zone /dev/nvme0 -n 1 -s 0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-open-zone.txt b/Documentation/nvme-zns-open-zone.txt
new file mode 100644
index 0000000..23acf1c
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.txt
@@ -0,0 +1,49 @@
+nvme-zns-open-zone(1)
+======================
+
+NAME
+----
+nvme-zns-open-zone - Opens one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns open-zone nvme zns id-ctrl' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"Open Zone" action. This will transition the zone to the opened state.
+
+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
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to open.
+
+-a::
+--select-all::
+ Select all zones for this action
+
+EXAMPLES
+--------
+* Open the first zone on namespace 1:
++
+------------
+# nvme zns open-zone /dev/nvme0 -n 1 -s 0
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-report-zones.1 b/Documentation/nvme-zns-report-zones.1
new file mode 100644
index 0000000..a1ec86e
--- /dev/null
+++ b/Documentation/nvme-zns-report-zones.1
@@ -0,0 +1,198 @@
+'\" t
+.\" Title: nvme-zns-report-zones
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-REPORT\-Z" "1" "10/20/2020" "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-zns-report-zones \- Retrieve and display the Report Zones data structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns report\-zones\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<IONUM> | \-s <IONUM>]
+ [\-\-descs=<NUM> | \-d <NUM>]
+ [\-\-state=<NUM> | \-S <NUM>]
+ [\-\-extended | \-e]
+ [\-\-partial | \-p]
+ [\-\-verbose | \-v]
+ [\-\-output\-format=<FMT> | \-o <FMT>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Zone Management Receive command with the Zone Receive Action set to either Report Zones or Extended Report Zones, depending on the \fIextended\fR option\&.
+.sp
+The <device> 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 data structure returned by the device will be decoded and displayed in one of several ways\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to begin the report
+.RE
+.PP
+\-d <NUM>, \-\-descs=<NUM>
+.RS 4
+The number of descriptors to request in the report\&.
+.RE
+.PP
+\-S <NUM>, \-\-state=<NUM>
+.RS 4
+The state of zones to request in the report\&. Known values include:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+List all zones (default)
+T}
+T{
+1
+T}:T{
+Empty State
+T}
+T{
+2
+T}:T{
+Implicitly Opened State
+T}
+T{
+3
+T}:T{
+Explicitly Opened State
+T}
+T{
+4
+T}:T{
+Closed State
+T}
+T{
+5
+T}:T{
+Full State
+T}
+T{
+6
+T}:T{
+Read Only State
+T}
+T{
+7
+T}:T{
+Offline State
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-e, \-\-extended
+.RS 4
+Request to use the Extended Report Zones option\&. The extended data is not decoded\&.
+.RE
+.PP
+\-p, \-\-partial
+.RS 4
+If set, the device will return the number of zones that match the state rather than the number of zones returned in the report\&.
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program interpret the report for 16 zones, and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns report\-zones /dev/nvme0 \-n 1 \-d 16
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the output in json format with extra details
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns report\-zones /dev/nvme0 \-n 1 \-d 16 \-o json
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-report-zones.html b/Documentation/nvme-zns-report-zones.html
new file mode 100644
index 0000000..fbdde5c
--- /dev/null
+++ b/Documentation/nvme-zns-report-zones.html
@@ -0,0 +1,964 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-report-zones(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-report-zones(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-report-zones -
+ Retrieve and display the Report Zones data structure
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns report-zones</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;IONUM&gt; | -s &lt;IONUM&gt;]
+ [--descs=&lt;NUM&gt; | -d &lt;NUM&gt;]
+ [--state=&lt;NUM&gt; | -S &lt;NUM&gt;]
+ [--extended | -e]
+ [--partial | -p]
+ [--verbose | -v]
+ [--output-format=&lt;FMT&gt; | -o &lt;FMT&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends the Zone Management Receive command with the
+Zone Receive Action set to either Report Zones or Extended Report Zones,
+depending on the <em>extended</em> option.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success, the data structure returned by the device will be decoded and
+displayed in one of several ways.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to begin the report
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--descs=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The number of descriptors to request in the report.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--state=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The state of zones to request in the report. Known values include:
+</p>
+<div class="tableblock">
+<table rules="all"
+width="100%"
+frame="border"
+cellspacing="0" cellpadding="4">
+<col width="50%" />
+<col width="50%" />
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table">Value</p></td>
+<td align="left" valign="top"><p class="table">Definition</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">List all zones (default)</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Empty State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Implicitly Opened State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Explicitly Opened State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4</p></td>
+<td align="left" valign="top"><p class="table">Closed State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">5</p></td>
+<td align="left" valign="top"><p class="table">Full State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">6</p></td>
+<td align="left" valign="top"><p class="table">Read Only State</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">7</p></td>
+<td align="left" valign="top"><p class="table">Offline State</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-e
+</dt>
+<dt class="hdlist1">
+--extended
+</dt>
+<dd>
+<p>
+ Request to use the Extended Report Zones option. The extended data is
+ not decoded.
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--partial
+</dt>
+<dd>
+<p>
+ If set, the device will return the number of zones that match the state
+ rather than the number of zones returned in the report.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program interpret the report for 16 zones, and display the known
+fields in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns report-zones /dev/nvme0 -n 1 -d 16</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the output in json format with extra details
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns report-zones /dev/nvme0 -n 1 -d 16 -o json</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-report-zones.txt b/Documentation/nvme-zns-report-zones.txt
new file mode 100644
index 0000000..35d5eda
--- /dev/null
+++ b/Documentation/nvme-zns-report-zones.txt
@@ -0,0 +1,102 @@
+nvme-zns-report-zones(1)
+========================
+
+NAME
+----
+nvme-zns-report-zones - Retrieve and display the Report Zones data structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns report-zones' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<IONUM> | -s <IONUM>]
+ [--descs=<NUM> | -d <NUM>]
+ [--state=<NUM> | -S <NUM>]
+ [--extended | -e]
+ [--partial | -p]
+ [--verbose | -v]
+ [--output-format=<FMT> | -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Zone Management Receive command with the
+Zone Receive Action set to either Report Zones or Extended Report Zones,
+depending on the 'extended' option.
+
+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 data structure returned by the device will be decoded and
+displayed in one of several ways.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to begin the report
+
+-d <NUM>::
+--descs=<NUM>::
+ The number of descriptors to request in the report.
+
+-S <NUM>::
+--state=<NUM>::
+ The state of zones to request in the report. Known values include:
++
+[]
+|=================
+|Value|Definition
+|0|List all zones (default)
+|1|Empty State
+|2|Implicitly Opened State
+|3|Explicitly Opened State
+|4|Closed State
+|5|Full State
+|6|Read Only State
+|7|Offline State
+|=================
+
+-e::
+--extended::
+ Request to use the Extended Report Zones option. The extended data is
+ not decoded.
+
+-p::
+--partial::
+ If set, the device will return the number of zones that match the state
+ rather than the number of zones returned in the report.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the report for 16 zones, and display the known
+fields in a human readable format:
++
+------------
+# nvme zns report-zones /dev/nvme0 -n 1 -d 16
+------------
++
+
+* Show the output in json format with extra details
++
+------------
+# nvme zns report-zones /dev/nvme0 -n 1 -d 16 -o json
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-reset-zone.1 b/Documentation/nvme-zns-reset-zone.1
new file mode 100644
index 0000000..b02d042
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-reset-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-RESET\-ZO" "1" "10/20/2020" "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-zns-reset-zone \- Resets one or all zones
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns reset\-zone\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "Reset Zone" action\&. This will transition the zone to the empty state, setting the write pointer for each zone back to the beginning on success\&.
+.sp
+The <device> 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
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to reset\&.
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Reset the first zone on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns reset\-zone /dev/nvme0 \-n 1 \-s 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-reset-zone.html b/Documentation/nvme-zns-reset-zone.html
new file mode 100644
index 0000000..46545b2
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.html
@@ -0,0 +1,842 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-reset-zone(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-reset-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-reset-zone -
+ Resets one or all zones
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns reset-zone</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--select-all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+"Reset Zone" action. This will transition the zone to the empty state, setting
+the write pointer for each zone back to the beginning on success.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to reset.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Reset the first zone on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns reset-zone /dev/nvme0 -n 1 -s 0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-reset-zone.txt b/Documentation/nvme-zns-reset-zone.txt
new file mode 100644
index 0000000..a04fd66
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.txt
@@ -0,0 +1,50 @@
+nvme-zns-reset-zone(1)
+======================
+
+NAME
+----
+nvme-zns-reset-zone - Resets one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns reset-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"Reset Zone" action. This will transition the zone to the empty state, setting
+the write pointer for each zone back to the beginning on success.
+
+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
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to reset.
+
+-a::
+--select-all::
+ Select all zones for this action
+
+EXAMPLES
+--------
+* Reset the first zone on namespace 1:
++
+------------
+# nvme zns reset-zone /dev/nvme0 -n 1 -s 0
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-set-zone-desc.1 b/Documentation/nvme-zns-set-zone-desc.1
new file mode 100644
index 0000000..a33b06a
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.1
@@ -0,0 +1,82 @@
+'\" t
+.\" Title: nvme-zns-set-zone-desc
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-SET\-ZONE" "1" "10/20/2020" "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-zns-set-zone-desc \- Set extended descriptor data for a zone
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns setzone\-desc\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<IONUM>, \-s <IONUM>]
+ [\-data=<FILE>, \-d <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the Set Zone Descriptor Extenions action\&. The input will default to stdin\&. Alternatively, the data may come from a file that can be specified\&. The data length will automatically be calculated from the zns identify namesapce\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to manage send\&.
+.RE
+.PP
+\-d <FILE, \-data=<FILE>
+.RS 4
+Optional file for data (default stdin)
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Write "hello world" into the zone descriptor for namespace 1\(cqs first zone (requires device supports a large enough zone extended data)
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# echo "hello world" | nvme zns set\-zone\-desc /dev/nvme0 \-n 1 \-s 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-set-zone-desc.html b/Documentation/nvme-zns-set-zone-desc.html
new file mode 100644
index 0000000..b69be1f
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.html
@@ -0,0 +1,842 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-set-zone-desc(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-set-zone-desc(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-set-zone-desc -
+ Set extended descriptor data for a zone
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns setzone-desc</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;IONUM&gt;, -s &lt;IONUM&gt;]
+ [-data=&lt;FILE&gt;, -d &lt;FILE&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+Set Zone Descriptor Extenions action. The input will default to stdin.
+Alternatively, the data may come from a file that can be specified. The data
+length will automatically be calculated from the zns identify namesapce.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to manage send.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;FILE
+</dt>
+<dt class="hdlist1">
+-data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Optional file for data (default stdin)
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Write "hello world" into the zone descriptor for namespace 1&#8217;s first zone
+ (requires device supports a large enough zone extended data)
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># echo "hello world" | nvme zns set-zone-desc /dev/nvme0 -n 1 -s 0</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-set-zone-desc.txt b/Documentation/nvme-zns-set-zone-desc.txt
new file mode 100644
index 0000000..5df3ecb
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.txt
@@ -0,0 +1,50 @@
+nvme-zns-set-zone-desc(1)
+=========================
+
+NAME
+----
+nvme-zns-set-zone-desc - Set extended descriptor data for a zone
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns setzone-desc' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<IONUM>, -s <IONUM>]
+ [-data=<FILE>, -d <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+Set Zone Descriptor Extenions action. The input will default to stdin.
+Alternatively, the data may come from a file that can be specified. The data
+length will automatically be calculated from the zns identify namesapce.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to manage send.
+
+-d <FILE::
+-data=<FILE>::
+ Optional file for data (default stdin)
+
+
+EXAMPLES
+--------
+* Write "hello world" into the zone descriptor for namespace 1's first zone
+ (requires device supports a large enough zone extended data)
++
+------------
+# echo "hello world" | nvme zns set-zone-desc /dev/nvme0 -n 1 -s 0
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-zone-append.1 b/Documentation/nvme-zns-zone-append.1
new file mode 100644
index 0000000..494e265
--- /dev/null
+++ b/Documentation/nvme-zns-zone-append.1
@@ -0,0 +1,133 @@
+'\" t
+.\" Title: nvme-zns-zone-append
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-APP" "1" "10/20/2020" "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-zns-zone-append \- Send an NVMe write command, provide results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-zns\-zone\-append\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-zslba=<IONUM> | \-s <IONUM>]
+ [\-\-data\-size=<IONUM> | \-z <IONUM>]
+ [\-\-metadata\-size=<IONUM> | \-y <IONUM>]
+ [\-\-data=<FILE> | \-d <FILE>]
+ [\-\-metadata=<FILE> | \-M <FILE>]
+ [\-\-limited\-retry | \-l]
+ [\-\-force\-unit\-access | \-f]
+ [\-\-ref\-tag=<NUM> | \-r <NUM>]
+ [\-\-app\-tag\-mask=<NUM> | \-m <NUM>]
+ [\-\-app\-tag=<NUM> | \-a <NUM>]
+ [\-\-prinfo=<NUM> | \-p <NUM>]
+.fi
+.SH "DESCRIPTION"
+.sp
+The zone append command writes the logical blocks specified by the command to the medium from the data data buffer provided\&. Will use stdin by default if you don\(cqt provide a file\&.
+.sp
+On sucess, the program will report the LBA that was assigned to the data for the append operation\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <IONUM>, \-\-zslba=<IONUM>, \-z <IONUM>, \-\-data\-size=<IONUM>
+.RS 4
+Size of data, in bytes\&.
+.RE
+.PP
+\-y <IONUM>, \-\-metadata\-size=<IONUM>
+.RS 4
+Size of metadata in bytes\&.
+.RE
+.PP
+\-d <FILE>, \-\-data=<FILE>
+.RS 4
+Data file providing the data to write\&. If none provided, contents are sent from STDIN\&.
+.RE
+.PP
+\-M <FILE>, \-\-metadata=<FILE>
+.RS 4
+Metadata file, if necessary\&.
+.RE
+.PP
+\-l, \-\-limited\-retry
+.RS 4
+Sets the limited retry flag\&.
+.RE
+.PP
+\-f, \-\-force\-unit\-access
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-r <NUM>, \-\-ref\-tag=<NUM>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-m <NUM>, \-\-app\-tag\-mask=<NUM>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-a <NUM>, \-\-app\-tag=<NUM>
+.RS 4
+Optional application tag when used with protection information\&.
+.RE
+.PP
+\-p <NUM>, \-\-prinfo=<NUM>
+.RS 4
+Protection Information field definition\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Append the data "hello world" into 4k worth of blocks into the zone starting at block 0 for namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# echo "hello world" | nvme zns zone\-append /dev/nvme0 \-n 1 \-s 0 \-z 4k
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-zns-zone-append.html b/Documentation/nvme-zns-zone-append.html
new file mode 100644
index 0000000..5acc06a
--- /dev/null
+++ b/Documentation/nvme-zns-zone-append.html
@@ -0,0 +1,947 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-zone-append(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-zone-append(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-zone-append -
+ Send an NVMe write command, provide results
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme-zns-zone-append</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--zslba=&lt;IONUM&gt; | -s &lt;IONUM&gt;]
+ [--data-size=&lt;IONUM&gt; | -z &lt;IONUM&gt;]
+ [--metadata-size=&lt;IONUM&gt; | -y &lt;IONUM&gt;]
+ [--data=&lt;FILE&gt; | -d &lt;FILE&gt;]
+ [--metadata=&lt;FILE&gt; | -M &lt;FILE&gt;]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--ref-tag=&lt;NUM&gt; | -r &lt;NUM&gt;]
+ [--app-tag-mask=&lt;NUM&gt; | -m &lt;NUM&gt;]
+ [--app-tag=&lt;NUM&gt; | -a &lt;NUM&gt;]
+ [--prinfo=&lt;NUM&gt; | -p &lt;NUM&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The zone append command writes the logical blocks specified by the command to
+the medium from the data data buffer provided. Will use stdin by default
+if you don&#8217;t provide a file.</p></div>
+<div class="paragraph"><p>On sucess, the program will report the LBA that was assigned to the data for
+the append operation.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;IONUM&gt;
+</dt>
+<dt class="hdlist1">
+--zslba=&lt;IONUM&gt;
+</dt>
+<dt class="hdlist1">
+-z &lt;IONUM&gt;
+</dt>
+<dt class="hdlist1">
+--data-size=&lt;IONUM&gt;
+</dt>
+<dd>
+<p>
+ Size of data, in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-y &lt;IONUM&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-size=&lt;IONUM&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Data file providing the data to write. If none provided, contents are
+ sent from STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--metadata=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Metadata file, if necessary.
+</p>
+</dd>
+<dt class="hdlist1">
+-l
+</dt>
+<dt class="hdlist1">
+--limited-retry
+</dt>
+<dd>
+<p>
+ Sets the limited retry flag.
+</p>
+</dd>
+<dt class="hdlist1">
+-f
+</dt>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dd>
+<p>
+ Set the force-unit access flag.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field definition.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Append the data "hello world" into 4k worth of blocks into the zone starting
+ at block 0 for namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># echo "hello world" | nvme zns zone-append /dev/nvme0 -n 1 -s 0 -z 4k</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-zone-append.txt b/Documentation/nvme-zns-zone-append.txt
new file mode 100644
index 0000000..37242a5
--- /dev/null
+++ b/Documentation/nvme-zns-zone-append.txt
@@ -0,0 +1,96 @@
+nvme-zns-zone-append(1)
+=======================
+
+NAME
+----
+nvme-zns-zone-append - Send an NVMe write command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-zns-zone-append' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--zslba=<IONUM> | -s <IONUM>]
+ [--data-size=<IONUM> | -z <IONUM>]
+ [--metadata-size=<IONUM> | -y <IONUM>]
+ [--data=<FILE> | -d <FILE>]
+ [--metadata=<FILE> | -M <FILE>]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--ref-tag=<NUM> | -r <NUM>]
+ [--app-tag-mask=<NUM> | -m <NUM>]
+ [--app-tag=<NUM> | -a <NUM>]
+ [--prinfo=<NUM> | -p <NUM>]
+
+DESCRIPTION
+-----------
+The zone append command writes the logical blocks specified by the command to
+the medium from the data data buffer provided. Will use stdin by default
+if you don't provide a file.
+
+On sucess, the program will report the LBA that was assigned to the data for
+the append operation.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <IONUM>::
+--zslba=<IONUM>::
+
+-z <IONUM>::
+--data-size=<IONUM>::
+ Size of data, in bytes.
+
+-y <IONUM>::
+--metadata-size=<IONUM>::
+ Size of metadata in bytes.
+
+-d <FILE>::
+--data=<FILE>::
+ Data file providing the data to write. If none provided, contents are
+ sent from STDIN.
+
+-M <FILE>::
+--metadata=<FILE>::
+ Metadata file, if necessary.
+
+-l::
+--limited-retry::
+ Sets the limited retry flag.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-r <NUM>::
+--ref-tag=<NUM>::
+ Optional reftag when used with protection information.
+
+-m <NUM>::
+--app-tag-mask=<NUM>::
+ Optional application tag mask when used with protection information.
+
+-a <NUM>::
+--app-tag=<NUM>::
+ Optional application tag when used with protection information.
+
+-p <NUM>::
+--prinfo=<NUM>::
+ Protection Information field definition.
+
+EXAMPLES
+--------
+* Append the data "hello world" into 4k worth of blocks into the zone starting
+ at block 0 for namespace 1:
++
+------------
+# echo "hello world" | nvme zns zone-append /dev/nvme0 -n 1 -s 0 -z 4k
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-zns-zone-mgmt-recv.1 b/Documentation/nvme-zns-zone-mgmt-recv.1
new file mode 100644
index 0000000..26feb54
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.1
@@ -0,0 +1,121 @@
+'\" t
+.\" Title: nvme-zns-zone-mgmt-recv
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-MGM" "1" "10/20/2020" "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-zns-zone-mgmt-recv \- Zone Management Receive command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns zone\-mgmt\-recv\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-data\-len=<IONUM>, \-l <IONUM>]
+ [\-\-zra=<NUM>, \-z <NUM>]
+ [\-\-zrasf=<NUM>, \-a <NUM>]
+ [\-\-zra\-spec\-feat, \-f]
+ [\-\-output\-format=<FMT>, \-o <FMT>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Receive command with the requested receive action and additional action specific parameters\&. This is the generic interface provided for forward compatibility as new actions are created that this program isn\(cqt aware of at the time of its development\&. As such, this is a generic command that does not do any additional decoding for specific types of data received\&. This will only report the data as a hex dump, or binary\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to manage receive\&.
+.RE
+.sp
+\-\-data\-len=<NUM> \-l <NUM> Received data buffer length
+.PP
+\-z <NUM>, \-\-zra=<NUM>
+.RS 4
+Zone Receive Action
+.RE
+.sp
+\-a <NUM> \-\-zrasf=<NUM> Zone Receive Action Specific field
+.PP
+\-f, \-\-zra\-spec\-feat
+.RS 4
+Enable Zone Receive Action Specific features
+.RE
+.PP
+\-o <FMT>, \-\-output\-format=<FMT>
+.RS 4
+Output format: normal|json|binary
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Hex dump of a report all zones
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns zone\-mgmt\-recv /dev/nvme0 \-n 1 \-s 0 \-z 0 \-a 0 \-l 4k
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Binary dump of a report all zones
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns zone\-mgmt\-recv /dev/nvme0 \-n 1 \-s 0 \-z 0 \-a 0 \-o \-l 4k binary > report\&.out
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-zone-mgmt-recv.html b/Documentation/nvme-zns-zone-mgmt-recv.html
new file mode 100644
index 0000000..74d6a8d
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.html
@@ -0,0 +1,889 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-zone-mgmt-recv(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-zone-mgmt-recv(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-zone-mgmt-recv -
+ Zone Management Receive command
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns zone-mgmt-recv</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;]
+ [--data-len=&lt;IONUM&gt;, -l &lt;IONUM&gt;]
+ [--zra=&lt;NUM&gt;, -z &lt;NUM&gt;]
+ [--zrasf=&lt;NUM&gt;, -a &lt;NUM&gt;]
+ [--zra-spec-feat, -f]
+ [--output-format=&lt;FMT&gt;, -o &lt;FMT&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Receive command with the
+requested receive action and additional action specific parameters. This is the
+generic interface provided for forward compatibility as new actions are created
+that this program isn&#8217;t aware of at the time of its development. As such, this
+is a generic command that does not do any additional decoding for specific
+types of data received. This will only report the data as a hex dump, or
+binary.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to manage receive.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>--data-len=&lt;NUM&gt;
+-l &lt;NUM&gt;
+ Received data buffer length</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-z &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--zra=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Zone Receive Action
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>-a &lt;NUM&gt;
+--zrasf=&lt;NUM&gt;
+ Zone Receive Action Specific field</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-f
+</dt>
+<dt class="hdlist1">
+--zra-spec-feat
+</dt>
+<dd>
+<p>
+ Enable Zone Receive Action Specific features
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;FMT&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;FMT&gt;
+</dt>
+<dd>
+<p>
+ Output format: normal|json|binary
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Hex dump of a report all zones
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns zone-mgmt-recv /dev/nvme0 -n 1 -s 0 -z 0 -a 0 -l 4k</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Binary dump of a report all zones
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns zone-mgmt-recv /dev/nvme0 -n 1 -s 0 -z 0 -a 0 -o -l 4k binary &gt; report.out</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-zone-mgmt-recv.txt b/Documentation/nvme-zns-zone-mgmt-recv.txt
new file mode 100644
index 0000000..07cd98e
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.txt
@@ -0,0 +1,78 @@
+nvme-zns-zone-mgmt-recv(1)
+==========================
+
+NAME
+----
+nvme-zns-zone-mgmt-recv - Zone Management Receive command
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns zone-mgmt-recv' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--data-len=<IONUM>, -l <IONUM>]
+ [--zra=<NUM>, -z <NUM>]
+ [--zrasf=<NUM>, -a <NUM>]
+ [--zra-spec-feat, -f]
+ [--output-format=<FMT>, -o <FMT>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Receive command with the
+requested receive action and additional action specific parameters. This is the
+generic interface provided for forward compatibility as new actions are created
+that this program isn't aware of at the time of its development. As such, this
+is a generic command that does not do any additional decoding for specific
+types of data received. This will only report the data as a hex dump, or
+binary.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to manage receive.
+
+--data-len=<NUM>
+-l <NUM>
+ Received data buffer length
+
+-z <NUM>::
+--zra=<NUM>::
+ Zone Receive Action
+
+-a <NUM>
+--zrasf=<NUM>
+ Zone Receive Action Specific field
+
+-f::
+--zra-spec-feat::
+ Enable Zone Receive Action Specific features
+
+-o <FMT>::
+--output-format=<FMT>::
+ Output format: normal|json|binary
+
+EXAMPLES
+--------
+* Hex dump of a report all zones
++
+------------
+# nvme zns zone-mgmt-recv /dev/nvme0 -n 1 -s 0 -z 0 -a 0 -l 4k
+------------
++
+
+* Binary dump of a report all zones
++
+------------
+# nvme zns zone-mgmt-recv /dev/nvme0 -n 1 -s 0 -z 0 -a 0 -o -l 4k binary > report.out
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-zns-zone-mgmt-send.1 b/Documentation/nvme-zns-zone-mgmt-send.1
new file mode 100644
index 0000000..f74d8a3
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.1
@@ -0,0 +1,126 @@
+'\" t
+.\" Title: nvme-zns-zone-mgmt-send
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 10/20/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-MGM" "1" "10/20/2020" "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-zns-zone-mgmt-send \- Zone Management Send command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns zone\-mgmt\-send\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<IONUM>, \-s <IONUM>]
+ [\-\-select\-all, \-a]
+ [\-\-zsa=<NUM>, \-z <NUM>]
+ [\-\-data\-len=<IONUM>, \-l <IONUM>]
+ [\-data=<FILE>, \-d <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the requested send action\&. If the send requires additional data, you may specify the data length\&. If data is required, the input will default to stdin\&. Alternatively, the data may come from a file that can be specified\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Use the provided namespace id for the command\&. If not provided, the namespace id of the block device will be used\&. If the command is issued to a non\-block device, the parameter is required\&.
+.RE
+.PP
+\-s <lba>, \-\-start\-lba=<lba>
+.RS 4
+The starting LBA of the zone to manage send\&.
+.RE
+.PP
+\-l <NUM>, \-\-data\-len=<NUM>
+.RS 4
+Send data buffer length
+.RE
+.PP
+\-\-select\-all, \-a
+.RS 4
+Send command to all zones
+.RE
+.PP
+\-z <NUM>, \-\-zsa=<NUM>
+.RS 4
+Zone send action\&.
+.RE
+.PP
+\-l <IONUM>, \-\-data\-len=<IONUM>
+.RS 4
+Buffer length if data required
+.RE
+.PP
+\-d <FILE, \-data=<FILE>
+.RS 4
+Optional file for data (default stdin)
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Send a zone management command with action set to 1 (close zone) to namespace 1\(cqs first zone:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns zone\-mgmt\-send /dev/nvme0 \-n 1 \-s 0 \-z 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Write "hello world" into the zone descriptor for namespace 1\(cqs first zone (requires device supports a large enough zone extended data)
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# echo "hello world" | nvme zns zone\-mgmt\-send /dev/nvme0 \-n 1 \-s 0 \-z 0x10
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-zone-mgmt-send.html b/Documentation/nvme-zns-zone-mgmt-send.html
new file mode 100644
index 0000000..6305707
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.html
@@ -0,0 +1,899 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-zns-zone-mgmt-send(1)</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+pre {
+ white-space: pre-wrap;
+}
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; vertical-align: text-bottom; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-zns-zone-mgmt-send(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-zone-mgmt-send -
+ Zone Management Send command
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><em>nvme zns zone-mgmt-send</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;IONUM&gt;, -s &lt;IONUM&gt;]
+ [--select-all, -a]
+ [--zsa=&lt;NUM&gt;, -z &lt;NUM&gt;]
+ [--data-len=&lt;IONUM&gt;, -l &lt;IONUM&gt;]
+ [-data=&lt;FILE&gt;, -d &lt;FILE&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, issues the Zone Management Send command with the
+requested send action. If the send requires additional data, you may specify
+the data length. If data is required, the input will default to stdin.
+Alternatively, the data may come from a file that can be specified.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The starting LBA of the zone to manage send.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Send data buffer length
+</p>
+</dd>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dt class="hdlist1">
+-a
+</dt>
+<dd>
+<p>
+ Send command to all zones
+</p>
+</dd>
+<dt class="hdlist1">
+-z &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--zsa=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Zone send action.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;IONUM&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;IONUM&gt;
+</dt>
+<dd>
+<p>
+ Buffer length if data required
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;FILE
+</dt>
+<dt class="hdlist1">
+-data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Optional file for data (default stdin)
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Send a zone management command with action set to 1 (close zone) to namespace
+ 1&#8217;s first zone:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns zone-mgmt-send /dev/nvme0 -n 1 -s 0 -z 1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Write "hello world" into the zone descriptor for namespace 1&#8217;s first zone
+ (requires device supports a large enough zone extended data)
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># echo "hello world" | nvme zns zone-mgmt-send /dev/nvme0 -n 1 -s 0 -z 0x10</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of nvme-cli</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2020-06-16 08:05:24 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-zone-mgmt-send.txt b/Documentation/nvme-zns-zone-mgmt-send.txt
new file mode 100644
index 0000000..e33b9a5
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.txt
@@ -0,0 +1,77 @@
+nvme-zns-zone-mgmt-send(1)
+==========================
+
+NAME
+----
+nvme-zns-zone-mgmt-send - Zone Management Send command
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns zone-mgmt-send' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<IONUM>, -s <IONUM>]
+ [--select-all, -a]
+ [--zsa=<NUM>, -z <NUM>]
+ [--data-len=<IONUM>, -l <IONUM>]
+ [-data=<FILE>, -d <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+requested send action. If the send requires additional data, you may specify
+the data length. If data is required, the input will default to stdin.
+Alternatively, the data may come from a file that can be specified.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-s <lba>::
+--start-lba=<lba>::
+ The starting LBA of the zone to manage send.
+
+-l <NUM>::
+--data-len=<NUM>::
+ Send data buffer length
+
+--select-all::
+-a::
+ Send command to all zones
+
+-z <NUM>::
+--zsa=<NUM>::
+ Zone send action.
+
+-l <IONUM>::
+--data-len=<IONUM>::
+ Buffer length if data required
+
+-d <FILE::
+-data=<FILE>::
+ Optional file for data (default stdin)
+
+
+EXAMPLES
+--------
+* Send a zone management command with action set to 1 (close zone) to namespace
+ 1's first zone:
++
+------------
+# nvme zns zone-mgmt-send /dev/nvme0 -n 1 -s 0 -z 1
+------------
++
+
+* Write "hello world" into the zone descriptor for namespace 1's first zone
+ (requires device supports a large enough zone extended data)
++
+------------
+# echo "hello world" | nvme zns zone-mgmt-send /dev/nvme0 -n 1 -s 0 -z 0x10
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme.1 b/Documentation/nvme.1
index 55dbfc8..295f5d1 100644
--- a/Documentation/nvme.1
+++ b/Documentation/nvme.1
@@ -1,13 +1,13 @@
'\" t
.\" Title: nvme
.\" Author: [see the "Authors" section]
-.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 04/24/2020
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 12/01/2020
.\" Manual: NVMe Manual
.\" Source: NVMe
.\" Language: English
.\"
-.TH "NVME" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.TH "NVME" "1" "12/01/2020" "NVMe" "NVMe Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -85,7 +85,12 @@ Format namespace(s)
.PP
\fBnvme-fw-activate\fR(1)
.RS 4
-F/W Activate
+F/W Activate (in old version < 1\&.2)
+.RE
+.PP
+\fBnvme-fw-commit\fR(1)
+.RS 4
+F/W Commit (in > 1\&.2)
.RE
.PP
\fBnvme-fw-download\fR(1)
@@ -113,11 +118,21 @@ Generic Get Log
Telemetry Host\-Initiated Log
.RE
.PP
+\fBnvme-changed-ns-list-log\fR(1)
+.RS 4
+Retrieve Changed Namespace List Log
+.RE
+.PP
\fBnvme-smart-log\fR(1)
.RS 4
Retrieve Smart Log
.RE
.PP
+\fBnvme-ana-log\fR(1)
+.RS 4
+Retreive ANA(Asymmetric Namespace Access) Log
+.RE
+.PP
\fBnvme-endurance-log\fR(1)
.RS 4
Retrieve endurance Log
@@ -128,6 +143,11 @@ Retrieve endurance Log
Retrieve effects Log
.RE
.PP
+\fBnvme-self-test-log\fR(1)
+.RS 4
+Retrieve Device Self\-test Log
+.RE
+.PP
\fBnvme-get-ns-id\fR(1)
.RS 4
Retrieve namespace identifier
@@ -148,6 +168,16 @@ Identify Controller
Identify Namespace
.RE
.PP
+\fBnvme-id-nvmset\fR(1)
+.RS 4
+Identify NVM Set List
+.RE
+.PP
+\fBnvme-id-iocs\fR(1)
+.RS 4
+Identify I/O Command Set
+.RE
+.PP
\fBnvme-create-ns\fR(1)
.RS 4
Create a new namespace
@@ -193,6 +223,21 @@ List all nvme controllers
List controller in NVMe subsystem
.RE
.PP
+\fBnvme-list-subsys\fR(1)
+.RS 4
+List NVMe subsystems
+.RE
+.PP
+\fBnvme-reset\fR(1)
+.RS 4
+Reset a NVMe controller
+.RE
+.PP
+\fBnvme-device-self-test\fR(1)
+.RS 4
+Issue Device Self\-test Command
+.RE
+.PP
\fBnvme-read\fR(1)
.RS 4
Issue IO Read Command
@@ -243,6 +288,16 @@ Security Receive
Security Send
.RE
.PP
+\fBnvme-dsm\fR(1)
+.RS 4
+Issue Data Set Management Command
+.RE
+.PP
+\fBnvme-copy\fR(1)
+.RS 4
+Issue Simple Copy Command
+.RE
+.PP
\fBnvme-set-feature\fR(1)
.RS 4
Set Feature
diff --git a/Documentation/nvme.html b/Documentation/nvme.html
index 5f9856c..6153179 100644
--- a/Documentation/nvme.html
+++ b/Documentation/nvme.html
@@ -839,7 +839,15 @@ available, run "nvme help".</p></div>
</dt>
<dd>
<p>
- F/W Activate
+ F/W Activate (in old version &lt; 1.2)
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-fw-commit.html">nvme-fw-commit(1)</a>
+</dt>
+<dd>
+<p>
+ F/W Commit (in &gt; 1.2)
</p>
</dd>
<dt class="hdlist1">
@@ -883,6 +891,14 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-changed-ns-list-log.html">nvme-changed-ns-list-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Changed Namespace List Log
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-smart-log.html">nvme-smart-log(1)</a>
</dt>
<dd>
@@ -891,6 +907,14 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-ana-log.html">nvme-ana-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retreive ANA(Asymmetric Namespace Access) Log
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-endurance-log.html">nvme-endurance-log(1)</a>
</dt>
<dd>
@@ -907,6 +931,14 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-self-test-log.html">nvme-self-test-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Device Self-test Log
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-get-ns-id.html">nvme-get-ns-id(1)</a>
</dt>
<dd>
@@ -939,6 +971,22 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-id-nvmset.html">nvme-id-nvmset(1)</a>
+</dt>
+<dd>
+<p>
+ Identify NVM Set List
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-id-iocs.html">nvme-id-iocs(1)</a>
+</dt>
+<dd>
+<p>
+ Identify I/O Command Set
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-create-ns.html">nvme-create-ns(1)</a>
</dt>
<dd>
@@ -1011,6 +1059,30 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-list-subsys.html">nvme-list-subsys(1)</a>
+</dt>
+<dd>
+<p>
+ List NVMe subsystems
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-reset.html">nvme-reset(1)</a>
+</dt>
+<dd>
+<p>
+ Reset a NVMe controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-device-self-test.html">nvme-device-self-test(1)</a>
+</dt>
+<dd>
+<p>
+ Issue Device Self-test Command
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-read.html">nvme-read(1)</a>
</dt>
<dd>
@@ -1091,6 +1163,22 @@ available, run "nvme help".</p></div>
</p>
</dd>
<dt class="hdlist1">
+<a href="nvme-dsm.html">nvme-dsm(1)</a>
+</dt>
+<dd>
+<p>
+ Issue Data Set Management Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-copy.html">nvme-copy(1)</a>
+</dt>
+<dd>
+<p>
+ Issue Simple Copy Command
+</p>
+</dd>
+<dt class="hdlist1">
<a href="nvme-set-feature.html">nvme-set-feature(1)</a>
</dt>
<dd>
@@ -1190,7 +1278,7 @@ NVM-Express Site</a>.</p></div>
<div id="footer">
<div id="footer-text">
Last updated
- 2020-02-15 08:33:28 JST
+ 2020-07-11 13:12:07 KST
</div>
</div>
</body>
diff --git a/Makefile b/Makefile
index 9db121c..86eb7c6 100644
--- a/Makefile
+++ b/Makefile
@@ -4,6 +4,7 @@ override CPPFLAGS += -D_GNU_SOURCE -D__CHECK_ENDIAN__
LIBUUID = $(shell $(LD) -o /dev/null -luuid >/dev/null 2>&1; echo $$?)
LIBHUGETLBFS = $(shell $(LD) -o /dev/null -lhugetlbfs >/dev/null 2>&1; echo $$?)
HAVE_SYSTEMD = $(shell pkg-config --exists libsystemd --atleast-version=242; echo $$?)
+LIBJSONC = $(shell $(LD) -o /dev/null -ljson-c >/dev/null 2>&1; echo $$?)
NVME = nvme
INSTALL ?= install
DESTDIR =
@@ -37,6 +38,11 @@ ifeq ($(HAVE_SYSTEMD),0)
override CFLAGS += -DHAVE_SYSTEMD
endif
+ifeq ($(LIBJSONC), 0)
+ override LDFLAGS += -ljson-c
+ override CFLAGS += -DLIBJSONC
+endif
+
RPMBUILD = rpmbuild
TAR = tar
RM = rm -f
@@ -58,14 +64,19 @@ override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"'
NVME_DPKG_VERSION=1~`lsb_release -sc`
-OBJS := nvme-print.o nvme-ioctl.o \
+OBJS := nvme-print.o nvme-ioctl.o nvme-rpmb.o \
nvme-lightnvm.o fabrics.o nvme-models.o plugin.o \
nvme-status.o nvme-filters.o nvme-topology.o
-UTIL_OBJS := util/argconfig.o util/suffix.o util/json.o util/parser.o
+UTIL_OBJS := util/argconfig.o util/suffix.o util/parser.o \
+ util/cleanup.o util/log.o
+ifneq ($(LIBJSONC), 0)
+override UTIL_OBJS += util/json.o
+endif
PLUGIN_OBJS := \
plugins/intel/intel-nvme.o \
+ plugins/amzn/amzn-nvme.o \
plugins/lnvm/lnvm-nvme.o \
plugins/memblaze/memblaze-nvme.o \
plugins/wdc/wdc-nvme.o \
@@ -77,15 +88,18 @@ PLUGIN_OBJS := \
plugins/seagate/seagate-nvme.o \
plugins/virtium/virtium-nvme.o \
plugins/shannon/shannon-nvme.o \
- plugins/dera/dera-nvme.o \
- plugins/scaleflux/sfx-nvme.o \
- plugins/transcend/transcend-nvme.o
+ plugins/dera/dera-nvme.o \
+ plugins/scaleflux/sfx-nvme.o \
+ plugins/transcend/transcend-nvme.o \
+ plugins/zns/zns.o \
+ plugins/nvidia/nvidia-nvme.o \
+ plugins/ymtc/ymtc-nvme.o
nvme: nvme.c nvme.h $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) NVME-VERSION-FILE
$(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) $< -o $(NVME) $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) $(LDFLAGS)
-verify-no-dep: nvme.c nvme.h $(OBJS) NVME-VERSION-FILE
- $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@ $(OBJS) $(LDFLAGS)
+verify-no-dep: nvme.c nvme.h $(OBJS) $(UTIL_OBJS) NVME-VERSION-FILE
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) $< -o $@ $(OBJS) $(UTIL_OBJS) $(LDFLAGS)
nvme.o: nvme.c nvme.h nvme-print.h nvme-ioctl.h util/argconfig.h util/suffix.h nvme-lightnvm.h fabrics.h
$(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $<
@@ -229,7 +243,10 @@ deb-light: $(NVME) pkg nvme.control.in
dpkg-deb --build nvme-$(NVME_VERSION)
rpm: dist
- $(RPMBUILD) --define '_libdir ${LIBDIR}' -ta nvme-$(NVME_VERSION).tar.gz
+ $(RPMBUILD) --define '_prefix $(DESTDIR)$(PREFIX)' \
+ --define '_libdir $(DESTDIR)${LIBDIR}' \
+ --define '_sysconfdir $(DESTDIR)$(SYSCONFDIR)' \
+ -ta nvme-$(NVME_VERSION).tar.gz
.PHONY: default doc all clean clobber install-man install-bin install
.PHONY: dist pkg dist-orig deb deb-light rpm FORCE test
diff --git a/NVME-VERSION-GEN b/NVME-VERSION-GEN
index 75b13d1..802bbd3 100755
--- a/NVME-VERSION-GEN
+++ b/NVME-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=NVME-VERSION-FILE
-DEF_VER=v1.12
+DEF_VER=v1.14
LF='
'
diff --git a/README.md b/README.md
index b4d2574..bb0219e 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,13 @@ The development version can be installed from AUR, e.g.:
$ yay -S nvme-cli-git
+### Debian
+
+nvme-cli is available in Debian 9 and up. Install it with your favorite
+package manager. For example:
+
+ $ sudo apt install nvme-cli
+
### Fedora
nvme-cli is available in Fedora 23 and up. Install it with your favorite
diff --git a/common.h b/common.h
index aed2a99..1c214a4 100644
--- a/common.h
+++ b/common.h
@@ -9,4 +9,7 @@
#define min(x, y) ((x) > (y) ? (y) : (x))
#define max(x, y) ((x) > (y) ? (x) : (y))
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
#endif
diff --git a/completions/_nvme b/completions/_nvme
index e076232..9267522 100644
--- a/completions/_nvme
+++ b/completions/_nvme
@@ -10,17 +10,25 @@ _nvme () {
'id-ctrl:display information about the controller'
'id-ns:display information about the namespace'
'list-ns:identify all namespace(s) attached'
+ 'id-iocs:display information about I/O command sets'
'create-ns:create a new namespace before attachment'
'delete-ns:delete a detached namespace'
'attach-ns:attach namespace to controller'
'detach-ns:detach namespace from controller'
'list-ctrl:identify all controller(s) attached'
+ 'nvm-id-ctrl:display information about the nvm command set'
'get-ns-id:get namespace id of opened block device'
'get-log:retrieve any log in raw format'
+ 'predictable-lat-log:retrieve predictable latency per nvmset log'
+ 'pred-lat-event-agg-log:retrieve predictable latency event aggregate log'
+ 'persistent-event-log:retrieve presistent event log'
'fw-log:retrieve fw log'
'smart-log:retrieve SMART log'
'smart-log-add:retrieve additional SMART log'
'error-log:retrieve error log'
+ 'endurance-event-agg-log:retrieve endurance group event aggregate log'
+ 'lba-status-log:retrieve lba status log'
+ 'resv-notif-log: retrieve reservation notification log'
'get-feature:display a controller feature'
'set-feature:set a controller feature and show results'
'format:apply new block format to namespace'
@@ -34,6 +42,7 @@ _nvme () {
'resv-register:register reservation on a namespace'
'resv-release:release reservation on a namespace'
'resv-report:report reservation on a namespace'
+ 'copy:submit a simple copy command'
'flush:submit a flush'
'compare:compare data on device to data elsewhere'
'read:submit a read command'
@@ -88,10 +97,30 @@ _nvme () {
/dev/nvme':supply a device to use (required)'
--namespace-id=':start namespace infos listing with this nsid'
-n':alias of --namespace-id'
+ --csi=':command set identifier'
+ -y':alias of --csi'
)
_arguments '*:: :->subcmds'
_describe -t commands "nvme list-ns options" _listns
;;
+ (id-iocs)
+ local _idiocs
+ _idiocs=(
+ /dev/nvme':supply a device to use (required)'
+ --controller-id=':show infos for controller <cntid>'
+ -c':alias of --controller-id'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-iocs options" _idiocs
+ ;;
+ nvm-id-ctrl)
+ local _nvmidctrl
+ _nvmidctrl=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme nvm-id-ctrl options" _nvmidctrl
+ ;;
(create-ns)
local _createns
_createns=(
@@ -106,6 +135,8 @@ _nvme () {
-d':alias of --dps'
--nmic=':multipath and sharing'
-n':alias of --nmic'
+ --csi=':command set identifier'
+ -y':alias of --csi'
)
_arguments '*:: :->subcmds'
_describe -t commands "nvme create-ns options" _createns
@@ -180,6 +211,46 @@ _nvme () {
_arguments '*:: :->subcmds'
_describe -t commands "nvme get-log options" _getlog
;;
+ (persistent-event-log)
+ local _persistenteventlog
+ _persistenteventlog=(
+ /dev/nvme':supply a device to use (required)'
+ --action=': action the controller shall take for this log page'
+ -a':alias to --action'
+ --log-len=':number of bytes to show for requested log'
+ -l':alias of --log-len'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "persistent-event-log options" _persistenteventlog
+ ;;
+ (pred-lat-event-agg-log)
+ local _predlateventagglog
+ _predlateventagglog=(
+ /dev/nvme':supply a device to use (required)'
+ --log-entries=': Number of pending NVM Set Entries log list'
+ -e':alias to --log-entries'
+ --rae': Retain an Asynchronous Event'
+ -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)
+ local _predictablelatlog
+ _predictablelatlog=(
+ /dev/nvme':supply a device to use (required)'
+ --nvmset-id=': NVM Set Identifier on which log page retrieve info'
+ -i':alias to --nvmset-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme predictable-lat-log options" _predictablelatlog
+ ;;
(fw-log)
local _fwlog
_fwlog=(
@@ -228,6 +299,38 @@ _nvme () {
_arguments '*:: :->subcmds'
_describe -t commands "nvme error-log options" _errlog
;;
+ (endurance-event-agg-log)
+ local _enduranceeventagglog
+ _enduranceeventagglog=(
+ /dev/nvme':supply a device to use (required)'
+ --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
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme endurance-event-agg-log options" _enduranceeventagglog
+ ;;
+ (lba-status-log)
+ local _lbastatuslog
+ _lbastatuslog=(
+ /dev/nvme':supply a device to use (required)'
+ --rae': Retain an Asynchronous Event'
+ -r':alias to --rae
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme lba-status-log options" _lbastatuslog
+ ;;
+ (resv-notif-log)
+ local _resvnotiflog
+ _resvnotiflog=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-notif-log options" _resvnotiflog
+ ;;
(get-feature)
local _getf
_getf=(
@@ -515,6 +618,46 @@ _nvme () {
_arguments '*:: :->subcmds'
_describe -t commands "nvme resv-register options" _reg
;;
+ (copy)
+ local _copy
+ _copy=(
+ /dev/nvme':supply a device to use (required)'
+ --sdlba=':64-bit addr of first destination logical block'
+ -d':alias of --sdlba'
+ --slbs=':64-bit addr of first block per range (comma-separated list)'
+ -s':alias of --slbs'
+ --blocks=':number of blocks per range (comma-separated list, zeroes-based values)'
+ -b':alias of --blocks'
+ --limited-retry':if included, controller should try less hard to retrieve data from media (if not included, all available data recovery means used)'
+ -l':alias of --limited-retry'
+ --force-unit-access':if included, the data shall be read from non-volatile media'
+ -f':alias of --force-unit access'
+ --prinfow=':protection information and check field (write part)'
+ -p':alias of --prinfow'
+ --prinfor=':protection information and check field (read part)'
+ -P':alias of --prinfor'
+ --ref-tag=':initial lba reference tag (write part)'
+ -r':alias of --ref-tag'
+ --expected-ref-tags=':expected lba reference tags (read part, comma-separated list)'
+ -R':alias of --expected-ref-tags'
+ --app-tag=':lba application tag (write part)'
+ -a':alias of --app-tag'
+ --expected-app-tags=':expected lba application tags (read part, comma-separated list)'
+ -A':alias of --expected-app-tags'
+ --app-tag-mask=':lba application tag mask (write part)'
+ -m':alias of --app-tag-mask'
+ --expected-app-tag-masks=':expected lba application tag masks (read part, comma-separated list)'
+ -M':alias of --expected-app-tag-masks'
+ --dir-type':directive type (write part)'
+ -T':alias of --dir-type'
+ --dir-spec':directive specific (write part)'
+ -S':alias of --dir-spec'
+ --format':source range entry format'
+ -F':alias of --format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme copy options" _copy
+ ;;
(flush)
local _flush
_flush=(
@@ -639,11 +782,13 @@ _nvme () {
;;
(help)
local _h
- _h=( id-ctrl id-ns list-ns create-ns delete-ns attach-ns detach-ns
+ _h=( id-ctrl id-ns list-ns id-iocs create-ns delete-ns attach-ns detach-ns
list-ctrl get-ns-id get-log fw-log smart-log error-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 flush compare read write show-regs
+ 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
)
_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 b7c2aa1..c022b89 100644
--- a/completions/bash-nvme-completion.sh
+++ b/completions/bash-nvme-completion.sh
@@ -2,16 +2,17 @@
# (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 create-ns delete-ns \
- attach-ns detach-ns list-ctrl get-ns-id get-log \
- fw-log smart-log smart-log-add error-log \
- get-feature set-feature format fw-activate \
+_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 reset subsystem-reset show-regs discover \
+ write-uncor copy reset subsystem-reset show-regs discover \
connect-all connect disconnect version help \
- intel lnvm memblaze list-subsys"
+ intel lnvm memblaze list-subsys endurance-event-agg-log \
+ lba-status-log resv-notif-log"
nvme_list_opts () {
local opts=""
@@ -44,11 +45,17 @@ nvme_list_opts () {
--force -f --output-format= -o"
;;
"list-ns")
- opts+=" --namespace-id= -n --al -a"
+ opts+=" --namespace-id= -n --al -a --csi= -y"
+ ;;
+ "id-iocs")
+ opts+=" --controller-id= -c"
+ ;;
+ "nvm-id-ctrl")
+ opts+=" --output-format= -o"
;;
"create-ns")
opts+=" --nsze= -s --ncap= -c --flbas= -f \
- --dps= -d --nmic= -n"
+ --dps= -d --nmic= -n --csi= -y"
;;
"delete-ns")
opts+=" -namespace-id= -n"
@@ -68,6 +75,18 @@ nvme_list_opts () {
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"
+ ;;
+ "predictable-lat-log")
+ opts+=" --nvmset-id= -i --raw-binary -b \
+ --output-format= -o"
+ ;;
"fw-log")
opts+=" --raw-binary -b --output-format= -o"
;;
@@ -82,6 +101,16 @@ nvme_list_opts () {
opts+=" --namespace-id= -n --raw-binary -b --log-entries= -e \
--output-format= -o"
;;
+ "endurance-event-agg-log")
+ opts+=" --log-entries= -e --rae -r \
+ --raw-binary -b --output-format= -o"
+ ;;
+ "lba-status-log")
+ opts+=" --rae -r --output-format= -o"
+ ;;
+ "resv-notif-log")
+ opts+=" --output-format= -o"
+ ;;
"get-feature")
opts+=" --namespace-id= -n --feature-id= -f --sel= -s \
--data-len= -l --cdw11= --raw-binary -b \
@@ -145,6 +174,15 @@ nvme_list_opts () {
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 \
+ --limited-retry -l --force-unit-access -f \
+ --prinfow= -p --prinfor= -P \
+ --ref-tag= -r --expected-ref-tag= -R \
+ --app-tag= -a --expected-app-tag= -A \
+ --app-tag-mask= -m --expected-app-tag-mask= -M \
+ --dir-type= -T --dir-spec= -S --format= -F"
+ ;;
"flush")
opts+=" --namespace-id= -n"
;;
diff --git a/fabrics.c b/fabrics.c
index 2fec802..7dd0d27 100644
--- a/fabrics.c
+++ b/fabrics.c
@@ -32,6 +32,8 @@
#include <libgen.h>
#include <sys/stat.h>
#include <stddef.h>
+#include <syslog.h>
+#include <time.h>
#include <sys/types.h>
#include <arpa/inet.h>
@@ -46,6 +48,8 @@
#include "util/argconfig.h"
#include "common.h"
+#include "util/log.h"
+#include "util/cleanup.h"
#ifdef HAVE_SYSTEMD
#include <systemd/sd-id128.h>
@@ -54,38 +58,19 @@
#define NVMF_HOSTID_SIZE 36
+/* default to 600 seconds of reconnect attempts before giving up */
+#define NVMF_DEF_CTRL_LOSS_TMO 600
+
const char *conarg_nqn = "nqn";
const char *conarg_transport = "transport";
const char *conarg_traddr = "traddr";
const char *conarg_trsvcid = "trsvcid";
const char *conarg_host_traddr = "host_traddr";
-static struct config {
- char *nqn;
- char *transport;
- char *traddr;
- char *trsvcid;
- char *host_traddr;
- char *hostnqn;
- char *hostid;
- int nr_io_queues;
- int nr_write_queues;
- int nr_poll_queues;
- int queue_size;
- int keep_alive_tmo;
- int reconnect_delay;
- int ctrl_loss_tmo;
- int tos;
- char *raw;
- char *device;
- int duplicate_connect;
- int disable_sqflow;
- int hdr_digest;
- int data_digest;
- bool persistent;
- bool quiet;
- bool matching_only;
-} cfg = { NULL };
+struct fabrics_config fabrics_cfg = {
+ .ctrl_loss_tmo = -1,
+ .output_format = "normal",
+};
struct connect_args {
char *subsysnqn;
@@ -93,9 +78,12 @@ struct connect_args {
char *traddr;
char *trsvcid;
char *host_traddr;
+ struct connect_args *next;
+ struct connect_args *tail;
};
-#define BUF_SIZE 4096
+struct connect_args *tracked_ctrls;
+
#define PATH_NVME_FABRICS "/dev/nvme-fabrics"
#define PATH_NVMF_DISC "/etc/nvme/discovery.conf"
#define PATH_NVMF_HOSTNQN "/etc/nvme/hostnqn"
@@ -115,7 +103,7 @@ static const match_table_t opt_tokens = {
{ OPT_ERR, NULL },
};
-static const char *arg_str(const char * const *strings,
+const char *arg_str(const char * const *strings,
size_t array_size, size_t idx)
{
if (idx < array_size && strings[idx])
@@ -123,7 +111,7 @@ static const char *arg_str(const char * const *strings,
return "unrecognized";
}
-static const char * const trtypes[] = {
+const char * const trtypes[] = {
[NVMF_TRTYPE_RDMA] = "rdma",
[NVMF_TRTYPE_FC] = "fc",
[NVMF_TRTYPE_TCP] = "tcp",
@@ -214,14 +202,12 @@ static const char *cms_str(__u8 cm)
return arg_str(cms, ARRAY_SIZE(cms), cm);
}
-static int do_discover(char *argstr, bool connect);
-
/*
* parse strings with connect arguments to find a particular field.
* If field found, return string containing field value. If field
* not found, return an empty string.
*/
-static char *parse_conn_arg(char *conargs, const char delim, const char *field)
+char *parse_conn_arg(const char *conargs, const char delim, const char *field)
{
char *s, *e;
size_t cnt;
@@ -265,17 +251,22 @@ empty_field:
return strdup("\0");
}
-static int ctrl_instance(char *device)
+int ctrl_instance(const char *device)
{
char d[64];
+ const char *p;
int ret, instance;
- device = basename(device);
- ret = sscanf(device, "nvme%d", &instance);
+ p = strrchr(device, '/');
+ if (p == NULL)
+ p = device;
+ else
+ p++;
+ ret = sscanf(p, "nvme%d", &instance);
if (ret <= 0)
return -EINVAL;
if (snprintf(d, sizeof(d), "nvme%d", instance) <= 0 ||
- strcmp(device, d))
+ strcmp(p, d))
return -EINVAL;
return instance;
}
@@ -286,25 +277,54 @@ static int ctrl_instance(char *device)
* given.
* Return true/false based on whether it matches
*/
-static bool ctrl_matches_connectargs(char *name, struct connect_args *args)
+static bool ctrl_matches_connectargs(const char *name, struct connect_args *args)
{
struct connect_args cargs;
bool found = false;
- char *path, *addr;
+ char *path = NULL, *addr;
int ret;
+ bool persistent = true;
ret = asprintf(&path, "%s/%s", SYS_NVME, name);
if (ret < 0)
return found;
addr = nvme_get_ctrl_attr(path, "address");
+ if (!addr) {
+ fprintf(stderr, "nvme_get_ctrl_attr failed\n");
+ return found;
+ }
+
cargs.subsysnqn = nvme_get_ctrl_attr(path, "subsysnqn");
cargs.transport = nvme_get_ctrl_attr(path, "transport");
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);
- if (!strcmp(cargs.subsysnqn, args->subsysnqn) &&
+ if (!strcmp(cargs.subsysnqn, NVME_DISC_SUBSYS_NAME)) {
+ char *kato_str = nvme_get_ctrl_attr(path, "kato"), *p;
+ unsigned int kato = 0;
+
+ /*
+ * When looking up discovery controllers we have to skip
+ * any non-persistent controllers (ie those with a zero
+ * kato value). Otherwise the controller will vanish from
+ * underneath us as they are owned by another program.
+ *
+ * On older kernels, the 'kato' attribute isn't present.
+ * Assume a persistent controller for these installations.
+ */
+ if (kato_str) {
+ kato = strtoul(kato_str, &p, 0);
+ if (p == kato_str)
+ kato = 0;
+ free(kato_str);
+ persistent = (kato != 0);
+ }
+ }
+
+ if (persistent &&
+ !strcmp(cargs.subsysnqn, args->subsysnqn) &&
!strcmp(cargs.transport, args->transport) &&
(!strcmp(cargs.traddr, args->traddr) ||
!strcmp(args->traddr, "none")) &&
@@ -319,6 +339,8 @@ static bool ctrl_matches_connectargs(char *name, struct connect_args *args)
free(cargs.traddr);
free(cargs.trsvcid);
free(cargs.host_traddr);
+ free(addr);
+ free(path);
return found;
}
@@ -338,7 +360,7 @@ static char *find_ctrl_with_connectargs(struct connect_args *args)
n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
if (n < 0) {
- fprintf(stderr, "no NVMe controller(s) detected.\n");
+ msg(LOG_ERR, "no NVMe controller(s) detected.\n");
return NULL;
}
@@ -346,7 +368,7 @@ static char *find_ctrl_with_connectargs(struct connect_args *args)
if (ctrl_matches_connectargs(devices[i]->d_name, args)) {
devname = strdup(devices[i]->d_name);
if (devname == NULL)
- fprintf(stderr, "no memory for ctrl name %s\n",
+ msg(LOG_ERR, "no memory for ctrl name %s\n",
devices[i]->d_name);
goto cleanup_devices;
}
@@ -360,6 +382,51 @@ cleanup_devices:
return devname;
}
+static struct connect_args *extract_connect_args(char *argstr)
+{
+ struct connect_args *cargs;
+
+ cargs = calloc(1, sizeof(*cargs));
+ if (!cargs)
+ return NULL;
+ cargs->subsysnqn = parse_conn_arg(argstr, ',', conarg_nqn);
+ cargs->transport = parse_conn_arg(argstr, ',', conarg_transport);
+ 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);
+ return cargs;
+}
+
+static void destruct_connect_args(struct connect_args *cargs)
+{
+ free(cargs->subsysnqn);
+ free(cargs->transport);
+ free(cargs->traddr);
+ free(cargs->trsvcid);
+ free(cargs->host_traddr);
+}
+
+static void free_connect_args(struct connect_args *cargs)
+{
+ destruct_connect_args(cargs);
+ free(cargs);
+}
+
+static void track_ctrl(char *argstr)
+{
+ struct connect_args *cargs;
+
+ cargs = extract_connect_args(argstr);
+ if (!cargs)
+ return;
+
+ if (!tracked_ctrls)
+ tracked_ctrls = cargs;
+ else
+ tracked_ctrls->tail->next = cargs;
+ tracked_ctrls->tail = cargs;
+}
+
static int add_ctrl(const char *argstr)
{
substring_t args[MAX_OPT_ARGS];
@@ -368,7 +435,7 @@ static int add_ctrl(const char *argstr)
fd = open(PATH_NVME_FABRICS, O_RDWR);
if (fd < 0) {
- fprintf(stderr, "Failed to open %s: %s\n",
+ msg(LOG_ERR, "Failed to open %s: %s\n",
PATH_NVME_FABRICS, strerror(errno));
ret = -errno;
goto out;
@@ -376,8 +443,8 @@ static int add_ctrl(const char *argstr)
ret = write(fd, argstr, len);
if (ret != len) {
- if (errno != EALREADY || !cfg.quiet)
- fprintf(stderr, "Failed to write to %s: %s\n",
+ if (errno != EALREADY)
+ msg(LOG_NOTICE, "Failed to write to %s: %s\n",
PATH_NVME_FABRICS, strerror(errno));
ret = -errno;
goto out_close;
@@ -385,7 +452,7 @@ static int add_ctrl(const char *argstr)
len = read(fd, buf, BUF_SIZE);
if (len < 0) {
- fprintf(stderr, "Failed to read from %s: %s\n",
+ msg(LOG_ERR, "Failed to read from %s: %s\n",
PATH_NVME_FABRICS, strerror(errno));
ret = -errno;
goto out_close;
@@ -403,6 +470,7 @@ static int add_ctrl(const char *argstr)
if (match_int(args, &token))
goto out_fail;
ret = token;
+ track_ctrl((char *)argstr);
goto out_close;
default:
/* ignore */
@@ -411,7 +479,7 @@ static int add_ctrl(const char *argstr)
}
out_fail:
- fprintf(stderr, "Failed to parse ctrl info for \"%s\"\n", argstr);
+ msg(LOG_ERR, "Failed to parse ctrl info for \"%s\"\n", argstr);
ret = -EINVAL;
out_close:
close(fd);
@@ -426,7 +494,7 @@ static int remove_ctrl_by_path(char *sysfs_path)
fd = open(sysfs_path, O_WRONLY);
if (fd < 0) {
ret = -errno;
- fprintf(stderr, "Failed to open %s: %s\n", sysfs_path,
+ msg(LOG_ERR, "Failed to open %s: %s\n", sysfs_path,
strerror(errno));
goto out;
}
@@ -443,7 +511,7 @@ out:
return ret;
}
-static int remove_ctrl(int instance)
+int remove_ctrl(int instance)
{
char *sysfs_path;
int ret;
@@ -480,7 +548,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path,
fd = open(dev_path, O_RDWR);
if (fd < 0) {
error = -errno;
- fprintf(stderr, "Failed to open %s: %s\n",
+ msg(LOG_ERR, "Failed to open %s: %s\n",
dev_path, strerror(errno));
goto out;
}
@@ -497,6 +565,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path,
*/
log = calloc(1, hdr_size);
if (!log) {
+ perror("could not alloc memory for discovery log header");
error = -ENOMEM;
goto out_close;
}
@@ -531,6 +600,7 @@ static int nvmf_get_log_page_discovery(const char *dev_path,
/* allocate discovery log pages based on page_hdr->numrec */
log = calloc(1, log_size);
if (!log) {
+ perror("could not alloc memory for discovery log page");
error = -ENOMEM;
goto out_close;
}
@@ -644,15 +714,67 @@ 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)
+{
+ struct json_object *root;
+ struct json_object *entries;
+ int i;
+
+ root = json_create_object();
+ entries = json_create_array();
+ json_object_add_value_uint(root, "genctr", le64_to_cpu(log->genctr));
+ json_object_add_value_array(root, "records", entries);
+
+ for (i = 0; i < numrec; i++) {
+ struct nvmf_disc_rsp_page_entry *e = &log->entries[i];
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_string(entry, "trtype",
+ trtype_str(e->trtype));
+ json_object_add_value_string(entry, "adrfam",
+ adrfam_str(e->adrfam));
+ json_object_add_value_string(entry, "subtype",
+ subtype_str(e->subtype));
+ 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, "subnqn", e->subnqn);
+ json_object_add_value_string(entry, "traddr", e->traddr);
+
+ switch (e->trtype) {
+ case NVMF_TRTYPE_RDMA:
+ json_object_add_value_string(entry, "rdma_prtype",
+ prtype_str(e->tsas.rdma.prtype));
+ json_object_add_value_string(entry, "rdma_qptype",
+ qptype_str(e->tsas.rdma.qptype));
+ 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);
+ break;
+ case NVMF_TRTYPE_TCP:
+ json_object_add_value_string(entry, "sectype",
+ sectype_str(e->tsas.tcp.sectype));
+ break;
+ }
+ json_array_add_value_object(entries, entry);
+ }
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec)
{
int fd;
int len, ret;
- fd = open(cfg.raw, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
+ fd = open(fabrics_cfg.raw, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
if (fd < 0) {
- fprintf(stderr, "failed to open %s: %s\n",
- cfg.raw, strerror(errno));
+ msg(LOG_ERR, "failed to open %s: %s\n",
+ fabrics_cfg.raw, strerror(errno));
return;
}
@@ -660,10 +782,10 @@ static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec)
numrec * sizeof(struct nvmf_disc_rsp_page_entry);
ret = write(fd, log, len);
if (ret < 0)
- fprintf(stderr, "failed to write to %s: %s\n",
- cfg.raw, strerror(errno));
+ msg(LOG_ERR, "failed to write to %s: %s\n",
+ fabrics_cfg.raw, strerror(errno));
else
- printf("Discovery log is saved to %s\n", cfg.raw);
+ printf("Discovery log is saved to %s\n", fabrics_cfg.raw);
close(fd);
}
@@ -707,6 +829,18 @@ static char *hostnqn_generate_systemd(void)
#endif
}
+static char *hostnqn_read_dmi(void)
+{
+ char uuid[16];
+ char *ret = NULL;
+
+ if (uuid_from_dmi(uuid) < 0)
+ return NULL;
+ if (asprintf(&ret, "nqn.2014-08.org.nvmexpress:uuid:%s", uuid) == -1)
+ return NULL;
+ return ret;
+}
+
/* returns an allocated string or NULL */
char *hostnqn_read(void)
{
@@ -716,6 +850,10 @@ char *hostnqn_read(void)
if (ret)
return ret;
+ ret = hostnqn_read_dmi();
+ if (ret)
+ return ret;
+
ret = hostnqn_generate_systemd();
if (ret)
return ret;
@@ -725,9 +863,9 @@ char *hostnqn_read(void)
static int nvmf_hostnqn_file(void)
{
- cfg.hostnqn = hostnqn_read();
+ fabrics_cfg.hostnqn = hostnqn_read();
- return cfg.hostnqn != NULL;
+ return fabrics_cfg.hostnqn != NULL;
}
static int nvmf_hostid_file(void)
@@ -743,8 +881,8 @@ static int nvmf_hostid_file(void)
if (fgets(hostid, sizeof(hostid), f) == NULL)
goto out;
- cfg.hostid = strdup(hostid);
- if (!cfg.hostid)
+ fabrics_cfg.hostid = strdup(hostid);
+ if (!fabrics_cfg.hostid)
goto out;
ret = true;
@@ -787,7 +925,7 @@ add_int_argument(char **argstr, int *max_len, char *arg_str, int arg,
}
static int
-add_argument(char **argstr, int *max_len, char *arg_str, char *arg)
+add_argument(char **argstr, int *max_len, char *arg_str, const char *arg)
{
int len;
@@ -802,91 +940,115 @@ add_argument(char **argstr, int *max_len, char *arg_str, char *arg)
return 0;
}
-static int build_options(char *argstr, int max_len, bool discover)
+int build_options(char *argstr, int max_len, bool discover)
{
int len;
- if (!cfg.transport) {
- fprintf(stderr, "need a transport (-t) argument\n");
+ if (!fabrics_cfg.transport) {
+ msg(LOG_ERR, "need a transport (-t) argument\n");
return -EINVAL;
}
- if (strncmp(cfg.transport, "loop", 4)) {
- if (!cfg.traddr) {
- fprintf(stderr, "need a address (-a) argument\n");
+ if (strncmp(fabrics_cfg.transport, "loop", 4)) {
+ if (!fabrics_cfg.traddr) {
+ msg(LOG_ERR, "need a address (-a) argument\n");
return -EINVAL;
}
+ /* Use the default ctrl loss timeout if unset */
+ if (fabrics_cfg.ctrl_loss_tmo == -1)
+ fabrics_cfg.ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO;
}
/* always specify nqn as first arg - this will init the string */
- len = snprintf(argstr, max_len, "nqn=%s", cfg.nqn);
+ len = snprintf(argstr, max_len, "nqn=%s", fabrics_cfg.nqn);
if (len < 0)
return -EINVAL;
argstr += len;
max_len -= len;
- if (add_argument(&argstr, &max_len, "transport", cfg.transport) ||
- add_argument(&argstr, &max_len, "traddr", cfg.traddr) ||
- add_argument(&argstr, &max_len, "host_traddr", cfg.host_traddr) ||
- add_argument(&argstr, &max_len, "trsvcid", cfg.trsvcid) ||
- ((cfg.hostnqn || nvmf_hostnqn_file()) &&
- add_argument(&argstr, &max_len, "hostnqn", cfg.hostnqn)) ||
- ((cfg.hostid || nvmf_hostid_file()) &&
- add_argument(&argstr, &max_len, "hostid", cfg.hostid)) ||
+ 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, "trsvcid", fabrics_cfg.trsvcid) ||
+ ((fabrics_cfg.hostnqn || nvmf_hostnqn_file()) &&
+ add_argument(&argstr, &max_len, "hostnqn", fabrics_cfg.hostnqn)) ||
+ ((fabrics_cfg.hostid || nvmf_hostid_file()) &&
+ add_argument(&argstr, &max_len, "hostid", fabrics_cfg.hostid)) ||
(!discover &&
add_int_argument(&argstr, &max_len, "nr_io_queues",
- cfg.nr_io_queues, false)) ||
+ fabrics_cfg.nr_io_queues, false)) ||
add_int_argument(&argstr, &max_len, "nr_write_queues",
- cfg.nr_write_queues, false) ||
+ fabrics_cfg.nr_write_queues, false) ||
add_int_argument(&argstr, &max_len, "nr_poll_queues",
- cfg.nr_poll_queues, false) ||
+ fabrics_cfg.nr_poll_queues, false) ||
(!discover &&
add_int_argument(&argstr, &max_len, "queue_size",
- cfg.queue_size, false)) ||
- (!discover &&
- add_int_argument(&argstr, &max_len, "keep_alive_tmo",
- cfg.keep_alive_tmo, false)) ||
+ fabrics_cfg.queue_size, false)) ||
+ add_int_argument(&argstr, &max_len, "keep_alive_tmo",
+ fabrics_cfg.keep_alive_tmo, false) ||
add_int_argument(&argstr, &max_len, "reconnect_delay",
- cfg.reconnect_delay, false) ||
- add_int_argument(&argstr, &max_len, "ctrl_loss_tmo",
- cfg.ctrl_loss_tmo, false) ||
+ fabrics_cfg.reconnect_delay, false) ||
+ (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, "tos",
- cfg.tos, true) ||
+ fabrics_cfg.tos, true) ||
add_bool_argument(&argstr, &max_len, "duplicate_connect",
- cfg.duplicate_connect) ||
+ fabrics_cfg.duplicate_connect) ||
add_bool_argument(&argstr, &max_len, "disable_sqflow",
- cfg.disable_sqflow) ||
- add_bool_argument(&argstr, &max_len, "hdr_digest", cfg.hdr_digest) ||
- add_bool_argument(&argstr, &max_len, "data_digest", cfg.data_digest))
+ fabrics_cfg.disable_sqflow) ||
+ add_bool_argument(&argstr, &max_len, "hdr_digest", fabrics_cfg.hdr_digest) ||
+ add_bool_argument(&argstr, &max_len, "data_digest", fabrics_cfg.data_digest))
return -EINVAL;
return 0;
}
-static bool traddr_is_hostname(struct config *cfg)
+static void set_discovery_kato(struct fabrics_config *cfg)
+{
+ /* Set kato to NVMF_DEF_DISC_TMO for persistent controllers */
+ if (cfg->persistent && !cfg->keep_alive_tmo)
+ cfg->keep_alive_tmo = NVMF_DEF_DISC_TMO;
+ /* Set kato to zero for non-persistent controllers */
+ else if (!cfg->persistent && (cfg->keep_alive_tmo > 0))
+ cfg->keep_alive_tmo = 0;
+}
+
+static void discovery_trsvcid(struct fabrics_config *fabrics_cfg)
+{
+ if (!strcmp(fabrics_cfg->transport, "tcp")) {
+ /* Default port for NVMe/TCP discovery controllers */
+ fabrics_cfg->trsvcid = __stringify(NVME_DISC_IP_PORT);
+ } else if (!strcmp(fabrics_cfg->transport, "rdma")) {
+ /* Default port for NVMe/RDMA controllers */
+ fabrics_cfg->trsvcid = __stringify(NVME_RDMA_IP_PORT);
+ }
+}
+
+static bool traddr_is_hostname(struct fabrics_config *fabrics_cfg)
{
char addrstr[NVMF_TRADDR_SIZE];
- if (!cfg->traddr)
+ if (!fabrics_cfg->traddr || !fabrics_cfg->transport)
return false;
- if (strcmp(cfg->transport, "tcp") && strcmp(cfg->transport, "rdma"))
+ if (strcmp(fabrics_cfg->transport, "tcp") && strcmp(fabrics_cfg->transport, "rdma"))
return false;
- if (inet_pton(AF_INET, cfg->traddr, addrstr) > 0 ||
- inet_pton(AF_INET6, cfg->traddr, addrstr) > 0)
+ if (inet_pton(AF_INET, fabrics_cfg->traddr, addrstr) > 0 ||
+ inet_pton(AF_INET6, fabrics_cfg->traddr, addrstr) > 0)
return false;
return true;
}
-static int hostname2traddr(struct config *cfg)
+static int hostname2traddr(struct fabrics_config *fabrics_cfg)
{
struct addrinfo *host_info, hints = {.ai_family = AF_UNSPEC};
char addrstr[NVMF_TRADDR_SIZE];
const char *p;
int ret;
- ret = getaddrinfo(cfg->traddr, NULL, &hints, &host_info);
+ ret = getaddrinfo(fabrics_cfg->traddr, NULL, &hints, &host_info);
if (ret) {
- fprintf(stderr, "failed to resolve host %s info\n", cfg->traddr);
+ msg(LOG_ERR, "failed to resolve host %s info\n", fabrics_cfg->traddr);
return ret;
}
@@ -902,18 +1064,18 @@ static int hostname2traddr(struct config *cfg)
addrstr, NVMF_TRADDR_SIZE);
break;
default:
- fprintf(stderr, "unrecognized address family (%d) %s\n",
- host_info->ai_family, cfg->traddr);
+ msg(LOG_ERR, "unrecognized address family (%d) %s\n",
+ host_info->ai_family, fabrics_cfg->traddr);
ret = -EINVAL;
goto free_addrinfo;
}
if (!p) {
- fprintf(stderr, "failed to get traddr for %s\n", cfg->traddr);
+ msg(LOG_ERR, "failed to get traddr for %s\n", fabrics_cfg->traddr);
ret = -errno;
goto free_addrinfo;
}
- cfg->traddr = strdup(addrstr);
+ fabrics_cfg->traddr = strdup(addrstr);
free_addrinfo:
freeaddrinfo(host_info);
@@ -937,7 +1099,7 @@ retry:
case NVME_NQN_NVME:
break;
default:
- fprintf(stderr, "skipping unsupported subtype %d\n",
+ msg(LOG_ERR, "skipping unsupported subtype %d\n",
e->subtype);
return -EINVAL;
}
@@ -947,78 +1109,78 @@ retry:
return -EINVAL;
p += len;
- if (cfg.hostnqn && strcmp(cfg.hostnqn, "none")) {
- len = sprintf(p, ",hostnqn=%s", cfg.hostnqn);
+ if (fabrics_cfg.hostnqn && strcmp(fabrics_cfg.hostnqn, "none")) {
+ len = sprintf(p, ",hostnqn=%s", fabrics_cfg.hostnqn);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.hostid && strcmp(cfg.hostid, "none")) {
- len = sprintf(p, ",hostid=%s", cfg.hostid);
+ if (fabrics_cfg.hostid && strcmp(fabrics_cfg.hostid, "none")) {
+ len = sprintf(p, ",hostid=%s", fabrics_cfg.hostid);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.queue_size && !discover) {
- len = sprintf(p, ",queue_size=%d", cfg.queue_size);
+ if (fabrics_cfg.queue_size && !discover) {
+ len = sprintf(p, ",queue_size=%d", fabrics_cfg.queue_size);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.nr_io_queues && !discover) {
- len = sprintf(p, ",nr_io_queues=%d", cfg.nr_io_queues);
+ if (fabrics_cfg.nr_io_queues && !discover) {
+ len = sprintf(p, ",nr_io_queues=%d", fabrics_cfg.nr_io_queues);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.nr_write_queues) {
- len = sprintf(p, ",nr_write_queues=%d", cfg.nr_write_queues);
+ if (fabrics_cfg.nr_write_queues) {
+ len = sprintf(p, ",nr_write_queues=%d", fabrics_cfg.nr_write_queues);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.nr_poll_queues) {
- len = sprintf(p, ",nr_poll_queues=%d", cfg.nr_poll_queues);
+ if (fabrics_cfg.nr_poll_queues) {
+ len = sprintf(p, ",nr_poll_queues=%d", fabrics_cfg.nr_poll_queues);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.host_traddr && strcmp(cfg.host_traddr, "none")) {
- len = sprintf(p, ",host_traddr=%s", cfg.host_traddr);
+ if (fabrics_cfg.host_traddr && strcmp(fabrics_cfg.host_traddr, "none")) {
+ len = sprintf(p, ",host_traddr=%s", fabrics_cfg.host_traddr);
if (len < 0)
return -EINVAL;
p+= len;
}
- if (cfg.reconnect_delay) {
- len = sprintf(p, ",reconnect_delay=%d", cfg.reconnect_delay);
+ if (fabrics_cfg.reconnect_delay) {
+ len = sprintf(p, ",reconnect_delay=%d", fabrics_cfg.reconnect_delay);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.ctrl_loss_tmo) {
- len = sprintf(p, ",ctrl_loss_tmo=%d", cfg.ctrl_loss_tmo);
+ if ((e->trtype != NVMF_TRTYPE_LOOP) && (fabrics_cfg.ctrl_loss_tmo >= -1)) {
+ len = sprintf(p, ",ctrl_loss_tmo=%d", fabrics_cfg.ctrl_loss_tmo);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.tos != -1) {
- len = sprintf(p, ",tos=%d", cfg.tos);
+ if (fabrics_cfg.tos != -1) {
+ len = sprintf(p, ",tos=%d", fabrics_cfg.tos);
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.keep_alive_tmo) {
- len = sprintf(p, ",keep_alive_tmo=%d", cfg.keep_alive_tmo);
+ if (fabrics_cfg.keep_alive_tmo) {
+ len = sprintf(p, ",keep_alive_tmo=%d", fabrics_cfg.keep_alive_tmo);
if (len < 0)
return -EINVAL;
p += len;
@@ -1026,7 +1188,7 @@ retry:
transport = trtype_str(e->trtype);
if (!strcmp(transport, "unrecognized")) {
- fprintf(stderr, "skipping unsupported transport %d\n",
+ msg(LOG_ERR, "skipping unsupported transport %d\n",
e->trtype);
return -EINVAL;
}
@@ -1036,14 +1198,14 @@ retry:
return -EINVAL;
p += len;
- if (cfg.hdr_digest) {
+ if (fabrics_cfg.hdr_digest) {
len = sprintf(p, ",hdr_digest");
if (len < 0)
return -EINVAL;
p += len;
}
- if (cfg.data_digest) {
+ if (fabrics_cfg.data_digest) {
len = sprintf(p, ",data_digest");
if (len < 0)
return -EINVAL;
@@ -1072,7 +1234,7 @@ retry:
p += len;
break;
default:
- fprintf(stderr, "skipping unsupported adrfam\n");
+ msg(LOG_ERR, "skipping unsupported adrfam\n");
return -EINVAL;
}
break;
@@ -1087,7 +1249,7 @@ retry:
p += len;
break;
default:
- fprintf(stderr, "skipping unsupported adrfam\n");
+ msg(LOG_ERR, "skipping unsupported adrfam\n");
return -EINVAL;
}
break;
@@ -1100,11 +1262,17 @@ retry:
p += len;
}
- if (discover)
- ret = do_discover(argstr, true);
- else
+ if (discover) {
+ enum nvme_print_flags flags;
+
+ flags = validate_output_format(fabrics_cfg.output_format);
+ if (flags < 0)
+ flags = NORMAL;
+ ret = do_discover(argstr, true, flags);
+ } else
ret = add_ctrl(argstr);
- if (ret == -EINVAL && e->treq & NVMF_TREQ_DISABLE_SQFLOW) {
+ if (ret == -EINVAL && disable_sqflow &&
+ e->treq & NVMF_TREQ_DISABLE_SQFLOW) {
/* disable_sqflow param might not be supported, try without it */
disable_sqflow = false;
goto retry;
@@ -1112,15 +1280,44 @@ retry:
return ret;
}
+static bool cargs_match_found(struct nvmf_disc_rsp_page_entry *entry)
+{
+ struct connect_args cargs __cleanup__(destruct_connect_args) = { NULL, };
+ struct connect_args *c = tracked_ctrls;
+
+ cargs.traddr = strdup(entry->traddr);
+ cargs.transport = strdup(trtype_str(entry->trtype));
+ cargs.subsysnqn = strdup(entry->subnqn);
+ cargs.trsvcid = strdup(entry->trsvcid);
+ cargs.host_traddr = strdup(fabrics_cfg.host_traddr ?: "\0");
+
+ /* check if we have a match in the discovery recursion */
+ while (c) {
+ if (!strcmp(cargs.subsysnqn, c->subsysnqn) &&
+ !strcmp(cargs.transport, c->transport) &&
+ !strcmp(cargs.traddr, c->traddr) &&
+ !strcmp(cargs.trsvcid, c->trsvcid) &&
+ !strcmp(cargs.host_traddr, c->host_traddr))
+ return true;
+ c = c->next;
+ }
+
+ /* check if we have a matching existing controller */
+ return find_ctrl_with_connectargs(&cargs) != NULL;
+}
+
static bool should_connect(struct nvmf_disc_rsp_page_entry *entry)
{
int len;
- if (!cfg.matching_only || !cfg.traddr)
+ if (cargs_match_found(entry))
+ return false;
+
+ if (!fabrics_cfg.matching_only || !fabrics_cfg.traddr)
return true;
len = space_strip_len(NVMF_TRADDR_SIZE, entry->traddr);
- return !strncmp(cfg.traddr, entry->traddr, len);
+ return !strncmp(fabrics_cfg.traddr, entry->traddr, len);
}
static int connect_ctrls(struct nvmf_disc_rsp_page_hdr *log, int numrec)
@@ -1143,9 +1340,7 @@ static int connect_ctrls(struct nvmf_disc_rsp_page_hdr *log, int numrec)
if (instance == -EALREADY) {
const char *traddr = log->entries[i].traddr;
- if (!cfg.quiet)
- fprintf(stderr,
- "traddr=%.*s is already connected\n",
+ msg(LOG_NOTICE, "traddr=%.*s is already connected\n",
space_strip_len(NVMF_TRADDR_SIZE,
traddr),
traddr);
@@ -1169,52 +1364,37 @@ static void nvmf_get_host_identifiers(int ctrl_instance)
if (asprintf(&path, "%s/nvme%d", SYS_NVME, ctrl_instance) < 0)
return;
- cfg.hostnqn = nvme_get_ctrl_attr(path, "hostnqn");
- cfg.hostid = nvme_get_ctrl_attr(path, "hostid");
+ fabrics_cfg.hostnqn = nvme_get_ctrl_attr(path, "hostnqn");
+ fabrics_cfg.hostid = nvme_get_ctrl_attr(path, "hostid");
}
-static int do_discover(char *argstr, bool connect)
+static DEFINE_CLEANUP_FUNC(cleanup_log, struct nvmf_disc_rsp_page_hdr *, free);
+
+int do_discover(char *argstr, bool connect, enum nvme_print_flags flags)
{
- struct nvmf_disc_rsp_page_hdr *log = NULL;
+ struct nvmf_disc_rsp_page_hdr *log __cleanup__(cleanup_log) = NULL;
char *dev_name;
int instance, numrec = 0, ret, err;
int status = 0;
+ struct connect_args *cargs;
- if (cfg.device) {
- struct connect_args cargs;
-
- memset(&cargs, 0, sizeof(cargs));
- cargs.subsysnqn = parse_conn_arg(argstr, ',', conarg_nqn);
- cargs.transport = parse_conn_arg(argstr, ',', conarg_transport);
- 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);
-
- /*
- * if the cfg.device passed in matches the connect args
- * cfg.device is left as-is
- * else if there exists a controller that matches the
- * connect args
- * cfg.device is the matching ctrl name
- * else if no ctrl matches the connect args
- * cfg.device is set to null. This will attempt to
- * create a new ctrl.
- * endif
- */
- if (!ctrl_matches_connectargs(cfg.device, &cargs))
- cfg.device = find_ctrl_with_connectargs(&cargs);
+ cargs = extract_connect_args(argstr);
+ if (!cargs)
+ return -ENOMEM;
- free(cargs.subsysnqn);
- free(cargs.transport);
- free(cargs.traddr);
- free(cargs.trsvcid);
- free(cargs.host_traddr);
+ if (fabrics_cfg.device &&
+ !ctrl_matches_connectargs(fabrics_cfg.device, cargs)) {
+ free(fabrics_cfg.device);
+ fabrics_cfg.device = NULL;
}
+ if (!fabrics_cfg.device)
+ fabrics_cfg.device = find_ctrl_with_connectargs(cargs);
+ free_connect_args(cargs);
- if (!cfg.device) {
+ if (!fabrics_cfg.device) {
instance = add_ctrl(argstr);
} else {
- instance = ctrl_instance(cfg.device);
+ instance = ctrl_instance(fabrics_cfg.device);
nvmf_get_host_identifiers(instance);
}
if (instance < 0)
@@ -1224,7 +1404,9 @@ static int do_discover(char *argstr, bool connect)
return -errno;
ret = nvmf_get_log_page_discovery(dev_name, &log, &numrec, &status);
free(dev_name);
- if (!cfg.device && !cfg.persistent) {
+ 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)
return err;
@@ -1234,18 +1416,20 @@ static int do_discover(char *argstr, bool connect)
case DISC_OK:
if (connect)
ret = connect_ctrls(log, numrec);
- else if (cfg.raw)
+ else if (fabrics_cfg.raw || flags == BINARY)
save_discovery_log(log, numrec);
+ else if (flags == JSON)
+ json_discovery_log(log, numrec);
else
print_discovery_log(log, numrec);
break;
case DISC_GET_NUMRECS:
- fprintf(stderr,
+ msg(LOG_ERR,
"Get number of discovery log entries failed.\n");
ret = status;
break;
case DISC_GET_LOG:
- fprintf(stderr, "Get discovery log entries failed.\n");
+ msg(LOG_ERR, "Get discovery log entries failed.\n");
ret = status;
break;
case DISC_NO_LOG:
@@ -1257,12 +1441,12 @@ static int do_discover(char *argstr, bool connect)
ret = -EAGAIN;
break;
case DISC_NOT_EQUAL:
- fprintf(stderr,
+ msg(LOG_ERR,
"Numrec values of last two get discovery log page not equal\n");
ret = -EBADSLT;
break;
default:
- fprintf(stderr, "Get discovery log page failed: %d\n", ret);
+ msg(LOG_ERR, "Get discovery log page failed: %d\n", ret);
break;
}
@@ -1273,30 +1457,33 @@ static int discover_from_conf_file(const char *desc, char *argstr,
const struct argconfig_commandline_options *opts, bool connect)
{
FILE *f;
- char line[256], *ptr, *args, **argv;
+ char line[256], *ptr, *all_args, *args, **argv;
int argc, err, ret = 0;
f = fopen(PATH_NVMF_DISC, "r");
if (f == NULL) {
- fprintf(stderr, "No discover params given and no %s conf\n",
+ msg(LOG_ERR, "No discover params given and no %s\n",
PATH_NVMF_DISC);
return -EINVAL;
}
while (fgets(line, sizeof(line), f) != NULL) {
+ enum nvme_print_flags flags;
+
if (line[0] == '#' || line[0] == '\n')
continue;
args = strdup(line);
if (!args) {
- fprintf(stderr, "failed to strdup args\n");
+ msg(LOG_ERR, "failed to strdup args\n");
ret = -ENOMEM;
goto out;
}
+ all_args = args;
argv = calloc(MAX_DISC_ARGS, BUF_SIZE);
if (!argv) {
- fprintf(stderr, "failed to allocate argv vector\n");
+ msg(LOG_ERR, "failed to allocate argv vector: %m\n");
free(args);
ret = -ENOMEM;
goto out;
@@ -1311,28 +1498,38 @@ static int discover_from_conf_file(const char *desc, char *argstr,
if (err)
goto free_and_continue;
- if (cfg.persistent && !cfg.keep_alive_tmo)
- cfg.keep_alive_tmo = NVMF_DEF_DISC_TMO;
+ if (!fabrics_cfg.transport || !fabrics_cfg.traddr)
+ goto free_and_continue;
+
+ err = flags = validate_output_format(fabrics_cfg.output_format);
+ if (err < 0)
+ goto free_and_continue;
+ set_discovery_kato(&fabrics_cfg);
- if (traddr_is_hostname(&cfg)) {
- ret = hostname2traddr(&cfg);
+ if (traddr_is_hostname(&fabrics_cfg)) {
+ ret = hostname2traddr(&fabrics_cfg);
if (ret)
goto out;
}
+ if (!fabrics_cfg.trsvcid)
+ discovery_trsvcid(&fabrics_cfg);
+
err = build_options(argstr, BUF_SIZE, true);
if (err) {
ret = err;
goto free_and_continue;
}
- err = do_discover(argstr, connect);
+ err = do_discover(argstr, connect, flags);
if (err)
ret = err;
free_and_continue:
- free(args);
+ free(all_args);
free(argv);
+ fabrics_cfg.transport = fabrics_cfg.traddr =
+ fabrics_cfg.trsvcid = fabrics_cfg.host_traddr = NULL;
}
out:
@@ -1344,59 +1541,78 @@ int fabrics_discover(const char *desc, int argc, char **argv, bool connect)
{
char argstr[BUF_SIZE];
int ret;
+ enum nvme_print_flags flags;
+ bool quiet = false;
OPT_ARGS(opts) = {
- OPT_LIST("transport", 't', &cfg.transport, "transport type"),
- OPT_LIST("traddr", 'a', &cfg.traddr, "transport address"),
- OPT_LIST("trsvcid", 's', &cfg.trsvcid, "transport service id (e.g. IP port)"),
- OPT_LIST("host-traddr", 'w', &cfg.host_traddr, "host traddr (e.g. FC WWN's)"),
- OPT_LIST("hostnqn", 'q', &cfg.hostnqn, "user-defined hostnqn (if default not used)"),
- OPT_LIST("hostid", 'I', &cfg.hostid, "user-defined hostid (if default not used)"),
- OPT_LIST("raw", 'r', &cfg.raw, "raw output file"),
- OPT_LIST("device", 'd', &cfg.device, "use existing discovery controller device"),
- OPT_INT("keep-alive-tmo", 'k', &cfg.keep_alive_tmo, "keep alive timeout period in seconds"),
- OPT_INT("reconnect-delay", 'c', &cfg.reconnect_delay, "reconnect timeout period in seconds"),
- OPT_INT("ctrl-loss-tmo", 'l', &cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"),
- OPT_INT("tos", 'T', &cfg.tos, "type of service"),
- OPT_FLAG("hdr_digest", 'g', &cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"),
- OPT_FLAG("data_digest", 'G', &cfg.data_digest, "enable transport protocol data digest (TCP transport)"),
- OPT_INT("nr-io-queues", 'i', &cfg.nr_io_queues, "number of io queues to use (default is core count)"),
- OPT_INT("nr-write-queues", 'W', &cfg.nr_write_queues, "number of write queues to use (default 0)"),
- OPT_INT("nr-poll-queues", 'P', &cfg.nr_poll_queues, "number of poll queues to use (default 0)"),
- OPT_INT("queue-size", 'Q', &cfg.queue_size, "number of io queue elements to use (default 128)"),
- OPT_FLAG("persistent", 'p', &cfg.persistent, "persistent discovery connection"),
- OPT_FLAG("quiet", 'S', &cfg.quiet, "suppress already connected errors"),
- OPT_FLAG("matching", 'm', &cfg.matching_only, "connect only records matching the traddr"),
+ 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("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"),
+ OPT_LIST("device", 'd', &fabrics_cfg.device, "existing discovery controller device"),
+ 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("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)"),
+ OPT_INT("nr-io-queues", 'i', &fabrics_cfg.nr_io_queues, "number of io queues to use (default is core count)"),
+ OPT_INT("nr-write-queues", 'W', &fabrics_cfg.nr_write_queues, "number of write queues to use (default 0)"),
+ 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("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()
};
- cfg.tos = -1;
+ fabrics_cfg.tos = -1;
ret = argconfig_parse(argc, argv, desc, opts);
if (ret)
goto out;
- if (cfg.device && !strcmp(cfg.device, "none"))
- cfg.device = NULL;
+ ret = flags = validate_output_format(fabrics_cfg.output_format);
+ if (ret < 0)
+ goto out;
+ if (fabrics_cfg.device && strcmp(fabrics_cfg.device, "none")) {
+ fabrics_cfg.device = strdup(fabrics_cfg.device);
+ if (!fabrics_cfg.device) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
- cfg.nqn = NVME_DISC_SUBSYS_NAME;
+ if (quiet)
+ log_level = LOG_WARNING;
- if (!cfg.transport && !cfg.traddr) {
+ if (fabrics_cfg.device && !strcmp(fabrics_cfg.device, "none"))
+ fabrics_cfg.device = NULL;
+
+ fabrics_cfg.nqn = NVME_DISC_SUBSYS_NAME;
+
+ if (!fabrics_cfg.transport && !fabrics_cfg.traddr) {
ret = discover_from_conf_file(desc, argstr, opts, connect);
} else {
- if (cfg.persistent && !cfg.keep_alive_tmo)
- cfg.keep_alive_tmo = NVMF_DEF_DISC_TMO;
+ set_discovery_kato(&fabrics_cfg);
- if (traddr_is_hostname(&cfg)) {
- ret = hostname2traddr(&cfg);
+ if (traddr_is_hostname(&fabrics_cfg)) {
+ ret = hostname2traddr(&fabrics_cfg);
if (ret)
goto out;
}
+ if (!fabrics_cfg.trsvcid)
+ discovery_trsvcid(&fabrics_cfg);
+
ret = build_options(argstr, BUF_SIZE, true);
if (ret)
goto out;
- ret = do_discover(argstr, connect);
+ ret = do_discover(argstr, connect, flags);
}
out:
@@ -1409,35 +1625,35 @@ int fabrics_connect(const char *desc, int argc, char **argv)
int instance, ret;
OPT_ARGS(opts) = {
- OPT_LIST("transport", 't', &cfg.transport, "transport type"),
- OPT_LIST("nqn", 'n', &cfg.nqn, "nqn name"),
- OPT_LIST("traddr", 'a', &cfg.traddr, "transport address"),
- OPT_LIST("trsvcid", 's', &cfg.trsvcid, "transport service id (e.g. IP port)"),
- OPT_LIST("host-traddr", 'w', &cfg.host_traddr, "host traddr (e.g. FC WWN's)"),
- OPT_LIST("hostnqn", 'q', &cfg.hostnqn, "user-defined hostnqn"),
- OPT_LIST("hostid", 'I', &cfg.hostid, "user-defined hostid (if default not used)"),
- OPT_INT("nr-io-queues", 'i', &cfg.nr_io_queues, "number of io queues to use (default is core count)"),
- OPT_INT("nr-write-queues", 'W', &cfg.nr_write_queues, "number of write queues to use (default 0)"),
- OPT_INT("nr-poll-queues", 'P', &cfg.nr_poll_queues, "number of poll queues to use (default 0)"),
- OPT_INT("queue-size", 'Q', &cfg.queue_size, "number of io queue elements to use (default 128)"),
- OPT_INT("keep-alive-tmo", 'k', &cfg.keep_alive_tmo, "keep alive timeout period in seconds"),
- OPT_INT("reconnect-delay", 'c', &cfg.reconnect_delay, "reconnect timeout period in seconds"),
- OPT_INT("ctrl-loss-tmo", 'l', &cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"),
- OPT_INT("tos", 'T', &cfg.tos, "type of service"),
- OPT_FLAG("duplicate-connect", 'D', &cfg.duplicate_connect, "allow duplicate connections between same transport host and subsystem port"),
- OPT_FLAG("disable-sqflow", 'd', &cfg.disable_sqflow, "disable controller sq flow control (default false)"),
- OPT_FLAG("hdr-digest", 'g', &cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"),
- OPT_FLAG("data-digest", 'G', &cfg.data_digest, "enable transport protocol data digest (TCP transport)"),
+ 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("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)"),
+ OPT_INT("nr-write-queues", 'W', &fabrics_cfg.nr_write_queues, "number of write queues to use (default 0)"),
+ 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_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("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_END()
};
- cfg.tos = -1;
+ fabrics_cfg.tos = -1;
ret = argconfig_parse(argc, argv, desc, opts);
if (ret)
goto out;
- if (traddr_is_hostname(&cfg)) {
- ret = hostname2traddr(&cfg);
+ if (traddr_is_hostname(&fabrics_cfg)) {
+ ret = hostname2traddr(&fabrics_cfg);
if (ret)
goto out;
}
@@ -1446,8 +1662,8 @@ int fabrics_connect(const char *desc, int argc, char **argv)
if (ret)
goto out;
- if (!cfg.nqn) {
- fprintf(stderr, "need a -n argument\n");
+ if (!fabrics_cfg.nqn) {
+ msg(LOG_ERR, "need a -n argument\n");
ret = -EINVAL;
goto out;
}
@@ -1472,7 +1688,7 @@ static int scan_sys_nvme_filter(const struct dirent *d)
/*
* Returns 1 if disconnect occurred, 0 otherwise.
*/
-static int disconnect_subsys(char *nqn, char *ctrl)
+static int disconnect_subsys(const char *nqn, char *ctrl)
{
char *sysfs_nqn_path = NULL, *sysfs_del_path = NULL;
char subsysnqn[NVMF_NQN_SIZE] = {};
@@ -1485,7 +1701,7 @@ static int disconnect_subsys(char *nqn, char *ctrl)
fd = open(sysfs_nqn_path, O_RDONLY);
if (fd < 0) {
- fprintf(stderr, "Failed to open %s: %s\n",
+ msg(LOG_ERR, "Failed to open %s: %s\n",
sysfs_nqn_path, strerror(errno));
goto free;
}
@@ -1510,7 +1726,7 @@ static int disconnect_subsys(char *nqn, char *ctrl)
/*
* Returns the number of controllers successfully disconnected.
*/
-static int disconnect_by_nqn(char *nqn)
+static int disconnect_by_nqn(const char *nqn)
{
struct dirent **devices = NULL;
int i, n, ret = 0;
@@ -1532,7 +1748,7 @@ static int disconnect_by_nqn(char *nqn)
return ret;
}
-static int disconnect_by_device(char *device)
+static int disconnect_by_device(const char *device)
{
int instance;
@@ -1549,8 +1765,8 @@ int fabrics_disconnect(const char *desc, int argc, char **argv)
int ret;
OPT_ARGS(opts) = {
- OPT_LIST("nqn", 'n', &cfg.nqn, nqn),
- OPT_LIST("device", 'd', &cfg.device, device),
+ OPT_LIST("nqn", 'n', &fabrics_cfg.nqn, nqn),
+ OPT_LIST("device", 'd', &fabrics_cfg.device, device),
OPT_END()
};
@@ -1558,29 +1774,29 @@ int fabrics_disconnect(const char *desc, int argc, char **argv)
if (ret)
goto out;
- if (!cfg.nqn && !cfg.device) {
- fprintf(stderr, "need a -n or -d argument\n");
+ if (!fabrics_cfg.nqn && !fabrics_cfg.device) {
+ msg(LOG_ERR, "need a -n or -d argument\n");
ret = -EINVAL;
goto out;
}
- if (cfg.nqn) {
- ret = disconnect_by_nqn(cfg.nqn);
+ if (fabrics_cfg.nqn) {
+ ret = disconnect_by_nqn(fabrics_cfg.nqn);
if (ret < 0)
- fprintf(stderr, "Failed to disconnect by NQN: %s\n",
- cfg.nqn);
+ msg(LOG_ERR, "Failed to disconnect by NQN: %s\n",
+ fabrics_cfg.nqn);
else {
- printf("NQN:%s disconnected %d controller(s)\n", cfg.nqn, ret);
+ printf("NQN:%s disconnected %d controller(s)\n", fabrics_cfg.nqn, ret);
ret = 0;
}
}
- if (cfg.device) {
- ret = disconnect_by_device(cfg.device);
+ if (fabrics_cfg.device) {
+ ret = disconnect_by_device(fabrics_cfg.device);
if (ret)
- fprintf(stderr,
+ msg(LOG_ERR,
"Failed to disconnect by device name: %s\n",
- cfg.device);
+ fabrics_cfg.device);
}
out:
@@ -1600,9 +1816,9 @@ int fabrics_disconnect_all(const char *desc, int argc, char **argv)
if (err)
goto out;
- err = scan_subsystems(&t, NULL, 0);
+ err = scan_subsystems(&t, NULL, 0, 0, NULL);
if (err) {
- fprintf(stderr, "Failed to scan namespaces\n");
+ msg(LOG_ERR, "Failed to scan namespaces\n");
goto out;
}
@@ -1612,7 +1828,7 @@ int fabrics_disconnect_all(const char *desc, int argc, char **argv)
for (j = 0; j < s->nr_ctrls; j++) {
struct nvme_ctrl *c = &s->ctrls[j];
- if (!strcmp(c->transport, "pcie"))
+ if (!c->transport || !strcmp(c->transport, "pcie"))
continue;
err = disconnect_by_device(c->name);
if (err)
diff --git a/fabrics.h b/fabrics.h
index f5b8eaf..41e6a2d 100644
--- a/fabrics.h
+++ b/fabrics.h
@@ -10,4 +10,46 @@ extern int fabrics_connect(const char *desc, int argc, char **argv);
extern int fabrics_disconnect(const char *desc, int argc, char **argv);
extern int fabrics_disconnect_all(const char *desc, int argc, char **argv);
+/* Symbols used by monitor.c */
+
+const char *arg_str(const char * const *strings, size_t array_size, size_t idx);
+
+struct fabrics_config {
+ const char *nqn;
+ const char *transport;
+ const char *traddr;
+ const char *trsvcid;
+ const char *host_traddr;
+ const char *hostnqn;
+ const char *hostid;
+ int nr_io_queues;
+ int nr_write_queues;
+ int nr_poll_queues;
+ int queue_size;
+ int keep_alive_tmo;
+ int reconnect_delay;
+ int ctrl_loss_tmo;
+ int tos;
+ const char *raw;
+ char *device;
+ int duplicate_connect;
+ int disable_sqflow;
+ int hdr_digest;
+ int data_digest;
+ bool persistent;
+ bool matching_only;
+ const char *output_format;
+};
+extern struct fabrics_config fabrics_cfg;
+
+extern const char *const trtypes[];
+
+#define BUF_SIZE 4096
+
+int build_options(char *argstr, int max_len, bool discover);
+int do_discover(char *argstr, bool connect, enum nvme_print_flags flags);
+int ctrl_instance(const char *device);
+char *parse_conn_arg(const char *conargs, const char delim, const char *field);
+int remove_ctrl(int instance);
+
#endif
diff --git a/linux/nvme.h b/linux/nvme.h
index f2c4fdb..4ad09ee 100644
--- a/linux/nvme.h
+++ b/linux/nvme.h
@@ -70,6 +70,7 @@ static inline uint64_t le64_to_cpu(__le64 x)
#define NVME_DISC_SUBSYS_NAME "nqn.2014-08.org.nvmexpress.discovery"
#define NVME_RDMA_IP_PORT 4420
+#define NVME_DISC_IP_PORT 8009
#define NVME_NSID_ALL 0xffffffff
@@ -139,6 +140,13 @@ enum {
NVMF_TCP_SECTYPE_TLS = 1, /* Transport Layer Security */
};
+/* I/O Command Sets
+ */
+enum {
+ NVME_IOCS_NVM = 0x00,
+ NVME_IOCS_ZONED = 0x02,
+};
+
#define NVME_AQ_DEPTH 32
#define NVME_NR_AEN_COMMANDS 1
#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
@@ -172,7 +180,8 @@ enum {
NVME_REG_PMRSTS = 0x0e08, /* Persistent Memory Region Status */
NVME_REG_PMREBS = 0x0e0c, /* Persistent Memory Region Elasticity Buffer Size */
NVME_REG_PMRSWTP= 0x0e10, /* Persistent Memory Region Sustained Write Throughput */
- NVME_REG_PMRMSC = 0x0e14, /* Persistent Memory Region Controller Memory Space Control */
+ NVME_REG_PMRMSCL= 0x0e14, /* Persistent Memory Region Controller Memory Space Control Lower */
+ NVME_REG_PMRMSCU= 0x0e18, /* Persistent Memory Region Controller Memory Space Control Upper*/
NVME_REG_DBS = 0x1000, /* SQ 0 Tail Doorbell */
};
@@ -325,7 +334,7 @@ struct nvme_id_ctrl {
__u8 vwc;
__le16 awun;
__le16 awupf;
- __u8 nvscc;
+ __u8 icsvscc;
__u8 nwpc;
__le16 acwu;
__u8 rsvd534[2];
@@ -337,9 +346,10 @@ struct nvme_id_ctrl {
__le32 ioccsz;
__le32 iorcsz;
__le16 icdoff;
- __u8 ctrattr;
+ __u8 fcatt;
__u8 msdbd;
- __u8 rsvd1804[244];
+ __le16 ofcs;
+ __u8 rsvd1806[242];
struct nvme_id_power_state psd[32];
__u8 vs[1024];
};
@@ -398,7 +408,10 @@ struct nvme_id_ns {
__le16 npdg;
__le16 npda;
__le16 nows;
- __u8 rsvd74[18];
+ __le16 mssrl;
+ __le32 mcl;
+ __u8 msrc;
+ __u8 rsvd81[11];
__le32 anagrpid;
__u8 rsvd96[3];
__u8 nsattr;
@@ -411,19 +424,30 @@ struct nvme_id_ns {
__u8 vs[3712];
};
+struct nvme_id_iocs {
+ __le64 iocs[512];
+};
+
enum {
NVME_ID_CNS_NS = 0x00,
NVME_ID_CNS_CTRL = 0x01,
NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
NVME_ID_CNS_NS_DESC_LIST = 0x03,
NVME_ID_CNS_NVMSET_LIST = 0x04,
+ NVME_ID_CNS_CSI_ID_NS = 0x05,
+ NVME_ID_CNS_CSI_ID_CTRL = 0x06,
+ NVME_ID_CNS_CSI_NS_ACTIVE_LIST = 0x07,
NVME_ID_CNS_NS_PRESENT_LIST = 0x10,
NVME_ID_CNS_NS_PRESENT = 0x11,
NVME_ID_CNS_CTRL_NS_LIST = 0x12,
NVME_ID_CNS_CTRL_LIST = 0x13,
+ NVME_ID_CNS_PRIMARY_CTRL_CAPS = 0x14,
NVME_ID_CNS_SCNDRY_CTRL_LIST = 0x15,
NVME_ID_CNS_NS_GRANULARITY = 0x16,
NVME_ID_CNS_UUID_LIST = 0x17,
+ NVME_ID_CNS_CSI_NS_PRESENT_LIST = 0x1a,
+ NVME_ID_CNS_CSI_NS_PRESENT = 0x1b,
+ NVME_ID_CNS_CSI = 0x1c,
};
enum {
@@ -468,11 +492,13 @@ struct nvme_ns_id_desc {
#define NVME_NIDT_EUI64_LEN 8
#define NVME_NIDT_NGUID_LEN 16
#define NVME_NIDT_UUID_LEN 16
+#define NVME_NIDT_CSI_LEN 1
enum {
NVME_NIDT_EUI64 = 0x01,
NVME_NIDT_NGUID = 0x02,
NVME_NIDT_UUID = 0x03,
+ NVME_NIDT_CSI = 0x04,
};
#define NVME_MAX_NVMSET 31
@@ -627,12 +653,14 @@ enum {
NVME_ST_VALID_SCT = 1 << 2,
NVME_ST_VALID_SC = 1 << 3,
NVME_ST_REPORTS = 20,
+ NVME_ST_LOG_ENTRY_SIZE = 28,
+ NVME_ST_LOG_HEAD_SIZE = 4,
};
struct nvme_self_test_log {
__u8 crnt_dev_selftest_oprn;
__u8 crnt_dev_selftest_compln;
- __u8 rsvd[2];
+ __u8 rsvd2[2];
struct nvme_self_test_res result[20];
} __attribute__((packed));
@@ -714,6 +742,209 @@ struct nvme_ana_rsp_hdr {
__le16 rsvd10[3];
};
+/* persistent event type 02h */
+struct nvme_fw_commit_event {
+ __le64 old_fw_rev;
+ __le64 new_fw_rev;
+ __u8 fw_commit_action;
+ __u8 fw_slot;
+ __u8 sct_fw;
+ __u8 sc_fw;
+ __le16 vndr_assign_fw_commit_rc;
+} __attribute__((packed));
+
+/* persistent event type 03h */
+struct nvme_time_stamp_change_event {
+ __le64 previous_timestamp;
+ __le64 ml_secs_since_reset;
+};
+
+/* persistent event type 04h */
+struct nvme_power_on_reset_info_list {
+ __le16 cid;
+ __u8 fw_act;
+ __u8 op_in_prog;
+ __u8 rsvd4[12];
+ __le32 ctrl_power_cycle;
+ __le64 power_on_ml_seconds;
+ __le64 ctrl_time_stamp;
+} __attribute__((packed));
+
+/* persistent event type 05h */
+struct nvme_nss_hw_err_event {
+ __le16 nss_hw_err_event_code;
+ __u8 rsvd2[2];
+ __u8 *add_hw_err_info;
+};
+
+/* persistent event type 06h */
+struct nvme_change_ns_event {
+ __le32 nsmgt_cdw10;
+ __u8 rsvd4[4];
+ __le64 nsze;
+ __u8 rsvd16[8];
+ __le64 nscap;
+ __u8 flbas;
+ __u8 dps;
+ __u8 nmic;
+ __u8 rsvd35;
+ __le32 ana_grp_id;
+ __le16 nvmset_id;
+ __le16 rsvd42;
+ __le32 nsid;
+};
+
+/* persistent event type 07h */
+struct nvme_format_nvm_start_event {
+ __le32 nsid;
+ __u8 fna;
+ __u8 rsvd5[3];
+ __le32 format_nvm_cdw10;
+};
+
+/* persistent event type 08h */
+struct nvme_format_nvm_compln_event {
+ __le32 nsid;
+ __u8 smallest_fpi;
+ __u8 format_nvm_status;
+ __le16 compln_info;
+ __le32 status_field;
+};
+
+/* persistent event type 09h */
+struct nvme_sanitize_start_event {
+ __le32 sani_cap;
+ __le32 sani_cdw10;
+ __le32 sani_cdw11;
+};
+
+/* persistent event type 0Ah */
+struct nvme_sanitize_compln_event {
+ __le16 sani_prog;
+ __le16 sani_status;
+ __le16 cmpln_info;
+ __u8 rsvd6[2];
+};
+
+/* persistent event type 0Dh */
+struct nvme_thermal_exc_event {
+ __u8 over_temp;
+ __u8 threshold;
+};
+
+/* persistent event entry head */
+struct nvme_persistent_event_entry_head {
+ __u8 etype;
+ __u8 etype_rev;
+ __u8 ehl;
+ __u8 rsvd3;
+ __le16 ctrl_id;
+ __le64 etimestamp;
+ __u8 rsvd14[6];
+ __le16 vsil;
+ __le16 el;
+} __attribute__((packed));
+
+/* persistent event log head */
+struct nvme_persistent_event_log_head {
+ __u8 log_id;
+ __u8 rsvd1[3];
+ __le32 tnev;
+ __le64 tll;
+ __u8 log_rev;
+ __u8 rsvd17;
+ __le16 head_len;
+ __le64 timestamp;
+ __u8 poh[16];
+ __le64 pcc;
+ __le16 vid;
+ __le16 ssvid;
+ __u8 sn[20];
+ __u8 mn[40];
+ __u8 subnqn[256];
+ __u8 rsvd372[108];
+ __u8 supp_event_bm[32];
+} __attribute__((packed));
+
+enum nvme_persistent_event_types {
+ NVME_SMART_HEALTH_EVENT = 0x01,
+ NVME_FW_COMMIT_EVENT = 0x02,
+ NVME_TIMESTAMP_EVENT = 0x03,
+ NVME_POWER_ON_RESET_EVENT = 0x04,
+ NVME_NSS_HW_ERROR_EVENT = 0x05,
+ NVME_CHANGE_NS_EVENT = 0x06,
+ NVME_FORMAT_START_EVENT = 0x07,
+ NVME_FORMAT_COMPLETION_EVENT = 0x08,
+ NVME_SANITIZE_START_EVENT = 0x09,
+ NVME_SANITIZE_COMPLETION_EVENT = 0x0a,
+ NVME_THERMAL_EXCURSION_EVENT = 0x0d
+};
+
+enum nvme_persistent_event_log_actions {
+ NVME_PEVENT_LOG_READ = 0x0,
+ NVME_PEVENT_LOG_EST_CTX_AND_READ = 0x1,
+ NVME_PEVENT_LOG_RELEASE_CTX = 0x2,
+};
+
+/**
+ * struct nvme_event_agg_log_page - is common for both
+ * predictable latency event aggregate log and endurance
+ * group event aggregate log
+ * @num_entries: indicates the number of entries in the list.
+ * @entries: indicates NVMSET ID or ENDURANCE Group ID entries
+ */
+struct nvme_event_agg_log_page {
+ __le64 num_entries;
+ __le16 entries[];
+};
+
+struct nvme_predlat_per_nvmset_log_page {
+ __u8 status;
+ __u8 rsvd1;
+ __le16 event_type;
+ __u8 rsvd4[28];
+ __le64 dtwin_rtyp;
+ __le64 dtwin_wtyp;
+ __le64 dtwin_timemax;
+ __le64 ndwin_timemin_high;
+ __le64 ndwin_timemin_low;
+ __u8 rsvd72[56];
+ __le64 dtwin_restimate;
+ __le64 dtwin_westimate;
+ __le64 dtwin_testimate;
+ __u8 rsvd152[360];
+};
+
+struct nvme_lba_status_range_desc {
+ __le64 rslba;
+ __le32 rnlb;
+ __u8 rsvd12[4];
+};
+
+struct nvme_lba_status_ns_element {
+ __le32 neid;
+ __le32 nlrd;
+ __u8 ratype;
+ __u8 rsvd9[7];
+};
+
+struct nvme_lba_status_hdr {
+ __le32 lslplen;
+ __le32 nlslne;
+ __le32 estulb;
+ __u8 rsvd12[2];
+ __le16 lsgc;
+};
+
+struct nvme_resv_notif_log {
+ __le64 log_page_count;
+ __u8 resv_notif_log_type;
+ __u8 num_logs;
+ __u8 rsvd10[2];
+ __le32 nsid;
+ __u8 rsvd16[48];
+};
+
enum {
NVME_SMART_CRIT_SPARE = 1 << 0,
NVME_SMART_CRIT_TEMPERATURE = 1 << 1,
@@ -814,6 +1045,10 @@ enum nvme_opcode {
nvme_cmd_resv_report = 0x0e,
nvme_cmd_resv_acquire = 0x11,
nvme_cmd_resv_release = 0x15,
+ nvme_cmd_copy = 0x19,
+ nvme_zns_cmd_mgmt_send = 0x79,
+ nvme_zns_cmd_mgmt_recv = 0x7a,
+ nvme_zns_cmd_append = 0x7d,
};
/*
@@ -919,6 +1154,7 @@ enum {
NVME_RW_DSM_LATENCY_LOW = 3 << 4,
NVME_RW_DSM_SEQ_REQ = 1 << 6,
NVME_RW_DSM_COMPRESSED = 1 << 7,
+ NVME_RW_PIREMAP = 1 << 9,
NVME_RW_PRINFO_PRCHK_REF = 1 << 10,
NVME_RW_PRINFO_PRCHK_APP = 1 << 11,
NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12,
@@ -940,6 +1176,16 @@ struct nvme_dsm_range {
__le64 slba;
};
+struct nvme_copy_range {
+ __u8 rsvd0[8];
+ __le64 slba;
+ __le16 nlb;
+ __u8 rsvd18[6];
+ __le32 eilbrt;
+ __le16 elbatm;
+ __le16 elbat;
+};
+
/* Features */
struct nvme_feat_auto_pst {
__le64 entries[32];
@@ -989,6 +1235,32 @@ enum {
NVME_SQ_PRIO_HIGH = (1 << 1),
NVME_SQ_PRIO_MEDIUM = (2 << 1),
NVME_SQ_PRIO_LOW = (3 << 1),
+ NVME_LOG_ERROR = 0x01,
+ NVME_LOG_SMART = 0x02,
+ NVME_LOG_FW_SLOT = 0x03,
+ NVME_LOG_CHANGED_NS = 0x04,
+ NVME_LOG_CMD_EFFECTS = 0x05,
+ NVME_LOG_DEVICE_SELF_TEST = 0x06,
+ NVME_LOG_TELEMETRY_HOST = 0x07,
+ NVME_LOG_TELEMETRY_CTRL = 0x08,
+ NVME_LOG_ENDURANCE_GROUP = 0x09,
+ NVME_LOG_PRELAT_PER_NVMSET = 0x0a,
+ NVME_LOG_ANA = 0x0c,
+ NVME_LOG_PRELAT_EVENT_AGG = 0x0b,
+ NVME_LOG_PERSISTENT_EVENT = 0x0d,
+ NVME_LOG_LBA_STATUS = 0x0e,
+ NVME_LOG_ENDURANCE_GROUP_EVENT_AGG = 0x0f,
+ NVME_LOG_DISC = 0x70,
+ NVME_LOG_RESERVATION = 0x80,
+ NVME_LOG_SANITIZE = 0x81,
+ NVME_LOG_ZONE_CHANGED_LIST = 0xbf,
+ NVME_FWACT_REPL = (0 << 3),
+ NVME_FWACT_REPL_ACTV = (1 << 3),
+ NVME_FWACT_ACTV = (2 << 3),
+};
+
+enum nvme_feat {
+ NVME_FEAT_NONE = 0x0,
NVME_FEAT_ARBITRATION = 0x01,
NVME_FEAT_POWER_MGMT = 0x02,
NVME_FEAT_LBA_RANGE = 0x03,
@@ -1009,30 +1281,17 @@ enum {
NVME_FEAT_RRL = 0x12,
NVME_FEAT_PLM_CONFIG = 0x13,
NVME_FEAT_PLM_WINDOW = 0x14,
+ NVME_LBA_STATUS_INFO = 0x15,
NVME_FEAT_HOST_BEHAVIOR = 0x16,
NVME_FEAT_SANITIZE = 0x17,
+ 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_LOG_ERROR = 0x01,
- NVME_LOG_SMART = 0x02,
- NVME_LOG_FW_SLOT = 0x03,
- NVME_LOG_CHANGED_NS = 0x04,
- NVME_LOG_CMD_EFFECTS = 0x05,
- NVME_LOG_DEVICE_SELF_TEST = 0x06,
- NVME_LOG_TELEMETRY_HOST = 0x07,
- NVME_LOG_TELEMETRY_CTRL = 0x08,
- NVME_LOG_ENDURANCE_GROUP = 0x09,
- NVME_LOG_ANA = 0x0c,
- NVME_LOG_DISC = 0x70,
- NVME_LOG_RESERVATION = 0x80,
- NVME_LOG_SANITIZE = 0x81,
- NVME_FWACT_REPL = (0 << 3),
- NVME_FWACT_REPL_ACTV = (1 << 3),
- NVME_FWACT_ACTV = (2 << 3),
-};
+} __attribute__ ((__packed__));
enum {
NVME_NO_LOG_LSP = 0x0,
@@ -1084,6 +1343,7 @@ struct nvme_sanitize_log_page {
__le32 est_ovrwrt_time_with_no_deallocate;
__le32 est_blk_erase_time_with_no_deallocate;
__le32 est_crypto_erase_time_with_no_deallocate;
+ __u8 rsvd32[480];
};
/*
@@ -1224,6 +1484,27 @@ struct nvme_controller_list {
__le16 identifier[2047];
};
+struct nvme_primary_ctrl_caps {
+ __le16 cntlid; /* Controller Identifier */
+ __le16 portid; /* Port Identifier */
+ __u8 crt; /* Controller Resource Types */
+ __u8 rsvd5[27];
+ __le32 vqfrt; /* VQ Resources Flexible Total */
+ __le32 vqrfa; /* VQ Resources Flexible Assigned */
+ __le16 vqrfap; /* VQ Resources Flexible Allocated to Primary */
+ __le16 vqprt; /* VQ Resources Private Total */
+ __le16 vqfrsm; /* VQ Resources Flexible Secondary Maximum */
+ __le16 vqgran; /* VQ Flexible Resource Preferred Granularity */
+ __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 */
+ __u8 rsvd80[4016];
+};
+
struct nvme_secondary_controller_entry {
__le16 scid; /* Secondary Controller Identifier */
__le16 pcid; /* Primary Controller Identifier */
@@ -1277,6 +1558,7 @@ enum {
NVME_SCT_GENERIC = 0x0,
NVME_SCT_CMD_SPECIFIC = 0x1,
NVME_SCT_MEDIA = 0x2,
+ NVME_SCT_PATH = 0x3,
};
enum {
@@ -1316,7 +1598,7 @@ enum {
NVME_SC_NS_WRITE_PROTECTED = 0x20,
NVME_SC_CMD_INTERRUPTED = 0x21,
- NVME_SC_TRANSIENT_TRANSPORT = 0x22,
+ NVME_SC_TRANSIENT_TRANSPORT = 0x22,
NVME_SC_LBA_RANGE = 0x80,
NVME_SC_CAP_EXCEEDED = 0x81,
@@ -1366,12 +1648,20 @@ enum {
NVME_SC_ANA_ATTACH_FAIL = 0x125,
/*
+ * Command Set Specific - Namespace Types commands:
+ */
+ NVME_SC_IOCS_NOT_SUPPORTED = 0x129,
+ NVME_SC_IOCS_NOT_ENABLED = 0x12A,
+ NVME_SC_IOCS_COMBINATION_REJECTED = 0x12B,
+ NVME_SC_INVALID_IOCS = 0x12C,
+
+ /*
* I/O Command Set Specific - NVM commands:
*/
NVME_SC_BAD_ATTRIBUTES = 0x180,
NVME_SC_INVALID_PI = 0x181,
NVME_SC_READ_ONLY = 0x182,
- NVME_SC_ONCS_NOT_SUPPORTED = 0x183,
+ NVME_SC_CMD_SIZE_LIMIT_EXCEEDED = 0x183,
/*
* I/O Command Set Specific - Fabrics commands:
@@ -1386,6 +1676,18 @@ enum {
NVME_SC_AUTH_REQUIRED = 0x191,
/*
+ * I/O Command Set Specific - Zoned Namespace commands:
+ */
+ NVME_SC_ZONE_BOUNDARY_ERROR = 0x1B8,
+ NVME_SC_ZONE_IS_FULL = 0x1B9,
+ NVME_SC_ZONE_IS_READ_ONLY = 0x1BA,
+ NVME_SC_ZONE_IS_OFFLINE = 0x1BB,
+ NVME_SC_ZONE_INVALID_WRITE = 0x1BC,
+ NVME_SC_TOO_MANY_ACTIVE_ZONES = 0x1BD,
+ NVME_SC_TOO_MANY_OPEN_ZONES = 0x1BE,
+ NVME_SC_ZONE_INVALID_STATE_TRANSITION = 0x1BF,
+
+ /*
* Media and Data Integrity Errors:
*/
NVME_SC_WRITE_FAULT = 0x280,
@@ -1400,10 +1702,22 @@ enum {
/*
* Path-related Errors:
*/
+ NVME_SC_INTERNAL_PATH_ERROR = 0x300,
NVME_SC_ANA_PERSISTENT_LOSS = 0x301,
NVME_SC_ANA_INACCESSIBLE = 0x302,
NVME_SC_ANA_TRANSITION = 0x303,
+ /*
+ * Controller Detected Path errors
+ */
+ NVME_SC_CTRL_PATHING_ERROR = 0x360,
+
+ /*
+ * Host Detected Path Errors
+ */
+ NVME_SC_HOST_PATHING_ERROR = 0x370,
+ NVME_SC_HOST_CMD_ABORT = 0x371,
+
NVME_SC_CRD = 0x1800,
NVME_SC_DNR = 0x4000,
};
@@ -1415,4 +1729,149 @@ enum {
#define NVME_MINOR(ver) (((ver) >> 8) & 0xff)
#define NVME_TERTIARY(ver) ((ver) & 0xff)
+
+/**
+ * struct nvme_zns_lbafe -
+ * zsze:
+ * zdes:
+ */
+struct nvme_zns_lbafe {
+ __le64 zsze;
+ __u8 zdes;
+ __u8 rsvd9[7];
+};
+
+/**
+ * struct nvme_zns_id_ns -
+ * @zoc:
+ * @ozcs:
+ * @mar:
+ * @mor:
+ * @rrl:
+ * @frl:
+ * @lbafe:
+ * @vs:
+ */
+struct nvme_zns_id_ns {
+ __le16 zoc;
+ __le16 ozcs;
+ __le32 mar;
+ __le32 mor;
+ __le32 rrl;
+ __le32 frl;
+ __u8 rsvd20[2796];
+ struct nvme_zns_lbafe lbafe[16];
+ __u8 rsvd3072[768];
+ __u8 vs[256];
+};
+
+struct nvme_id_ctrl_nvm {
+ __u8 vsl;
+ __u8 wzsl;
+ __u8 wusl;
+ __u8 dmrl;
+ __u32 dmrsl;
+ __u64 dmsl;
+ __u8 rsvd16[4080];
+};
+
+/**
+ * struct nvme_zns_id_ctrl -
+ * @zasl:
+ */
+struct nvme_zns_id_ctrl {
+ __u8 zasl;
+ __u8 rsvd1[4095];
+};
+
+#define NVME_ZNS_CHANGED_ZONES_MAX 511
+
+/**
+ * struct nvme_zns_changed_zone_log - ZNS Changed Zone List log
+ * @nrzid:
+ * @zid:
+ */
+struct nvme_zns_changed_zone_log {
+ __le16 nrzid;
+ __u8 rsvd2[6];
+ __le64 zid[NVME_ZNS_CHANGED_ZONES_MAX];
+};
+
+/**
+ * enum nvme_zns_zt -
+ */
+enum nvme_zns_zt {
+ NVME_ZONE_TYPE_SEQWRITE_REQ = 0x2,
+};
+
+/**
+ * enum nvme_zns_za -
+ */
+enum nvme_zns_za {
+ NVME_ZNS_ZA_ZFC = 1 << 0,
+ NVME_ZNS_ZA_FZR = 1 << 1,
+ NVME_ZNS_ZA_RZR = 1 << 2,
+ NVME_ZNS_ZA_ZDEV = 1 << 7,
+};
+
+/**
+ * enum nvme_zns_zs -
+ */
+enum nvme_zns_zs {
+ NVME_ZNS_ZS_EMPTY = 0x1,
+ NVME_ZNS_ZS_IMPL_OPEN = 0x2,
+ NVME_ZNS_ZS_EXPL_OPEN = 0x3,
+ NVME_ZNS_ZS_CLOSED = 0x4,
+ NVME_ZNS_ZS_READ_ONLY = 0xd,
+ NVME_ZNS_ZS_FULL = 0xe,
+ NVME_ZNS_ZS_OFFLINE = 0xf,
+};
+
+/**
+ * struct nvme_zns_desc -
+ */
+struct nvme_zns_desc {
+ __u8 zt;
+ __u8 zs;
+ __u8 za;
+ __u8 rsvd3[5];
+ __le64 zcap;
+ __le64 zslba;
+ __le64 wp;
+ __u8 rsvd32[32];
+};
+
+/**
+ * struct nvme_zone_report -
+ */
+struct nvme_zone_report {
+ __le64 nr_zones;
+ __u8 resv8[56];
+ struct nvme_zns_desc entries[];
+};
+
+enum nvme_zns_send_action {
+ NVME_ZNS_ZSA_CLOSE = 0x1,
+ NVME_ZNS_ZSA_FINISH = 0x2,
+ NVME_ZNS_ZSA_OPEN = 0x3,
+ NVME_ZNS_ZSA_RESET = 0x4,
+ NVME_ZNS_ZSA_OFFLINE = 0x5,
+ NVME_ZNS_ZSA_SET_DESC_EXT = 0x10,
+};
+
+enum nvme_zns_recv_action {
+ NVME_ZNS_ZRA_REPORT_ZONES = 0x0,
+ NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES = 0x1,
+};
+
+enum nvme_zns_report_options {
+ NVME_ZNS_ZRAS_REPORT_ALL = 0x0,
+ NVME_ZNS_ZRAS_REPORT_EMPTY = 0x1,
+ NVME_ZNS_ZRAS_REPORT_IMPL_OPENED = 0x2,
+ NVME_ZNS_ZRAS_REPORT_EXPL_OPENED = 0x3,
+ NVME_ZNS_ZRAS_REPORT_CLOSED = 0x4,
+ NVME_ZNS_ZRAS_REPORT_FULL = 0x5,
+ NVME_ZNS_ZRAS_REPORT_READ_ONLY = 0x6,
+ NVME_ZNS_ZRAS_REPORT_OFFLINE = 0x7,
+};
#endif /* _LINUX_NVME_H */
diff --git a/nvme-builtin.h b/nvme-builtin.h
index bfb907d..a413d00 100644
--- a/nvme-builtin.h
+++ b/nvme-builtin.h
@@ -14,10 +14,13 @@ COMMAND_LIST(
ENTRY("id-ns-granularity", "Send NVMe Identify Namespace Granularity List, display structure", id_ns_granularity)
ENTRY("list-ns", "Send NVMe Identify List, display structure", list_ns)
ENTRY("list-ctrl", "Send NVMe Identify Controller List, display structure", list_ctrl)
+ ENTRY("nvm-id-ctrl", "Send NVMe Identify Controller NVM Command Set, display structure", nvm_id_ctrl)
+ ENTRY("primary-ctrl-caps", "Send NVMe Identify Primary Controller Capabilities", primary_ctrl_caps)
ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl)
ENTRY("ns-descs", "Send NVMe Namespace Descriptor List, display structure", ns_descs)
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("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)
@@ -32,6 +35,12 @@ COMMAND_LIST(
ENTRY("error-log", "Retrieve Error Log, show it", get_error_log)
ENTRY("effects-log", "Retrieve Command Effects Log, show it", get_effects_log)
ENTRY("endurance-log", "Retrieve Endurance Group Log, show it", get_endurance_log)
+ ENTRY("predictable-lat-log", "Retrieve Predictable Latency per Nvmset Log, show it", get_pred_lat_per_nvmset_log)
+ ENTRY("pred-lat-event-agg-log", "Retrieve Predictable Latency Event Aggregate Log, show it", get_pred_lat_event_agg_log)
+ ENTRY("persistent-event-log", "Retrieve Presistent Event Log, show it", get_persistent_event_log)
+ ENTRY("endurance-event-agg-log", "Retrieve Endurance Group Event Aggregate Log, show it", get_endurance_event_agg_log)
+ ENTRY("lba-status-log", "Retrieve LBA Status Information Log, show it", get_lba_status_log)
+ ENTRY("resv-notif-log", "Retrieve Reservation Notification Log, show it", get_resv_notif_log)
ENTRY("get-feature", "Get feature and show the resulting value", get_feature)
ENTRY("device-self-test", "Perform the necessary tests to observe the performance", device_self_test)
ENTRY("self-test-log", "Retrieve the SELF-TEST Log, show it", self_test_log)
@@ -51,6 +60,7 @@ COMMAND_LIST(
ENTRY("resv-release", "Submit a Reservation Release, return results", resv_release)
ENTRY("resv-report", "Submit a Reservation Report, return results", resv_report)
ENTRY("dsm", "Submit a Data Set Management command, return results", dsm)
+ ENTRY("copy", "Submit a Simple Copy command, return results", copy)
ENTRY("flush", "Submit a Flush command, return results", flush)
ENTRY("compare", "Submit a Compare command, return results", compare)
ENTRY("read", "Submit a read command, return results", read_cmd)
@@ -74,6 +84,7 @@ COMMAND_LIST(
ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive)
ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send)
ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller ", virtual_mgmt)
+ ENTRY("rpmb", "Replay Protection Memory Block commands", rpmb_cmd)
);
#endif
diff --git a/nvme-filters.c b/nvme-filters.c
index a4133f8..17c375f 100644
--- a/nvme-filters.c
+++ b/nvme-filters.c
@@ -7,6 +7,22 @@
/* global, used for controller specific namespace filter */
int current_index;
+int scan_ctrl_namespace_filter(const struct dirent *d)
+{
+ int c, i, n;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme")) {
+ if (sscanf(d->d_name, "nvme%dc%dn%d", &i, &c, &n) == 3)
+ return 1;
+ if (sscanf(d->d_name, "nvme%dn%d", &i, &n) == 2)
+ return 1;
+ }
+ return 0;
+}
+
int scan_namespace_filter(const struct dirent *d)
{
int i, n;
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
index 39685d6..2801075 100644
--- a/nvme-ioctl.c
+++ b/nvme-ioctl.c
@@ -145,30 +145,6 @@ int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
}
-int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
- __u32 reftag, __u16 apptag, __u16 appmask, void *data,
- void *metadata)
-{
- return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
- reftag, apptag, appmask, data, metadata);
-}
-
-int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
- __u32 reftag, __u16 apptag, __u16 appmask, void *data,
- void *metadata)
-{
- return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
- reftag, apptag, appmask, data, metadata);
-}
-
-int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
- __u32 reftag, __u16 apptag, __u16 appmask, void *data,
- void *metadata)
-{
- return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
- reftag, apptag, appmask, data, metadata);
-}
-
int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
__u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
{
@@ -251,8 +227,9 @@ int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
return nvme_submit_io_passthru(fd, &cmd);
}
-struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
- __u64 *slbas, __u16 nr_ranges)
+struct nvme_dsm_range *nvme_setup_dsm_range(int *ctx_attrs, int *llbas,
+ unsigned long long *slbas,
+ __u16 nr_ranges)
{
int i;
struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
@@ -269,6 +246,52 @@ struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
return dsm;
}
+int nvme_copy(int fd, __u32 nsid, struct nvme_copy_range *copy, __u64 sdlba,
+ __u16 nr, __u8 prinfor, __u8 prinfow, __u8 dtype, __u16 dspec,
+ __u8 format, int lr, int fua, __u32 ilbrt, __u16 lbatm,
+ __u16 lbat)
+{
+ __u32 cdw12 = ((nr - 1) & 0xff) | ((format & 0xf) << 8) |
+ ((prinfor & 0xf) << 12) | ((dtype & 0xf) << 20) |
+ ((prinfow & 0xf) << 26) | ((fua & 0x1) << 30) |
+ ((lr & 0x1) << 31);
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_copy,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t)copy,
+ .data_len = nr * sizeof(*copy),
+ .cdw10 = sdlba & 0xffffffff,
+ .cdw11 = sdlba >> 32,
+ .cdw12 = cdw12,
+ .cdw13 = (dspec & 0xffff) << 16,
+ .cdw14 = ilbrt,
+ .cdw15 = (lbatm << 16) | lbat,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+struct nvme_copy_range *nvme_setup_copy_range(int *nlbs, unsigned long long *slbas,
+ int *eilbrts, int *elbatms, int *elbats, __u16 nr)
+{
+ struct nvme_copy_range *copy = malloc(nr * sizeof(*copy));
+ if (!copy) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ for (int i = 0; i < nr; i++) {
+ copy[i].nlb = cpu_to_le16(nlbs[i]);
+ copy[i].slba = cpu_to_le64(slbas[i]);
+ copy[i].eilbrt = cpu_to_le32(eilbrts[i]);
+ copy[i].elbatm = cpu_to_le16(elbatms[i]);
+ copy[i].elbat = cpu_to_le16(elbats[i]);
+ }
+
+ return copy;
+}
+
int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
bool iekey, __u64 crkey, __u64 nrkey)
{
@@ -365,11 +388,22 @@ int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
return nvme_identify(fd, nsid, cns, 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 cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
+ int cns;
- return nvme_identify(fd, nsid, cns, data);
+ if (csi) {
+ cns = all ? NVME_ID_CNS_CSI_NS_PRESENT_LIST : NVME_ID_CNS_CSI_NS_ACTIVE_LIST;
+ } else {
+ cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
+ }
+
+ 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)
@@ -379,6 +413,11 @@ int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
}
+int nvme_identify_primary_ctrl_caps(int fd, void *data)
+{
+ return nvme_identify(fd, 0, NVME_ID_CNS_PRIMARY_CTRL_CAPS, data);
+}
+
int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
{
return nvme_identify(fd, nsid, (cntid << 16) | NVME_ID_CNS_SCNDRY_CTRL_LIST, data);
@@ -405,6 +444,26 @@ int nvme_identify_uuid(int fd, void *data)
return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
}
+int nvme_identify_ctrl_nvm(int fd, void *data)
+{
+ return nvme_identify13(fd, 0, NVME_ID_CNS_CSI_ID_CTRL, 0, data);
+}
+
+int nvme_zns_identify_ns(int fd, __u32 nsid, void *data)
+{
+ return nvme_identify13(fd, nsid, NVME_ID_CNS_CSI_ID_NS, 2 << 24, data);
+}
+
+int nvme_zns_identify_ctrl(int fd, void *data)
+{
+ return nvme_identify13(fd, 0, NVME_ID_CNS_CSI_ID_CTRL, 2 << 24, data);
+}
+
+int nvme_identify_iocs(int fd, __u16 cntid, void *data)
+{
+ return nvme_identify(fd, 0, (cntid << 16) | NVME_ID_CNS_CSI, 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)
{
@@ -436,7 +495,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp,
}
int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
- __u32 data_len, void *data)
+ __u8 lsp, __u32 data_len, void *data)
{
__u32 offset = 0, xfer_len = data_len;
void *ptr = data;
@@ -452,7 +511,7 @@ int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
if (xfer_len > 4096)
xfer_len = 4096;
- ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP,
+ ret = nvme_get_log13(fd, nsid, log_id, lsp,
offset, 0, rae, xfer_len, ptr);
if (ret)
return ret;
@@ -484,20 +543,20 @@ int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
{
return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, true,
- sizeof(*fw_log), fw_log);
+ NVME_NO_LOG_LSP, sizeof(*fw_log), fw_log);
}
int nvme_changed_ns_list_log(int fd, struct nvme_changed_ns_list_log *changed_ns_list_log)
{
return nvme_get_log(fd, 0, NVME_LOG_CHANGED_NS, true,
- sizeof(changed_ns_list_log->log),
+ NVME_NO_LOG_LSP, sizeof(changed_ns_list_log->log),
changed_ns_list_log->log);
}
int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log)
{
return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, false,
- entries * sizeof(*err_log), err_log);
+ NVME_NO_LOG_LSP, entries * sizeof(*err_log), err_log);
}
int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log)
@@ -509,7 +568,7 @@ int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *
int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
{
return nvme_get_log(fd, nsid, NVME_LOG_SMART, false,
- sizeof(*smart_log), smart_log);
+ NVME_NO_LOG_LSP, sizeof(*smart_log), smart_log);
}
int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
@@ -518,27 +577,72 @@ int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
true, ana_log_len, ana_log);
}
-int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_log)
+int nvme_self_test_log(int fd, __u32 size, struct nvme_self_test_log *self_test_log)
{
- return nvme_get_log(fd, nsid, NVME_LOG_DEVICE_SELF_TEST, false,
- sizeof(*self_test_log), self_test_log);
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_DEVICE_SELF_TEST, false,
+ NVME_NO_LOG_LSP, size, self_test_log);
}
int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log)
{
return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, false,
- sizeof(*effects_log), effects_log);
+ NVME_NO_LOG_LSP, sizeof(*effects_log), effects_log);
}
int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size)
{
- return nvme_get_log(fd, 0, NVME_LOG_DISC, false, size, log);
+ return nvme_get_log(fd, 0, NVME_LOG_DISC, false, NVME_NO_LOG_LSP, size, log);
}
-int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
+int nvme_sanitize_log(int fd, bool rae, struct nvme_sanitize_log_page *sanitize_log)
{
- return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, false,
- sizeof(*sanitize_log), sanitize_log);
+ return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, rae,
+ NVME_NO_LOG_LSP, sizeof(*sanitize_log), sanitize_log);
+}
+
+int nvme_predictable_latency_per_nvmset_log(int fd,
+ __u16 nvmset_id,
+ struct nvme_predlat_per_nvmset_log_page *plpns_log)
+{
+ return nvme_get_log13(fd, NVME_NSID_ALL,
+ NVME_LOG_PRELAT_PER_NVMSET, 0, 0, nvmset_id,
+ false, sizeof(*plpns_log), plpns_log);
+}
+
+int nvme_predictable_latency_event_agg_log(int fd,
+ void *pea_log, bool rae, __u32 size)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL,
+ NVME_LOG_PRELAT_EVENT_AGG, rae, NVME_NO_LOG_LSP,
+ size, pea_log);
+}
+
+int nvme_persistent_event_log(int fd, __u8 action, __u32 size,
+ void *pevent_log_info)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_PERSISTENT_EVENT,
+ false, action, size, pevent_log_info);
+}
+
+int nvme_endurance_group_event_agg_log(int fd,
+ void *endurance_log, bool rae, __u32 size)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL,
+ NVME_LOG_ENDURANCE_GROUP_EVENT_AGG, rae, NVME_NO_LOG_LSP,
+ size, endurance_log);
+}
+
+int nvme_lba_status_log(int fd, void *lba_status, bool rae,
+ __u32 size)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_LBA_STATUS,
+ rae, NVME_NO_LOG_LSP, size, lba_status);
+}
+
+int nvme_resv_notif_log(int fd, struct nvme_resv_notif_log *resv)
+{
+ return nvme_get_log(fd, 0, NVME_LOG_RESERVATION, false,
+ NVME_NO_LOG_LSP, sizeof(*resv), resv);
}
int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
@@ -659,8 +763,8 @@ int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
}
int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, __u8 dps,
- __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u32 timeout,
- __u32 *result)
+ __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u8 csi,
+ __u32 timeout, __u32 *result)
{
struct nvme_id_ns ns = {
.nsze = cpu_to_le64(nsze),
@@ -676,6 +780,7 @@ int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, __u8 dps,
.opcode = nvme_admin_ns_mgmt,
.addr = (__u64)(uintptr_t) ((void *)&ns),
.cdw10 = 0,
+ .cdw11 = csi << 24,
.data_len = 0x1000,
.timeout_ms = timeout,
};
@@ -745,7 +850,7 @@ int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid)
}
int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
- __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
+ __u8 secp, __u32 tl, __u32 data_len, void *data)
{
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_security_send,
@@ -755,16 +860,12 @@ int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
.cdw10 = secp << 24 | spsp << 8 | nssf,
.cdw11 = tl,
};
- int err;
- err = nvme_submit_admin_passthru(fd, &cmd);
- if (!err && result)
- *result = cmd.result;
- return err;
+ return nvme_submit_admin_passthru(fd, &cmd);
}
int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
- __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
+ __u8 secp, __u32 al, __u32 data_len, void *data)
{
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_security_recv,
@@ -774,24 +875,23 @@ int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
.addr = (__u64)(uintptr_t) data,
.data_len = data_len,
};
- int err;
- err = nvme_submit_admin_passthru(fd, &cmd);
- if (!err && result)
- *result = cmd.result;
- return err;
+ return nvme_submit_admin_passthru(fd, &cmd);
}
-int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
- void *data)
+int nvme_get_lba_status(int fd, __u32 namespace_id, __u64 slba, __u32 mndw,
+ __u8 atype, __u16 rl, void *data, __u32 timeout_ms)
{
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_get_lba_status,
+ .nsid = namespace_id,
.addr = (__u64)(uintptr_t) data,
+ .data_len = (mndw + 1) * 4,
.cdw10 = slba & 0xffffffff,
.cdw11 = slba >> 32,
.cdw12 = mndw,
.cdw13 = (atype << 24) | rl,
+ .timeout_ms = timeout_ms,
};
return nvme_submit_admin_passthru(fd, &cmd);
@@ -851,12 +951,12 @@ int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
return nvme_submit_admin_passthru(fd, &cmd);
}
-int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10)
+int nvme_self_test_start(int fd, __u32 nsid, __u8 stc)
{
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_dev_self_test,
.nsid = nsid,
- .cdw10 = cdw10,
+ .cdw10 = stc,
};
return nvme_submit_admin_passthru(fd, &cmd);
@@ -877,3 +977,95 @@ int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result)
return err;
}
+
+int nvme_zns_mgmt_send(int fd, __u32 nsid, __u64 slba, bool select_all,
+ enum nvme_zns_send_action zsa, __u32 data_len,
+ void *data)
+{
+ __u32 cdw10 = slba & 0xffffffff;
+ __u32 cdw11 = slba >> 32;
+ __u32 cdw13 = zsa | (!!select_all) << 8;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_zns_cmd_mgmt_send,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw13 = cdw13,
+ .addr = (__u64)(uintptr_t)data,
+ .data_len = data_len,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba,
+ enum nvme_zns_recv_action zra, __u8 zrasf,
+ bool zras_feat, __u32 data_len, void *data)
+{
+ __u32 cdw10 = slba & 0xffffffff;
+ __u32 cdw11 = slba >> 32;
+ __u32 cdw12 = (data_len >> 2) - 1;
+ __u32 cdw13 = zra | zrasf << 8 | zras_feat << 16;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_zns_cmd_mgmt_recv,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw12 = cdw12,
+ .cdw13 = cdw13,
+ .addr = (__u64)(uintptr_t)data,
+ .data_len = data_len,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba, bool extended,
+ enum nvme_zns_report_options opts, bool partial,
+ __u32 data_len, void *data)
+{
+ enum nvme_zns_recv_action zra;
+
+ if (extended)
+ zra = NVME_ZNS_ZRA_EXTENDED_REPORT_ZONES;
+ else
+ zra = NVME_ZNS_ZRA_REPORT_ZONES;
+
+ return nvme_zns_mgmt_recv(fd, nsid, slba, zra, opts, partial,
+ data_len, data);
+}
+
+int nvme_zns_append(int fd, __u32 nsid, __u64 zslba, __u16 nlb, __u16 control,
+ __u32 ilbrt, __u16 lbat, __u16 lbatm, __u32 data_len,
+ void *data, __u32 metadata_len, void *metadata,
+ __u64 *result)
+{
+ __u32 cdw10 = zslba & 0xffffffff;
+ __u32 cdw11 = zslba >> 32;
+ __u32 cdw12 = nlb | (control << 16);
+ __u32 cdw14 = ilbrt;
+ __u32 cdw15 = lbat | (lbatm << 16);
+
+ struct nvme_passthru_cmd64 cmd = {
+ .opcode = nvme_zns_cmd_append,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw12 = cdw12,
+ .cdw14 = cdw14,
+ .cdw15 = cdw15,
+ .metadata = (__u64)(uintptr_t)metadata,
+ .addr = (__u64)(uintptr_t)data,
+ .metadata_len = metadata_len,
+ .data_len = data_len,
+ };
+
+ int err;
+
+ err = ioctl(fd, NVME_IOCTL_IO64_CMD, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
index aae4e49..b0184c7 100644
--- a/nvme-ioctl.h
+++ b/nvme-ioctl.h
@@ -29,18 +29,6 @@ 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_read(int fd, __u64 slba, __u16 nblocks, __u16 control,
- __u32 dsmgmt, __u32 reftag, __u16 apptag,
- __u16 appmask, void *data, void *metadata);
-
-int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control,
- __u32 dsmgmt, __u32 reftag, __u16 apptag,
- __u16 appmask, void *data, void *metadata);
-
-int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
- __u32 dsmgmt, __u32 reftag, __u16 apptag,
- __u16 appmask, void *data, void *metadata);
-
/* NVME_IO_CMD */
int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
__u32 nsid, __u32 cdw2, __u32 cdw3,
@@ -61,10 +49,17 @@ int nvme_flush(int fd, __u32 nsid);
int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
__u16 nr_ranges);
-struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs,
- __u32 *llbas, __u64 *slbas,
+struct nvme_dsm_range *nvme_setup_dsm_range(int *ctx_attrs, int *llbas,
+ unsigned long long *slbas,
__u16 nr_ranges);
+int nvme_copy(int fd, __u32 nsid, struct nvme_copy_range *copy, __u64 sdlba,
+ __u16 nr, __u8 prinfor, __u8 prinfow, __u8 dtype, __u16 dspec,
+ __u8 format, int lr, int fua, __u32 ilbrt, __u16 lbatm,
+ __u16 lbat);
+struct nvme_copy_range *nvme_setup_copy_range(int *nlbs, unsigned long long *slbas,
+ int *eilbrts, int *elbatms, int *elbats, __u16 nr);
+
int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
bool iekey, __u64 crkey, __u64 nrkey);
int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
@@ -79,14 +74,20 @@ 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);
int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
int nvme_identify_uuid(int fd, void *data);
+int nvme_identify_primary_ctrl_caps(int fd, void *data);
int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
int nvme_identify_ns_granularity(int fd, void *data);
+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_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
- __u32 data_len, void *data);
+ __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,
__u32 data_len, void *data);
@@ -103,10 +104,20 @@ int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
-int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
+int nvme_sanitize_log(int fd, bool rae, struct nvme_sanitize_log_page *sanitize_log);
+int nvme_predictable_latency_per_nvmset_log(int fd,
+ __u16 nvmset_id, struct nvme_predlat_per_nvmset_log_page *plpns_log);
+int nvme_predictable_latency_event_agg_log(int fd, void *pea_log,
+ bool rae, __u32 size);
+int nvme_persistent_event_log(int fd, __u8 action, __u32 size,
+ void *pevent_log_info);
+int nvme_endurance_group_event_agg_log(int fd, void *endurance_log,
+ bool rae, __u32 size);
int nvme_endurance_log(int fd, __u16 group_id,
struct nvme_endurance_group_log *endurance_log);
-
+int nvme_lba_status_log(int fd, void *lba_status, bool rae,
+ __u32 size);
+int nvme_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);
@@ -119,8 +130,8 @@ int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
__u8 pil, __u8 ms, __u32 timeout);
int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, __u8 dps,
- __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u32 timeout,
- __u32 *result);
+ __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u8 csi,
+ __u32 timeout, __u32 *result);
int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout);
int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
@@ -130,16 +141,16 @@ 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_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
- __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result);
+ __u8 secp, __u32 tl, __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, __u32 *result);
+ __u8 secp, __u32 al, __u32 data_len, void *data);
int nvme_subsystem_reset(int fd);
int nvme_reset_controller(int fd);
int nvme_ns_rescan(int fd);
-int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
- void *data);
+int nvme_get_lba_status(int fd, __u32 namespace_id, __u64 slba, __u32 mndw,
+ __u8 atype, __u16 rl, void *data, __u32 timeout_ms);
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,
@@ -149,7 +160,22 @@ int nvme_set_property(int fd, int offset, uint64_t value);
int nvme_get_property(int fd, int offset, uint64_t *value);
int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
__u8 no_dealloc, __u32 ovrpat);
-int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
+int nvme_self_test_start(int fd, __u32 nsid, __u8 stc);
int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_log);
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,
+ void *data);
+int nvme_zns_mgmt_recv(int fd, __u32 nsid, __u64 slba,
+ enum nvme_zns_recv_action zra, __u8 zrasf,
+ bool zras_feat, __u32 data_len, void *data);
+int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba, bool extended,
+ enum nvme_zns_report_options opts, bool partial,
+ __u32 data_len, void *data);
+int nvme_zns_append(int fd, __u32 nsid, __u64 zslba, __u16 nlb, __u16 control,
+ __u32 ilbrt, __u16 lbat, __u16 lbatm, __u32 data_len,
+ void *data, __u32 metadata_len, void *metadata,
+ __u64 *result);
+
#endif /* _NVME_LIB_H */
diff --git a/nvme-print.c b/nvme-print.c
index 30fca29..b01a842 100644..100755
--- a/nvme-print.c
+++ b/nvme-print.c
@@ -3,9 +3,10 @@
#include <string.h>
#include <stdlib.h>
#include <time.h>
+#include <sys/stat.h>
+#include "nvme.h"
#include "nvme-print.h"
-#include "util/json.h"
#include "nvme-models.h"
#include "util/suffix.h"
#include "common.h"
@@ -43,7 +44,7 @@ static const char *nvme_ana_state_to_string(enum nvme_ana_state state)
return "invalid state";
}
-static const char *nvme_cmd_to_string(int admin, __u8 opcode)
+const char *nvme_cmd_to_string(int admin, __u8 opcode)
{
if (admin) {
switch (opcode) {
@@ -73,6 +74,7 @@ static const char *nvme_cmd_to_string(int admin, __u8 opcode)
case nvme_admin_security_send: return "Security Send";
case nvme_admin_security_recv: return "Security Receive";
case nvme_admin_sanitize_nvm: return "Sanitize";
+ case nvme_admin_get_lba_status: return "Get LBA Status";
}
} else {
switch (opcode) {
@@ -87,6 +89,8 @@ static const char *nvme_cmd_to_string(int admin, __u8 opcode)
case nvme_cmd_resv_report: return "Reservation Report";
case nvme_cmd_resv_acquire: return "Reservation Acquire";
case nvme_cmd_resv_release: return "Reservation Release";
+ case nvme_cmd_verify: return "Verify";
+ case nvme_cmd_copy: return "Copy";
}
}
@@ -107,38 +111,29 @@ static const char *fw_to_string(__u64 fw)
static const char *get_sanitize_log_sstat_status_str(__u16 status)
{
- const char *str;
-
switch (status & NVME_SANITIZE_LOG_STATUS_MASK) {
case NVME_SANITIZE_LOG_NEVER_SANITIZED:
- str = "NVM Subsystem has never been sanitized.";
- break;
+ return "NVM Subsystem has never been sanitized.";
case NVME_SANITIZE_LOG_COMPLETED_SUCCESS:
- str = "Most Recent Sanitize Command Completed Successfully.";
- break;
+ return "Most Recent Sanitize Command Completed Successfully.";
case NVME_SANITIZE_LOG_IN_PROGESS:
- str = "Sanitize in Progress.";
- break;
+ return "Sanitize in Progress.";
case NVME_SANITIZE_LOG_COMPLETED_FAILED:
- str = "Most Recent Sanitize Command Failed.";
- break;
+ return "Most Recent Sanitize Command Failed.";
case NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS:
- str = "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully.";
- break;
+ return "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully.";
default:
- str = "Unknown.";
+ return "Unknown";
}
-
- return str;
}
-static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
+static void json_nvme_id_ns(struct nvme_id_ns *ns)
{
char nguid_buf[2 * sizeof(ns->nguid) + 1],
eui64_buf[2 * sizeof(ns->eui64) + 1];
char *nguid = nguid_buf, *eui64 = eui64_buf;
struct json_object *root;
- struct json_array *lbafs;
+ struct json_object *lbafs;
int i;
long double nvmcap = int128_to_double(ns->nvmcap);
@@ -176,6 +171,10 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
json_object_add_value_int(root, "nows", le16_to_cpu(ns->nows));
}
+ json_object_add_value_int(root, "mssrl", le16_to_cpu(ns->mssrl));
+ json_object_add_value_int(root, "mcl", le32_to_cpu(ns->mcl));
+ json_object_add_value_int(root, "msrc", ns->msrc);
+
json_object_add_value_int(root, "anagrpid", le32_to_cpu(ns->anagrpid));
json_object_add_value_int(root, "endgid", le16_to_cpu(ns->endgid));
@@ -209,11 +208,11 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
json_free_object(root);
}
-static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
+static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl,
void (*vs)(__u8 *vs, struct json_object *root))
{
struct json_object *root;
- struct json_array *psds;
+ struct json_object *psds;
long double tnvmcap = int128_to_double(ctrl->tnvmcap);
long double unvmcap = int128_to_double(ctrl->unvmcap);
@@ -296,7 +295,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
json_object_add_value_int(root, "vwc", ctrl->vwc);
json_object_add_value_int(root, "awun", le16_to_cpu(ctrl->awun));
json_object_add_value_int(root, "awupf", le16_to_cpu(ctrl->awupf));
- json_object_add_value_int(root, "nvscc", ctrl->nvscc);
+ 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, "sgls", le32_to_cpu(ctrl->sgls));
@@ -307,8 +306,9 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
json_object_add_value_int(root, "ioccsz", le32_to_cpu(ctrl->ioccsz));
json_object_add_value_int(root, "iorcsz", le32_to_cpu(ctrl->iorcsz));
json_object_add_value_int(root, "icdoff", le16_to_cpu(ctrl->icdoff));
- json_object_add_value_int(root, "ctrattr", ctrl->ctrattr);
+ json_object_add_value_int(root, "fcatt", ctrl->fcatt);
json_object_add_value_int(root, "msdbd", ctrl->msdbd);
+ json_object_add_value_int(root, "ofcs", le16_to_cpu(ctrl->ofcs));
psds = json_create_array();
json_object_add_value_array(root, "psds", psds);
@@ -353,7 +353,7 @@ static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
static void json_error_log(struct nvme_error_log_page *err_log, int entries)
{
struct json_object *root;
- struct json_array *errors;
+ struct json_object *errors;
int i;
root = json_create_object();
@@ -370,7 +370,9 @@ static void json_error_log(struct nvme_error_log_page *err_log, int entries)
json_object_add_value_int(error, "cmdid",
le16_to_cpu(err_log[i].cmdid));
json_object_add_value_int(error, "status_field",
- le16_to_cpu(err_log[i].status_field));
+ le16_to_cpu(err_log[i].status_field >> 0x1));
+ json_object_add_value_int(error, "phase_tag",
+ le16_to_cpu(err_log[i].status_field & 0x1));
json_object_add_value_int(error, "parm_error_location",
le16_to_cpu(err_log[i].parm_error_location));
json_object_add_value_uint(error, "lba",
@@ -396,7 +398,7 @@ static void json_nvme_resv_report(struct nvme_reservation_status *status,
int bytes, __u32 cdw11)
{
struct json_object *root;
- struct json_array *rcs;
+ struct json_object *rcs;
int i, j, regctl, entries;
regctl = status->regctl[0] | (status->regctl[1] << 8);
@@ -678,8 +680,8 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
int offset = sizeof(struct nvme_ana_rsp_hdr);
struct nvme_ana_rsp_hdr *hdr = ana_log;
struct nvme_ana_group_desc *ana_desc;
- struct json_array *desc_list;
- struct json_array *ns_list;
+ struct json_object *desc_list;
+ struct json_object *ns_list;
struct json_object *desc;
struct json_object *nsid;
struct json_object *root;
@@ -690,7 +692,7 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
root = json_create_object();
json_object_add_value_string(root,
- "Asynchronous Namespace Access Log for NVMe device",
+ "Asymmetric Namespace Access Log for NVMe device",
devname);
json_object_add_value_uint(root, "chgcnt",
le64_to_cpu(hdr->chgcnt));
@@ -731,12 +733,13 @@ static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
json_free_object(root);
}
-static void json_self_test_log(struct nvme_self_test_log *self_test)
+static void json_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries)
{
struct json_object *valid_attrs;
struct json_object *root;
- struct json_array *valid;
+ struct json_object *valid;
int i;
+ __u32 num_entries;
root = json_create_object();
json_object_add_value_int(root, "Current Device Self-Test Operation",
@@ -745,7 +748,8 @@ static void json_self_test_log(struct nvme_self_test_log *self_test)
self_test->crnt_dev_selftest_compln);
valid = json_create_array();
- for (i = 0; i < NVME_ST_REPORTS; i++) {
+ num_entries = min(dst_entries, NVME_ST_REPORTS);
+ for (i = 0; i < num_entries; i++) {
valid_attrs = json_create_object();
json_object_add_value_int(valid_attrs, "Self test result",
self_test->result[i].dsts & 0xf);
@@ -786,26 +790,36 @@ add:
static void json_effects_log(struct nvme_effects_log_page *effects_log)
{
struct json_object *root;
+ struct json_object *acs;
+ struct json_object *iocs;
unsigned int opcode;
char key[128];
__u32 effect;
root = json_create_object();
-
+ acs = json_create_object();
for (opcode = 0; opcode < 256; opcode++) {
- sprintf(key, "ACS%d (%s)", opcode,
- nvme_cmd_to_string(1, opcode));
effect = le32_to_cpu(effects_log->acs[opcode]);
- json_object_add_value_uint(root, key, effect);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ sprintf(key, "ACS_%u (%s)", opcode,
+ nvme_cmd_to_string(1, opcode));
+ json_object_add_value_uint(acs, key, effect);
+ }
}
+ json_object_add_value_object(root, "admin_cmd_set", acs);
+
+ iocs = json_create_object();
for (opcode = 0; opcode < 256; opcode++) {
- sprintf(key, "IOCS%d (%s)", opcode,
- nvme_cmd_to_string(0, opcode));
effect = le32_to_cpu(effects_log->iocs[opcode]);
- json_object_add_value_uint(root, key, effect);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ sprintf(key, "IOCS_%u (%s)", opcode,
+ nvme_cmd_to_string(0, opcode));
+ json_object_add_value_uint(iocs, key, effect);
+ }
}
+ json_object_add_value_object(root, "io_cmd_set", iocs);
json_print_object(root, NULL);
printf("\n");
json_free_object(root);
@@ -860,6 +874,915 @@ static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
json_free_object(root);
}
+void json_predictable_latency_per_nvmset(
+ struct nvme_predlat_per_nvmset_log_page *plpns_log,
+ __u16 nvmset_id)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "nvmset_id",
+ le16_to_cpu(nvmset_id));
+ json_object_add_value_uint(root, "status",
+ plpns_log->status);
+ json_object_add_value_uint(root, "event_type",
+ le16_to_cpu(plpns_log->event_type));
+ json_object_add_value_uint(root, "dtwin_reads_typical",
+ le64_to_cpu(plpns_log->dtwin_rtyp));
+ json_object_add_value_uint(root, "dtwin_writes_typical",
+ le64_to_cpu(plpns_log->dtwin_wtyp));
+ json_object_add_value_uint(root, "dtwin_time_maximum",
+ le64_to_cpu(plpns_log->dtwin_timemax));
+ json_object_add_value_uint(root, "ndwin_time_minimum_high",
+ le64_to_cpu(plpns_log->ndwin_timemin_high));
+ json_object_add_value_uint(root, "ndwin_time_minimum_low",
+ le64_to_cpu(plpns_log->ndwin_timemin_low));
+ json_object_add_value_uint(root, "dtwin_reads_estimate",
+ le64_to_cpu(plpns_log->dtwin_restimate));
+ json_object_add_value_uint(root, "dtwin_writes_estimate",
+ le64_to_cpu(plpns_log->dtwin_westimate));
+ json_object_add_value_uint(root, "dtwin_time_estimate",
+ le64_to_cpu(plpns_log->dtwin_testimate));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_predictable_latency_per_nvmset(
+ struct nvme_predlat_per_nvmset_log_page *plpns_log,
+ __u16 nvmset_id, const char *devname,
+ enum nvme_print_flags flags)
+{
+ if (flags & BINARY)
+ return d_raw((unsigned char *)plpns_log,
+ sizeof(*plpns_log));
+ if (flags & JSON)
+ return json_predictable_latency_per_nvmset(plpns_log,
+ nvmset_id);
+
+ printf("Predictable Latency Per NVM Set Log for device: %s\n",
+ devname);
+ printf("Predictable Latency Per NVM Set Log for NVM Set ID: %u\n",
+ le16_to_cpu(nvmset_id));
+ printf("Status: %u\n", plpns_log->status);
+ printf("Event Type: %u\n",
+ le16_to_cpu(plpns_log->event_type));
+ printf("DTWIN Reads Typical: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_rtyp));
+ printf("DTWIN Writes Typical: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_wtyp));
+ printf("DTWIN Time Maximum: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_timemax));
+ printf("NDWIN Time Minimum High: %"PRIu64" \n",
+ le64_to_cpu(plpns_log->ndwin_timemin_high));
+ printf("NDWIN Time Minimum Low: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->ndwin_timemin_low));
+ printf("DTWIN Reads Estimate: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_restimate));
+ printf("DTWIN Writes Estimate: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_westimate));
+ printf("DTWIN Time Estimate: %"PRIu64"\n\n\n",
+ le64_to_cpu(plpns_log->dtwin_testimate));
+}
+
+void json_predictable_latency_event_agg_log(
+ struct nvme_event_agg_log_page *pea_log,
+ __u64 log_entries)
+{
+ struct json_object *root;
+ struct json_object *valid_attrs;
+ struct json_object *valid;
+ __u64 num_iter;
+ __u64 num_entries;
+
+ root = json_create_object();
+ num_entries = le64_to_cpu(pea_log->num_entries);
+ json_object_add_value_uint(root, "num_entries_avail",
+ num_entries);
+ valid = json_create_array();
+
+ num_iter = min(num_entries, log_entries);
+ for (int i = 0; i < num_iter; i++) {
+ valid_attrs = json_create_object();
+ json_object_add_value_uint(valid_attrs, "entry",
+ le16_to_cpu(pea_log->entries[i]));
+ json_array_add_value_object(valid, valid_attrs);
+ }
+ json_object_add_value_array(root, "list_of_entries", valid);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_predictable_latency_event_agg_log(
+ struct nvme_event_agg_log_page *pea_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+ __u64 num_iter;
+ __u64 num_entries;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)pea_log, size);
+ if (flags & JSON)
+ return json_predictable_latency_event_agg_log(pea_log,
+ log_entries);
+
+ num_entries = le64_to_cpu(pea_log->num_entries);
+ printf("Predictable Latency Event Aggregate Log for"\
+ " device: %s\n", devname);
+
+ printf("Number of Entries Available: %"PRIu64"\n",
+ (uint64_t)num_entries);
+
+ num_iter = min(num_entries, log_entries);
+ for (int i = 0; i < num_iter; i++) {
+ printf("Entry[%d]: %u\n", i + 1,
+ le16_to_cpu(pea_log->entries[i]));
+ }
+}
+
+static const char *nvme_show_nss_hw_error(__u16 error_code)
+{
+ switch (error_code) {
+ case 0x01:
+ return "PCIe Correctable Error";
+ case 0x02:
+ return "PCIe Uncorrectable Non fatal Error";
+ case 0x03:
+ return "PCIe Uncorrectable Fatal Error";
+ case 0x04:
+ return "PCIe Link Status Change";
+ case 0x05:
+ return "PCIe Link Not Active";
+ case 0x06:
+ return "Critical Warning Condition";
+ case 0x07:
+ return "Endurance Group Critical Warning Condition";
+ case 0x08:
+ return "Unsafe Shutdown";
+ case 0x09:
+ return "Controller Fatal Status";
+ case 0xA:
+ return "Media and Data Integrity Status";
+ default:
+ return "Reserved";
+ }
+}
+
+void json_persistent_event_log(void *pevent_log_info, __u32 size)
+{
+ struct json_object *root;
+ struct json_object *valid_attrs;
+ struct json_object *valid;
+ __u32 offset, por_info_len, por_info_list;
+ __u64 *fw_rev;
+ char key[128];
+ struct nvme_smart_log *smart_event;
+ struct nvme_fw_commit_event *fw_commit_event;
+ struct nvme_time_stamp_change_event *ts_change_event;
+ struct nvme_power_on_reset_info_list *por_event;
+ struct nvme_nss_hw_err_event *nss_hw_err_event;
+ struct nvme_change_ns_event *ns_event;
+ struct nvme_format_nvm_start_event *format_start_event;
+ struct nvme_format_nvm_compln_event *format_cmpln_event;
+ struct nvme_sanitize_start_event *sanitize_start_event;
+ struct nvme_sanitize_compln_event *sanitize_cmpln_event;
+ struct nvme_thermal_exc_event *thermal_exc_event;
+ struct nvme_persistent_event_log_head *pevent_log_head;
+ struct nvme_persistent_event_entry_head *pevent_entry_head;
+
+ root = json_create_object();
+ valid = json_create_array();
+
+ offset = sizeof(*pevent_log_head);
+ if (size >= offset) {
+ pevent_log_head = pevent_log_info;
+ char sn[sizeof(pevent_log_head->sn) + 1],
+ mn[sizeof(pevent_log_head->mn) + 1],
+ subnqn[sizeof(pevent_log_head->subnqn) + 1];
+
+ snprintf(sn, sizeof(sn), "%-.*s",
+ (int)sizeof(pevent_log_head->sn), pevent_log_head->sn);
+ snprintf(mn, sizeof(mn), "%-.*s",
+ (int)sizeof(pevent_log_head->mn), pevent_log_head->mn);
+ snprintf(subnqn, sizeof(subnqn), "%-.*s",
+ (int)sizeof(pevent_log_head->subnqn), pevent_log_head->subnqn);
+
+ json_object_add_value_uint(root, "log_id",
+ pevent_log_head->log_id);
+ json_object_add_value_uint(root, "total_num_of_events",
+ le32_to_cpu(pevent_log_head->tnev));
+ json_object_add_value_uint(root, "total_log_len",
+ le64_to_cpu(pevent_log_head->tll));
+ json_object_add_value_uint(root, "log_revision",
+ pevent_log_head->log_rev);
+ json_object_add_value_uint(root, "log_header_len",
+ le16_to_cpu(pevent_log_head->head_len));
+ json_object_add_value_uint(root, "timestamp",
+ le64_to_cpu(pevent_log_head->timestamp));
+ json_object_add_value_float(root, "power_on_hours",
+ int128_to_double(pevent_log_head->poh));
+ json_object_add_value_uint(root, "power_cycle_count",
+ le64_to_cpu(pevent_log_head->pcc));
+ json_object_add_value_uint(root, "pci_vid",
+ le16_to_cpu(pevent_log_head->vid));
+ json_object_add_value_uint(root, "pci_ssvid",
+ le16_to_cpu(pevent_log_head->ssvid));
+ json_object_add_value_string(root, "sn", sn);
+ json_object_add_value_string(root, "mn", mn);
+ json_object_add_value_string(root, "subnqn", subnqn);
+ for (int i = 0; i < 32; i++) {
+ if (pevent_log_head->supp_event_bm[i] == 0)
+ continue;
+ sprintf(key, "bitmap_%d", i);
+ json_object_add_value_uint(root, key,
+ pevent_log_head->supp_event_bm[i]);
+ }
+ } else {
+ printf("No log data can be shown with this log len at least " \
+ "512 bytes is required or can be 0 to read the complete "\
+ "log page after context established\n");
+ return;
+ }
+ for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) {
+ if (offset + sizeof(*pevent_entry_head) >= size)
+ break;
+
+ pevent_entry_head = pevent_log_info + offset;
+
+ if ((offset + pevent_entry_head->ehl + 3 +
+ le16_to_cpu(pevent_entry_head->el)) >= size)
+ break;
+ valid_attrs = json_create_object();
+
+ json_object_add_value_uint(valid_attrs, "event_type",
+ pevent_entry_head->etype);
+ json_object_add_value_uint(valid_attrs, "event_type_rev",
+ pevent_entry_head->etype_rev);
+ json_object_add_value_uint(valid_attrs, "event_header_len",
+ pevent_entry_head->ehl);
+ json_object_add_value_uint(valid_attrs, "ctrl_id",
+ le16_to_cpu(pevent_entry_head->ctrl_id));
+ json_object_add_value_uint(valid_attrs, "event_time_stamp",
+ le64_to_cpu(pevent_entry_head->etimestamp));
+ json_object_add_value_uint(valid_attrs, "vu_info_len",
+ le16_to_cpu(pevent_entry_head->vsil));
+ json_object_add_value_uint(valid_attrs, "event_len",
+ le16_to_cpu(pevent_entry_head->el));
+
+ offset += pevent_entry_head->ehl + 3;
+
+ switch (pevent_entry_head->etype) {
+ case NVME_SMART_HEALTH_EVENT:
+ smart_event = pevent_log_info + offset;
+ unsigned int temperature = ((smart_event->temperature[1] << 8) |
+ smart_event->temperature[0]);
+
+ long double data_units_read = int128_to_double(smart_event->data_units_read);
+ long double data_units_written = int128_to_double(smart_event->data_units_written);
+ long double host_read_commands = int128_to_double(smart_event->host_reads);
+ long double host_write_commands = int128_to_double(smart_event->host_writes);
+ long double controller_busy_time = int128_to_double(smart_event->ctrl_busy_time);
+ long double power_cycles = int128_to_double(smart_event->power_cycles);
+ long double power_on_hours = int128_to_double(smart_event->power_on_hours);
+ long double unsafe_shutdowns = int128_to_double(smart_event->unsafe_shutdowns);
+ long double media_errors = int128_to_double(smart_event->media_errors);
+ long double num_err_log_entries = int128_to_double(smart_event->num_err_log_entries);
+ json_object_add_value_int(valid_attrs, "critical_warning",
+ smart_event->critical_warning);
+
+ json_object_add_value_int(valid_attrs, "temperature",
+ temperature);
+ json_object_add_value_int(valid_attrs, "avail_spare",
+ smart_event->avail_spare);
+ json_object_add_value_int(valid_attrs, "spare_thresh",
+ smart_event->spare_thresh);
+ json_object_add_value_int(valid_attrs, "percent_used",
+ smart_event->percent_used);
+ json_object_add_value_int(valid_attrs,
+ "endurance_grp_critical_warning_summary",
+ smart_event->endu_grp_crit_warn_sumry);
+ json_object_add_value_float(valid_attrs, "data_units_read",
+ data_units_read);
+ json_object_add_value_float(valid_attrs, "data_units_written",
+ data_units_written);
+ json_object_add_value_float(valid_attrs, "host_read_commands",
+ host_read_commands);
+ json_object_add_value_float(valid_attrs, "host_write_commands",
+ host_write_commands);
+ json_object_add_value_float(valid_attrs, "controller_busy_time",
+ controller_busy_time);
+ json_object_add_value_float(valid_attrs, "power_cycles",
+ power_cycles);
+ json_object_add_value_float(valid_attrs, "power_on_hours",
+ power_on_hours);
+ json_object_add_value_float(valid_attrs, "unsafe_shutdowns",
+ unsafe_shutdowns);
+ json_object_add_value_float(valid_attrs, "media_errors",
+ media_errors);
+ json_object_add_value_float(valid_attrs, "num_err_log_entries",
+ num_err_log_entries);
+ json_object_add_value_uint(valid_attrs, "warning_temp_time",
+ le32_to_cpu(smart_event->warning_temp_time));
+ json_object_add_value_uint(valid_attrs, "critical_comp_time",
+ le32_to_cpu(smart_event->critical_comp_time));
+
+ for (int c = 0; c < 8; c++) {
+ __s32 temp = le16_to_cpu(smart_event->temp_sensor[c]);
+ if (temp == 0)
+ continue;
+ sprintf(key, "temperature_sensor_%d",c + 1);
+ json_object_add_value_int(valid_attrs, key, temp);
+ }
+
+ json_object_add_value_uint(valid_attrs, "thm_temp1_trans_count",
+ le32_to_cpu(smart_event->thm_temp1_trans_count));
+ json_object_add_value_uint(valid_attrs, "thm_temp2_trans_count",
+ le32_to_cpu(smart_event->thm_temp2_trans_count));
+ json_object_add_value_uint(valid_attrs, "thm_temp1_total_time",
+ le32_to_cpu(smart_event->thm_temp1_total_time));
+ json_object_add_value_uint(valid_attrs, "thm_temp2_total_time",
+ le32_to_cpu(smart_event->thm_temp2_total_time));
+ break;
+ case NVME_FW_COMMIT_EVENT:
+ fw_commit_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "old_fw_rev",
+ le64_to_cpu(fw_commit_event->old_fw_rev));
+ json_object_add_value_uint(valid_attrs, "new_fw_rev",
+ le64_to_cpu(fw_commit_event->new_fw_rev));
+ json_object_add_value_uint(valid_attrs, "fw_commit_action",
+ fw_commit_event->fw_commit_action);
+ json_object_add_value_uint(valid_attrs, "fw_slot",
+ fw_commit_event->fw_slot);
+ json_object_add_value_uint(valid_attrs, "sct_fw",
+ fw_commit_event->sct_fw);
+ json_object_add_value_uint(valid_attrs, "sc_fw",
+ fw_commit_event->sc_fw);
+ json_object_add_value_uint(valid_attrs,
+ "vu_assign_fw_commit_rc",
+ le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc));
+ break;
+ case NVME_TIMESTAMP_EVENT:
+ ts_change_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "prev_ts",
+ le64_to_cpu(ts_change_event->previous_timestamp));
+ json_object_add_value_uint(valid_attrs,
+ "ml_secs_since_reset",
+ le64_to_cpu(ts_change_event->ml_secs_since_reset));
+ break;
+ case NVME_POWER_ON_RESET_EVENT:
+ por_info_len = (le16_to_cpu(pevent_entry_head->el) -
+ le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev));
+
+ por_info_list = por_info_len / sizeof(*por_event);
+
+ fw_rev = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "fw_rev",
+ le64_to_cpu(*fw_rev));
+ for (int i = 0; i < por_info_list; i++) {
+ por_event = pevent_log_info + offset +
+ sizeof(*fw_rev) + i * sizeof(*por_event);
+ json_object_add_value_uint(valid_attrs, "ctrl_id",
+ le16_to_cpu(por_event->cid));
+ json_object_add_value_uint(valid_attrs, "fw_act",
+ por_event->fw_act);
+ json_object_add_value_uint(valid_attrs, "op_in_prog",
+ por_event->op_in_prog);
+ json_object_add_value_uint(valid_attrs, "ctrl_power_cycle",
+ le32_to_cpu(por_event->ctrl_power_cycle));
+ json_object_add_value_uint(valid_attrs, "power_on_ml_secs",
+ le64_to_cpu(por_event->power_on_ml_seconds));
+ json_object_add_value_uint(valid_attrs, "ctrl_time_stamp",
+ le64_to_cpu(por_event->ctrl_time_stamp));
+ }
+ break;
+ case NVME_NSS_HW_ERROR_EVENT:
+ nss_hw_err_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "nss_hw_err_code",
+ le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code));
+ break;
+ case NVME_CHANGE_NS_EVENT:
+ ns_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "nsmgt_cdw10",
+ le32_to_cpu(ns_event->nsmgt_cdw10));
+ json_object_add_value_uint(valid_attrs, "nsze",
+ le64_to_cpu(ns_event->nsze));
+ json_object_add_value_uint(valid_attrs, "nscap",
+ le64_to_cpu(ns_event->nscap));
+ json_object_add_value_uint(valid_attrs, "flbas",
+ ns_event->flbas);
+ json_object_add_value_uint(valid_attrs, "dps",
+ ns_event->dps);
+ json_object_add_value_uint(valid_attrs, "nmic",
+ ns_event->nmic);
+ json_object_add_value_uint(valid_attrs, "ana_grp_id",
+ le32_to_cpu(ns_event->ana_grp_id));
+ json_object_add_value_uint(valid_attrs, "nvmset_id",
+ le16_to_cpu(ns_event->nvmset_id));
+ json_object_add_value_uint(valid_attrs, "nsid",
+ le32_to_cpu(ns_event->nsid));
+ break;
+ case NVME_FORMAT_START_EVENT:
+ format_start_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "nsid",
+ le32_to_cpu(format_start_event->nsid));
+ json_object_add_value_uint(valid_attrs, "fna",
+ format_start_event->fna);
+ json_object_add_value_uint(valid_attrs, "format_nvm_cdw10",
+ le32_to_cpu(format_start_event->format_nvm_cdw10));
+ break;
+ case NVME_FORMAT_COMPLETION_EVENT:
+ format_cmpln_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "nsid",
+ le32_to_cpu(format_cmpln_event->nsid));
+ json_object_add_value_uint(valid_attrs, "smallest_fpi",
+ format_cmpln_event->smallest_fpi);
+ json_object_add_value_uint(valid_attrs, "format_nvm_status",
+ format_cmpln_event->format_nvm_status);
+ json_object_add_value_uint(valid_attrs, "compln_info",
+ le16_to_cpu(format_cmpln_event->compln_info));
+ json_object_add_value_uint(valid_attrs, "status_field",
+ le32_to_cpu(format_cmpln_event->status_field));
+ break;
+ case NVME_SANITIZE_START_EVENT:
+ sanitize_start_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "SANICAP",
+ le32_to_cpu(sanitize_start_event->sani_cap));
+ json_object_add_value_uint(valid_attrs, "sani_cdw10",
+ le32_to_cpu(sanitize_start_event->sani_cdw10));
+ json_object_add_value_uint(valid_attrs, "sani_cdw11",
+ le32_to_cpu(sanitize_start_event->sani_cdw11));
+ break;
+ case NVME_SANITIZE_COMPLETION_EVENT:
+ sanitize_cmpln_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "sani_prog",
+ le16_to_cpu(sanitize_cmpln_event->sani_prog));
+ json_object_add_value_uint(valid_attrs, "sani_status",
+ le16_to_cpu(sanitize_cmpln_event->sani_status));
+ json_object_add_value_uint(valid_attrs, "cmpln_info",
+ le16_to_cpu(sanitize_cmpln_event->cmpln_info));
+ break;
+ case NVME_THERMAL_EXCURSION_EVENT:
+ thermal_exc_event = pevent_log_info + offset;
+ json_object_add_value_uint(valid_attrs, "over_temp",
+ thermal_exc_event->over_temp);
+ json_object_add_value_uint(valid_attrs, "threshold",
+ thermal_exc_event->threshold);
+ break;
+ }
+
+ json_array_add_value_object(valid, valid_attrs);
+ offset += le16_to_cpu(pevent_entry_head->el);
+ }
+
+ json_object_add_value_array(root, "list_of_event_entries", valid);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+ __u32 offset, por_info_len, por_info_list;
+ __u64 *fw_rev;
+ struct nvme_smart_log *smart_event;
+ struct nvme_fw_commit_event *fw_commit_event;
+ struct nvme_time_stamp_change_event *ts_change_event;
+ struct nvme_power_on_reset_info_list *por_event;
+ struct nvme_nss_hw_err_event *nss_hw_err_event;
+ struct nvme_change_ns_event *ns_event;
+ struct nvme_format_nvm_start_event *format_start_event;
+ struct nvme_format_nvm_compln_event *format_cmpln_event;
+ struct nvme_sanitize_start_event *sanitize_start_event;
+ struct nvme_sanitize_compln_event *sanitize_cmpln_event;
+ struct nvme_thermal_exc_event *thermal_exc_event;
+ struct nvme_persistent_event_log_head *pevent_log_head;
+ struct nvme_persistent_event_entry_head *pevent_entry_head;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)pevent_log_info, size);
+ if (flags & JSON)
+ return json_persistent_event_log(pevent_log_info, size);
+
+ offset = sizeof(*pevent_log_head);
+
+ printf("Persistent Event Log for device: %s\n", devname);
+ printf("Action for Persistent Event Log: %u\n", action);
+ if (size >= offset) {
+ pevent_log_head = pevent_log_info;
+ printf("Log Identifier: %u\n", pevent_log_head->log_id);
+ printf("Total Number of Events: %u\n",
+ le32_to_cpu(pevent_log_head->tnev));
+ printf("Total Log Length : %"PRIu64"\n",
+ le64_to_cpu(pevent_log_head->tll));
+ printf("Log Revision: %u\n", pevent_log_head->log_rev);
+ printf("Log Header Length: %u\n", pevent_log_head->head_len);
+ printf("Timestamp: %"PRIu64"\n",
+ le64_to_cpu(pevent_log_head->timestamp));
+ printf("Power On Hours (POH): %'.0Lf\n",
+ int128_to_double(pevent_log_head->poh));
+ printf("Power Cycle Count: %"PRIu64"\n",
+ le64_to_cpu(pevent_log_head->pcc));
+ printf("PCI Vendor ID (VID): %u\n",
+ le16_to_cpu(pevent_log_head->vid));
+ printf("PCI Subsystem Vendor ID (SSVID): %u\n",
+ le16_to_cpu(pevent_log_head->ssvid));
+ printf("Serial Number (SN): %-.*s\n",
+ (int)sizeof(pevent_log_head->sn), pevent_log_head->sn);
+ printf("Model Number (MN): %-.*s\n",
+ (int)sizeof(pevent_log_head->mn), pevent_log_head->mn);
+ printf("NVM Subsystem NVMe Qualified Name (SUBNQN): %-.*s\n",
+ (int)sizeof(pevent_log_head->subnqn),
+ pevent_log_head->subnqn);
+ printf("Supported Events Bitmap: ");
+ for (int i = 0; i < 32; i++) {
+ if (pevent_log_head->supp_event_bm[i] == 0)
+ continue;
+ printf("BitMap[%d] is 0x%x\n", i,
+ pevent_log_head->supp_event_bm[i]);
+ }
+ } else {
+ printf("No log data can be shown with this log len at least " \
+ "512 bytes is required or can be 0 to read the complete "\
+ "log page after context established\n");
+ return;
+ }
+ printf("\n");
+ printf("\nPersistent Event Entries:\n");
+ for (int i = 0; i < le32_to_cpu(pevent_log_head->tnev); i++) {
+ if (offset + sizeof(*pevent_entry_head) >= size)
+ break;
+
+ pevent_entry_head = pevent_log_info + offset;
+
+ if ((offset + pevent_entry_head->ehl + 3 +
+ le16_to_cpu(pevent_entry_head->el)) >= size)
+ break;
+
+ printf("Event Type: %u\n", pevent_entry_head->etype);
+ printf("Event Type Revision: %u\n", pevent_entry_head->etype_rev);
+ printf("Event Header Length: %u\n", pevent_entry_head->ehl);
+ printf("Controller Identifier: %u\n",
+ le16_to_cpu(pevent_entry_head->ctrl_id));
+ printf("Event Timestamp: %"PRIu64"\n",
+ le64_to_cpu(pevent_entry_head->etimestamp));
+ printf("Vendor Specific Information Length: %u\n",
+ le16_to_cpu(pevent_entry_head->vsil));
+ printf("Event Length: %u\n", le16_to_cpu(pevent_entry_head->el));
+
+ offset += pevent_entry_head->ehl + 3;
+
+ switch (pevent_entry_head->etype) {
+ case NVME_SMART_HEALTH_EVENT:
+ smart_event = pevent_log_info + offset;
+ printf("Smart Health Event: \n");
+ nvme_show_smart_log(smart_event, NVME_NSID_ALL, devname, flags);
+ break;
+ case NVME_FW_COMMIT_EVENT:
+ fw_commit_event = pevent_log_info + offset;
+ printf("FW Commit Event: \n");
+ printf("Old Firmware Revision: %"PRIu64"\n",
+ le64_to_cpu(fw_commit_event->old_fw_rev));
+ printf("New Firmware Revision: %"PRIu64"\n",
+ le64_to_cpu(fw_commit_event->new_fw_rev));
+ printf("FW Commit Action: %u\n",
+ fw_commit_event->fw_commit_action);
+ printf("FW Slot: %u\n", fw_commit_event->fw_slot);
+ printf("Status Code Type for Firmware Commit Command: %u\n",
+ fw_commit_event->sct_fw);
+ printf("Status Returned for Firmware Commit Command: %u\n",
+ fw_commit_event->sc_fw);
+ printf("Vendor Assigned Firmware Commit Result Code: %u\n",
+ le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc));
+ break;
+ case NVME_TIMESTAMP_EVENT:
+ ts_change_event = pevent_log_info + offset;
+ printf("Time Stamp Change Event: \n");
+ printf("Previous Timestamp: %"PRIu64"\n",
+ le64_to_cpu(ts_change_event->previous_timestamp));
+ printf("Milliseconds Since Reset: %"PRIu64"\n",
+ le64_to_cpu(ts_change_event->ml_secs_since_reset));
+ break;
+ case NVME_POWER_ON_RESET_EVENT:
+ por_info_len = (le16_to_cpu(pevent_entry_head->el) -
+ le16_to_cpu(pevent_entry_head->vsil) - sizeof(*fw_rev));
+
+ por_info_list = por_info_len / sizeof(*por_event);
+
+ printf("Power On Reset Event: \n");
+ fw_rev = pevent_log_info + offset;
+ printf("Firmware Revision: %"PRIu64"\n", le64_to_cpu(*fw_rev));
+ printf("Reset Information List: \n");
+
+ for (int i = 0; i < por_info_list; i++) {
+ por_event = pevent_log_info + offset +
+ sizeof(*fw_rev) + i * sizeof(*por_event);
+ printf("Controller ID: %u\n", le16_to_cpu(por_event->cid));
+ printf("Firmware Activation: %u\n",
+ por_event->fw_act);
+ printf("Operation in Progress: %u\n",
+ por_event->op_in_prog);
+ printf("Controller Power Cycle: %u\n",
+ le32_to_cpu(por_event->ctrl_power_cycle));
+ printf("Power on milliseconds: %"PRIu64"\n",
+ le64_to_cpu(por_event->power_on_ml_seconds));
+ printf("Controller Timestamp: %"PRIu64"\n",
+ le64_to_cpu(por_event->ctrl_time_stamp));
+ }
+ break;
+ case NVME_NSS_HW_ERROR_EVENT:
+ nss_hw_err_event = pevent_log_info + offset;
+ printf("NVM Subsystem Hardware Error Event Code: %u, %s\n",
+ le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code),
+ nvme_show_nss_hw_error(nss_hw_err_event->nss_hw_err_event_code));
+ break;
+ case NVME_CHANGE_NS_EVENT:
+ ns_event = pevent_log_info + offset;
+ printf("Change Namespace Event: \n");
+ printf("Namespace Management CDW10: %u\n",
+ le32_to_cpu(ns_event->nsmgt_cdw10));
+ printf("Namespace Size: %"PRIu64"\n",
+ le64_to_cpu(ns_event->nsze));
+ printf("Namespace Capacity: %"PRIu64"\n",
+ le64_to_cpu(ns_event->nscap));
+ printf("Formatted LBA Size: %u\n", ns_event->flbas);
+ printf("End-to-end Data Protection Type Settings: %u\n",
+ ns_event->dps);
+ printf("Namespace Multi-path I/O and Namespace Sharing" \
+ " Capabilities: %u\n", ns_event->nmic);
+ printf("ANA Group Identifier: %u\n",
+ le32_to_cpu(ns_event->ana_grp_id));
+ printf("NVM Set Identifier: %u\n", le16_to_cpu(ns_event->nvmset_id));
+ printf("Namespace ID: %u\n", le32_to_cpu(ns_event->nsid));
+ break;
+ case NVME_FORMAT_START_EVENT:
+ format_start_event = pevent_log_info + offset;
+ printf("Format NVM Start Event: \n");
+ printf("Namespace Identifier: %u\n",
+ le32_to_cpu(format_start_event->nsid));
+ printf("Format NVM Attributes: %u\n",
+ format_start_event->fna);
+ printf("Format NVM CDW10: %u\n",
+ le32_to_cpu(format_start_event->format_nvm_cdw10));
+ break;
+ case NVME_FORMAT_COMPLETION_EVENT:
+ format_cmpln_event = pevent_log_info + offset;
+ printf("Format NVM Completion Event: \n");
+ printf("Namespace Identifier: %u\n",
+ le32_to_cpu(format_cmpln_event->nsid));
+ printf("Smallest Format Progress Indicator: %u\n",
+ format_cmpln_event->smallest_fpi);
+ printf("Format NVM Status: %u\n",
+ format_cmpln_event->format_nvm_status);
+ printf("Completion Information: %u\n",
+ le16_to_cpu(format_cmpln_event->compln_info));
+ printf("Status Field: %u\n",
+ le32_to_cpu(format_cmpln_event->status_field));
+ break;
+ case NVME_SANITIZE_START_EVENT:
+ sanitize_start_event = pevent_log_info + offset;
+ printf("Sanitize Start Event: \n");
+ printf("SANICAP: %u\n", sanitize_start_event->sani_cap);
+ printf("Sanitize CDW10: %u\n",
+ le32_to_cpu(sanitize_start_event->sani_cdw10));
+ printf("Sanitize CDW11: %u\n",
+ le32_to_cpu(sanitize_start_event->sani_cdw11));
+ break;
+ case NVME_SANITIZE_COMPLETION_EVENT:
+ sanitize_cmpln_event = pevent_log_info + offset;
+ printf("Sanitize Completion Event: \n");
+ printf("Sanitize Progress: %u\n",
+ le16_to_cpu(sanitize_cmpln_event->sani_prog));
+ printf("Sanitize Status: %u\n",
+ le16_to_cpu(sanitize_cmpln_event->sani_status));
+ printf("Completion Information: %u\n",
+ le16_to_cpu(sanitize_cmpln_event->cmpln_info));
+ break;
+ case NVME_THERMAL_EXCURSION_EVENT:
+ thermal_exc_event = pevent_log_info + offset;
+ printf("Thermal Excursion Event: \n");
+ printf("Over Temperature: %u\n", thermal_exc_event->over_temp);
+ printf("Threshold: %u\n", thermal_exc_event->threshold);
+ break;
+ default:
+ printf("Reserved Event\n\n");
+ }
+ offset += le16_to_cpu(pevent_entry_head->el);
+ printf("\n");
+ }
+}
+
+void json_endurance_group_event_agg_log(
+ struct nvme_event_agg_log_page *endurance_log,
+ __u64 log_entries)
+{
+ struct json_object *root;
+ struct json_object *valid_attrs;
+ struct json_object *valid;
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "num_entries_avail",
+ le64_to_cpu(endurance_log->num_entries));
+ valid = json_create_array();
+
+ for (int i = 0; i < log_entries; i++) {
+ valid_attrs = json_create_object();
+ json_object_add_value_uint(valid_attrs, "entry",
+ le16_to_cpu(endurance_log->entries[i]));
+ json_array_add_value_object(valid, valid_attrs);
+ }
+ json_object_add_value_array(root, "list_of_entries", valid);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_endurance_group_event_agg_log(
+ struct nvme_event_agg_log_page *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)endurance_log, size);
+ if (flags & JSON)
+ return json_endurance_group_event_agg_log(endurance_log,
+ log_entries);
+
+ printf("Endurance Group Event Aggregate Log for"\
+ " device: %s\n", devname);
+
+ printf("Number of Entries Available: %"PRIu64"\n",
+ le64_to_cpu(endurance_log->num_entries));
+
+ for (int i = 0; i < log_entries; i++) {
+ printf("Entry[%d]: %u\n", i + 1,
+ le16_to_cpu(endurance_log->entries[i]));
+ }
+}
+
+void json_lba_status_log(void *lba_status)
+{
+ struct json_object *root;
+ struct json_object *desc;
+ struct json_object *element;
+ struct json_object *desc_list;
+ struct json_object *elements_list;
+ struct nvme_lba_status_hdr *hdr;
+ struct nvme_lba_status_ns_element *ns_element;
+ struct nvme_lba_status_range_desc *range_desc;
+ int offset = sizeof(*hdr);
+ __u32 num_lba_desc, num_elements;
+
+ root = json_create_object();
+ hdr = lba_status;
+ json_object_add_value_uint(root, "lslplen", le32_to_cpu(hdr->lslplen));
+ num_elements = le32_to_cpu(hdr->nlslne);
+ json_object_add_value_uint(root, "nlslne", num_elements);
+ json_object_add_value_uint(root, "estulb", le32_to_cpu(hdr->estulb));
+ json_object_add_value_uint(root, "lsgc", le16_to_cpu(hdr->lsgc));
+
+ elements_list = json_create_array();
+ for (int ele = 0; ele < num_elements; ele++) {
+ ns_element = lba_status + offset;
+ element = json_create_object();
+ json_object_add_value_uint(element, "neid",
+ le32_to_cpu(ns_element->neid));
+ num_lba_desc = le32_to_cpu(ns_element->nlrd);
+ json_object_add_value_uint(element, "nlrd", num_lba_desc);
+ json_object_add_value_uint(element, "ratype", ns_element->ratype);
+
+ offset += sizeof(*ns_element);
+ desc_list = json_create_array();
+ if (num_lba_desc != 0xffffffff) {
+ for (int i = 0; i < num_lba_desc; i++) {
+ range_desc = lba_status + offset;
+ desc = json_create_object();
+ json_object_add_value_uint(desc, "rslba",
+ le64_to_cpu(range_desc->rslba));
+ json_object_add_value_uint(desc, "rnlb",
+ le32_to_cpu(range_desc->rnlb));
+
+ offset += sizeof(*range_desc);
+ json_array_add_value_object(desc_list, desc);
+ }
+ } else {
+ printf("Number of LBA Range Descriptors (NLRD) set to %#x for " \
+ "NS element %d", num_lba_desc, ele);
+ }
+
+ json_object_add_value_array(element, "descs", desc_list);
+ json_array_add_value_object(elements_list, element);
+ }
+
+ json_object_add_value_array(root, "ns_elements", elements_list);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_lba_status_log(void *lba_status, __u32 size,
+ const char *devname, enum nvme_print_flags flags)
+{
+ struct nvme_lba_status_hdr *hdr;
+ struct nvme_lba_status_ns_element *ns_element;
+ struct nvme_lba_status_range_desc *range_desc;
+ int offset = sizeof(*hdr);
+ __u32 num_lba_desc, num_elements;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)lba_status, size);
+ if (flags & JSON)
+ return json_lba_status_log(lba_status);
+
+ hdr = lba_status;
+ printf("LBA Status Log for device: %s\n", devname);
+ printf("LBA Status Log Page Length: %"PRIu32"\n",
+ le32_to_cpu(hdr->lslplen));
+ num_elements = le32_to_cpu(hdr->nlslne);
+ printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n",
+ num_elements);
+ printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n",
+ le32_to_cpu(hdr->estulb));
+ printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc));
+ for (int ele = 0; ele < num_elements; ele++) {
+ ns_element = lba_status + offset;
+ printf("Namespace Element Identifier: %"PRIu32"\n",
+ le32_to_cpu(ns_element->neid));
+ num_lba_desc = le32_to_cpu(ns_element->nlrd);
+ printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc);
+ printf("Recommended Action Type: %u\n", ns_element->ratype);
+
+ offset += sizeof(*ns_element);
+ if (num_lba_desc != 0xffffffff) {
+ for (int i = 0; i < num_lba_desc; i++) {
+ range_desc = lba_status + offset;
+ printf("RSLBA[%d]: %"PRIu64"\n", i,
+ le64_to_cpu(range_desc->rslba));
+ printf("RNLB[%d]: %"PRIu32"\n", i,
+ le32_to_cpu(range_desc->rnlb));
+ offset += sizeof(*range_desc);
+ }
+ } else {
+ printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\
+ "NS element %d\n", num_lba_desc, ele);
+ }
+ }
+}
+
+static const char *resv_notif_to_string(__u8 type)
+{
+ switch (type) {
+ case 0x1: return "Empty Log Page";
+ case 0x2: return "Registration Preempted";
+ case 0x3: return "Reservation Released";
+ case 0x4: return "Reservation Preempted";
+ default: return "Reserved";
+ }
+}
+
+static void json_resv_notif_log(struct nvme_resv_notif_log *resv)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "count",
+ le64_to_cpu(resv->log_page_count));
+ json_object_add_value_uint(root, "rn_log_type",
+ resv->resv_notif_log_type);
+ json_object_add_value_uint(root, "num_logs",
+ resv->num_logs);
+ json_object_add_value_uint(root, "nsid",
+ le32_to_cpu(resv->nsid));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_resv_notif_log(struct nvme_resv_notif_log *resv,
+ const char *devname, enum nvme_print_flags flags)
+{
+ if (flags & BINARY)
+ return d_raw((unsigned char *)resv, sizeof(*resv));
+ if (flags & JSON)
+ return json_resv_notif_log(resv);
+
+ printf("Reservation Notif Log for device: %s\n", devname);
+ printf("Log Page Count : %"PRIx64"\n",
+ le64_to_cpu(resv->log_page_count));
+ printf("Resv Notif Log Page Type : %u (%s)\n",
+ resv->resv_notif_log_type,
+ resv_notif_to_string(resv->resv_notif_log_type));
+ printf("Num of Available Log Pages : %u\n", resv->num_logs);
+ printf("Namespace ID: : %"PRIx32"\n",
+ le32_to_cpu(resv->nsid));
+}
+
static void nvme_show_subsystem(struct nvme_subsystem *s)
{
int i;
@@ -869,9 +1792,9 @@ static void nvme_show_subsystem(struct nvme_subsystem *s)
for (i = 0; i < s->nr_ctrls; i++) {
printf(" +- %s %s %s %s %s\n", s->ctrls[i].name,
- s->ctrls[i].transport,
- s->ctrls[i].address,
- s->ctrls[i].state,
+ s->ctrls[i].transport ? : "",
+ s->ctrls[i].address ? : "",
+ s->ctrls[i].state ? : "",
s->ctrls[i].ana_state ? : "");
}
}
@@ -879,7 +1802,7 @@ static void nvme_show_subsystem(struct nvme_subsystem *s)
static void json_print_nvme_subsystem_list(struct nvme_topology *t)
{
struct json_object *subsystem_attrs, *path_attrs;
- struct json_array *subsystems, *paths;
+ struct json_object *subsystems, *paths;
struct json_object *root;
int i, j;
@@ -904,12 +1827,15 @@ static void json_print_nvme_subsystem_list(struct nvme_topology *t)
path_attrs = json_create_object();
json_object_add_value_string(path_attrs, "Name",
c->name);
- json_object_add_value_string(path_attrs, "Transport",
- c->transport);
- json_object_add_value_string(path_attrs, "Address",
- c->address);
- json_object_add_value_string(path_attrs, "State",
- c->state);
+ if (c->transport)
+ json_object_add_value_string(path_attrs,
+ "Transport", c->transport);
+ if (c->address)
+ json_object_add_value_string(path_attrs,
+ "Address", c->address);
+ if (c->state)
+ json_object_add_value_string(path_attrs,
+ "State", c->state);
if (c->ana_state)
json_object_add_value_string(path_attrs,
"ANAState", c->ana_state);
@@ -946,14 +1872,16 @@ static void nvme_show_registers_cap(struct nvme_bar_cap *cap)
"Not Supported");
printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n",
(cap->rsvd_cmbs_pmrs & 0x01) ? "Supported" : "Not Supported");
- printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n",
+ printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n",
1 << (12 + ((cap->mpsmax_mpsmin & 0xf0) >> 4)));
printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n",
1 << (12 + (cap->mpsmax_mpsmin & 0x0f)));
printf("\tBoot Partition Support (BPS): %s\n",
(cap->bps_css_nssrs_dstrd & 0x2000) ? "Yes":"No");
printf("\tCommand Sets Supported (CSS): NVM command set is %s\n",
- (cap->bps_css_nssrs_dstrd & 0x0020) ? "supported":"not supported");
+ (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("\tNVM Subsystem Reset Supported (NSSRS): %s\n",
(cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No");
printf("\tDoorbell Stride (DSTRD): %u bytes\n",
@@ -962,7 +1890,7 @@ static void nvme_show_registers_cap(struct nvme_bar_cap *cap)
cap->to * 500);
printf("\tArbitration Mechanism Supported (AMS): Weighted Round Robin with Urgent Priority Class is %s\n",
(cap->ams_cqr & 0x02) ? "supported":"not supported");
- printf("\tContiguous Queues Required (CQR): %s\n",
+ printf("\tContiguous Queues Required (CQR): %s\n",
(cap->ams_cqr & 0x01) ? "Yes":"No");
printf("\tMaximum Queue Entries Supported (MQES): %u\n\n",
cap->mqes + 1);
@@ -1020,8 +1948,10 @@ static void nvme_show_registers_cc(__u32 cc)
nvme_show_registers_cc_ams((cc & 0x00003800) >> NVME_CC_AMS_SHIFT);
printf("\tMemory Page Size (MPS): %u bytes\n",
1 << (12 + ((cc & 0x00000780) >> NVME_CC_MPS_SHIFT)));
- printf("\tI/O Command Sets Selected (CSS): %s\n",
- (cc & 0x00000070) ? "Reserved":"NVM Command Set");
+ printf("\tI/O Command Set Selected (CSS): %s\n",
+ (cc & 0x00000070) == 0x00 ? "NVM Command Set" :
+ (cc & 0x00000070) == 0x60 ? "All supported I/O Command Sets" :
+ (cc & 0x00000070) == 0x70 ? "Admin Command Set only" : "Reserved");
printf("\tEnable (EN): %s\n\n",
(cc & 0x00000001) ? "Yes":"No");
}
@@ -1199,11 +2129,11 @@ static void nvme_show_registers_bpmbl(uint64_t bpmbl)
static void nvme_show_registers_cmbmsc(uint64_t cmbmsc)
{
- printf("\tController Base Address (CBA) : %" PRIx64 "\n",
+ printf("\tController Base Address (CBA): %" PRIx64 "\n",
(cmbmsc & 0xfffffffffffff000) >> 12);
printf("\tController Memory Space Enable (CMSE): %" PRIx64 "\n",
(cmbmsc & 0x0000000000000002) >> 1);
- printf("\tCapabilities Registers Enabled (CRE) : CMBLOC and "\
+ printf("\tCapabilities Registers Enabled (CRE): CMBLOC and "\
"CMBSZ registers are%senabled\n\n",
(cmbmsc & 0x0000000000000001) ? " " : " NOT ");
}
@@ -1216,20 +2146,20 @@ static void nvme_show_registers_cmbsts(__u32 cmbsts)
static void nvme_show_registers_pmrcap(__u32 pmrcap)
{
- printf("\tController Memory Space Supported (CMSS) : "\
+ printf("\tController Memory Space Supported (CMSS): "\
"Referencing PMR with host supplied addresses is %s\n",
((pmrcap & 0x01000000) >> 24) ? "Supported" : "Not Supported");
- printf("\tPersistent Memory Region Timeout (PMRTO): %x\n",
+ printf("\tPersistent Memory Region Timeout (PMRTO): %x\n",
(pmrcap & 0x00ff0000) >> 16);
- printf("\tPersistent Memory Region Write Barrier Mechanisms(PMRWBM): %x\n",
+ printf("\tPersistent Memory Region Write Barrier Mechanisms (PMRWBM): %x\n",
(pmrcap & 0x00003c00) >> 10);
- printf("\tPersistent Memory Region Time Units (PMRTU): PMR time unit is %s\n",
+ printf("\tPersistent Memory Region Time Units (PMRTU): PMR time unit is %s\n",
(pmrcap & 0x00000300) >> 8 ? "minutes":"500 milliseconds");
- printf("\tBase Indicator Register (BIR): %x\n",
+ printf("\tBase Indicator Register (BIR): %x\n",
(pmrcap & 0x000000e0) >> 5);
- printf("\tWrite Data Support (WDS): Write data to the PMR is %s\n",
+ printf("\tWrite Data Support (WDS): Write data to the PMR is %s\n",
(pmrcap & 0x00000010) ? "supported":"not supported");
- printf("\tRead Data Support (RDS): Read data from the PMR is %s\n",
+ printf("\tRead Data Support (RDS): Read data from the PMR is %s\n",
(pmrcap & 0x00000008) ? "supported":"not supported");
}
@@ -1254,14 +2184,14 @@ static void nvme_show_registers_pmrsts(__u32 pmrsts, __u32 pmrctl)
{
printf("\tController Base Address Invalid (CBAI): %x\n",
(pmrsts & 0x00001000) >> 12);
- printf("\tHealth Status (HSTS): %s\n",
+ printf("\tHealth Status (HSTS): %s\n",
nvme_register_pmr_hsts_to_string((pmrsts & 0x00000e00) >> 9));
- printf("\tNot Ready (NRDY): "\
+ printf("\tNot Ready (NRDY): "\
"The Persistent Memory Region is %s to process "\
"PCI Express memory read and write requests\n",
(pmrsts & 0x00000100) == 0 && (pmrctl & 0x00000001) ?
"READY":"Not Ready");
- printf("\tError (ERR) : %x\n", (pmrsts & 0x000000ff));
+ printf("\tError (ERR): %x\n", (pmrsts & 0x000000ff));
}
static const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu)
@@ -1278,7 +2208,7 @@ static const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu)
static void nvme_show_registers_pmrebs(__u32 pmrebs)
{
printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", (pmrebs & 0xffffff00) >> 8);
- printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\
+ printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\
"in the PMR Elasticity Buffer %s bypass those memory writes\n",
(pmrebs & 0x00000010) ? "SHALL":"MAY");
printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n",
@@ -1293,12 +2223,18 @@ static void nvme_show_registers_pmrswtp(__u32 pmrswtp)
nvme_register_pmr_pmrszu_to_string(pmrswtp & 0x0000000f));
}
-static void nvme_show_registers_pmrmsc(uint64_t pmrmsc)
+static void nvme_show_registers_pmrmscl(uint32_t pmrmscl)
+{
+ printf("\tController Base Address (CBA): %#x\n",
+ (pmrmscl & 0xfffff000) >> 12);
+ printf("\tController Memory Space Enable (CMSE): %#x\n\n",
+ (pmrmscl & 0x00000002) >> 1);
+}
+
+static void nvme_show_registers_pmrmscu(uint32_t pmrmscu)
{
- printf("\tController Base Address (CBA) : %" PRIx64 "\n",
- (pmrmsc & 0xfffffffffffff000) >> 12);
- printf("\tController Memory Space Enable (CMSE) : %" PRIx64 "\n\n",
- (pmrmsc & 0x0000000000000002) >> 1);
+ printf("\tController Base Address (CBA): %#x\n",
+ pmrmscu);
}
static inline uint32_t mmio_read32(void *addr)
@@ -1311,16 +2247,21 @@ static inline uint32_t mmio_read32(void *addr)
/* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */
static inline __u64 mmio_read64(void *addr)
{
- __le32 *p = addr;
+ const volatile __u32 *p = addr;
+ __u32 low, high;
+
+ low = le32_to_cpu(*p);
+ high = le32_to_cpu(*(p + 1));
- return le32_to_cpu(*p) | ((uint64_t)le32_to_cpu(*(p + 1)) << 32);
+ return ((__u64) high << 32) | low;
}
static void json_ctrl_registers(void *bar)
{
- uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc;
+ uint64_t cap, asq, acq, bpmbl, cmbmsc;
uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc,
- bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp;
+ bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp,
+ pmrmscl, pmrmscu;
struct json_object *root;
cap = mmio_read64(bar + NVME_REG_CAP);
@@ -1345,7 +2286,8 @@ static void json_ctrl_registers(void *bar)
pmrsts = mmio_read32(bar + NVME_REG_PMRSTS);
pmrebs = mmio_read32(bar + NVME_REG_PMREBS);
pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP);
- pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC);
+ pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL);
+ pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU);
root = json_create_object();
json_object_add_value_uint(root, "cap", cap);
@@ -1370,7 +2312,8 @@ static void json_ctrl_registers(void *bar)
json_object_add_value_int(root, "pmrsts", pmrsts);
json_object_add_value_int(root, "pmrebs", pmrebs);
json_object_add_value_int(root, "pmrswtp", pmrswtp);
- json_object_add_value_uint(root, "pmrmsc", pmrmsc);
+ json_object_add_value_uint(root, "pmrmscl", pmrmscl);
+ json_object_add_value_uint(root, "pmrmscu", pmrmscu);
json_print_object(root, NULL);
printf("\n");
json_free_object(root);
@@ -1378,10 +2321,11 @@ static void json_ctrl_registers(void *bar)
void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags)
{
- const unsigned int reg_size = 0x50; /* 00h to 4Fh */
- uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc;
+ const unsigned int reg_size = 0x0e1c; /* 0x0000 to 0x0e1b */
+ uint64_t cap, asq, acq, bpmbl, cmbmsc;
uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc, bpinfo,
- bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp;
+ bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp,
+ pmrmscl, pmrmscu;
int human = flags & VERBOSE;
if (flags & BINARY)
@@ -1411,7 +2355,8 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla
pmrsts = mmio_read32(bar + NVME_REG_PMRSTS);
pmrebs = mmio_read32(bar + NVME_REG_PMREBS);
pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP);
- pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC);
+ pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL);
+ pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU);
if (human) {
if (cap != 0xffffffff) {
@@ -1490,8 +2435,11 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla
printf("pmrswtp : %x\n", pmrswtp);
nvme_show_registers_pmrswtp(pmrswtp);
- printf("pmrmsc : %"PRIx64"\n", pmrmsc);
- nvme_show_registers_pmrmsc(pmrmsc);
+ printf("pmrmscl : %#x\n", pmrmscl);
+ nvme_show_registers_pmrmscl(pmrmscl);
+
+ printf("pmrmscu : %#x\n", pmrmscu);
+ nvme_show_registers_pmrmscu(pmrmscu);
}
} else {
if (cap != 0xffffffff)
@@ -1522,7 +2470,8 @@ void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags fla
printf("pmrsts : %x\n", pmrsts);
printf("pmrebs : %x\n", pmrebs);
printf("pmrswtp : %x\n", pmrswtp);
- printf("pmrmsc : %"PRIx64"\n", pmrmsc);
+ printf("pmrmscl : %#x\n", pmrmscl);
+ printf("pmrmscu : %#x\n", pmrmscu);
}
}
}
@@ -1615,7 +2564,7 @@ void nvme_show_relatives(const char *name)
free(path);
return;
}
- err = scan_subsystems(&t, subsysnqn, 0);
+ err = scan_subsystems(&t, subsysnqn, 0, 0, NULL);
if (err || t.nr_subsystems != 1) {
free(subsysnqn);
free(path);
@@ -1698,7 +2647,7 @@ void d_raw(unsigned char *buf, unsigned len)
{
unsigned i;
for (i = 0; i < len; i++)
- putchar(*(buf+i));
+ putchar(*(buf + i));
}
void nvme_show_status(__u16 status)
@@ -1765,17 +2714,23 @@ 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 & 0xFFFF8000) >> 15;
+ __u32 rsvd0 = (oaes & 0xF0000000) >> 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 egealpcn = (oaes & 0x4000) >> 14;
- __u32 rsvd1 = oaes & 0xFF;
+ __u32 rsvd2 = oaes & 0xFF;
if (rsvd0)
- printf(" [31:10] : %#x\tReserved\n", rsvd0);
+ printf(" [31: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"\
" Change Notice %sSupported\n",
egealpcn, egealpcn ? "" : "Not ");
@@ -1790,7 +2745,7 @@ static void nvme_show_id_ctrl_oaes(__le32 ctrl_oaes)
fan, fan ? "" : "Not ");
printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n",
nace, nace ? "" : "Not ");
- if (rsvd1)
+ if (rsvd2)
printf(" [7:0] : %#x\tReserved\n", rsvd1);
printf("\n");
}
@@ -1955,7 +2910,7 @@ static void nvme_show_id_ctrl_apsta(__u8 apsta)
printf("\n");
}
-static void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs)
+void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs)
{
__u32 rpmbs = le32_to_cpu(ctrl_rpmbs);
__u32 asz = (rpmbs & 0xFF000000) >> 24;
@@ -2068,7 +3023,8 @@ static void nvme_show_id_ctrl_cqes(__u8 cqes)
static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs)
{
__u16 oncs = le16_to_cpu(ctrl_oncs);
- __u16 rsvd = (oncs & 0xFF00) >> 8;
+ __u16 rsvd = (oncs & 0xFE00) >> 9;
+ __u16 copy = (oncs & 0x100) >> 8;
__u16 vrfy = (oncs & 0x80) >> 7;
__u16 tmst = (oncs & 0x40) >> 6;
__u16 resv = (oncs & 0x20) >> 5;
@@ -2079,7 +3035,9 @@ static void nvme_show_id_ctrl_oncs(__le16 ctrl_oncs)
__u16 cmp = oncs & 0x1;
if (rsvd)
- printf(" [15:8] : %#x\tReserved\n", rsvd);
+ printf(" [15:9] : %#x\tReserved\n", rsvd);
+ printf(" [8:8] : %#x\tCopy %sSupported\n",
+ copy, copy ? "" : "Not ");
printf(" [7:7] : %#x\tVerify %sSupported\n",
vrfy, vrfy ? "" : "Not ");
printf(" [6:6] : %#x\tTimestamp %sSupported\n",
@@ -2150,10 +3108,10 @@ static void nvme_show_id_ctrl_vwc(__u8 vwc)
printf("\n");
}
-static void nvme_show_id_ctrl_nvscc(__u8 nvscc)
+static void nvme_show_id_ctrl_icsvscc(__u8 icsvscc)
{
- __u8 rsvd = (nvscc & 0xFE) >> 1;
- __u8 fmt = nvscc & 0x1;
+ __u8 rsvd = (icsvscc & 0xFE) >> 1;
+ __u8 fmt = icsvscc & 0x1;
if (rsvd)
printf(" [7:1] : %#x\tReserved\n", rsvd);
printf(" [0:0] : %#x\tNVM Vendor Specific Commands uses %s Format\n",
@@ -2233,10 +3191,10 @@ static void nvme_show_id_ctrl_sgls(__le32 ctrl_sgls)
printf("\n");
}
-static void nvme_show_id_ctrl_ctrattr(__u8 ctrattr)
+static void nvme_show_id_ctrl_fcatt(__u8 fcatt)
{
- __u8 rsvd = (ctrattr & 0xFE) >> 1;
- __u8 scm = ctrattr & 0x1;
+ __u8 rsvd = (fcatt & 0xFE) >> 1;
+ __u8 scm = fcatt & 0x1;
if (rsvd)
printf(" [7:1] : %#x\tReserved\n", rsvd);
printf(" [0:0] : %#x\t%s Controller Model\n",
@@ -2244,10 +3202,23 @@ static void nvme_show_id_ctrl_ctrattr(__u8 ctrattr)
printf("\n");
}
+static void nvme_show_id_ctrl_ofcs(__le16 ofcs)
+{
+ __u16 rsvd = (ofcs & 0xfffe) >> 1;
+ __u8 disconn = ofcs & 0x1;
+ if (rsvd)
+ printf(" [15:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tDisconnect command %s Supported\n",
+ disconn, disconn ? "" : "Not");
+ printf("\n");
+
+}
+
static void nvme_show_id_ns_nsfeat(__u8 nsfeat)
{
__u8 rsvd = (nsfeat & 0xE0) >> 5;
__u8 ioopt = (nsfeat & 0x10) >> 4;
+ __u8 uidreuse = (nsfeat & 0x8) >> 3;
__u8 dulbe = (nsfeat & 0x4) >> 2;
__u8 na = (nsfeat & 0x2) >> 1;
__u8 thin = nsfeat & 0x1;
@@ -2255,6 +3226,8 @@ static void nvme_show_id_ns_nsfeat(__u8 nsfeat)
printf(" [7:5] : %#x\tReserved\n", rsvd);
printf(" [4:4] : %#x\tNPWG, NPWA, NPDG, NPDA, and NOWS are %sSupported\n",
ioopt, ioopt ? "" : "Not ");
+ printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n",
+ uidreuse, uidreuse ? "Never " : "");
printf(" [2:2] : %#x\tDeallocated or Unwritten Logical Block error %sSupported\n",
dulbe, dulbe ? "" : "Not ");
printf(" [1:1] : %#x\tNamespace uses %s\n",
@@ -2344,7 +3317,7 @@ static void nvme_show_id_ns_nmic(__u8 nmic)
static void nvme_show_id_ns_rescap(__u8 rescap)
{
- __u8 rsvd = (rescap & 0x80) >> 7;
+ __u8 iekr = (rescap & 0x80) >> 7;
__u8 eaar = (rescap & 0x40) >> 6;
__u8 wear = (rescap & 0x20) >> 5;
__u8 earo = (rescap & 0x10) >> 4;
@@ -2352,8 +3325,9 @@ static void nvme_show_id_ns_rescap(__u8 rescap)
__u8 ea = (rescap & 0x4) >> 2;
__u8 we = (rescap & 0x2) >> 1;
__u8 ptpl = rescap & 0x1;
- if (rsvd)
- printf(" [7:7] : %#x\tReserved\n", rsvd);
+
+ printf(" [7:7] : %#x\tIgnore Existing Key - Used as defined in revision %s\n",
+ iekr, iekr ? "1.3 or later" : "1.2.1 or earlier");
printf(" [6:6] : %#x\tExclusive Access - All Registrants %sSupported\n",
eaar, eaar ? "" : "Not ");
printf(" [5:5] : %#x\tWrite Exclusive - All Registrants %sSupported\n",
@@ -2412,7 +3386,7 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
if (flags & BINARY)
return d_raw((unsigned char *)ns, sizeof(*ns));
if (flags & JSON)
- return json_nvme_id_ns(ns, flags);
+ return json_nvme_id_ns(ns);
printf("NVME Identify Namespace %d:\n", nsid);
printf("nsze : %#"PRIx64"\n", le64_to_cpu(ns->nsze));
@@ -2461,9 +3435,12 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
printf("npda : %u\n", le16_to_cpu(ns->npda));
printf("nows : %u\n", le16_to_cpu(ns->nows));
}
+ printf("mssrl : %u\n", le16_to_cpu(ns->mssrl));
+ printf("mcl : %d\n", le32_to_cpu(ns->mcl));
+ printf("msrc : %u\n", ns->msrc);
+ printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid));
printf("nsattr : %u\n", ns->nsattr);
printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid));
- printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid));
printf("endgid : %d\n", le16_to_cpu(ns->endgid));
printf("nguid : ");
@@ -2492,6 +3469,7 @@ void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
ns->lbaf[i].rp,
i == (ns->flbas & 0xf) ? "(in use)" : "");
}
+
if (vs) {
printf("vs[]:\n");
d(ns->vs, sizeof(ns->vs), 16, 1);
@@ -2512,10 +3490,11 @@ static void json_nvme_id_ns_descs(void *data)
#ifdef LIBUUID
uuid_t uuid;
#endif
+ __u8 csi;
} desc;
struct json_object *root;
- struct json_array *json_array = NULL;
+ struct json_object *json_array = NULL;
off_t off;
int pos, len = 0;
@@ -2557,6 +3536,12 @@ static void json_nvme_id_ns_descs(void *data)
nidt_name = "uuid";
break;
#endif
+ case NVME_NIDT_CSI:
+ memcpy(&desc.csi, data + off, sizeof(desc.csi));
+ json_str_p += sprintf(json_str_p, "%#x", desc.csi);
+ len += sizeof(desc.csi);
+ nidt_name = "csi";
+ break;
default:
/* Skip unnkown types */
len = cur->nidl;
@@ -2602,6 +3587,7 @@ void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flag
#endif
__u8 eui64[8];
__u8 nguid[16];
+ __u8 csi;
if (flags & BINARY)
return d_raw((unsigned char *)data, 0x1000);
@@ -2640,6 +3626,11 @@ void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flag
len = sizeof(uuid);
break;
#endif
+ case NVME_NIDT_CSI:
+ memcpy(&csi, data + pos + sizeof(*cur), 1);
+ printf("csi : %#x\n", csi);
+ len += sizeof(csi);
+ break;
default:
/* Skip unnkown types */
len = cur->nidl;
@@ -2716,7 +3707,7 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
if (flags & BINARY)
return d_raw((unsigned char *)ctrl, sizeof(*ctrl));
else if (flags & JSON)
- return json_nvme_id_ctrl(ctrl, flags, vendor_show);
+ return json_nvme_id_ctrl(ctrl, vendor_show);
printf("NVME Identify Controller:\n");
printf("vid : %#x\n", le16_to_cpu(ctrl->vid));
@@ -2824,9 +3815,9 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
nvme_show_id_ctrl_vwc(ctrl->vwc);
printf("awun : %d\n", le16_to_cpu(ctrl->awun));
printf("awupf : %d\n", le16_to_cpu(ctrl->awupf));
- printf("nvscc : %d\n", ctrl->nvscc);
+ printf("icsvscc : %d\n", ctrl->icsvscc);
if (human)
- nvme_show_id_ctrl_nvscc(ctrl->nvscc);
+ nvme_show_id_ctrl_icsvscc(ctrl->icsvscc);
printf("nwpc : %d\n", ctrl->nwpc);
if (human)
nvme_show_id_ctrl_nwpc(ctrl->nwpc);
@@ -2839,10 +3830,13 @@ void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
printf("ioccsz : %d\n", le32_to_cpu(ctrl->ioccsz));
printf("iorcsz : %d\n", le32_to_cpu(ctrl->iorcsz));
printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff));
- printf("ctrattr : %#x\n", ctrl->ctrattr);
+ printf("fcatt : %#x\n", ctrl->fcatt);
if (human)
- nvme_show_id_ctrl_ctrattr(ctrl->ctrattr);
+ nvme_show_id_ctrl_fcatt(ctrl->fcatt);
printf("msdbd : %d\n", ctrl->msdbd);
+ printf("ofcs : %d\n", le16_to_cpu(ctrl->ofcs));
+ if (human)
+ nvme_show_id_ctrl_ofcs(ctrl->ofcs);
nvme_show_id_ctrl_power(ctrl);
if (vendor_show)
@@ -2858,10 +3852,292 @@ void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
__nvme_show_id_ctrl(ctrl, mode, NULL);
}
+static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "vsl", ctrl_nvm->vsl);
+ 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_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm,
+ enum nvme_print_flags flags)
+{
+ if (flags & BINARY)
+ return d_raw((unsigned char *)ctrl_nvm, sizeof(*ctrl_nvm));
+ else if (flags & JSON)
+ return json_nvme_id_ctrl_nvm(ctrl_nvm);
+
+ printf("NVMe Identify Controller NVM:\n");
+ printf("vsl : %u\n", ctrl_nvm->vsl);
+ printf("wzsl : %u\n", ctrl_nvm->wzsl);
+ printf("wusl : %u\n", ctrl_nvm->wusl);
+ printf("dmrl : %u\n", ctrl_nvm->dmrl);
+ printf("dmrsl : %u\n", le32_to_cpu(ctrl_nvm->dmrsl));
+ printf("dmsl : %"PRIu64"\n", le64_to_cpu(ctrl_nvm->dmsl));
+}
+
+static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_int(root, "zasl", ctrl->zasl);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode)
+{
+ if (mode & BINARY)
+ return d_raw((unsigned char *)ctrl, sizeof(*ctrl));
+ else if (mode & JSON)
+ return json_nvme_zns_id_ctrl(ctrl);
+
+ printf("NVMe ZNS Identify Controller:\n");
+ printf("zasl : %u\n", ctrl->zasl);
+}
+
+void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns)
+{
+ struct json_object *root;
+ struct json_object *lbafs;
+ int i;
+
+ root = json_create_object();
+ json_object_add_value_int(root, "zoc", le16_to_cpu(ns->zoc));
+ json_object_add_value_int(root, "ozcs", le16_to_cpu(ns->ozcs));
+ json_object_add_value_int(root, "mar", le32_to_cpu(ns->mar));
+ json_object_add_value_int(root, "mor", le32_to_cpu(ns->mor));
+ json_object_add_value_int(root, "rrl", le32_to_cpu(ns->rrl));
+ json_object_add_value_int(root, "frl", le32_to_cpu(ns->frl));
+
+ lbafs = json_create_array();
+ json_object_add_value_array(root, "lbafe", lbafs);
+
+ for (i = 0; i <= id_ns->nlbaf; i++) {
+ struct json_object *lbaf = json_create_object();
+
+ json_object_add_value_int(lbaf, "zsze",
+ le64_to_cpu(ns->lbafe[i].zsze));
+ json_object_add_value_int(lbaf, "zdes", ns->lbafe[i].zdes);
+
+ json_array_add_value_object(lbafs, lbaf);
+ }
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void show_nvme_id_ns_zoned_zoc(__le16 ns_zoc)
+{
+ __u16 zoc = le16_to_cpu(ns_zoc);
+ __u8 rsvd = (zoc & 0xfffc) >> 2;
+ __u8 ze = (zoc & 0x2) >> 1;
+ __u8 vzc = zoc & 0x1;
+ if (rsvd)
+ printf(" [15:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] : %#x\t Zone Active Excursions: %s\n",
+ ze, ze ? "Yes (Host support required)" : "No");
+ printf(" [0:0] : %#x\t Variable Zone Capacity: %s\n",
+ vzc, vzc ? "Yes (Host support required)" : "No");
+ printf("\n");
+}
+
+static void show_nvme_id_ns_zoned_ozcs(__le16 ns_ozcs)
+{
+ __u16 ozcs = le16_to_cpu(ns_ozcs);
+ __u8 rsvd = (ozcs & 0xfffe) >> 1;
+ __u8 razb = ozcs & 0x1;
+
+ if (rsvd)
+ printf(" [15:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\t Read Across Zone Boundaries: %s\n",
+ razb, razb ? "Yes" : "No");
+}
+
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns, unsigned long flags)
+{
+ int human = flags & VERBOSE, vs = flags & VS;
+ uint8_t lbaf = id_ns->flbas & NVME_NS_FLBAS_LBA_MASK;
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)ns, sizeof(*ns));
+ else if (flags & JSON)
+ return json_nvme_zns_id_ns(ns, id_ns);
+
+ printf("ZNS Command Set Identify Namespace:\n");
+
+ if (human) {
+ printf("zoc : %u\tZone Operation Characteristics\n", le16_to_cpu(ns->zoc));
+ show_nvme_id_ns_zoned_zoc(ns->zoc);
+ } else {
+ printf("zoc : %u\n", le16_to_cpu(ns->zoc));
+ }
+
+ if (human) {
+ printf("ozcs : %u\tOptional Zoned Command Support\n", le16_to_cpu(ns->ozcs));
+ show_nvme_id_ns_zoned_ozcs(ns->ozcs);
+ } else {
+ printf("ozcs : %u\n", le16_to_cpu(ns->ozcs));
+ }
+
+ if (human) {
+ if (ns->mar == 0xffffffff) {
+ printf("mar : No Active Resource Limit\n");
+ } else {
+ printf("mar : %u\tActive Resources\n", le32_to_cpu(ns->mar) + 1);
+ }
+ } else {
+ printf("mar : %#x\n", le32_to_cpu(ns->mar));
+ }
+
+ if (human) {
+ if (ns->mor == 0xffffffff) {
+ printf("mor : No Open Resource Limit\n");
+ } else {
+ printf("mor : %u\tOpen Resources\n", le32_to_cpu(ns->mor) + 1);
+ }
+ } else {
+ printf("mor : %#x\n", le32_to_cpu(ns->mor));
+ }
+
+ if (!le32_to_cpu(ns->rrl) && human)
+ printf("rrl : Not Reported\n");
+ else
+ printf("rrl : %d\n", le32_to_cpu(ns->rrl));
+
+ if (!le32_to_cpu(ns->frl) && human)
+ printf("frl : Not Reported\n");
+ else
+ printf("frl : %d\n", le32_to_cpu(ns->frl));
+
+ for (i = 0; i <= id_ns->nlbaf; i++){
+ if (human)
+ printf("LBA Format Extension %2d : Zone Size: 0x%"PRIx64" LBAs - "
+ "Zone Descriptor Extension Size: %-1d bytes%s\n",
+ i, le64_to_cpu(ns->lbafe[i].zsze), ns->lbafe[i].zdes << 6,
+ i == lbaf ? " (in use)" : "");
+ else
+ printf("lbafe %2d: zsze:0x%"PRIx64" zdes:%u%s\n", i,
+ (uint64_t)le64_to_cpu(ns->lbafe[i].zsze),
+ ns->lbafe[i].zdes, i == lbaf ? " (in use)" : "");
+ }
+
+ if (vs) {
+ printf("vs[] :\n");
+ d(ns->vs, sizeof(ns->vs), 16, 1);
+ }
+}
+
+void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log,
+ unsigned long flags)
+{
+ uint16_t nrzid;
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)log, sizeof(*log));
+
+ nrzid = le16_to_cpu(log->nrzid);
+ printf("NVMe Changed Zone List:\n");
+
+ if (nrzid == 0xFFFF) {
+ printf("Too many zones have changed to fit into the log. Use report zones for changes.\n");
+ return;
+ }
+
+ printf("nrzid: %u\n", nrzid);
+ for (i = 0; i < nrzid; i++)
+ printf("zid %03d: %"PRIu64"\n", i, (uint64_t)le64_to_cpu(log->zid[i]));
+}
+
+char *zone_type_to_string(__u8 cond)
+{
+ switch (cond) {
+ case NVME_ZONE_TYPE_SEQWRITE_REQ:
+ return "SEQWRITE_REQ";
+ default:
+ return "Unknown";
+ }
+}
+
+char *zone_state_to_string(__u8 state)
+{
+ switch (state) {
+ case NVME_ZNS_ZS_EMPTY:
+ return "EMPTY";
+ case NVME_ZNS_ZS_IMPL_OPEN:
+ return "IMP_OPENED";
+ case NVME_ZNS_ZS_EXPL_OPEN:
+ return "EXP_OPENED";
+ case NVME_ZNS_ZS_CLOSED:
+ return "CLOSED";
+ case NVME_ZNS_ZS_READ_ONLY:
+ return "READONLY";
+ case NVME_ZNS_ZS_FULL:
+ return "FULL";
+ case NVME_ZNS_ZS_OFFLINE:
+ return "OFFLINE";
+ default:
+ return "Unknown State";
+ }
+}
+
+void nvme_show_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size, unsigned long flags)
+{
+ struct nvme_zone_report *r = report;
+ struct nvme_zns_desc *desc;
+ int i;
+
+ __u64 nr_zones = le64_to_cpu(r->nr_zones);
+
+ if (nr_zones < descs)
+ descs = nr_zones;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)report, report_size);
+
+ printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(r->nr_zones));
+ for (i = 0; i < descs; i++) {
+ desc = (struct nvme_zns_desc *)
+ (report + sizeof(*r) + i * (sizeof(*desc) + ext_size));
+ printf("SLBA: 0x%-8"PRIx64" WP: 0x%-8"PRIx64" Cap: 0x%-8"PRIx64" State: %-12s Type: %-14s Attrs: 0x%-x\n",
+ (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp),
+ (uint64_t)le64_to_cpu(desc->zcap), zone_state_to_string(desc->zs >> 4),
+ zone_type_to_string(desc->zt), desc->za);
+
+ if (ext_size) {
+ printf("Extension Data: ");
+ if (desc->za & NVME_ZNS_ZA_ZDEV) {
+ d((unsigned char *)desc + sizeof(*desc), ext_size, 16, 1);
+ printf("..\n");
+ } else {
+ printf(" Not valid\n");
+ }
+ }
+ }
+}
+
static void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
{
__u32 nent = nvmset->nid;
- struct json_array *entries;
+ struct json_object *entries;
struct json_object *root;
int i;
@@ -2926,12 +4202,83 @@ void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id,
}
}
+static void json_nvme_primary_ctrl_caps(const struct nvme_primary_ctrl_caps *caps)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+
+ json_object_add_value_uint(root, "cntlid", le16_to_cpu(caps->cntlid));
+ json_object_add_value_uint(root, "portid", le16_to_cpu(caps->portid));
+ json_object_add_value_uint(root, "crt", caps->crt);
+
+ json_object_add_value_int(root, "vqfrt", le32_to_cpu(caps->vqfrt));
+ json_object_add_value_int(root, "vqrfa", le32_to_cpu(caps->vqrfa));
+ json_object_add_value_int(root, "vqrfap", le16_to_cpu(caps->vqrfap));
+ json_object_add_value_int(root, "vqprt", le16_to_cpu(caps->vqprt));
+ json_object_add_value_int(root, "vqfrsm", le16_to_cpu(caps->vqfrsm));
+ json_object_add_value_int(root, "vqgran", le16_to_cpu(caps->vqgran));
+
+ json_object_add_value_int(root, "vifrt", le32_to_cpu(caps->vifrt));
+ json_object_add_value_int(root, "virfa", le32_to_cpu(caps->virfa));
+ json_object_add_value_int(root, "virfap", le16_to_cpu(caps->virfap));
+ json_object_add_value_int(root, "viprt", le16_to_cpu(caps->viprt));
+ json_object_add_value_int(root, "vifrsm", le16_to_cpu(caps->vifrsm));
+ json_object_add_value_int(root, "vigran", le16_to_cpu(caps->vigran));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void nvme_show_primary_ctrl_caps_crt(__u8 crt)
+{
+ __u8 rsvd = (crt & 0xFC) >> 2;
+ __u8 vi = (crt & 0x2) >> 1;
+ __u8 vq = crt & 0x1;
+
+ if (rsvd)
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] %#x\tVI Resources are %ssupported\n", vi, vi ? "" : "not ");
+ printf(" [0:0] %#x\tVQ Resources are %ssupported\n", vq, vq ? "" : "not ");
+}
+
+void nvme_show_primary_ctrl_caps(const struct nvme_primary_ctrl_caps *caps,
+ enum nvme_print_flags flags)
+{
+ int human = flags & VERBOSE;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)caps, sizeof(*caps));
+ else if (flags & JSON)
+ return json_nvme_primary_ctrl_caps(caps);
+
+ printf("NVME Identify Primary Controller Capabilities:\n");
+ printf("cntlid : %#x\n", le16_to_cpu(caps->cntlid));
+ printf("portid : %#x\n", le16_to_cpu(caps->portid));
+ printf("crt : %#x\n", caps->crt);
+ if (human)
+ nvme_show_primary_ctrl_caps_crt(caps->crt);
+ printf("vqfrt : %d\n", le32_to_cpu(caps->vqfrt));
+ printf("vqrfa : %d\n", le32_to_cpu(caps->vqrfa));
+ printf("vqrfap : %d\n", le16_to_cpu(caps->vqrfap));
+ printf("vqprt : %d\n", le16_to_cpu(caps->vqprt));
+ printf("vqfrsm : %d\n", le16_to_cpu(caps->vqfrsm));
+ printf("vqgran : %d\n", le16_to_cpu(caps->vqgran));
+ printf("vifrt : %d\n", le32_to_cpu(caps->vifrt));
+ printf("virfa : %d\n", le32_to_cpu(caps->virfa));
+ printf("virfap : %d\n", le16_to_cpu(caps->virfap));
+ printf("viprt : %d\n", le16_to_cpu(caps->viprt));
+ printf("vifrsm : %d\n", le16_to_cpu(caps->vifrsm));
+ printf("vigran : %d\n", le16_to_cpu(caps->vigran));
+}
+
static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list,
__u32 count)
{
const struct nvme_secondary_controller_entry *sc_entry = &sc_list->sc_entry[0];
__u32 nent = min(sc_list->num, count);
- struct json_array *entries;
+ struct json_object *entries;
struct json_object *root;
int i;
@@ -3011,7 +4358,7 @@ static void json_nvme_id_ns_granularity_list(
{
int i;
struct json_object *root;
- struct json_array *entries;
+ struct json_object *entries;
root = json_create_object();
@@ -3067,7 +4414,7 @@ void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *
static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list)
{
struct json_object *root;
- struct json_array *entries;
+ struct json_object *entries;
int i;
root = json_create_object();
@@ -3140,9 +4487,19 @@ void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list,
}
}
+void nvme_show_id_iocs(struct nvme_id_iocs *iocs)
+{
+ __u16 i;
+
+ for (i = 0; i < 512; i++)
+ if (iocs->iocs[i])
+ printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i,
+ (uint64_t)le64_to_cpu(iocs->iocs[i]));
+}
+
static const char *nvme_trtype_to_string(__u8 trtype)
{
- switch(trtype) {
+ switch (trtype) {
case 0: return "The transport type is not indicated or the error "\
"is not transport related.";
case 1: return "RDMA Transport error.";
@@ -3174,9 +4531,11 @@ void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries,
le64_to_cpu(err_log[i].error_count));
printf("sqid : %d\n", err_log[i].sqid);
printf("cmdid : %#x\n", err_log[i].cmdid);
- printf("status_field : %#x(%s)\n", err_log[i].status_field,
+ printf("status_field : %#x(%s)\n", err_log[i].status_field >> 0x1,
nvme_status_to_string(
le16_to_cpu(err_log[i].status_field) >> 1));
+ printf("phase_tag : %#x\n",
+ le16_to_cpu(err_log[i].status_field & 0x1));
printf("parm_err_loc : %#x\n",
err_log[i].parm_error_location);
printf("lba : %#"PRIx64"\n",
@@ -3503,7 +4862,7 @@ void nvme_show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname,
else if (flags & JSON)
return json_ana_log(ana_log, devname);
- printf("Asynchronous Namespace Access Log for NVMe device: %s\n",
+ printf("Asymmetric Namespace Access Log for NVMe device: %s\n",
devname);
printf("ANA LOG HEADER :-\n");
printf("chgcnt : %"PRIu64"\n",
@@ -3608,20 +4967,22 @@ static void nvme_show_self_test_result(struct nvme_self_test_res *res,
res->vs[0], res->vs[1]);
}
-void nvme_show_self_test_log(struct nvme_self_test_log *self_test, const char *devname,
- enum nvme_print_flags flags)
+void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries,
+ __u32 size, const char *devname, enum nvme_print_flags flags)
{
int i;
+ __u8 num_entries;
if (flags & BINARY)
- return d_raw((unsigned char *)self_test, sizeof(*self_test));
+ return d_raw((unsigned char *)self_test, size);
if (flags & JSON)
- return json_self_test_log(self_test);
+ return json_self_test_log(self_test, dst_entries);
printf("Device Self Test Log for NVME device:%s\n", devname);
printf("Current operation : %#x\n", self_test->crnt_dev_selftest_oprn);
printf("Current Completion : %u%%\n", self_test->crnt_dev_selftest_compln);
- for (i = 0; i < NVME_ST_REPORTS; i++) {
+ num_entries = min(dst_entries, NVME_ST_REPORTS);
+ for (i = 0; i < num_entries; i++) {
printf("Self Test Result[%d]:\n", i);
nvme_show_self_test_result(&self_test->result[i], flags);
}
@@ -3704,9 +5065,10 @@ void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
le32_to_cpu(sanitize->est_crypto_erase_time_with_no_deallocate));
}
-const char *nvme_feature_to_string(int feature)
+const char *nvme_feature_to_string(enum nvme_feat feature)
{
switch (feature) {
+ case NVME_FEAT_NONE: return "Reserved";
case NVME_FEAT_ARBITRATION: return "Arbitration";
case NVME_FEAT_POWER_MGMT: return "Power Management";
case NVME_FEAT_LBA_RANGE: return "LBA Range Type";
@@ -3725,6 +5087,9 @@ const char *nvme_feature_to_string(int feature)
case NVME_FEAT_RRL: return "Read Recovery Level";
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_IOCS_PROFILE: return "I/O Command Set Profile";
case NVME_FEAT_SW_PROGRESS: return "Software Progress";
case NVME_FEAT_HOST_ID: return "Host Identifier";
case NVME_FEAT_RESV_MASK: return "Reservation Notification Mask";
@@ -3734,8 +5099,13 @@ const char *nvme_feature_to_string(int feature)
case NVME_FEAT_HCTM: return "Host Controlled Thermal Management";
case NVME_FEAT_HOST_BEHAVIOR: return "Host Behavior";
case NVME_FEAT_SANITIZE: return "Sanitize";
- default: return "Unknown";
}
+ /*
+ * We don't use the "default:" statement to let the compiler warning if
+ * some values of the enum nvme_feat are missing in the switch().
+ * The following return is acting as the default: statement.
+ */
+ return "Unknown";
}
const char *nvme_register_to_string(int reg)
@@ -3778,9 +5148,9 @@ void nvme_show_select_result(__u32 result)
printf(" Feature is changeable\n");
}
-const char *nvme_status_to_string(__u32 status)
+const char *nvme_status_to_string(__u16 status)
{
- switch (status & 0x3ff) {
+ switch (status & 0x7ff) {
case NVME_SC_SUCCESS:
return "SUCCESS: The command completed successfully";
case NVME_SC_INVALID_OPCODE:
@@ -3839,6 +5209,14 @@ const char *nvme_status_to_string(__u32 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_IOCS_NOT_SUPPORTED:
+ return "IOCS_NOT_SUPPORTED: The I/O command set is not supported";
+ case NVME_SC_IOCS_NOT_ENABLED:
+ return "IOCS_NOT_ENABLED: The I/O command set is not enabled";
+ case NVME_SC_IOCS_COMBINATION_REJECTED:
+ 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_LBA_RANGE:
return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace";
case NVME_SC_NS_WRITE_PROTECTED:
@@ -3853,6 +5231,22 @@ const char *nvme_status_to_string(__u32 status)
return "RESERVATION_CONFLICT: The command was aborted due to a conflict with a reservation held on the accessed namespace";
case NVME_SC_FORMAT_IN_PROGRESS:
return "FORMAT_IN_PROGRESS: A Format NVM command is in progress on the namespace.";
+ case NVME_SC_ZONE_BOUNDARY_ERROR:
+ return "ZONE_BOUNDARY_ERROR: Invalid Zone Boundary crossing";
+ case NVME_SC_ZONE_IS_FULL:
+ return "ZONE_IS_FULL: The accessed zone is in ZSF:Full state";
+ case NVME_SC_ZONE_IS_READ_ONLY:
+ return "ZONE_IS_READ_ONLY: The accessed zone is in ZSRO:Read Only state";
+ case NVME_SC_ZONE_IS_OFFLINE:
+ return "ZONE_IS_OFFLINE: The access zone is in ZSO:Offline state";
+ case NVME_SC_ZONE_INVALID_WRITE:
+ return "ZONE_INVALID_WRITE: The write to zone was not at the write pointer offset";
+ case NVME_SC_TOO_MANY_ACTIVE_ZONES:
+ return "TOO_MANY_ACTIVE_ZONES: The controller does not allow additional active zones";
+ case NVME_SC_TOO_MANY_OPEN_ZONES:
+ return "TOO_MANY_OPEN_ZONES: The controller does not allow additional open zones";
+ case NVME_SC_ZONE_INVALID_STATE_TRANSITION:
+ return "INVALID_ZONE_STATE_TRANSITION: The zone state change was invalid";
case NVME_SC_CQ_INVALID:
return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist";
case NVME_SC_QID_INVALID:
@@ -3927,6 +5321,12 @@ const char *nvme_status_to_string(__u32 status)
return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition";
case NVME_SC_BAD_ATTRIBUTES:
return "BAD_ATTRIBUTES: Bad attributes were given";
+ case NVME_SC_INVALID_PI:
+ return "INVALID_PROTECION_INFO: The Protection Information Field settings specified in the command are invalid";
+ case NVME_SC_READ_ONLY:
+ return "WRITE_ATTEMPT_READ_ONLY_RANGE: The LBA range specified contains read-only blocks";
+ case NVME_SC_CMD_SIZE_LIMIT_EXCEEDED:
+ return "CMD_SIZE_LIMIT_EXCEEDED: Command size limit exceeded";
case NVME_SC_WRITE_FAULT:
return "WRITE_FAULT: The write data could not be committed to the media";
case NVME_SC_READ_ERROR:
@@ -3943,12 +5343,20 @@ const char *nvme_status_to_string(__u32 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_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:
return "ASYMMETRIC_NAMESPACE_ACCESS_PERSISTENT_LOSS: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Persistent Loss state";
case NVME_SC_ANA_INACCESSIBLE:
return "ASYMMETRIC_NAMESPACE_ACCESS_INACCESSIBLE: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Inaccessible state";
case NVME_SC_ANA_TRANSITION:
return "ASYMMETRIC_NAMESPACE_ACCESS_TRANSITION: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace transitioning between Asymmetric Namespace Access states";
+ case NVME_SC_CTRL_PATHING_ERROR:
+ return "CONTROLLER_PATHING_ERROR: A pathing error was detected by the controller";
+ case NVME_SC_HOST_PATHING_ERROR:
+ return "HOST_PATHING_ERROR: A pathing error was detected by the host";
+ case NVME_SC_HOST_CMD_ABORT:
+ return "HOST_COMMAND_ABORT: The command was aborted as a result of host action";
case NVME_SC_CMD_INTERRUPTED:
return "CMD_INTERRUPTED: Command processing was interrupted and the controller is unable to successfully complete the command. The host should retry the command.";
case NVME_SC_PMR_SAN_PROHIBITED:
@@ -3967,7 +5375,7 @@ static const char *nvme_feature_lba_type_to_string(__u8 type)
case 3: return "Cache";
case 4: return "Page / Swap file";
default:
- if (type>=0x05 && type<=0x7f)
+ if (type >= 0x05 && type <= 0x7f)
return "Reserved";
else
return "Vendor Specific";
@@ -4019,8 +5427,7 @@ static const char *nvme_feature_temp_type_to_string(__u8 type)
static const char *nvme_feature_temp_sel_to_string(__u8 sel)
{
- switch (sel)
- {
+ switch (sel) {
case 0: return "Composite Temperature";
case 1: return "Temperature Sensor 1";
case 2: return "Temperature Sensor 2";
@@ -4077,13 +5484,13 @@ static void nvme_show_timestamp(struct nvme_timestamp *ts)
static void nvme_show_host_mem_buffer(struct nvme_host_mem_buffer *hmb)
{
printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n",
- hmb->hmdlec);
+ le32_to_cpu(hmb->hmdlec));
printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n",
- hmb->hmdlau);
+ le32_to_cpu(hmb->hmdlau));
printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n",
- hmb->hmdlal);
+ le32_to_cpu(hmb->hmdlal));
printf("\tHost Memory Buffer Size (HSIZE): %u\n",
- hmb->hsize);
+ le32_to_cpu(hmb->hsize));
}
static void nvme_directive_show_fields(__u8 dtype, __u8 doper,
@@ -4121,6 +5528,8 @@ static void nvme_directive_show_fields(__u8 dtype, __u8 doper,
*(__u16 *) (field + 2));
printf("\tNVM Subsystem Streams Open (NSSO): %u\n",
*(__u16 *) (field + 4));
+ printf("\tNVM Subsystem Stream Capability (NSSC): %u\n",
+ *(__u16 *) (field + 6));
printf("\tStream Write Size (in unit of LB size) (SWS): %u\n",
*(__u32 *) (field + 16));
printf("\tStream Granularity Size (in unit of SWS) (SGS): %u\n",
@@ -4183,6 +5592,11 @@ static const char *nvme_plm_window(__u32 plm)
}
}
+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);
+}
+
static void nvme_show_plm_config(struct nvme_plm_config *plmcfg)
{
printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->enable_event));
@@ -4191,12 +5605,15 @@ 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(__u32 fid, unsigned int result, unsigned char *buf)
+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_ARBITRATION:
printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1);
printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1);
@@ -4247,6 +5664,10 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf
printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False");
break;
case NVME_FEAT_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");
+ printf("\tAsymmetric Namespace Access Change Notices: %s\n", ((result & 0x00000800) >> 11) ? "Send async event":"Do not send async event");
printf("\tTelemetry Log Notices : %s\n", ((result & 0x00000400) >> 10) ? "Send async event":"Do not send async event");
printf("\tFirmware Activation Notices : %s\n", ((result & 0x00000200) >> 9) ? "Send async event":"Do not send async event");
printf("\tNamespace Attribute Notices : %s\n", ((result & 0x00000100) >> 8) ? "Send async event":"Do not send async event");
@@ -4257,7 +5678,6 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf
nvme_show_auto_pst((struct nvme_auto_pst *)buf);
break;
case NVME_FEAT_HOST_MEM_BUF:
- printf("\tMemory Return (MR): %s\n", ((result & 0x00000002) >> 1) ? "True":"False");
printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled":"Disabled");
nvme_show_host_mem_buffer((struct nvme_host_mem_buffer *)buf);
break;
@@ -4271,6 +5691,16 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf
case NVME_FEAT_PLM_WINDOW:
printf("\tWindow Select: %s", nvme_plm_window(result));
break;
+ 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_IOCS_PROFILE:
+ printf("\tI/O Command Set Comination Index(IOCSCI): %u\n", result & 0x1ff);
+ break;
case NVME_FEAT_HOST_ID:
ull = buf[7]; ull <<= 8; ull |= buf[6]; ull <<= 8; ull |= buf[5]; ull <<= 8;
ull |= buf[4]; ull <<= 8; ull |= buf[3]; ull <<= 8; ull |= buf[2]; ull <<= 8;
@@ -4304,6 +5734,12 @@ void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf
case NVME_FEAT_HOST_BEHAVIOR:
printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False");
break;
+ case NVME_FEAT_SANITIZE:
+ printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1);
+ break;
+ case NVME_FEAT_RRL:
+ printf("\tRead Recovery Level (RRL): %u\n", result & 0xf);
+ break;
}
}
@@ -4351,13 +5787,20 @@ static void nvme_show_list_item(struct nvme_namespace *n)
const char *l_suffix = suffix_binary_get(&lba);
char usage[128];
- char format[128];
+ char format[128], path[256];
+ struct stat st;
+ int ret;
+
+ sprintf(path, "%s%s", n->ctrl->path, n->name);
+ ret = stat(path, &st);
+ if (ret < 0)
+ 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,
le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms));
- printf("/dev/%-11s %-*.*s %-*.*s %-9d %-26s %-16s %-.*s\n", n->name,
+ printf("%-21s %-*.*s %-*.*s %-9d %-26s %-16s %-.*s\n", path,
(int)sizeof(n->ctrl->id.sn), (int)sizeof(n->ctrl->id.sn), n->ctrl->id.sn,
(int)sizeof(n->ctrl->id.mn), (int)sizeof(n->ctrl->id.mn), n->ctrl->id.mn,
n->nsid, usage, format, (int)sizeof(n->ctrl->id.fr), n->ctrl->id.fr);
@@ -4367,9 +5810,9 @@ static void nvme_show_simple_list(struct nvme_topology *t)
{
int i, j, k;
- printf("%-16s %-20s %-40s %-9s %-26s %-16s %-8s\n",
+ printf("%-21s %-20s %-40s %-9s %-26s %-16s %-8s\n",
"Node", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev");
- printf("%-.16s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash,
+ printf("%-.21s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash,
dash, dash, dash, dash, dash);
for (i = 0; i < t->nr_subsystems; i++) {
@@ -4409,16 +5852,28 @@ static void nvme_show_details_ns(struct nvme_namespace *n, bool ctrl)
sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix,
le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms));
- printf("%-12s %-8x %-26s %-16s ", n->name, n->nsid, usage, format);
+ printf("%-12s %-8d %-26s %-16s ", n->name, n->nsid, usage, format);
if (ctrl)
printf("%s", n->ctrl->name);
else {
struct nvme_subsystem *s = n->ctrl->subsys;
- int i;
+ int i, j;
+ bool comma = false;
- for (i = 0; i < s->nr_ctrls; i++)
- printf("%s%s", i ? ", " : "", s->ctrls[i].name);
+ for (i = 0; i < s->nr_ctrls; i++) {
+ struct nvme_ctrl *c = &s->ctrls[i];
+
+ for (j = 0; j < c->nr_namespaces; j++) {
+ struct nvme_namespace *ns = &c->namespaces[j];
+
+ if (ns->nsid == n->nsid) {
+ printf("%s%s", comma ? ", " : "",
+ c->name);
+ comma = true;
+ }
+ }
+ }
}
printf("\n");
}
@@ -4456,15 +5911,11 @@ static void nvme_show_detailed_list(struct nvme_topology *t)
printf("%-8s %-.20s %-.40s %-.8s %-6s %-14s %-12s ",
c->name, c->id.sn, c->id.mn, c->id.fr,
- c->transport, c->address, s->name);
+ c->transport ? : "", c->address ? : "", s->name);
for (k = 0; k < c->nr_namespaces; k++) {
struct nvme_namespace *n = &c->namespaces[k];
- printf("%s%s", comma ? ", " : "", n->name);
- comma = true;
- }
- for (k = 0; k < s->nr_namespaces; k++) {
- struct nvme_namespace *n = &s->namespaces[k];
+
printf("%s%s", comma ? ", " : "", n->name);
comma = true;
}
@@ -4479,18 +5930,21 @@ static void nvme_show_detailed_list(struct nvme_topology *t)
for (i = 0; i < t->nr_subsystems; i++) {
struct nvme_subsystem *s = &t->subsystems[i];
- for (j = 0; j < s->nr_ctrls; j++) {
- struct nvme_ctrl *c = &s->ctrls[j];
+ if (s->nr_namespaces) {
+ for (j = 0; j < s->nr_namespaces; j++) {
+ struct nvme_namespace *n = &s->namespaces[j];
+ nvme_show_details_ns(n, false);
+ }
+ } else {
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
- for (k = 0; k < c->nr_namespaces; k++) {
- struct nvme_namespace *n = &c->namespaces[k];
- nvme_show_details_ns(n, true);
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct nvme_namespace *n = &c->namespaces[k];
+ nvme_show_details_ns(n, true);
+ }
}
}
- for (j = 0; j < s->nr_namespaces; j++) {
- struct nvme_namespace *n = &s->namespaces[j];
- nvme_show_details_ns(n, false);
- }
}
}
@@ -4517,7 +5971,7 @@ static void json_detail_list(struct nvme_topology *t)
{
int i, j, k;
struct json_object *root;
- struct json_array *devices;
+ struct json_object *devices;
char formatter[41] = { 0 };
root = json_create_object();
@@ -4526,7 +5980,7 @@ static void json_detail_list(struct nvme_topology *t)
for (i = 0; i < t->nr_subsystems; i++) {
struct nvme_subsystem *s = &t->subsystems[i];
struct json_object *subsys_attrs;
- struct json_array *namespaces, *ctrls;
+ struct json_object *namespaces, *ctrls;
subsys_attrs = json_create_object();
json_object_add_value_string(subsys_attrs, "Subsystem", s->name);
@@ -4537,12 +5991,15 @@ static void json_detail_list(struct nvme_topology *t)
for (j = 0; j < s->nr_ctrls; j++) {
struct json_object *ctrl_attrs = json_create_object();
struct nvme_ctrl *c = &s->ctrls[j];
- struct json_array *namespaces;
+ struct json_object *namespaces;
json_object_add_value_string(ctrl_attrs, "Controller", c->name);
- json_object_add_value_string(ctrl_attrs, "Transport", c->transport);
- json_object_add_value_string(ctrl_attrs, "Address", c->address);
- json_object_add_value_string(ctrl_attrs, "State", c->state);
+ if (c->transport)
+ json_object_add_value_string(ctrl_attrs, "Transport", c->transport);
+ if (c->address)
+ json_object_add_value_string(ctrl_attrs, "Address", c->address);
+ if (c->state)
+ json_object_add_value_string(ctrl_attrs, "State", c->state);
if (c->hostnqn)
json_object_add_value_string(ctrl_attrs, "HostNQN", c->hostnqn);
if (c->hostid)
@@ -4596,16 +6053,21 @@ static void json_detail_list(struct nvme_topology *t)
json_free_object(root);
}
-static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices)
+static void json_simple_ns(struct nvme_namespace *n, struct json_object *devices)
{
struct json_object *device_attrs;
char formatter[41] = { 0 };
double nsze, nuse;
- int index = -1;
+ int ret, index = -1;
long long lba;
char *devnode;
+ struct stat st;
+
+ if (asprintf(&devnode, "%s%s", n->ctrl->path, n->name) < 0)
+ return;
- if (asprintf(&devnode, "/dev/%s", n->name) < 0)
+ ret = stat(devnode, &st);
+ if (ret < 0)
return;
device_attrs = json_create_object();
@@ -4629,7 +6091,7 @@ static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices)
json_object_add_value_string(device_attrs, "ModelNumber", formatter);
- if (index >= 0 && !strcmp(n->ctrl->transport, "pcie")) {
+ if (index >= 0 && n->ctrl->transport && !strcmp(n->ctrl->transport, "pcie")) {
char *product = nvme_product_name(index);
json_object_add_value_string(device_attrs, "ProductName", product);
@@ -4658,7 +6120,7 @@ static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices)
static void json_simple_list(struct nvme_topology *t)
{
struct json_object *root;
- struct json_array *devices;
+ struct json_object *devices;
int i, j, k;
root = json_create_object();
diff --git a/nvme-print.h b/nvme-print.h
index 2a6f5ee..2d8ed4d 100644
--- a/nvme-print.h
+++ b/nvme-print.h
@@ -2,7 +2,6 @@
#define NVME_PRINT_H
#include "nvme.h"
-#include "util/json.h"
#include <inttypes.h>
void d(unsigned char *buf, int len, int width, int group);
@@ -11,7 +10,7 @@ uint64_t int48_to_long(__u8 *data);
void nvme_show_status(__u16 status);
void nvme_show_relatives(const char *name);
-
+const char *nvme_cmd_to_string(int admin, __u8 opcode);
void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
void (*vendor_show)(__u8 *vs, struct json_object *root));
void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode);
@@ -26,8 +25,8 @@ void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
const char *devname, enum nvme_print_flags flags);
void nvme_show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname,
enum nvme_print_flags flags, size_t len);
-void nvme_show_self_test_log(struct nvme_self_test_log *self_test, const char *devname,
- enum nvme_print_flags flags);
+void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries,
+ __u32 size, const char *devname, enum nvme_print_flags flags);
void nvme_show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname,
enum nvme_print_flags flags);
void nvme_show_effects_log(struct nvme_effects_log_page *effects, unsigned int flags);
@@ -37,6 +36,35 @@ void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
__u16 group_id, const char *devname, enum nvme_print_flags flags);
void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
const char *devname, enum nvme_print_flags flags);
+void json_predictable_latency_per_nvmset(
+ struct nvme_predlat_per_nvmset_log_page *plpns_log,
+ __u16 nvmset_id);
+void nvme_show_predictable_latency_per_nvmset(
+ struct nvme_predlat_per_nvmset_log_page *plpns_log,
+ __u16 nvmset_id, const char *devname, enum nvme_print_flags flags);
+void json_predictable_latency_event_agg_log(
+ struct nvme_event_agg_log_page *pea_log,
+ __u64 log_entries);
+void nvme_show_predictable_latency_event_agg_log(
+ struct nvme_event_agg_log_page *pea_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+void json_persistent_event_log(void *pevent_log_info, __u32 size);
+void nvme_show_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+void json_endurance_group_event_agg_log(
+ struct nvme_event_agg_log_page *endurance_log,
+ __u64 log_entries);
+void nvme_show_endurance_group_event_agg_log(
+ struct nvme_event_agg_log_page *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+void json_lba_status_log(void *lba_status);
+void nvme_show_lba_status_log(void *lba_status, __u32 size,
+ const char *devname, enum nvme_print_flags flags);
+void nvme_show_resv_notif_log(struct nvme_resv_notif_log *resv,
+ const char *devname, enum nvme_print_flags flags);
void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags);
void nvme_show_single_property(int offset, uint64_t prop, int human);
void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags);
@@ -47,21 +75,35 @@ void nvme_show_subsystem_list(struct nvme_topology *t,
enum nvme_print_flags flags);
void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id,
enum nvme_print_flags flags);
+void nvme_show_primary_ctrl_caps(const struct nvme_primary_ctrl_caps *caps,
+ enum nvme_print_flags flags);
void nvme_show_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list,
__u32 count, enum nvme_print_flags flags);
void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist,
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_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf);
+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,
void *buf, __u32 len, enum nvme_print_flags flags);
void nvme_show_select_result(__u32 result);
+void nvme_show_lba_status_info(__u32 result);
+
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl, unsigned int mode);
+void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm,
+ enum nvme_print_flags flags);
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns, unsigned long flags);
+void nvme_show_zns_changed( struct nvme_zns_changed_zone_log *log,
+ unsigned long flags);
+void nvme_show_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size, unsigned long flags);
-const char *nvme_status_to_string(__u32 status);
+const char *nvme_status_to_string(__u16 status);
const char *nvme_select_to_string(int sel);
-const char *nvme_feature_to_string(int feature);
+const char *nvme_feature_to_string(enum nvme_feat feature);
const char *nvme_register_to_string(int reg);
#endif
diff --git a/nvme-rpmb.c b/nvme-rpmb.c
new file mode 100644
index 0000000..0e11ef3
--- /dev/null
+++ b/nvme-rpmb.c
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (C) 2020 Micron Techology Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * nvme-rpmb.c - Implementation of NVMe RPMB support commands in Nvme
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <linux/if_alg.h>
+#include <linux/socket.h>
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+
+#define CREATE_CMD
+
+
+#ifndef AF_ALG
+#define AF_ALG 38
+#endif
+#ifndef SOL_ALG
+#define SOL_ALG 279
+#endif
+
+#define HMAC_SHA256_ALGO_NAME "hmac(sha256)"
+#define MD5_HASH_ALGO_NAME "md5"
+#define HMAC_SHA256_HASH_SIZE 32
+#define MD5_HASH_HASH_SIZE 16
+
+extern int nvme_show_id_ctrl_rpmbs(unsigned int);
+/*
+ * Utility function to create hash value of given data (with given key) using
+ * given hash algorithm; this function uses kernel crypto services
+ */
+unsigned char *create_hash(const char *algo,
+ int hash_size,
+ unsigned char *data,
+ int datalen,
+ unsigned char *key,
+ int keylen)
+{
+ int error, infd, outfd = -1;
+ unsigned char *hash = NULL;
+ struct sockaddr_alg provider_sa = {
+ .salg_family = AF_ALG,
+ .salg_type = "hash",
+ .salg_name = { 0 }
+ };
+
+ /* copy algorith name */
+ memcpy(provider_sa.salg_name, algo, strlen(algo));
+
+ /* open netlink socket connection to algorigm provider and bind */
+ infd = socket(AF_ALG, SOCK_SEQPACKET, 0);
+ if (infd < 0) {
+ perror("socket");
+ return hash;
+ }
+ error = bind(infd, (struct sockaddr *)&provider_sa, sizeof(provider_sa));
+ if (error < 0) {
+ perror("bind");
+ goto out;
+ }
+
+ /* if algorithm requires key, set it first - empty keys not accepted !*/
+ if (key != NULL && keylen > 0) {
+ error = setsockopt(infd, SOL_ALG, ALG_SET_KEY, key, keylen);
+ if (error < 0) {
+ perror("setsockopt");
+ goto out;
+ }
+ }
+
+ /* now send data to hash */
+ outfd = accept(infd, NULL, 0);
+ if (outfd < 0) {
+ perror("accept");
+ goto out;
+ }
+ error = send(outfd, data, datalen, 0);
+ if (error < 0) {
+ perror("send");
+ goto out;
+ }
+
+ /* read computed hash */
+ hash = (unsigned char *)calloc(hash_size, 1);
+ if (hash == NULL) {
+ perror("calloc");
+ goto out;
+ }
+
+ error = read(outfd, hash, hash_size);
+ if (error != hash_size) {
+ perror("read");
+ free(hash);
+ hash = NULL;
+ }
+out:
+ if (outfd > 0) close(outfd);
+ if (infd > 0) close(infd);
+
+ return hash;
+}
+
+/* Function that computes hmac-sha256 hash of given data and key pair. Returns
+ * byte stream (non-null terminated) upon success, NULL otherwise.
+ */
+unsigned char *
+hmac_sha256(unsigned char *data, int datalen, unsigned char *key, int keylen)
+{
+ return create_hash(HMAC_SHA256_ALGO_NAME,
+ HMAC_SHA256_HASH_SIZE,
+ data,
+ datalen,
+ key,
+ keylen);
+}
+
+/* Function that computes md5 of given buffer - md5 hash is used as nonce
+ * Returns byte stream (non-null terminated) upon success, NULL otherwise.
+ */
+unsigned char *
+rpmb_md5(unsigned char *data, int datalen)
+{
+ return create_hash(MD5_HASH_ALGO_NAME,
+ MD5_HASH_HASH_SIZE,
+ data,
+ datalen,
+ NULL,
+ 0);
+}
+
+/* Read data from given file into buffer and return its length */
+static int read_file(const char *file, unsigned char **data, unsigned int *len)
+{
+ struct stat sb;
+ size_t size;
+ unsigned char *buf = NULL;
+ int fd;
+ int err = -EINVAL;
+
+ if (file == NULL) return err;
+
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+ return fd;
+ }
+
+ err = fstat(fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ goto out;
+ }
+
+ size = sb.st_size;
+ if (posix_memalign((void **)&buf, getpagesize(), size)) {
+ fprintf(stderr, "No memory for reading file :%s\n", file);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = read(fd, buf, size);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "Failed to read data from file"
+ " %s with %s\n", file, strerror(errno));
+ free(buf);
+ goto out;
+ }
+ err -= size;
+ *data = buf;
+ *len = size;
+out:
+ close(fd);
+ return err;
+}
+
+/* Write given buffer data to specified file */
+static void write_file(unsigned char *data, size_t len, const char *dir,
+ const char *file, const char *msg)
+{
+ char temp_folder[PATH_MAX] = { 0 };
+ FILE *fp = NULL;
+
+ if (dir != NULL)
+ sprintf(temp_folder, "%s/%s", dir, file);
+ else
+ sprintf(temp_folder, "./%s", file);
+
+ if ((fp = fopen(temp_folder, "ab+")) != NULL) {
+ if (fwrite(data, 1, len, fp) != len) {
+ fprintf(stderr, "Failed to write %s data to %s\n",
+ msg ? msg : "", temp_folder);
+ }
+ fclose(fp);
+ } else {
+ fprintf(stderr, "Failed to open %s file to write %s\n",
+ temp_folder, msg ? msg : "");
+ }
+}
+
+/* Various definitions used in RPMB related support */
+enum rpmb_request_type {
+ RPMB_REQ_AUTH_KEY_PROGRAM = 0x0001,
+ RPMB_REQ_READ_WRITE_CNTR = 0x0002,
+ RPMB_REQ_AUTH_DATA_WRITE = 0x0003,
+ RPMB_REQ_AUTH_DATA_READ = 0x0004,
+ RPMB_REQ_READ_RESULT = 0x0005,
+ RPMB_REQ_AUTH_DCB_WRITE = 0x0006,
+ RPMB_REQ_AUTH_DCB_READ = 0x0007
+};
+
+enum rpmb_response_type {
+ RPMB_RSP_AUTH_KEY_PROGRAM = (RPMB_REQ_AUTH_KEY_PROGRAM << 8),
+ RPMB_RSP_READ_WRITE_CNTR = (RPMB_REQ_READ_WRITE_CNTR << 8),
+ RPMB_RSP_AUTH_DATA_WRITE = (RPMB_REQ_AUTH_DATA_WRITE << 8),
+ RPMB_RSP_AUTH_DATA_READ = (RPMB_REQ_AUTH_DATA_READ << 8),
+ RPMB_RSP_READ_RESULT = (RPMB_REQ_READ_RESULT << 8),
+ RPMB_RSP_AUTH_DCB_WRITE = (RPMB_REQ_AUTH_DCB_WRITE << 8),
+ RPMB_RSP_AUTH_DCB_READ = (RPMB_REQ_AUTH_DCB_READ << 8)
+};
+
+/* RPMB data frame structure */
+#pragma pack(1)
+struct rpmb_data_frame_t {
+ unsigned char pad[191];
+ unsigned char mac[32];
+ unsigned char target; /* 0-6, should match with NSSF with SS, SR */
+ unsigned char nonce[16];
+ unsigned int write_counter;
+ unsigned int address;
+ unsigned int sectors;
+ unsigned short result;
+ unsigned short type; /* req or response */
+ unsigned char data[0]; /* in sector count times */
+};
+#pragma pack()
+
+struct rpmb_config_block_t {
+ unsigned char bp_enable;
+ unsigned char bp_lock;
+ unsigned char rsvd[510];
+};
+
+#define RPMB_DATA_FRAME_SIZE 256
+#define RPMB_NVME_SECP 0xEA
+#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, \
+ (unsigned char *)(req))
+
+#define RECV_RPMB_RSP(tgt, size, rsp) \
+nvme_sec_recv(fd, 0, tgt, RPMB_NVME_SPSP, RPMB_NVME_SECP, size, size, \
+ (unsigned char *)(rsp))
+
+/* Initialize nonce value in rpmb request frame */
+static void rpmb_nonce_init(struct rpmb_data_frame_t *req)
+{
+ int num = rand();
+ unsigned char *hash = rpmb_md5((unsigned char *)&num, sizeof(num));
+ if (hash) memcpy(req->nonce, hash, sizeof(req->nonce));
+}
+
+/* Read key from a given key buffer or key file */
+static unsigned char *read_rpmb_key(char *keystr, char *keyfile, unsigned int *keysize)
+{
+ unsigned char *keybuf = NULL;
+
+ if (keystr == NULL) {
+ if (keyfile != NULL)
+ read_file(keyfile, &keybuf, keysize);
+ } else if ((keybuf = (unsigned char *)malloc(strlen(keystr))) != NULL) {
+ *keysize = strlen(keystr);
+ memcpy(keybuf, keystr, *keysize);
+ }
+
+ return keybuf;
+}
+
+/* Initialize RPMB request frame with given values */
+static struct rpmb_data_frame_t *
+rpmb_request_init(unsigned int req_size,
+ unsigned short type,
+ unsigned char target,
+ unsigned char nonce,
+ unsigned int addr,
+ unsigned int sectors,
+ unsigned char *data,
+ unsigned short data_offset,
+ unsigned int data_size)
+{
+ struct rpmb_data_frame_t *req = NULL;
+
+ if ((req = (struct rpmb_data_frame_t *)calloc(req_size, 1)) == NULL) {
+ fprintf(stderr, "Memory allocation failed for request 0x%04x\n",
+ type);
+ return req;
+ }
+
+ req->type = type;
+ req->target = target;
+ req->address = addr;
+ req->sectors = sectors;
+
+ if (nonce) rpmb_nonce_init(req);
+ if (data) memcpy((unsigned char *)req + data_offset, data, data_size);
+
+ return req;
+}
+
+/* Process rpmb response and print appropriate error message */
+static int check_rpmb_response( struct rpmb_data_frame_t *req,
+ struct rpmb_data_frame_t *rsp,
+ char *msg)
+{
+ const char *rpmb_result_string [] = {
+ "Operation successful",
+ "General failure",
+ "Authentication (MAC) failure",
+ "Counter failure (not matching/incrementing failure)",
+ "Address failure (out of range or wrong alignment)",
+ "Write (data/counter/result) failure",
+ "Read (data/counter/result) failure",
+ "Authentication key not yet programmed",
+ "Invalid device configuration block",
+ "Unknown error"
+ };
+
+ /* check error status before comparing nonce and mac */
+ if (rsp->result != 0) {
+ if (rsp->type != ((req->type << 8) & 0xFF00)) {
+ fprintf(stderr, "%s ! non-matching response 0x%04x for"
+ " 0x%04x\n", msg, rsp->type, req->type);
+ } else if ((rsp->result & 0x80) == 0x80) {
+ fprintf(stderr, "%s ! Expired write-counter !\n", msg);
+ } else if (rsp->result) {
+ fprintf(stderr, "%s ! %s\n", msg,
+ rpmb_result_string[rsp->result & 0x7F]);
+ } else if (memcmp(req->nonce, rsp->nonce, 16)) {
+ fprintf(stderr, "%s ! non-matching nonce\n", msg);
+ } else if (memcmp(req->mac, rsp->mac, 32)) {
+ fprintf(stderr, "%s ! non-matching MAC\n", msg);
+ } else if ((req->write_counter + 1) != rsp->write_counter) {
+ fprintf(stderr, "%s ! out-of-sync write-counters\n", msg);
+ }
+ }
+
+ return (int)(rsp->result);
+}
+
+/* send an initialized rpmb request to the controller and read its response
+ * expected response size give in 'rsp_size'. returns response buffer upon
+ * successful completion (caller must free), NULL otherwise
+ */
+static struct rpmb_data_frame_t *
+rpmb_read_request(int fd,
+ struct rpmb_data_frame_t *req,
+ int req_size,
+ int rsp_size)
+{
+ struct rpmb_data_frame_t *rsp = NULL;
+ unsigned char msg[1024] = { 0 };
+ int error;
+
+ sprintf((char *)msg, "RPMB request 0x%04x to target 0x%x",
+ req->type, req->target);
+
+ error = SEND_RPMB_REQ(req->target, req_size, req);
+ if (error != 0) {
+ fprintf(stderr, "%s failed with error = 0x%x\n",
+ msg, error);
+ goto error_out;
+ }
+
+ /* read the result back */
+ rsp = (struct rpmb_data_frame_t *)calloc(rsp_size, 1);
+ if (rsp == NULL) {
+ fprintf(stderr, "memory alloc failed for %s\n", msg);
+ goto error_out;
+ }
+
+ /* Read result of previous request */
+ error = RECV_RPMB_RSP(req->target, rsp_size, rsp);
+ if (error) {
+ fprintf(stderr, "error 0x%x receiving response for %s\n",
+ error, msg);
+ goto error_out;
+ }
+
+ /* validate response buffer - match target, nonce, and mac */
+ error = check_rpmb_response(req, rsp, (char *)msg);
+ if (error == 0) return rsp;
+
+error_out:
+ free(rsp);
+ return NULL;
+}
+
+/* read current write counter value from controller */
+static int rpmb_read_write_counter(int fd,
+ unsigned char target,
+ unsigned int *counter)
+{
+ int error = -1;
+ int req_size = sizeof(struct rpmb_data_frame_t);
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+
+ req = rpmb_request_init(req_size, RPMB_REQ_READ_WRITE_CNTR,
+ target, 1, 0, 0, NULL, 0, 0);
+ if (req == NULL) goto out;
+ if ((rsp = rpmb_read_request(fd, req, req_size, req_size)) == NULL) {
+ goto out;
+ }
+ *counter = rsp->write_counter;
+ error = 0;
+
+out:
+ free(req);
+ free(rsp);
+ return error;
+}
+
+/* Read current device configuration block into specified buffer. It also returns
+ * current write counter value returned as part of response, in case of error it
+ * returns 0
+ */
+static unsigned int rpmb_read_config_block(int fd, unsigned char **config_buf)
+{
+ int req_size = sizeof(struct rpmb_data_frame_t);
+ int cfg_size = sizeof(struct rpmb_config_block_t);
+ int rsp_size = req_size + cfg_size;
+
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+ struct rpmb_config_block_t *cfg = NULL;
+ unsigned int retval = 0;
+
+ /* initialize request with nonce, no data on input */
+ req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_READ, 0, 1, 0, 1,
+ 0, 0, 0);
+ if ((req == NULL) ||
+ (rsp = rpmb_read_request(fd, req, req_size, rsp_size)) == NULL)
+ {
+ goto out;
+ }
+
+ /* copy configuration data to be sent back to caller */
+ cfg = (struct rpmb_config_block_t *)calloc(cfg_size, 1);
+ if (cfg == NULL) {
+ fprintf(stderr, "failed to allocate RPMB config buffer\n");
+ goto out;
+ }
+
+ memcpy(cfg, rsp->data, cfg_size);
+ *config_buf = (unsigned char *)cfg;
+ cfg = NULL;
+ retval = rsp->write_counter;
+out:
+ free(req);
+ free(rsp);
+ free(cfg);
+ return retval;
+}
+
+
+static int rpmb_auth_data_read(int fd, unsigned char target,
+ unsigned int offset,
+ unsigned char **msg_buf,
+ int msg_size, int acc_size)
+{
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+ int req_size = sizeof(struct rpmb_data_frame_t);
+ int chunk_size = (acc_size < msg_size) ? acc_size : msg_size;
+ int xfer = chunk_size;
+ unsigned char *bufp = (unsigned char *)malloc(msg_size * 512);
+ unsigned char *tbufp = bufp;
+ int data_size, rsp_size;
+ int error = -1;
+
+ if (bufp == NULL) {
+ fprintf(stderr, "Failed to allocated memory for read-data req\n");
+ goto out;
+ }
+
+ while (xfer > 0) {
+ rsp_size = req_size + xfer * 512;
+ req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_READ,
+ target, 1, offset, xfer, 0, 0, 0);
+ if (req == NULL) break;
+ if ((rsp = rpmb_read_request(fd, req, req_size, rsp_size)) == NULL)
+ {
+ fprintf(stderr, "read_request failed\n");
+ free(rsp);
+ goto out;
+ }
+
+ data_size = rsp->sectors * 512;
+ memcpy(tbufp, rsp->data, data_size);
+ offset += rsp->sectors;
+ tbufp += data_size;
+ if (offset + chunk_size > msg_size)
+ xfer = msg_size - offset;
+ else
+ xfer = chunk_size;
+ free(req);
+ free(rsp);
+ }
+
+ *msg_buf = bufp;
+ error = offset;
+out:
+ return error;
+}
+
+/* Implementation of programming authentication key to given RPMB target */
+static int rpmb_program_auth_key(int fd, unsigned char target,
+ unsigned char *key_buf, int key_size)
+{
+ int req_size = sizeof(struct rpmb_data_frame_t);
+ int rsp_size = sizeof(struct rpmb_data_frame_t);
+
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+
+ int err = -ENOMEM;
+
+ req = rpmb_request_init(req_size, RPMB_REQ_AUTH_KEY_PROGRAM, target,
+ 0, 0, 0, key_buf, (223 - key_size), key_size);
+ if (req == NULL) {
+ fprintf(stderr, "failed to allocate request buffer memory\n");
+ goto out;
+ }
+
+ /* send request and read the result first */
+ rsp = rpmb_read_request(fd, req, req_size, rsp_size);
+ if (rsp == NULL || rsp->result != 0) {
+ goto out;
+ }
+
+ /* re-use response buffer */
+ memset(rsp, 0, rsp_size);
+ err = RECV_RPMB_RSP(req->target, rsp_size, (unsigned char *)rsp);
+ if (err != 0) {
+ err = check_rpmb_response(req, rsp, "Failed to Program Key");
+ }
+out:
+ free(req);
+ free(rsp);
+
+ return err;
+}
+
+
+/* Implementation of RPMB authenticated data write command; this function
+ * transfers msg_size bytes from msg_buf to controller 'addr'. Returns
+ * number of bytes actually written to, otherwise negetive error code
+ * on failures.
+ */
+static int auth_data_write_chunk(int fd, unsigned char tgt, unsigned int addr,
+ unsigned char *msg_buf, int msg_size,
+ unsigned char *keybuf, int keysize)
+{
+ int req_size = sizeof(struct rpmb_data_frame_t) + msg_size;
+ int rsp_size = sizeof(struct rpmb_data_frame_t);
+
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+
+ unsigned int write_cntr = 0;
+ unsigned char *mac = NULL;
+ int error = -ENOMEM;
+
+ /* get current write counter and copy to the request */
+ error = rpmb_read_write_counter(fd, tgt, &write_cntr);
+ if (error != 0) {
+ fprintf(stderr, "Failed to read write counter for write-data\n");
+ goto out;
+ }
+
+ req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DATA_WRITE, tgt, 0,
+ addr, (msg_size / 512), msg_buf,
+ offsetof(struct rpmb_data_frame_t, data), msg_size);
+ if (req == NULL) {
+ fprintf(stderr, "Memory alloc failed for write-data command\n");
+ goto out;
+ }
+
+ req->write_counter = write_cntr;
+
+ /* compute HMAC hash */
+ mac = hmac_sha256(((unsigned char *)req + 223), req_size - 223,
+ keybuf, keysize);
+ if (mac == NULL) {
+ fprintf(stderr, "failed to compute HMAC-SHA256\n");
+ error = -1;
+ goto out;
+ }
+
+ memcpy(req->mac, mac, 32);
+
+ /* send the request and get response */
+ error = SEND_RPMB_REQ(tgt, req_size, (unsigned char *)req);
+ if (error != 0) {
+ fprintf(stderr, "RPMB request 0x%04x for 0x%x, error: %d\n",
+ req->type, tgt, error);
+ goto out;
+ }
+
+ /* send the request to get the result and then request to get the response */
+ rsp = (struct rpmb_data_frame_t *)calloc(rsp_size, 1);
+ rsp->target = req->target;
+ rsp->type = RPMB_REQ_READ_RESULT;
+ error = SEND_RPMB_REQ(tgt, rsp_size, (unsigned char *)rsp);
+ if (error != 0 || rsp->result != 0) {
+ fprintf(stderr, "Write-data read result 0x%x, error = 0x%x\n",
+ rsp->result, error);
+ goto out;
+ }
+
+ /* Read final response */
+ memset(rsp, 0, rsp_size);
+ error = RECV_RPMB_RSP(tgt, rsp_size, (unsigned char *)rsp);
+ if (error != 0)
+ fprintf(stderr, "Auth data write recv error = 0x%x\n", error);
+ else
+ error = check_rpmb_response(req, rsp, "Failed to write-data");
+out:
+ free(req);
+ free(rsp);
+ free(mac);
+
+ return error;
+}
+
+/* send the request and get response */
+static int rpmb_auth_data_write(int fd, unsigned char target,
+ unsigned int addr, int acc_size,
+ unsigned char *msg_buf, int msg_size,
+ unsigned char *keybuf, int keysize)
+{
+ int chunk_size = acc_size < msg_size ? acc_size : msg_size;
+ int xfer = chunk_size;
+ int offset = 0;
+
+ while (xfer > 0 ) {
+ if (auth_data_write_chunk(fd, target, (addr + offset / 512),
+ msg_buf + offset, xfer,
+ keybuf, keysize) != 0)
+ {
+ /* error writing chunk data */
+ break;
+ }
+
+ offset += xfer;
+ if (offset + chunk_size > msg_size)
+ xfer = msg_size - offset;
+ else
+ xfer = chunk_size;
+ }
+
+ return offset;
+}
+
+/* writes given config_block buffer to the drive target 0 */
+static int rpmb_write_config_block(int fd, unsigned char *cfg_buf,
+ unsigned char *keybuf, int keysize)
+{
+ int cfg_size = sizeof(struct rpmb_config_block_t);
+ int rsp_size = sizeof(struct rpmb_data_frame_t);
+ int req_size = rsp_size + cfg_size;
+
+ struct rpmb_data_frame_t *req = NULL;
+ struct rpmb_data_frame_t *rsp = NULL;
+ unsigned char *cfg_buf_read = NULL, *mac = NULL;
+ unsigned int write_cntr = 0;
+ int error = -ENOMEM;
+
+ /* initialize request */
+ req = rpmb_request_init(req_size, RPMB_REQ_AUTH_DCB_WRITE, 0, 0, 0, 1,
+ cfg_buf, offsetof(struct rpmb_data_frame_t, data),
+ cfg_size);
+ if (req == NULL) {
+ fprintf(stderr, "failed to allocate rpmb request buffer\n");
+ goto out;
+ }
+
+ /* read config block write_counter from controller */
+ write_cntr = rpmb_read_config_block(fd, &cfg_buf_read);
+ if (cfg_buf_read == NULL) {
+ fprintf(stderr, "failed to read config block write counter\n");
+ error = -EIO;
+ goto out;
+ }
+
+ free(cfg_buf_read);
+ req->write_counter = write_cntr;
+ mac = hmac_sha256(((unsigned char *)req + 223), req_size - 223,
+ keybuf, keysize);
+ if (mac == NULL) {
+ fprintf(stderr, "failed to compute hmac-sha256 hash\n");
+ error = -EINVAL;
+ goto out;
+ }
+
+ memcpy(req->mac, mac, sizeof(req->mac));
+
+ error = SEND_RPMB_REQ(0, req_size, (unsigned char *)req);
+ if (error != 0) {
+ fprintf(stderr, "Write-config RPMB request, error = 0x%x\n",
+ error);
+ goto out;
+ }
+
+ /* get response */
+ rsp = (struct rpmb_data_frame_t *)calloc(rsp_size, 1);
+ if (rsp == NULL) {
+ fprintf(stderr, "failed to allocate response buffer memory\n");
+ error = -ENOMEM;
+ goto out;
+ }
+
+ /* get result first */
+ memset(rsp, 0, rsp_size);
+ rsp->target = req->target;
+ rsp->type = RPMB_REQ_READ_RESULT;
+ /* get the response and validate */
+ error = RECV_RPMB_RSP(req->target, rsp_size, rsp);
+ if (error != 0) {
+ fprintf(stderr,"Failed getting write-config response\
+ error = 0x%x\n", error);
+ goto out;
+ }
+ error = check_rpmb_response(req, rsp,
+ "Failed to retrieve write-config response");
+out:
+ free(req);
+ free(rsp);
+ free(mac);
+
+ return error;
+}
+
+static bool invalid_xfer_size(int blocks, unsigned int bpsz)
+{
+ return ((blocks <= 0) ||
+ (blocks * 512) > ((bpsz + 1) * 128 * 1024));
+}
+
+/* Handling rpmb sub-command */
+int rpmb_cmd_option(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Run RPMB command on the supporting controller";
+ const char *msg = "data to be written on write-data or write-config commands";
+ const char *mfile = "data file for read/write-data, read/write-config options";
+ const char *kfile = "key file that has authentication key to be used";
+ const char *target = "RPMB target - numerical value of 0 to 6, default 0";
+ const char *address = "Sector offset to read from or write to for an RPMB target, default 0";
+ const char *blocks = "Number of 512 blocks to read or write";
+ const char *key = "key to be used for authentication";
+ const char *opt = "RPMB action - info, program-key, read-counter, write-data, " \
+ "read-data, write-config and read-config";
+
+ struct config {
+ char *cmd;
+ char *key;
+ char *msg;
+ char *keyfile;
+ char *msgfile;
+ int opt;
+ int address;
+ int blocks;
+ char target;
+ };
+
+ struct config cfg = {
+ .cmd = "info",
+ .key = NULL,
+ .msg = NULL,
+ .msgfile = NULL,
+ .keyfile = NULL,
+ .opt = 0,
+ .address = 0,
+ .blocks = 0,
+ .target = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("cmd", 'c', "command", &cfg.cmd, opt),
+ OPT_STRING("msgfile", 'f', "FILE", &cfg.msgfile, mfile),
+ OPT_STRING("keyfile", 'g', "FILE", &cfg.keyfile, kfile),
+ OPT_STRING("key", 'k', "key", &cfg.key, key),
+ OPT_STRING("msg", 'd', "data", &cfg.msg, msg),
+ OPT_UINT("address", 'o', &cfg.address, address),
+ OPT_UINT("blocks", 'b', &cfg.blocks, blocks),
+ OPT_UINT("target", 't', &cfg.target, target),
+ OPT_END()
+ };
+
+ unsigned int write_cntr = 0;
+ unsigned char *key_buf = NULL;
+ unsigned char *msg_buf = NULL;
+ unsigned int msg_size = 0;
+ unsigned int key_size = 0;
+ int fd = -1, err = -1;
+ struct nvme_id_ctrl ctrl;
+
+ union ctrl_rpmbs_reg {
+ struct {
+ unsigned int num_targets:3;
+ unsigned int auth_method:3;
+ unsigned int reserved:10;
+ unsigned int total_size:8; /* 128K units */
+ unsigned int access_size:8; /* in 512 byte count */
+ };
+ unsigned int rpmbs;
+ } regs;
+
+ if ((fd = parse_and_open(argc, argv, desc, opts)) < 0)
+ goto out;
+
+ /* before parsing commands, check if controller supports any RPMB targets */
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ goto out;
+
+ regs.rpmbs = le32_to_cpu(ctrl.rpmbs);
+ if (regs.num_targets == 0) {
+ fprintf(stderr, "No RPMB targets are supported by the drive\n");
+ goto out;
+ }
+
+ /* parse and validate options; default print rpmb support info */
+ if (cfg.cmd == 0 || strcmp(cfg.cmd, "info") == 0) {
+ nvme_show_id_ctrl_rpmbs(regs.rpmbs);
+ goto out;
+ }
+
+ if (strcmp(cfg.cmd, "program-key") == 0)
+ cfg.opt = RPMB_REQ_AUTH_KEY_PROGRAM;
+ else if (strcmp(cfg.cmd, "read-counter") == 0)
+ cfg.opt = RPMB_REQ_READ_WRITE_CNTR;
+ else if (strcmp(cfg.cmd, "write-data") == 0)
+ cfg.opt = RPMB_REQ_AUTH_DATA_WRITE;
+ else if (strcmp(cfg.cmd, "read-data") == 0)
+ cfg.opt = RPMB_REQ_AUTH_DATA_READ;
+ else if (strcmp(cfg.cmd, "write-config") == 0)
+ cfg.opt = RPMB_REQ_AUTH_DCB_WRITE;
+ else if (strcmp(cfg.cmd, "read-config") == 0)
+ cfg.opt = RPMB_REQ_AUTH_DCB_READ;
+ else {
+ fprintf(stderr, "Invalid option %s for rpmb command\n", cfg.cmd);
+ goto out;
+ }
+
+ /* input file/data processing */
+ if (cfg.opt == RPMB_REQ_AUTH_DCB_WRITE ||
+ cfg.opt == RPMB_REQ_AUTH_DATA_WRITE ||
+ cfg.opt == RPMB_REQ_AUTH_KEY_PROGRAM)
+ {
+ key_buf = read_rpmb_key(cfg.key, cfg.keyfile, &key_size);
+ if (key_buf == NULL) {
+ fprintf(stderr, "Failed to read key\n");
+ goto out;
+ }
+
+ if (key_size > 223 || key_size <= 0) {
+ fprintf(stderr, "Invalid key size %d, valid input 1 to 223\n",
+ key_size);
+ goto out;
+ }
+
+ if (cfg.opt == RPMB_REQ_AUTH_DCB_WRITE ||
+ cfg.opt == RPMB_REQ_AUTH_DATA_WRITE) {
+ if (cfg.msg != NULL) {
+ msg_size = strlen(cfg.msg);
+ msg_buf = (unsigned char *)malloc(msg_size);
+ memcpy(msg_buf, cfg.msg, msg_size);
+ } else {
+ err = read_file(cfg.msgfile, &msg_buf, &msg_size);
+ if (err || msg_size <= 0) {
+ fprintf(stderr, "Failed to read file %s\n",
+ cfg.msgfile);
+ goto out;
+ }
+ }
+ }
+ }
+
+ switch (cfg.opt) {
+ case RPMB_REQ_READ_WRITE_CNTR:
+ err = rpmb_read_write_counter(fd, cfg.target, &write_cntr);
+ if (err == 0)
+ printf("Write Counter is: %u\n", write_cntr);
+ break;
+
+ case RPMB_REQ_AUTH_DCB_READ:
+ write_cntr = rpmb_read_config_block(fd, &msg_buf);
+ if (msg_buf == NULL) {
+ fprintf(stderr, "failed read config blk\n");
+ goto out;
+ }
+
+ /* no output file is given, print the data on stdout */
+ if (cfg.msgfile == 0) {
+ struct rpmb_config_block_t *cfg =
+ (struct rpmb_config_block_t *)msg_buf;
+ printf("Boot Parition Protection is %s\n",
+ ((cfg->bp_enable & 0x1) ? "Enabled" : "Disabled"));
+ printf("Boot Parition 1 is %s\n",
+ ((cfg->bp_lock & 0x2) ? "Locked" : "Unlocked"));
+ printf("Boot Parition 0 is %s\n",
+ ((cfg->bp_lock & 0x1) ? "Locked" : "Unlocked"));
+ } else {
+ printf("Saving received config data to %s file\n", cfg.msgfile);
+ write_file(msg_buf, sizeof(struct rpmb_config_block_t), NULL,
+ cfg.msgfile, NULL);
+ }
+ err = (write_cntr == 0);
+ break;
+
+ case RPMB_REQ_AUTH_DATA_READ:
+ /* check if requested data is beyond what target supports */
+ msg_size = cfg.blocks * 512;
+ if (invalid_xfer_size(cfg.blocks, regs.total_size)) {
+ fprintf(stderr, "invalid transfer size %d \n",
+ msg_size);
+ break;
+ }
+ err = rpmb_auth_data_read(fd, cfg.target, cfg.address,
+ &msg_buf, cfg.blocks,
+ (regs.access_size + 1));
+ if (err > 0 && msg_buf != NULL) {
+ printf("Writting %d bytes to file %s\n",
+ err * 512, cfg.msgfile);
+ write_file(msg_buf, err * 512, NULL,
+ cfg.msgfile, NULL);
+ }
+ break;
+
+ case RPMB_REQ_AUTH_DATA_WRITE:
+ if (invalid_xfer_size(cfg.blocks, regs.total_size) ||
+ (cfg.blocks * 512) > msg_size) {
+ fprintf(stderr, "invalid transfer size %d\n",
+ cfg.blocks * 512);
+ break;
+ } else if ((cfg.blocks * 512) < msg_size) {
+ msg_size = cfg.blocks * 512;
+ }
+ err = rpmb_auth_data_write(fd, cfg.target, cfg.address,
+ ((regs.access_size + 1) * 512),
+ msg_buf, msg_size,
+ key_buf, key_size);
+
+ /* print whatever extent of data written to target */
+ printf("Written %d sectors out of %d @target(%d):0x%x\n",
+ err/512, msg_size/512, cfg.target, cfg.address);
+ break;
+
+ case RPMB_REQ_AUTH_DCB_WRITE:
+ err = rpmb_write_config_block(fd, msg_buf, key_buf, key_size);
+ break;
+
+ case RPMB_REQ_AUTH_KEY_PROGRAM:
+ err = rpmb_program_auth_key(fd, cfg.target, key_buf, key_size);
+ break;
+ default:
+ break;
+ }
+
+out:
+ /* release memory */
+ free(key_buf);
+ free(msg_buf);
+
+ /* close file descriptor */
+ if (fd > 0) close(fd);
+
+ return err;
+}
diff --git a/nvme-status.c b/nvme-status.c
index 1b060dc..270eb06 100644
--- a/nvme-status.c
+++ b/nvme-status.c
@@ -97,7 +97,6 @@ static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status)
case NVME_SC_NS_ALREADY_ATTACHED:
return EALREADY;
case NVME_SC_THIN_PROV_NOT_SUPP:
- case NVME_SC_ONCS_NOT_SUPPORTED:
return EOPNOTSUPP;
case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
return EINPROGRESS;
@@ -127,6 +126,22 @@ static inline __u8 nvme_fabrics_status_to_errno(__u16 status)
return EIO;
}
+static inline __u8 nvme_path_status_to_errno(__u16 status)
+{
+ switch (status) {
+ case NVME_SC_INTERNAL_PATH_ERROR:
+ case NVME_SC_ANA_PERSISTENT_LOSS:
+ case NVME_SC_ANA_INACCESSIBLE:
+ case NVME_SC_ANA_TRANSITION:
+ case NVME_SC_CTRL_PATHING_ERROR:
+ case NVME_SC_HOST_PATHING_ERROR:
+ case NVME_SC_HOST_CMD_ABORT:
+ return EACCES;
+ }
+
+ return EIO;
+}
+
/*
* nvme_status_to_errno - It converts given status to errno mapped
* @status: >= 0 for nvme status field in completion queue entry,
@@ -142,8 +157,11 @@ __u8 nvme_status_to_errno(int status, bool fabrics)
if (!status)
return 0;
- if (status < 0)
- return ECOMM;
+ if (status < 0) {
+ if (errno)
+ return errno;
+ return status;
+ }
/*
* The actual status code is enough with masking 0xff, but we need to
@@ -152,12 +170,17 @@ __u8 nvme_status_to_errno(int status, bool fabrics)
status &= 0x7ff;
sct = nvme_status_type(status);
- if (sct == NVME_SCT_GENERIC)
+ switch (sct) {
+ case NVME_SCT_GENERIC:
return nvme_generic_status_to_errno(status);
- else if (sct == NVME_SCT_CMD_SPECIFIC && !fabrics)
- return nvme_cmd_specific_status_to_errno(status);
- else if (sct == NVME_SCT_CMD_SPECIFIC && fabrics)
+ case NVME_SCT_CMD_SPECIFIC:
+ if (!fabrics) {
+ return nvme_cmd_specific_status_to_errno(status);
+ }
return nvme_fabrics_status_to_errno(status);
+ case NVME_SCT_PATH:
+ return nvme_path_status_to_errno(status);
+ }
/*
* Media, integrity related status, and the others will be mapped to
diff --git a/nvme-topology.c b/nvme-topology.c
index d24ef6b..31cf7f9 100644
--- a/nvme-topology.c
+++ b/nvme-topology.c
@@ -9,8 +9,14 @@
#include "nvme.h"
#include "nvme-ioctl.h"
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-id128.h>
+#define NVME_HOSTNQN_ID SD_ID128_MAKE(c7,f4,61,81,12,be,49,32,8c,83,10,6f,9d,dd,d8,6b)
+#endif
+
static const char *dev = "/dev/";
static const char *subsys_dir = "/sys/class/nvme-subsystem/";
+static void free_ctrl(struct nvme_ctrl *c);
char *get_nvme_subsnqn(char *path)
{
@@ -45,7 +51,7 @@ close_fd:
return subsysnqn;
}
-char *nvme_get_ctrl_attr(char *path, const char *attr)
+char *nvme_get_ctrl_attr(const char *path, const char *attr)
{
char *attrpath, *value;
ssize_t ret;
@@ -144,7 +150,7 @@ static int scan_namespace(struct nvme_namespace *n)
int ret, fd;
char *path;
- ret = asprintf(&path, "%s%s", dev, n->name);
+ ret = asprintf(&path, "%s%s", n->ctrl->path, n->name);
if (ret < 0)
return ret;
@@ -152,9 +158,11 @@ static int scan_namespace(struct nvme_namespace *n)
if (fd < 0)
goto free;
- n->nsid = nvme_get_nsid(fd);
- if (n->nsid < 0)
- goto close_fd;
+ if (!n->nsid) {
+ n->nsid = nvme_get_nsid(fd);
+ if (n->nsid < 0)
+ goto close_fd;
+ }
ret = nvme_identify_ns(fd, n->nsid, 0, &n->ns);
if (ret < 0)
@@ -228,6 +236,19 @@ static char *get_nvme_ctrl_path_ana_state(char *path, int nsid)
return ana_state;
}
+static bool ns_attached_to_ctrl(int nsid, struct nvme_ctrl *ctrl)
+{
+ struct nvme_namespace *n;
+ int i;
+
+ for (i = 0; i < ctrl->nr_namespaces; i++) {
+ n = &ctrl->namespaces[i];
+ if (nsid == n->nsid)
+ return true;
+ }
+ return false;
+}
+
static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
{
struct nvme_namespace *n;
@@ -248,7 +269,7 @@ static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
if (ns_instance)
c->ana_state = get_nvme_ctrl_path_ana_state(path, ns_instance);
- ret = scandir(path, &ns, scan_namespace_filter, alphasort);
+ ret = scandir(path, &ns, scan_ctrl_namespace_filter, alphasort);
if (ret == -1) {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
return errno;
@@ -256,11 +277,36 @@ static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
c->nr_namespaces = ret;
c->namespaces = calloc(c->nr_namespaces, sizeof(*n));
- for (i = 0; i < c->nr_namespaces; i++) {
- n = &c->namespaces[i];
- n->name = strdup(ns[i]->d_name);
- n->ctrl = c;
- scan_namespace(n);
+ if (c->namespaces) {
+ for (i = 0; i < c->nr_namespaces; i++) {
+ char *ns_path, nsid[16];
+ int ns_fd;
+
+ n = &c->namespaces[i];
+ n->name = strdup(ns[i]->d_name);
+ n->ctrl = c;
+ ret = asprintf(&ns_path, "%s/%s/nsid", path, n->name);
+ if (ret < 0)
+ continue;
+ ns_fd = open(ns_path, O_RDONLY);
+ if (ns_fd < 0) {
+ free(ns_path);
+ continue;
+ }
+ ret = read(ns_fd, nsid, 16);
+ if (ret < 0) {
+ close(ns_fd);
+ free(ns_path);
+ continue;
+ }
+ n->nsid = (unsigned)strtol(nsid, NULL, 10);
+ scan_namespace(n);
+ close(ns_fd);
+ free(ns_path);
+ }
+ } else {
+ i = c->nr_namespaces;
+ c->nr_namespaces = 0;
}
while (i--)
@@ -268,7 +314,7 @@ static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
free(ns);
free(path);
- ret = asprintf(&path, "%s%s", dev, c->name);
+ ret = asprintf(&path, "%s%s", c->path, c->name);
if (ret < 0)
return ret;
@@ -288,12 +334,12 @@ free:
return 0;
}
-static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
+static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance, int nsid)
{
struct dirent **ctrls, **ns;
struct nvme_namespace *n;
struct nvme_ctrl *c;
- int i, ret;
+ int i, j = 0, ret;
char *path;
ret = asprintf(&path, "%s%s", subsys_dir, s->name);
@@ -309,11 +355,18 @@ static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
s->nr_ctrls = ret;
s->ctrls = calloc(s->nr_ctrls, sizeof(*c));
for (i = 0; i < s->nr_ctrls; i++) {
- c = &s->ctrls[i];
+ c = &s->ctrls[j];
c->name = strdup(ctrls[i]->d_name);
+ c->path = strdup(dev);
c->subsys = s;
scan_ctrl(c, path, ns_instance);
+
+ if (!ns_instance || ns_attached_to_ctrl(nsid, c))
+ j++;
+ else
+ free_ctrl(c);
}
+ s->nr_ctrls = j;
while (i--)
free(ctrls[i]);
@@ -327,11 +380,16 @@ static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
s->nr_namespaces = ret;
s->namespaces = calloc(s->nr_namespaces, sizeof(*n));
- 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);
+ if (s->namespaces) {
+ 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);
+ }
+ } else {
+ i = s->nr_namespaces;
+ s->nr_namespaces = 0;
}
while (i--)
@@ -349,7 +407,7 @@ static int verify_legacy_ns(struct nvme_namespace *n)
char *path;
int ret, fd;
- ret = asprintf(&path, "%s%s", dev, n->name);
+ ret = asprintf(&path, "%s%s", n->ctrl->path, n->name);
if (ret < 0)
return ret;
@@ -388,7 +446,7 @@ static int verify_legacy_ns(struct nvme_namespace *n)
* is the controller to nvme0n1 for such older kernels. We will also assume
* every controller is its own subsystem.
*/
-static int legacy_list(struct nvme_topology *t)
+static int legacy_list(struct nvme_topology *t, char *dev_dir)
{
struct nvme_ctrl *c;
struct nvme_subsystem *s;
@@ -397,10 +455,10 @@ static int legacy_list(struct nvme_topology *t)
int ret = 0, fd, i;
char *path;
- t->nr_subsystems = scandir(dev, &devices, scan_ctrls_filter, alphasort);
- if (t->nr_subsystems < 0) {
- fprintf(stderr, "no NVMe device(s) detected.\n");
- return t->nr_subsystems;
+ t->nr_subsystems = scandir(dev_dir, &devices, scan_ctrls_filter, alphasort);
+ if (t->nr_subsystems == -1) {
+ fprintf(stderr, "Failed to open %s: %s\n", dev_dir, strerror(errno));
+ return errno;
}
t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
@@ -417,11 +475,18 @@ static int legacy_list(struct nvme_topology *t)
c = s->ctrls;
c->name = strdup(s->name);
sscanf(c->name, "nvme%d", &current_index);
- c->nr_namespaces = scandir(dev, &namespaces, scan_dev_filter,
+ c->path = strdup(dev_dir);
+ c->nr_namespaces = scandir(c->path, &namespaces, scan_dev_filter,
alphasort);
c->namespaces = calloc(c->nr_namespaces, sizeof(*n));
+ if (!c->namespaces) {
+ while (c->nr_namespaces--)
+ free(namespaces[c->nr_namespaces]);
+ free(namespaces);
+ continue;
+ }
- ret = asprintf(&path, "%s%s", dev, c->name);
+ ret = asprintf(&path, "%s%s", c->path, c->name);
if (ret < 0)
continue;
ret = 0;
@@ -463,6 +528,7 @@ static void free_ctrl(struct nvme_ctrl *c)
free(n->name);
}
free(c->name);
+ free(c->path);
free(c->transport);
free(c->address);
free(c->state);
@@ -488,35 +554,64 @@ static void free_subsystem(struct nvme_subsystem *s)
free(s->namespaces);
}
+static int scan_subsystem_dir(struct nvme_topology *t, char *dev_dir)
+{
+ struct nvme_topology dev_dir_t = { };
+ int ret, i, total_nr_subsystems;
+
+ ret = legacy_list(&dev_dir_t, dev_dir);
+ if (ret != 0)
+ return ret;
+
+ total_nr_subsystems = t->nr_subsystems + dev_dir_t.nr_subsystems;
+ t->subsystems = realloc(t->subsystems,
+ total_nr_subsystems * sizeof(struct nvme_subsystem));
+ for (i = 0; i < dev_dir_t.nr_subsystems; i++){
+ t->subsystems[i+t->nr_subsystems] = dev_dir_t.subsystems[i];
+ }
+ t->nr_subsystems = total_nr_subsystems;
+
+ return 0;
+}
+
int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
- __u32 ns_instance)
+ __u32 ns_instance, int nsid, char *dev_dir)
{
struct nvme_subsystem *s;
struct dirent **subsys;
- int i, j = 0;
+ int ret = 0, i, j = 0;
t->nr_subsystems = scandir(subsys_dir, &subsys, scan_subsys_filter,
alphasort);
- if (t->nr_subsystems < 0)
- return legacy_list(t);
+ if (t->nr_subsystems < 0) {
+ ret = legacy_list(t, (char *)dev);
+ if (ret != 0)
+ return ret;
+ } else {
+
+ t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
+ for (i = 0; i < t->nr_subsystems; i++) {
+ s = &t->subsystems[j];
+ s->name = strdup(subsys[i]->d_name);
+ scan_subsystem(s, ns_instance, nsid);
+
+ if (!subsysnqn || !strcmp(s->subsysnqn, subsysnqn))
+ j++;
+ else
+ free_subsystem(s);
+ }
+ t->nr_subsystems = j;
- t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
- for (i = 0; i < t->nr_subsystems; i++) {
- s = &t->subsystems[j];
- s->name = strdup(subsys[i]->d_name);
- scan_subsystem(s, ns_instance);
+ while (i--)
+ free(subsys[i]);
+ free(subsys);
+ }
- if (!subsysnqn || !strcmp(s->subsysnqn, subsysnqn))
- j++;
- else
- free_subsystem(s);
+ if (dev_dir != NULL && strcmp(dev_dir, "/dev/")) {
+ ret = scan_subsystem_dir(t, dev_dir);
}
- t->nr_subsystems = j;
- while (i--)
- free(subsys[i]);
- free(subsys);
- return 0;
+ return ret;
}
void free_topology(struct nvme_topology *t)
@@ -606,3 +701,75 @@ void *mmap_registers(const char *dev)
return membase;
}
+#define PATH_DMI_ENTRIES "/sys/firmware/dmi/entries"
+
+int uuid_from_dmi(char *system_uuid)
+{
+ int f;
+ DIR *d;
+ struct dirent *de;
+ char buf[512];
+
+ system_uuid[0] = '\0';
+ d = opendir(PATH_DMI_ENTRIES);
+ if (!d)
+ return -ENXIO;
+ while ((de = readdir(d))) {
+ char filename[PATH_MAX];
+ int len, type;
+
+ if (de->d_name[0] == '.')
+ continue;
+ sprintf(filename, "%s/%s/type", PATH_DMI_ENTRIES, de->d_name);
+ f = open(filename, O_RDONLY);
+ if (f < 0)
+ continue;
+ len = read(f, buf, 512);
+ close(f);
+ if (len < 0)
+ continue;
+ if (sscanf(buf, "%d", &type) != 1)
+ continue;
+ if (type != 1)
+ continue;
+ sprintf(filename, "%s/%s/raw", PATH_DMI_ENTRIES, de->d_name);
+ f = open(filename, O_RDONLY);
+ if (f < 0)
+ continue;
+ len = read(f, buf, 512);
+ close(f);
+ if (len < 0)
+ continue;
+ /* Sigh. https://en.wikipedia.org/wiki/Overengineering */
+ /* DMTF SMBIOS 3.0 Section 7.2.1 System UUID */
+ sprintf(system_uuid,
+ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
+ "%02x%02x%02x%02x%02x%02x",
+ (uint8_t)buf[8 + 3], (uint8_t)buf[8 + 2],
+ (uint8_t)buf[8 + 1], (uint8_t)buf[8 + 0],
+ (uint8_t)buf[8 + 5], (uint8_t)buf[8 + 4],
+ (uint8_t)buf[8 + 7], (uint8_t)buf[8 + 6],
+ (uint8_t)buf[8 + 8], (uint8_t)buf[8 + 9],
+ (uint8_t)buf[8 + 10], (uint8_t)buf[8 + 11],
+ (uint8_t)buf[8 + 12], (uint8_t)buf[8 + 13],
+ (uint8_t)buf[8 + 14], (uint8_t)buf[8 + 15]);
+ break;
+ }
+ closedir(d);
+ return strlen(system_uuid) ? 0 : -ENXIO;
+}
+
+int uuid_from_systemd(char *systemd_uuid)
+{
+#ifdef HAVE_SYSTEMD
+ sd_id128_t id;
+
+ if (sd_id128_get_machine_app_specific(NVME_HOSTNQN_ID, &id) < 0)
+ return -ENXIO;
+
+ sprintf(systemd_uuid, SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(id));
+ return 0;
+#else
+ return -ENOTSUP;
+#endif
+}
diff --git a/nvme.c b/nvme.c
index 107f012..a2075bf 100644
--- a/nvme.c
+++ b/nvme.c
@@ -47,7 +47,6 @@
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include "common.h"
#include "nvme-print.h"
@@ -85,7 +84,17 @@ static struct program nvme = {
.extensions = &builtin,
};
-static const char *output_format = "Output format: normal|json|binary";
+static __u16 nvme_feat_buf_len[0x100] = {
+ [NVME_FEAT_LBA_RANGE] = 4096,
+ [NVME_FEAT_AUTO_PST] = 256,
+ [NVME_FEAT_HOST_MEM_BUF] = 4096,
+ [NVME_FEAT_HOST_ID] = 8,
+ [NVME_FEAT_PLM_CONFIG] = 512,
+ [NVME_FEAT_TIMESTAMP] = 8,
+ [NVME_FEAT_HOST_BEHAVIOR] = 512
+};
+
+const char *output_format = "Output format: normal|json|binary";
static const char *output_format_no_binary = "Output format: normal|json";
static void *__nvme_alloc(size_t len, bool *huge)
@@ -100,10 +109,10 @@ static void *__nvme_alloc(size_t len, bool *huge)
return NULL;
}
-#ifdef LIBHUGETLBFS
#define HUGE_MIN 0x80000
-static void nvme_free(void *p, bool huge)
+#ifdef LIBHUGETLBFS
+void nvme_free(void *p, bool huge)
{
if (huge)
free_hugepage_region(p);
@@ -111,7 +120,7 @@ static void nvme_free(void *p, bool huge)
free(p);
}
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
{
void *p;
@@ -126,17 +135,27 @@ static void *nvme_alloc(size_t len, bool *huge)
return p;
}
#else
-static void nvme_free(void *p, bool huge)
+void nvme_free(void *p, bool huge)
{
free(p);
}
-static void *nvme_alloc(size_t len, bool *huge)
+void *nvme_alloc(size_t len, bool *huge)
{
return __nvme_alloc(len, huge);
}
#endif
+static bool is_chardev(void)
+{
+ return S_ISCHR(nvme_stat.st_mode);
+}
+
+static bool is_blkdev(void)
+{
+ return S_ISBLK(nvme_stat.st_mode);
+}
+
static int open_dev(char *dev)
{
int err, fd;
@@ -152,7 +171,7 @@ static int open_dev(char *dev)
close(fd);
goto perror;
}
- if (!S_ISCHR(nvme_stat.st_mode) && !S_ISBLK(nvme_stat.st_mode)) {
+ if (!is_chardev() && !is_blkdev()) {
fprintf(stderr, "%s is not a block or character device\n", dev);
close(fd);
return -ENODEV;
@@ -200,7 +219,7 @@ int parse_and_open(int argc, char **argv, const char *desc,
return ret;
}
-enum nvme_print_flags validate_output_format(char *format)
+enum nvme_print_flags validate_output_format(const char *format)
{
if (!format)
return -EINVAL;
@@ -386,8 +405,7 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
hdr = malloc(bs);
page_log = malloc(bs);
if (!hdr || !page_log) {
- fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n",
- bs, strerror(errno));
+ perror("failed to allocate buf for log\n");
err = -ENOMEM;
goto free_mem;
}
@@ -623,7 +641,7 @@ static int get_error_log(int argc, char **argv, struct command *cmd, struct plug
cfg.log_entries = min(cfg.log_entries, ctrl.elpe + 1);
err_log = calloc(cfg.log_entries, sizeof(struct nvme_error_log_page));
if (!err_log) {
- fprintf(stderr, "could not alloc buffer for error log\n");
+ perror("could not alloc buffer for error log\n");
err = -ENOMEM;
goto close_fd;
}
@@ -738,6 +756,470 @@ ret:
return nvme_status_to_errno(err, false);
}
+static int get_pred_lat_per_nvmset_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Predictable latency per nvm set log "\
+ "page and prints it for the given device in either decoded " \
+ "format(default),json or binary.";
+ const char *nvmset_id = "NVM Set Identifier";
+ const char *raw = "use binary output";
+ struct nvme_predlat_per_nvmset_log_page plpns_log;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u16 nvmset_id;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 1,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("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()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_predictable_latency_per_nvmset_log(fd,
+ cfg.nvmset_id, &plpns_log);
+ if (!err)
+ nvme_show_predictable_latency_per_nvmset(&plpns_log,
+ cfg.nvmset_id, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("predictable latency per nvm set");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_pred_lat_event_agg_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Predictable Latency Event" \
+ "Aggregate Log page and prints it, for the given" \
+ "device in either decoded format(default)," \
+ "json or binary.";
+ const char *log_entries = "Number of pending NVM Set" \
+ "log Entries list";
+ const char *rae = "Retain an Asynchronous Event";
+ const char *raw = "use binary output";
+ void *pea_log;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 log_size;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ fprintf(stderr, "non-zero log-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err < 0) {
+ perror("identify controller");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le32_to_cpu(ctrl.nsetidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+ pea_log = calloc(log_size, 1);
+ if (!pea_log) {
+ perror("could not alloc buffer for predictable " \
+ "latency event agggregate log entries\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_predictable_latency_event_agg_log(fd, pea_log, cfg.rae,
+ log_size);
+ if (!err)
+ nvme_show_predictable_latency_event_agg_log(pea_log, cfg.log_entries,
+ log_size, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("predictable latency event gggregate log page");
+ free(pea_log);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_persistent_event_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Persistent Event log info for"\
+ " the given device in either decoded format(default),"\
+ " json or binary.";
+ const char *action = "action the controller shall take during"\
+ " processing this persistent log page command.";
+ 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;
+ enum nvme_print_flags flags;
+ int err, fd;
+ bool huge;
+
+ struct config {
+ __u8 action;
+ __u32 log_len;
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .action = 0xff,
+ .log_len = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ 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;
+ goto close_fd;
+ }
+
+ err = nvme_persistent_event_log(fd, cfg.action,
+ sizeof(*pevent_log_head), pevent_log_head);
+ if (err < 0) {
+ perror("persistent event log");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ if (cfg.action == NVME_PEVENT_LOG_RELEASE_CTX) {
+ printf("Releasing Persistent Event Log Context\n");
+ goto close_fd;
+ }
+
+ if (!cfg.log_len && cfg.action != NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ cfg.log_len = le64_to_cpu(pevent_log_head->tll);
+ } else if (!cfg.log_len && cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ printf("Establishing Persistent Event Log Context\n");
+ goto close_fd;
+ }
+
+ /*
+ * if header aleady read with context establish action 0x1,
+ * action shall not be 0x1 again in the subsequent request,
+ * until the current context is released by issuing action
+ * with 0x2, otherwise throws command sequence error, make
+ * it as zero to read the log page
+ */
+ if (cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ)
+ cfg.action = NVME_PEVENT_LOG_READ;
+
+ 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;
+ goto close_fd;
+ }
+ err = nvme_persistent_event_log(fd, cfg.action,
+ cfg.log_len, pevent_log_info);
+ if (!err)
+ nvme_show_persistent_event_log(pevent_log_info, cfg.action,
+ cfg.log_len, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("persistent event log");
+
+ nvme_free(pevent_log_info, huge);
+
+close_fd:
+ free(pevent_log_head);
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_endurance_event_agg_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Retrieve Predictable Latency " \
+ "Event Aggregate page and prints it, for the given " \
+ "device in either decoded format(default), " \
+ "json or binary.";
+ const char *log_entries = "Number of pending Endurance Group " \
+ "Event log Entries list";
+ const char *rae = "Retain an Asynchronous Event";
+ const char *raw = "use binary output";
+ void *endurance_log;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 log_size;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ char *output_format;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ fprintf(stderr, "non-zero log-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err < 0) {
+ perror("identify controller");
+ goto close_fd;
+ } else if (err) {
+ fprintf(stderr, "could not identify controller\n");
+ err = -ENODEV;
+ goto close_fd;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le16_to_cpu(ctrl.endgidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+ endurance_log = calloc(log_size, 1);
+ if (!endurance_log) {
+ perror("could not alloc buffer for endurance group" \
+ " event agggregate log entries\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_endurance_group_event_agg_log(fd, endurance_log, cfg.rae,
+ log_size);
+ if (!err)
+ nvme_show_endurance_group_event_agg_log(endurance_log, cfg.log_entries,
+ log_size, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("endurance group event aggregate log page");
+ free(endurance_log);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_lba_status_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Get LBA Status Info Log " \
+ "and prints it, for the given device in either " \
+ "decoded format(default),json or binary.";
+ const char *rae = "Retain an Asynchronous Event";
+ void *lab_status;
+ enum nvme_print_flags flags;
+ int err, fd;
+ __u32 lslplen;
+
+ struct config {
+ bool rae;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .rae = false,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_lba_status_log(fd, &lslplen, true, sizeof(__u32));
+ if (err < 0) {
+ perror("lba status log page");
+ goto close_fd;
+ } else if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ lab_status = calloc(lslplen, 1);
+ if (!lab_status) {
+ perror("could not alloc buffer for lba status log");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_lba_status_log(fd, lab_status, cfg.rae, lslplen);
+ if (!err)
+ nvme_show_lba_status_log(lab_status, lslplen, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("lba status log page");
+ free(lab_status);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_resv_notif_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+
+ const char *desc = "Retrieve Reservation Notification " \
+ "log page and prints it, for the given " \
+ "device in either decoded format(default), " \
+ "json or binary.";
+ struct nvme_resv_notif_log resv;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_resv_notif_log(fd, &resv);
+ if (!err)
+ nvme_show_resv_notif_log(&resv, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("resv notifi log");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+
+}
+
static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve desired number of bytes "\
@@ -756,7 +1238,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config {
__u32 namespace_id;
- __u32 log_id;
+ __u8 log_id;
__u32 log_len;
__u32 aen;
__u64 lpo;
@@ -768,7 +1250,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
- .log_id = 0xffffffff,
+ .log_id = 0xff,
.log_len = 0,
.lpo = NVME_NO_LOG_LPO,
.lsp = NVME_NO_LOG_LSP,
@@ -798,12 +1280,6 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
cfg.log_id = (cfg.aen >> 16) & 0xff;
}
- if (cfg.log_id > 0xff) {
- fprintf(stderr, "Invalid log identifier: %d. Valid range: 0-255\n", cfg.log_id);
- err = -EINVAL;
- goto close_fd;
- }
-
if (!cfg.log_len) {
fprintf(stderr, "non-zero log-len is required param\n");
err = -EINVAL;
@@ -812,9 +1288,8 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
log = malloc(cfg.log_len);
if (!log) {
- fprintf(stderr, "could not alloc buffer for log: %s\n",
- strerror(errno));
- err = -EINVAL;
+ perror("could not alloc buffer for log\n");
+ err = -ENOMEM;
goto close_fd;
}
@@ -844,6 +1319,7 @@ ret:
static int sanitize_log(int argc, char **argv, struct command *command, struct plugin *plugin)
{
const char *desc = "Retrieve sanitize log and show it.";
+ const char *rae = "Retain an Asynchronous Event";
const char *raw = "show log in binary format";
const char *human_readable = "show log in readable format";
struct nvme_sanitize_log_page sanitize_log;
@@ -851,16 +1327,19 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
int fd, err;
struct config {
+ bool rae;
int raw_binary;
int human_readable;
char *output_format;
};
struct config cfg = {
+ .rae = false,
.output_format = "normal",
};
OPT_ARGS(opts) = {
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
@@ -879,7 +1358,7 @@ static int sanitize_log(int argc, char **argv, struct command *command, struct p
if (cfg.human_readable)
flags |= VERBOSE;
- err = nvme_sanitize_log(fd, &sanitize_log);
+ err = nvme_sanitize_log(fd, cfg.rae, &sanitize_log);
if (!err)
nvme_show_sanitize_log(&sanitize_log, devicename, flags);
else if (err > 0)
@@ -932,8 +1411,7 @@ static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *
for (i = 0; i < (min(num, 2048)); i++)
printf("[%4u]:%#x\n", i, le16_to_cpu(cntlist->identifier[i]));
- }
- else if (err > 0)
+ } else if (err > 0)
nvme_show_status(err);
else
perror("id controller list");
@@ -950,6 +1428,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
const char *desc = "For the specified controller handle, show the "\
"namespace list in the associated NVMe subsystem, optionally starting with a given nsid.";
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;
__le32 ns_list[1024];
@@ -957,6 +1436,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
struct config {
__u32 namespace_id;
int all;
+ __u16 csi;
};
struct config cfg = {
@@ -965,6 +1445,7 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
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_END()
};
@@ -979,8 +1460,8 @@ static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *pl
goto close_fd;
}
- err = nvme_identify_ns_list(fd, cfg.namespace_id - 1, !!cfg.all,
- ns_list);
+ 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])
@@ -1028,13 +1509,9 @@ static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id == 0) {
- err = -EINVAL;
- goto close_fd;
- }
- else if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1145,15 +1622,18 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
"parameters. The next available namespace ID is used for the "\
"create operation. Note that create-ns does not attach the "\
"namespace to a controller, the attach-ns command is needed.";
- const char *nsze = "size of ns";
- const char *ncap = "capacity of ns";
- const char *flbas = "FLBA size";
- const char *dps = "data protection capabilities";
- const char *nmic = "multipath and sharing capabilities";
- const char *anagrpid = "ANA Group Identifier";
- const char *nvmsetid = "NVM Set Identifier";
+ const char *nsze = "size of ns (NSZE)";
+ const char *ncap = "capacity of ns (NCAP)";
+ const char *flbas = "Formatted LBA size (FLBAS), if entering this "\
+ "value ignore \'block-size\' field";
+ const char *dps = "data protection settings (DPS)";
+ const char *nmic = "multipath and sharing capabilities (NMIC)";
+ const char *anagrpid = "ANA Group Identifier (ANAGRPID)";
+ const char *nvmsetid = "NVM Set Identifier (NVMSETID)";
+ const char *csi = "command set identifier (CSI)";
const char *timeout = "timeout value, in milliseconds";
- const char *bs = "target block size";
+ const char *bs = "target block size, specify only if \'FLBAS\' "\
+ "value not entered";
int err = 0, fd, i;
struct nvme_id_ns ns;
@@ -1169,6 +1649,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
__u16 nvmsetid;
__u64 bs;
__u32 timeout;
+ __u8 csi;
};
struct config cfg = {
@@ -1189,6 +1670,7 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
OPT_UINT("nvmset-id", 'i', &cfg.nvmsetid, nvmsetid),
OPT_SUFFIX("block-size", 'b', &cfg.bs, bs),
OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
OPT_END()
};
@@ -1240,7 +1722,8 @@ static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *
}
err = nvme_ns_create(fd, cfg.nsze, cfg.ncap, cfg.flbas, cfg.dps, cfg.nmic,
- cfg.anagrpid, cfg.nvmsetid, cfg.timeout, &nsid);
+ cfg.anagrpid, cfg.nvmsetid, cfg.csi, cfg.timeout,
+ &nsid);
if (!err)
printf("%s: Success, created nsid:%d\n", cmd->name, nsid);
else if (err > 0)
@@ -1263,7 +1746,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;
+ int err, nsid = 0;
struct config {
char *output_format;
@@ -1288,7 +1771,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
devicename = NULL;
if (optind < argc) {
char path[512];
- int id;
+ int id, fd;
devicename = basename(argv[optind]);
if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
@@ -1297,6 +1780,22 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
err = -EINVAL;
goto ret;
}
+ sprintf(path, "/dev/%s", devicename);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
+ nsid = nvme_get_nsid(fd);
+ close(fd);
+ if (nsid < 0) {
+ fprintf(stderr, "Cannot read nsid from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
sprintf(path, "/sys/block/%s/device", devicename);
subsysnqn = get_nvme_subsnqn(path);
if (!subsysnqn) {
@@ -1318,7 +1817,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, subsysnqn, ns_instance);
+ err = scan_subsystems(&t, subsysnqn, ns_instance, nsid, NULL);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
goto free;
@@ -1326,8 +1825,7 @@ static int list_subsys(int argc, char **argv, struct command *cmd,
nvme_show_subsystem_list(&t, flags);
free:
free_topology(&t);
- if (subsysnqn)
- free(subsysnqn);
+ free(subsysnqn);
ret:
return nvme_status_to_errno(err, false);
}
@@ -1335,22 +1833,26 @@ ret:
static int list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Retrieve basic information for all NVMe namespaces";
+ const char *device_dir = "Additional directory to search for devices";
const char *verbose = "Increase output verbosity";
struct nvme_topology t = { };
enum nvme_print_flags flags;
int err = 0;
struct config {
+ char *device_dir;
char *output_format;
int verbose;
};
struct config cfg = {
+ .device_dir = NULL,
.output_format = "normal",
.verbose = 0,
};
OPT_ARGS(opts) = {
+ OPT_STRING("directory", 'd', "DIR", &cfg.device_dir, device_dir),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
OPT_END()
@@ -1370,7 +1872,7 @@ static int list(int argc, char **argv, struct command *cmd, struct plugin *plugi
if (cfg.verbose)
flags |= VERBOSE;
- err = scan_subsystems(&t, NULL, 0);
+ err = scan_subsystems(&t, NULL, 0, 0, cfg.device_dir);
if (err) {
fprintf(stderr, "Failed to scan namespaces\n");
return err;
@@ -1447,6 +1949,50 @@ static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *pl
return __id_ctrl(argc, argv, cmd, plugin, NULL);
}
+static int nvm_id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Controller NVM Command Set "\
+ "command to the given device and report information about "\
+ "the specified controller in various formats.";
+ enum nvme_print_flags flags;
+ struct nvme_id_ctrl_nvm ctrl_nvm;
+ int fd, err = -1;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_identify_ctrl_nvm(fd, &ctrl_nvm);
+ if (!err)
+ nvme_show_id_ctrl_nvm(&ctrl_nvm, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("nvm identify controller");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send Namespace Identification Descriptors command to the "\
@@ -1487,9 +2033,9 @@ static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *p
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1569,15 +2115,9 @@ static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plug
flags |= VERBOSE;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
- goto close_fd;
- }
- else if (!cfg.namespace_id) {
- fprintf(stderr,
- "Error: requesting namespace-id from non-block device\n");
- err = -ENOTBLK;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -1749,6 +2289,48 @@ close_fd:
return err;
}
+static int id_iocs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Command Set Data command to the "\
+ "given device, returns properties of the specified controller "\
+ "in either human-readable or binary format.";
+ const char *controller_id = "identifier of desired controller";
+ struct nvme_id_iocs iocs;
+ int err, fd;
+
+ struct config {
+ __u16 cntid;
+ };
+
+ struct config cfg = {
+ .cntid = 0xffff,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ err = fd;
+ goto ret;
+ }
+
+ err = nvme_identify_iocs(fd, cfg.cntid, &iocs);
+ if (!err) {
+ printf("NVMe Identify I/O Command Set:\n");
+ nvme_show_id_iocs(&iocs);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("NVMe Identify I/O Command Set");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = 0, nsid, fd;
@@ -1795,29 +2377,27 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
"9h: Secondary Online";
const char *nr = "Number of Controller Resources(NR)";
int fd, err;
- __u32 result;
+ __u32 result, cdw10;
struct config {
- int cntlid;
- int rt;
- int act;
- __u32 cdw10;
- __u32 cdw11;
+ __u16 cntlid;
+ __u8 rt;
+ __u8 act;
+ __u16 nr;
};
struct config cfg = {
.cntlid = 0,
.rt = 0,
.act = 0,
- .cdw10 = 0,
- .cdw11 = 0,
+ .nr = 0,
};
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.cdw11, nr),
+ OPT_UINT("nr", 'n', &cfg.nr, nr),
OPT_END()
};
@@ -1825,13 +2405,12 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi
if (fd < 0)
goto ret;
- cfg.cdw10 = cfg.cntlid << 16;
- cfg.cdw10 = cfg.cdw10 | (cfg.rt << 8);
- cfg.cdw10 = cfg.cdw10 | cfg.act;
+ cdw10 = cfg.act | (cfg.rt << 8) | (cfg.cntlid << 16);
- err = nvme_virtual_mgmt(fd, cfg.cdw10, cfg.cdw11, &result);
+ err = nvme_virtual_mgmt(fd, cdw10, cfg.nr, &result);
if (!err) {
- printf("success, Number of Resources allocated:%#x\n", result);
+ printf("success, Number of Controller Resources Modified "\
+ "(NRM):%#x\n", result);
} else if (err > 0) {
nvme_show_status(err);
} else
@@ -1842,6 +2421,55 @@ ret:
return nvme_status_to_errno(err, false);
}
+static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Primary Controller Capabilities "\
+ "command to the given device and report the information in a "\
+ "decoded format (default), json or binary.";
+ const char *human_readable = "show info in readable format";
+ struct nvme_primary_ctrl_caps caps;
+
+ int err, fd;
+ enum nvme_print_flags flags;
+
+ struct config {
+ char *output_format;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_identify_primary_ctrl_caps(fd, &caps);
+ if (!err)
+ nvme_show_primary_ctrl_caps(&caps, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify primary controller capabilities");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Show secondary controller list associated with the primary controller "\
@@ -1927,17 +2555,17 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
struct config {
__u32 namespace_id;
- __u32 cdw10;
+ __u8 stc;
};
struct config cfg = {
.namespace_id = NVME_NSID_ALL,
- .cdw10 = 0,
+ .stc = 0,
};
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("self-test-code", 's', &cfg.cdw10, self_test_code),
+ OPT_UINT("self-test-code", 's', &cfg.stc, self_test_code),
OPT_END()
};
@@ -1945,12 +2573,14 @@ static int device_self_test(int argc, char **argv, struct command *cmd, struct p
if (fd < 0)
goto ret;
- err = nvme_self_test_start(fd, cfg.namespace_id, cfg.cdw10);
+ err = nvme_self_test_start(fd, cfg.namespace_id, cfg.stc);
if (!err) {
- if ((cfg.cdw10 & 0xf) == 0xf)
+ if (cfg.stc == 0xf)
printf("Aborting device self-test operation\n");
- else
- printf("Device self-test started\n");
+ else if (cfg.stc == 0x2)
+ printf("Extended Device self-test started\n");
+ else if (cfg.stc == 0x1)
+ printf("Short Device self-test started\n");
} else if (err > 0) {
nvme_show_status(err);
} else
@@ -1966,27 +2596,28 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
const char *desc = "Retrieve the self-test log for the given device and given test "\
"(or optionally a namespace) in either decoded format "\
"(default) or binary.";
- const char *namespace_id = "Indicate the namespace from which the self-test "\
- "log has to be obtained";
+ const char *dst_entries = "Indicate how many DST log entries to be retrieved, "\
+ "by default all the 20 entries will be retrieved";
const char *verbose = "Increase output verbosity";
struct nvme_self_test_log self_test_log;
enum nvme_print_flags flags;
int err, fd;
+ __u32 log_size;
struct config {
- __u32 namespace_id;
+ __u8 dst_entries;
char *output_format;
int verbose;
};
struct config cfg = {
- .namespace_id = NVME_NSID_ALL,
+ .dst_entries = NVME_ST_REPORTS,
.output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("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()
@@ -2002,9 +2633,11 @@ static int self_test_log(int argc, char **argv, struct command *cmd, struct plug
if (cfg.verbose)
flags |= VERBOSE;
- err = nvme_self_test_log(fd, cfg.namespace_id, &self_test_log);
+ log_size = NVME_ST_LOG_HEAD_SIZE + cfg.dst_entries * NVME_ST_LOG_ENTRY_SIZE;
+ err = nvme_self_test_log(fd, log_size, &self_test_log);
if (!err)
- nvme_show_self_test_log(&self_test_log, devicename, flags);
+ nvme_show_self_test_log(&self_test_log, cfg.dst_entries, log_size,
+ devicename, flags);
else if (err > 0)
nvme_show_status(err);
else
@@ -2039,7 +2672,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
struct config {
__u32 namespace_id;
- __u32 feature_id;
+ __u8 feature_id;
__u8 sel;
__u32 cdw11;
__u32 data_len;
@@ -2048,7 +2681,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
};
struct config cfg = {
- .namespace_id = 1,
+ .namespace_id = 0,
.feature_id = 0,
.sel = 0,
.cdw11 = 0,
@@ -2070,6 +2703,18 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
goto ret;
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
if (cfg.sel > 7) {
fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
err = -EINVAL;
@@ -2081,32 +2726,11 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
goto close_fd;
}
- switch (cfg.feature_id) {
- case NVME_FEAT_LBA_RANGE:
- cfg.data_len = 4096;
- break;
- case NVME_FEAT_AUTO_PST:
- cfg.data_len = 256;
- break;
- case NVME_FEAT_HOST_MEM_BUF:
- cfg.data_len = 4096;
- break;
- case NVME_FEAT_HOST_ID:
- cfg.data_len = 8;
- /* check for Extended Host Identifier */
- if (cfg.cdw11 & 0x1)
- cfg.data_len = 16;
- break;
- case NVME_FEAT_PLM_CONFIG:
- cfg.data_len = 512;
- break;
- case NVME_FEAT_TIMESTAMP:
- cfg.data_len = 8;
- break;
- case NVME_FEAT_HOST_BEHAVIOR:
- cfg.data_len = 512;
- break;
- }
+ 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))
+ cfg.data_len = 16;
if (cfg.sel == 3)
cfg.data_len = 0;
@@ -2140,8 +2764,7 @@ static int get_feature(int argc, char **argv, struct command *cmd, struct plugin
} else
perror("get-feature");
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
@@ -2207,22 +2830,27 @@ static int fw_download(int argc, char **argv, struct command *cmd, struct plugin
}
fw_size = sb.st_size;
- if (fw_size & 0x3) {
+ if ((fw_size & 0x3) || (fw_size == 0)) {
fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
err = -EINVAL;
goto close_fw_fd;
}
- fw_buf = nvme_alloc(fw_size, &huge);
+ if (cfg.xfer == 0 || cfg.xfer % 4096)
+ cfg.xfer = 4096;
+
+ if (cfg.xfer < HUGE_MIN)
+ fw_buf = __nvme_alloc(fw_size, &huge);
+ else
+ fw_buf = nvme_alloc(fw_size, &huge);
+
if (!fw_buf) {
- fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ perror("No memory for f/w size:\n");
err = -ENOMEM;
goto close_fw_fd;
}
buf = fw_buf;
- if (cfg.xfer == 0 || cfg.xfer % 4096)
- cfg.xfer = 4096;
if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
err = -errno;
fprintf(stderr, "read :%s :%s\n", cfg.fw, strerror(errno));
@@ -2257,9 +2885,9 @@ ret:
return nvme_status_to_errno(err, false);
}
-static char *nvme_fw_status_reset_type(__u32 status)
+static char *nvme_fw_status_reset_type(__u16 status)
{
- switch (status & 0x3ff) {
+ switch (status & 0x7ff) {
case NVME_SC_FW_NEEDS_CONV_RESET: return "conventional";
case NVME_SC_FW_NEEDS_SUBSYS_RESET: return "subsystem";
case NVME_SC_FW_NEEDS_RESET: return "any controller";
@@ -2322,7 +2950,7 @@ static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *
if (err < 0)
perror("fw-commit");
else if (err != 0)
- switch (err & 0x3ff) {
+ switch (err & 0x7ff) {
case NVME_SC_FW_NEEDS_CONV_RESET:
case NVME_SC_FW_NEEDS_SUBSYS_RESET:
case NVME_SC_FW_NEEDS_RESET:
@@ -2486,8 +3114,8 @@ 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-16]\n");
+ if (cfg.owpass >= 16) {
+ fprintf(stderr, "OWPASS out of range [0-15]\n");
ret = -EINVAL;
goto close_fd;
}
@@ -2697,8 +3325,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
struct nvme_id_ns ns;
struct nvme_id_ctrl ctrl;
int err, fd, i;
+ int block_size;
__u8 prev_lbaf = 0;
- __u8 lbads = 0;
struct config {
__u32 namespace_id;
@@ -2771,13 +3399,11 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
* format of all namespaces.
*/
cfg.namespace_id = NVME_NSID_ALL;
- } else {
- if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
- goto close_fd;
- }
+ } else if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
}
}
@@ -2813,8 +3439,8 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
}
if (cfg.lbaf == 0xff) {
fprintf(stderr,
- "LBAF corresponding to block size %"PRIu64"(LBAF %u) not found\n",
- (uint64_t)cfg.bs, lbads);
+ "LBAF corresponding to given block size %"PRIu64" not found\n",
+ (uint64_t)cfg.bs);
fprintf(stderr,
"Please correct block size, or specify LBAF directly\n");
err = -EINVAL;
@@ -2822,8 +3448,7 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
}
} else if (cfg.lbaf == 0xff)
cfg.lbaf = prev_lbaf;
- }
- else {
+ } else {
if (cfg.lbaf == 0xff) cfg.lbaf = 0;
}
@@ -2874,13 +3499,38 @@ static int format(int argc, char **argv, struct command *cmd, struct plugin *plu
nvme_show_status(err);
else {
printf("Success formatting namespace:%x\n", cfg.namespace_id);
- if (cfg.lbaf != prev_lbaf && ioctl(fd, BLKRRPART) < 0) {
- fprintf(stderr, "failed to re-read partition table\n");
- err = -errno;
- goto close_fd;
- }
+ if (cfg.lbaf != prev_lbaf){
+ if (is_chardev()) {
+ if(ioctl(fd, NVME_IOCTL_RESCAN) < 0){
+ fprintf(stderr, "failed to rescan namespaces\n");
+ err = -errno;
+ goto close_fd;
+ }
+ } else {
+ block_size = 1 << ns.lbaf[cfg.lbaf].ds;
+
+ /*
+ * If block size has been changed by the format
+ * command up there, we should notify it to
+ * kernel blkdev to update its own block size
+ * to the given one because blkdev will not
+ * update by itself without re-opening fd.
+ */
+ if (ioctl(fd, BLKBSZSET, &block_size) < 0) {
+ fprintf(stderr, "failed to set block size to %d\n",
+ block_size);
+ err = -errno;
+ goto close_fd;
+ }
- if (cfg.reset && S_ISCHR(nvme_stat.st_mode))
+ if(ioctl(fd, BLKRRPART) < 0) {
+ fprintf(stderr, "failed to re-read partition table\n");
+ err = -errno;
+ goto close_fd;
+ }
+ }
+ }
+ if (cfg.reset && is_chardev())
nvme_reset_controller(fd);
}
@@ -2890,6 +3540,9 @@ ret:
return nvme_status_to_errno(err, false);
}
+#define STRTOUL_AUTO_BASE (0)
+#define NVME_FEAT_TIMESTAMP_DATA_SIZE (6)
+
static int set_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Modify the saveable or changeable "\
@@ -2912,12 +3565,14 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
__u32 result;
void *buf = NULL;
int fd, ffd = STDIN_FILENO;
+ char *endptr = NULL;
+ uint64_t number = 0;
struct config {
char *file;
__u32 namespace_id;
- __u32 feature_id;
- __u32 value;
+ __u8 feature_id;
+ __u64 value;
__u32 cdw12;
__u32 data_len;
int save;
@@ -2935,7 +3590,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
OPT_ARGS(opts) = {
OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_LONG("value", 'v', &cfg.value, value),
OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12),
OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
OPT_FILE("data", 'd', &cfg.file, data),
@@ -2947,13 +3602,26 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
goto ret;
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
if (!cfg.feature_id) {
fprintf(stderr, "feature-id required param\n");
err = -EINVAL;
goto close_fd;
}
- if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
- cfg.data_len = 4096;
+
+ 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");
@@ -2964,22 +3632,33 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
}
if (buf) {
- 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, 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);
+ }
+ }
}
err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
@@ -2987,8 +3666,12 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
if (err < 0) {
perror("set-feature");
} else if (!err) {
- printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
- nvme_feature_to_string(cfg.feature_id), cfg.value);
+ 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);
+ if (cfg.feature_id == NVME_LBA_STATUS_INFO) {
+ nvme_show_lba_status_info(result);
+ }
if (buf) {
if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
nvme_show_lba_range((struct nvme_lba_range_type *)buf,
@@ -3002,8 +3685,7 @@ static int set_feature(int argc, char **argv, struct command *cmd, struct plugin
close_ffd:
close(ffd);
free:
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
@@ -3027,7 +3709,6 @@ static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *p
int err, fd, sec_fd = -1;
void *sec_buf;
unsigned int sec_size;
- __u32 result;
struct config {
__u32 namespace_id;
@@ -3089,13 +3770,13 @@ 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, &result);
+ cfg.tl, sec_size, sec_buf);
if (err < 0)
perror("security-send");
else if (err != 0)
- fprintf(stderr, "NVME Security Send Command Error:%d\n", err);
+ nvme_show_status(err);
else
- printf("NVME Security Send Command Success:%d\n", result);
+ printf("NVME Security Send Command Success\n");
free:
free(sec_buf);
@@ -3244,15 +3925,13 @@ static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *p
else
d_raw(buf, cfg.data_len);
}
- }
- else if (err > 0)
+ } else if (err > 0)
nvme_show_status(err);
close_ffd:
close(ffd);
free:
- if (buf)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
@@ -3292,9 +3971,9 @@ static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3384,9 +4063,9 @@ static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugi
if (cfg.deac)
control |= NVME_RW_DEAC;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3477,16 +4156,16 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
}
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
if (!cfg.cdw11)
cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0);
- dsm = nvme_setup_dsm_range((__u32 *)ctx_attrs, (__u32 *)nlbs, (__u64 *)slbas, nr);
+ dsm = nvme_setup_dsm_range(ctx_attrs, nlbs, slbas, nr);
if (!dsm) {
fprintf(stderr, "failed to allocate data set payload\n");
err = -ENOMEM;
@@ -3501,6 +4180,144 @@ static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin
else
printf("NVMe DSM: success\n");
+ free(dsm);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int copy(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Copy command is used by the host to copy data "
+ "from one or more source logical block ranges to a "
+ "single consecutive destination logical block "
+ "range.";
+
+ const char *d_nsid = "identifier of desired namespace";
+ const char *d_sdlba = "64-bit addr of first destination logical block";
+ const char *d_slbas = "64-bit addr of first block per range (comma-separated list)";
+ const char *d_nlbs = "number of blocks per range (comma-separated list, zeroes-based values)";
+ const char *d_lr = "limited retry";
+ const char *d_fua = "force unit access";
+ const char *d_prinfor = "protection information and check field (read part)";
+ const char *d_prinfow = "protection information and check field (write part)";
+ const char *d_ilbrt = "initial lba reference tag (write part)";
+ const char *d_eilbrts = "expected lba reference tags (read part, comma-separated list)";
+ const char *d_lbat = "lba application tag (write part)";
+ const char *d_elbats = "expected lba application tags (read part, comma-separated list)";
+ const char *d_lbatm = "lba application tag mask (write part)";
+ const char *d_elbatms = "expected lba application tag masks (read part, comma-separated list)";
+ const char *d_dtype = "directive type (write part)";
+ const char *d_dspec = "directive specific (write part)";
+ const char *d_format = "source range entry format";
+
+ int err, fd;
+ uint16_t nr, nb, ns, nrts, natms, nats;
+ int nlbs[128] = { 0 };
+ unsigned long long slbas[128] = {0,};
+ int eilbrts[128] = { 0 };
+ int elbatms[128] = { 0 };
+ int elbats[128] = { 0 };
+ struct nvme_copy_range *copy;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 sdlba;
+ char *nlbs;
+ char *slbas;
+ __u32 ilbrt;
+ char *eilbrts;
+ __u16 lbatm;
+ char *elbatms;
+ __u16 lbat;
+ char *elbats;
+ __u8 prinfow;
+ __u8 prinfor;
+ int lr;
+ int fua;
+ __u8 dtype;
+ __u16 dspec;
+ __u8 format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .nlbs = "",
+ .slbas = "",
+ .eilbrts = "",
+ .elbatms = "",
+ .elbats = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, d_nsid),
+ OPT_SUFFIX("sdlba", 'd', &cfg.sdlba, d_sdlba),
+ OPT_LIST("slbs", 's', &cfg.slbas, d_slbas),
+ OPT_LIST("blocks", 'b', &cfg.nlbs, d_nlbs),
+ OPT_FLAG("limited-retry", 'l', &cfg.lr, d_lr),
+ OPT_FLAG("force-unit-access", 'f', &cfg.fua, d_fua),
+ OPT_BYTE("prinfow", 'p', &cfg.prinfow, d_prinfow),
+ OPT_BYTE("prinfor", 'P', &cfg.prinfor, d_prinfor),
+ OPT_UINT("ref-tag", 'r', &cfg.ilbrt, d_ilbrt),
+ OPT_LIST("expected-ref-tags", 'R', &cfg.eilbrts, d_eilbrts),
+ OPT_SHRT("app-tag", 'a', &cfg.lbat, d_lbat),
+ OPT_LIST("expected-app-tags", 'A', &cfg.elbats, d_elbats),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, d_lbatm),
+ OPT_LIST("expected-app-tag-masks", 'M', &cfg.elbatms, d_elbatms),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, d_dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, d_dspec),
+ OPT_BYTE("format", 'F', &cfg.format, d_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ err = fd;
+ goto ret;
+ }
+
+ nb = argconfig_parse_comma_sep_array(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs));
+ ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas));
+ nrts = argconfig_parse_comma_sep_array(cfg.eilbrts, eilbrts, ARRAY_SIZE(eilbrts));
+ natms = argconfig_parse_comma_sep_array(cfg.elbatms, elbatms, ARRAY_SIZE(elbatms));
+ nats = argconfig_parse_comma_sep_array(cfg.elbats, elbats, ARRAY_SIZE(elbats));
+
+ nr = max(nb, max(ns, max(nrts, max(natms, nats))));
+ if (!nr || nr > 128) {
+ fprintf(stderr, "invalid range\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ copy = nvme_setup_copy_range(nlbs, slbas, eilbrts, elbatms, elbats, nr);
+ if (!copy) {
+ fprintf(stderr, "failed to allocate payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_copy(fd, cfg.namespace_id, copy, cfg.sdlba, nr, cfg.prinfor,
+ cfg.prinfow, cfg.dtype, cfg.dspec, cfg.format, cfg.lr,
+ cfg.fua, cfg.ilbrt, cfg.lbatm, cfg.lbat);
+ if (err < 0)
+ perror("NVMe Copy");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe Copy: success\n");
+
+ free(copy);
+
close_fd:
close(fd);
ret:
@@ -3535,9 +4352,9 @@ static int flush(int argc, char **argv, struct command *cmd, struct plugin *plug
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3603,9 +4420,9 @@ static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugi
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3675,9 +4492,9 @@ static int resv_register(int argc, char **argv, struct command *cmd, struct plug
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3755,9 +4572,9 @@ static int resv_release(int argc, char **argv, struct command *cmd, struct plugi
goto ret;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3833,9 +4650,9 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
flags = BINARY;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -3858,7 +4675,7 @@ static int resv_report(int argc, char **argv, struct command *cmd, struct plugin
if (!err)
nvme_show_resv_report(status, size, cfg.cdw11, flags);
else if (err > 0)
- fprintf(stderr, "NVME IO command error:%04x\n", err);
+ nvme_show_status(err);
else
perror("reservation report");
free(status);
@@ -3868,7 +4685,7 @@ ret:
return nvme_status_to_errno(err, false);
}
-static unsigned long long elapsed_utime(struct timeval start_time,
+unsigned long long elapsed_utime(struct timeval start_time,
struct timeval end_time)
{
unsigned long long err = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
@@ -3886,10 +4703,12 @@ static int submit_io(int opcode, char *command, const char *desc,
int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
__u16 control = 0;
- __u32 dsmgmt = 0;
- int phys_sector_size = 0;
- long long buffer_size = 0;
+ __u32 dsmgmt = 0, nsid = 0;
+ int logical_block_size = 0;
+ long long buffer_size = 0, mbuffer_size = 0;
bool huge;
+ struct nvme_id_ns ns;
+ __u8 lba_index, ms = 0;
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";
@@ -4017,10 +4836,10 @@ static int submit_io(int opcode, char *command, const char *desc,
goto close_mfd;
}
- if (ioctl(fd, BLKPBSZGET, &phys_sector_size) < 0)
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0)
goto close_mfd;
- buffer_size = (cfg.block_count + 1) * phys_sector_size;
+ buffer_size = (cfg.block_count + 1) * logical_block_size;
if (cfg.data_size < buffer_size) {
fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n",
buffer_size);
@@ -4030,20 +4849,41 @@ static int submit_io(int opcode, char *command, const char *desc,
buffer = nvme_alloc(buffer_size, &huge);
if (!buffer) {
- fprintf(stderr, "can not allocate io payload\n");
+ perror("can not allocate io payload\n");
err = -ENOMEM;
goto close_mfd;
}
if (cfg.metadata_size) {
- mbuffer = malloc(cfg.metadata_size);
+ err = nsid = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_mfd;
+ }
+ err = nvme_identify_ns(fd, nsid, false, &ns);
+ if (err) {
+ nvme_show_status(err);
+ goto free_buffer;
+ } else if (err < 0) {
+ perror("identify namespace");
+ goto free_buffer;
+ }
+ lba_index = ns.flbas & NVME_NS_FLBAS_LBA_MASK;
+ ms = ns.lbaf[lba_index].ms;
+ mbuffer_size = (cfg.block_count + 1) * ms;
+ if (ms && cfg.metadata_size < mbuffer_size) {
+ fprintf(stderr, "Rounding metadata size to fit block count (%lld bytes)\n",
+ mbuffer_size);
+ } else {
+ mbuffer_size = cfg.metadata_size;
+ }
+ mbuffer = malloc(mbuffer_size);
if (!mbuffer) {
- fprintf(stderr, "can not allocate io metadata "
- "payload: %s\n", strerror(errno));
+ perror("can not allocate buf for io metadata payload\n");
err = -ENOMEM;
goto free_buffer;
}
- memset(mbuffer, 0, cfg.metadata_size);
+ memset(mbuffer, 0, mbuffer_size);
}
if ((opcode & 1)) {
@@ -4057,7 +4897,7 @@ static int submit_io(int opcode, char *command, const char *desc,
}
if ((opcode & 1) && cfg.metadata_size) {
- err = read(mfd, (void *)mbuffer, cfg.metadata_size);
+ err = read(mfd, (void *)mbuffer, mbuffer_size);
if (err < 0) {
err = -errno;
fprintf(stderr, "failed to read meta-data buffer from"
@@ -4071,7 +4911,6 @@ static int submit_io(int opcode, char *command, const char *desc,
printf("flags : %02x\n", 0);
printf("control : %04x\n", control);
printf("nblocks : %04x\n", cfg.block_count);
- printf("rsvd : %04x\n", 0);
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);
@@ -4100,7 +4939,7 @@ static int submit_io(int opcode, char *command, const char *desc,
strerror(errno));
err = -EINVAL;
} else if (!(opcode & 1) && cfg.metadata_size &&
- write(mfd, (void *)mbuffer, cfg.metadata_size) < 0) {
+ 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;
@@ -4109,8 +4948,7 @@ static int submit_io(int opcode, char *command, const char *desc,
}
free_mbuffer:
- if (cfg.metadata_size)
- free(mbuffer);
+ free(mbuffer);
free_buffer:
nvme_free(buffer, huge);
close_mfd:
@@ -4215,9 +5053,9 @@ static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin
control |= NVME_RW_FUA;
if (!cfg.namespace_id) {
- cfg.namespace_id = nvme_get_nsid(fd);
- if (cfg.namespace_id < 0) {
- err = cfg.namespace_id;
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
goto close_fd;
}
}
@@ -4254,7 +5092,6 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
const char *nssf = "NVMe Security Specific Field";
int err, fd;
void *sec_buf = NULL;
- __u32 result;
struct config {
__u32 namespace_id;
@@ -4298,16 +5135,14 @@ static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *p
}
err = nvme_sec_recv(fd, cfg.namespace_id, cfg.nssf, cfg.spsp,
- cfg.secp, cfg.al, cfg.size, sec_buf, &result);
+ cfg.secp, cfg.al, cfg.size, sec_buf);
if (err < 0)
perror("security receive");
else if (err != 0)
- fprintf(stderr, "NVME Security Receive Command Error:%d\n",
- err);
+ nvme_show_status(err);
else {
+ printf("NVME Security Receive Command Success\n");
if (!cfg.raw_binary) {
- printf("NVME Security Receive Command Success:%d\n",
- result);
d(sec_buf, cfg.size, 16, 1);
} else if (cfg.size)
d_raw((unsigned char *)sec_buf, cfg.size);
@@ -4325,6 +5160,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
struct plugin *plugin)
{
const char *desc = "Information about potentially unrecoverable LBAs.";
+ const char *namespace_id = "Desired Namespace";
const char *slba = "Starting LBA(SLBA) in 64-bit address of the first"\
" logical block addressed by this command";
const char *mndw = "Maximum Number of Dwords(MNDW) specifies maximum"\
@@ -4334,6 +5170,7 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
" Status Descriptors to return.";
const char *rl = "Range Length(RL) specifies the length of the range"\
" of contiguous LBAs beginning at SLBA";
+ const char *timeout = "timeout value, in milliseconds";
enum nvme_print_flags flags;
unsigned long buf_len;
@@ -4341,26 +5178,32 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
void *buf;
struct config {
+ __u32 namespace_id;
__u64 slba;
__u32 mndw;
__u8 atype;
__u16 rl;
+ __u32 timeout;
char *output_format;
};
struct config cfg = {
+ .namespace_id = 0,
.slba = 0,
.mndw = 0,
.atype = 0,
.rl = 0,
+ .timeout = 0,
.output_format = "normal",
};
OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
OPT_SUFFIX("start-lba", 's', &cfg.slba, slba),
OPT_UINT("max-dw", 'm', &cfg.mndw, mndw),
OPT_BYTE("action", 'a', &cfg.atype, atype),
OPT_SHRT("range-len", 'l', &cfg.rl, rl),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
OPT_END()
};
@@ -4382,16 +5225,17 @@ static int get_lba_status(int argc, char **argv, struct command *cmd,
buf_len = (cfg.mndw + 1) * 4;
buf = calloc(1, buf_len);
if (!buf) {
+ perror("could not alloc memory for get lba status");
err = -ENOMEM;
goto close_fd;
}
- err = nvme_get_lba_status(fd, cfg.slba, cfg.mndw, cfg.atype, cfg.rl,
- buf);
+ err = nvme_get_lba_status(fd, cfg.namespace_id, cfg.slba, cfg.mndw,
+ cfg.atype, cfg.rl, buf, cfg.timeout);
if (!err)
nvme_show_lba_status(buf, buf_len, flags);
else if (err > 0)
- fprintf(stderr, "NVME command error:%04x\n", err);
+ nvme_show_status(err);
else
perror("get lba status");
free(buf);
@@ -4518,20 +5362,50 @@ static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin
else if (err < 0)
perror("dir-receive");
- if (cfg.data_len)
- free(buf);
+ free(buf);
close_fd:
close(fd);
ret:
return nvme_status_to_errno(err, false);
}
-static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, struct command *cmd)
+/* rpmb_cmd_option is defined in nvme-rpmb.c */
+extern int rpmb_cmd_option(int, char **, struct command *, struct plugin *);
+static int rpmb_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
+ return rpmb_cmd_option(argc, argv, cmd, plugin);
+}
+
+static int passthru(int argc, char **argv, int ioctl_cmd, uint8_t cmd_type,
+ const char *desc, struct command *cmd)
+{
+ const char *opcode = "opcode (required)";
+ const char *flags = "command flags";
+ const char *rsvd = "value for reserved field";
+ const char *namespace_id = "desired namespace";
+ const char *data_len = "data I/O length (bytes)";
+ const char *metadata_len = "metadata seg. length (bytes)";
+ const char *timeout = "timeout value, in milliseconds";
+ const char *cdw2 = "command dword 2 value";
+ const char *cdw3 = "command dword 3 value";
+ const char *cdw10 = "command dword 10 value";
+ const char *cdw11 = "command dword 11 value";
+ const char *cdw12 = "command dword 12 value";
+ const char *cdw13 = "command dword 13 value";
+ const char *cdw14 = "command dword 14 value";
+ const char *cdw15 = "command dword 15 value";
+ const char *input = "write/send file (default stdin)";
+ const char *raw_binary = "dump output in binary format";
+ const char *show = "print command before sending";
+ const char *dry = "show command instead of sending";
+ 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";
void *data = NULL, *metadata = NULL;
int err = 0, wfd = STDIN_FILENO, fd;
__u32 result;
bool huge;
+ const char *cmd_name = NULL;
struct config {
__u8 opcode;
@@ -4578,29 +5452,6 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
.prefill = 0,
};
- const char *opcode = "opcode (required)";
- const char *flags = "command flags";
- const char *rsvd = "value for reserved field";
- const char *namespace_id = "desired namespace";
- const char *data_len = "data I/O length (bytes)";
- const char *metadata_len = "metadata seg. length (bytes)";
- const char *timeout = "timeout value, in milliseconds";
- const char *cdw2 = "command dword 2 value";
- const char *cdw3 = "command dword 3 value";
- const char *cdw10 = "command dword 10 value";
- const char *cdw11 = "command dword 11 value";
- const char *cdw12 = "command dword 12 value";
- const char *cdw13 = "command dword 13 value";
- const char *cdw14 = "command dword 14 value";
- const char *cdw15 = "command dword 15 value";
- const char *input = "write/send file (default stdin)";
- const char *raw_binary = "dump output in binary format";
- const char *show = "print command before sending";
- const char *dry = "show command instead of sending";
- 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";
-
OPT_ARGS(opts) = {
OPT_BYTE("opcode", 'o', &cfg.opcode, opcode),
OPT_BYTE("flags", 'f', &cfg.flags, flags),
@@ -4631,7 +5482,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (fd < 0)
goto ret;
- if (strlen(cfg.input_file)){
+ if (strlen(cfg.input_file)) {
wfd = open(cfg.input_file, O_RDONLY,
S_IRUSR | S_IRGRP | S_IROTH);
if (wfd < 0) {
@@ -4644,8 +5495,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (cfg.metadata_len) {
metadata = malloc(cfg.metadata_len);
if (!metadata) {
- fprintf(stderr, "can not allocate metadata "
- "payload: %s\n", strerror(errno));
+ perror("can not allocate metadata payload\n");
err = -ENOMEM;
goto close_wfd;
}
@@ -4654,7 +5504,7 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
if (cfg.data_len) {
data = nvme_alloc(cfg.data_len, &huge);
if (!data) {
- fprintf(stderr, "can not allocate data payload\n");
+ perror("can not allocate data payload\n");
err = -ENOMEM;
goto free_metadata;
}
@@ -4714,19 +5564,21 @@ static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, stru
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",
+ result);
if (!cfg.raw_binary) {
- fprintf(stderr, "NVMe command result:%08x\n", result);
if (data && cfg.read && !err)
d((unsigned char *)data, cfg.data_len, 16, 1);
} else if (data && cfg.read)
d_raw((unsigned char *)data, cfg.data_len);
}
free_data:
- if (cfg.data_len)
- nvme_free(data, huge);
+ nvme_free(data, huge);
free_metadata:
- if (cfg.metadata_len)
- free(metadata);
+ free(metadata);
close_wfd:
if (strlen(cfg.input_file))
close(wfd);
@@ -4740,35 +5592,42 @@ static int io_passthru(int argc, char **argv, struct command *cmd, struct plugin
{
const char *desc = "Send a user-defined IO command to the specified "\
"device via IOCTL passthrough, return results.";
- return passthru(argc, argv, NVME_IOCTL_IO_CMD, desc, cmd);
+ return passthru(argc, argv, NVME_IOCTL_IO_CMD, 0, desc, cmd);
}
static int admin_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc = "Send a user-defined Admin command to the specified "\
"device via IOCTL passthrough, return results.";
- return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD, desc, cmd);
+ return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD, 1, desc, cmd);
}
-#ifdef LIBUUID
static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
{
- uuid_t uuid;
+ int ret;
char uuid_str[37]; /* e.g. 1b4e28ba-2fa1-11d2-883f-0016d3cca427 + \0 */
+#ifdef LIBUUID
+ uuid_t uuid;
+#endif
- uuid_generate_random(uuid);
- uuid_unparse_lower(uuid, uuid_str);
+ ret = uuid_from_dmi(uuid_str);
+ if (ret < 0)
+ ret = uuid_from_systemd(uuid_str);
+#ifdef LIBUUID
+ if (ret < 0) {
+ uuid_generate_random(uuid);
+ uuid_unparse_lower(uuid, uuid_str);
+ ret = 0;
+ }
+#endif
+ if (ret < 0) {
+ fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n",
+ command->name);
+ return -ENOTSUP;
+ }
printf("nqn.2014-08.org.nvmexpress:uuid:%s\n", uuid_str);
return 0;
}
-#else
-static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
-{
- fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n",
- command->name);
- return -ENOTSUP;
-}
-#endif
static int show_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
{
diff --git a/nvme.h b/nvme.h
index 017148a..e33094d 100644
--- a/nvme.h
+++ b/nvme.h
@@ -19,9 +19,35 @@
#include <stdbool.h>
#include <stdint.h>
#include <endian.h>
+#include <sys/time.h>
#include "plugin.h"
+#ifdef LIBJSONC
+#include <json-c/json.h>
+
+#define json_create_object(o) json_object_new_object(o)
+#define json_create_array(a) json_object_new_array(a)
+#define json_free_object(o) json_object_put(o)
+#define json_free_array(a) json_object_put(a)
+#define json_object_add_value_uint(o, k, v) \
+ json_object_object_add(o, k, json_object_new_int(v))
+#define json_object_add_value_int(o, k, v) \
+ json_object_object_add(o, k, json_object_new_int(v))
+#define json_object_add_value_float(o, k, v) \
+ json_object_object_add(o, k, json_object_new_double(v))
+#define json_object_add_value_string(o, k, v) \
+ json_object_object_add(o, k, json_object_new_string(v))
+#define json_object_add_value_array(o, k, v) \
+ json_object_object_add(o, k, v)
+#define json_object_add_value_object(o, k, v) \
+ json_object_object_add(o, k, v)
+#define json_array_add_value_object(o, k) \
+ json_object_array_add(o, k)
+#define json_print_object(o, u) \
+ printf("%s", json_object_to_json_string_ext(o, JSON_C_TO_STRING_PRETTY))
+#else
#include "util/json.h"
+#endif
#include "util/argconfig.h"
#include "linux/nvme.h"
@@ -46,6 +72,7 @@ struct nvme_namespace {
struct nvme_ctrl {
char *name;
+ char *path;
struct nvme_subsystem *subsys;
char *address;
@@ -87,14 +114,16 @@ int parse_and_open(int argc, char **argv, const char *desc,
const struct argconfig_commandline_options *clo);
extern const char *devicename;
+extern const char *output_format;
-enum nvme_print_flags validate_output_format(char *format);
+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);
void *mmap_registers(const char *dev);
extern int current_index;
+int scan_ctrl_namespace_filter(const struct dirent *d);
int scan_namespace_filter(const struct dirent *d);
int scan_ctrl_paths_filter(const struct dirent *d);
int scan_ctrls_filter(const struct dirent *d);
@@ -102,9 +131,17 @@ int scan_subsys_filter(const struct dirent *d);
int scan_dev_filter(const struct dirent *d);
int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
- __u32 ns_instance);
+ __u32 ns_instance, int nsid, char *dev_dir);
void free_topology(struct nvme_topology *t);
char *get_nvme_subsnqn(char *path);
-char *nvme_get_ctrl_attr(char *path, const char *attr);
+char *nvme_get_ctrl_attr(const char *path, const char *attr);
+void *nvme_alloc(size_t len, bool *huge);
+void nvme_free(void *p, bool huge);
+
+int uuid_from_dmi(char *uuid);
+int uuid_from_systemd(char *uuid);
+
+unsigned long long elapsed_utime(struct timeval start_time,
+ struct timeval end_time);
#endif /* _NVME_H */
diff --git a/nvme.spec.in b/nvme.spec.in
index 74e681e..7154a87 100644
--- a/nvme.spec.in
+++ b/nvme.spec.in
@@ -7,7 +7,7 @@ Group: Development/Tools
URL: https://github.com/linux-nvme/nvme-cli/
Source: nvme-@@VERSION@@.tar.gz
Provides: nvme
-Requires(post): util-linux
+Requires(post): util-linux systemd systemd-udev
BuildRoot: %{_tmppath}/%{name}-%{version}-root
%description
@@ -49,7 +49,7 @@ rm -rf $RPM_BUILD_ROOT
%post
if [ $1 -eq 1 ]; then # 1 : This package is being installed for the first time
if [ ! -s %{_sysconfdir}/nvme/hostnqn ]; then
- echo $(nvme gen-hostnqn) > %{_sysconfdir}/nvme/hostnqn
+ echo $(%{_sbindir}/nvme gen-hostnqn) > %{_sysconfdir}/nvme/hostnqn
fi
if [ ! -s %{_sysconfdir}/nvme/hostid ]; then
uuidgen > %{_sysconfdir}/nvme/hostid
diff --git a/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in b/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
index 41ea83c..b32f2c3 100644
--- a/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
+++ b/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
@@ -1 +1 @@
-install_items+="@@UDEVRULESDIR@@/70-nvmf-autoconnect.rules"
+install_items+=" @@UDEVRULESDIR@@/70-nvmf-autoconnect.rules "
diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c
new file mode 100644
index 0000000..47a2d82
--- /dev/null
+++ b/plugins/amzn/amzn-nvme.c
@@ -0,0 +1,59 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "amzn-nvme.h"
+
+struct nvme_vu_id_ctrl_field {
+ __u8 bdev[32];
+ __u8 reserved0[992];
+};
+
+static void json_amzn_id_ctrl(struct nvme_vu_id_ctrl_field *id,
+ char *bdev,
+ struct json_object *root)
+{
+ json_object_add_value_string(root, "bdev", bdev);
+}
+
+static void amzn_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ struct nvme_vu_id_ctrl_field* id = (struct nvme_vu_id_ctrl_field *)vs;
+
+ char bdev[32] = { 0 };
+
+ int len = 0;
+ while (len < 31) {
+ if (id->bdev[++len] == ' ') {
+ break;
+ }
+ }
+ snprintf(bdev, len+1, "%s", id->bdev);
+
+ if (root) {
+ json_amzn_id_ctrl(id, bdev, root);
+ return;
+ }
+
+ printf("bdev : %s\n", bdev);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, amzn_id_ctrl);
+}
diff --git a/plugins/amzn/amzn-nvme.h b/plugins/amzn/amzn-nvme.h
new file mode 100644
index 0000000..9b8d797
--- /dev/null
+++ b/plugins/amzn/amzn-nvme.h
@@ -0,0 +1,17 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/amzn/amzn-nvme
+
+#if !defined(AMZN_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define AMZN_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("amzn", "Amazon vendor specific extensions"),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c
index dbb40cc..be78930 100644
--- a/plugins/dera/dera-nvme.c
+++ b/plugins/dera/dera-nvme.c
@@ -131,7 +131,8 @@ static int get_status(int argc, char **argv, struct command *cmd, struct plugin
if (fd < 0)
return fd;
- err = nvme_get_log(fd, 0xffffffff, 0xc0, false, sizeof(log), &log);
+ err = nvme_get_log(fd, 0xffffffff, 0xc0, false, NVME_NO_LOG_LSP,
+ sizeof(log), &log);
if (err) {
goto exit;
}
diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c
index 482ea0d..b39d861 100644
--- a/plugins/huawei/huawei-nvme.c
+++ b/plugins/huawei/huawei-nvme.c
@@ -32,7 +32,6 @@
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
-#include "json.h"
#include "argconfig.h"
#include "suffix.h"
@@ -143,7 +142,7 @@ static void huawei_json_print_list_items(struct huawei_list_item *list_items,
unsigned len)
{
struct json_object *root;
- struct json_array *devices;
+ struct json_object *devices;
struct json_object *device_attrs;
char formatter[128] = { 0 };
int index, i = 0;
diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c
index 8217c46..27b065d 100644
--- a/plugins/intel/intel-nvme.c
+++ b/plugins/intel/intel-nvme.c
@@ -11,7 +11,6 @@
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
-#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@@ -54,6 +53,13 @@ struct nvme_additional_smart_log {
struct nvme_additional_smart_log_item pll_lock_loss_cnt;
struct nvme_additional_smart_log_item nand_bytes_written;
struct nvme_additional_smart_log_item host_bytes_written;
+ struct nvme_additional_smart_log_item host_ctx_wear_used;
+ struct nvme_additional_smart_log_item perf_stat_indicator;
+ struct nvme_additional_smart_log_item re_alloc_sectr_cnt;
+ struct nvme_additional_smart_log_item soft_ecc_err_rate;
+ struct nvme_additional_smart_log_item unexp_power_loss;
+ struct nvme_additional_smart_log_item media_bytes_read;
+ struct nvme_additional_smart_log_item avail_fw_downgrades;
};
struct nvme_vu_id_ctrl_field { /* CDR MR5 */
@@ -218,60 +224,118 @@ static void show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart,
json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_bytes_written.raw));
json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats);
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->host_ctx_wear_used.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->host_ctx_wear_used.raw));
+ json_object_add_value_object(dev_stats, "host_ctx_wear_used", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->perf_stat_indicator.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->perf_stat_indicator.raw));
+ json_object_add_value_object(dev_stats, "perf_stat_indicator", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->re_alloc_sectr_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->re_alloc_sectr_cnt.raw));
+ json_object_add_value_object(dev_stats, "re_alloc_sectr_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->soft_ecc_err_rate.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->soft_ecc_err_rate.raw));
+ json_object_add_value_object(dev_stats, "soft_ecc_err_rate", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->unexp_power_loss.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->unexp_power_loss.raw));
+ json_object_add_value_object(dev_stats, "unexp_power_loss", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->media_bytes_read.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->media_bytes_read.raw));
+ json_object_add_value_object(dev_stats, "media_bytes_read", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->avail_fw_downgrades.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->avail_fw_downgrades.raw));
+ json_object_add_value_object(dev_stats, "avail_fw_downgrades", entry_stats);
+
json_object_add_value_object(root, "Device stats", dev_stats);
json_print_object(root, NULL);
json_free_object(root);
}
+static char *id_to_key(__u8 id)
+{
+ switch (id) {
+ case 0xAB:
+ return "program_fail_count";
+ case 0xAC:
+ return "erase_fail_count";
+ case 0xAD:
+ return "wear_leveling_count";
+ case 0xB8:
+ return "e2e_error_detect_count";
+ case 0xC7:
+ return "crc_error_count";
+ case 0xE2:
+ return "media_wear_percentage";
+ case 0xE3:
+ return "host_reads";
+ case 0xE4:
+ return "timed_work_load";
+ case 0xEA:
+ return "thermal_throttle_status";
+ case 0xF0:
+ return "retry_buff_overflow_count";
+ case 0xF3:
+ return "pll_lock_loss_counter";
+ case 0xF4:
+ return "nand_bytes_written";
+ case 0xF5:
+ return "host_bytes_written";
+ case 0xF6:
+ return "host_context_wear_used";
+ case 0xF7:
+ return "performance_status_indicator";
+ case 0xF8:
+ return "media_bytes_read";
+ case 0xF9:
+ return "available_fw_downgrades";
+ case 0x05:
+ return "re-allocated_sector_count";
+ case 0x0D:
+ return "soft_ecc_error_rate";
+ case 0xAE:
+ return "unexpected_power_loss";
+ default:
+ return "Invalid ID";
+ }
+}
+
+static void print_intel_smart_log_items(struct nvme_additional_smart_log_item *item)
+{
+ if (!item->key)
+ return;
+
+ printf("%#x %-45s %3d %"PRIu64"\n",
+ item->key, id_to_key(item->key),
+ item->norm, int48_to_long(item->raw));
+}
+
static void show_intel_smart_log(struct nvme_additional_smart_log *smart,
unsigned int nsid, const char *devname)
{
+ struct nvme_additional_smart_log_item *iter = &smart->program_fail_cnt;
+ int num_items = sizeof(struct nvme_additional_smart_log) /
+ sizeof(struct nvme_additional_smart_log_item);
+
printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
devname, nsid);
- printf("key normalized raw\n");
- printf("program_fail_count : %3d%% %"PRIu64"\n",
- smart->program_fail_cnt.norm,
- int48_to_long(smart->program_fail_cnt.raw));
- printf("erase_fail_count : %3d%% %"PRIu64"\n",
- smart->erase_fail_cnt.norm,
- int48_to_long(smart->erase_fail_cnt.raw));
- printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
- smart->wear_leveling_cnt.norm,
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
- printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
- smart->e2e_err_cnt.norm,
- int48_to_long(smart->e2e_err_cnt.raw));
- printf("crc_error_count : %3d%% %"PRIu64"\n",
- smart->crc_err_cnt.norm,
- int48_to_long(smart->crc_err_cnt.raw));
- printf("timed_workload_media_wear : %3d%% %.3f%%\n",
- smart->timed_workload_media_wear.norm,
- ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
- printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
- smart->timed_workload_host_reads.norm,
- int48_to_long(smart->timed_workload_host_reads.raw));
- printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
- smart->timed_workload_timer.norm,
- int48_to_long(smart->timed_workload_timer.raw));
- printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
- smart->thermal_throttle_status.norm,
- smart->thermal_throttle_status.thermal_throttle.pct,
- smart->thermal_throttle_status.thermal_throttle.count);
- printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
- smart->retry_buffer_overflow_cnt.norm,
- int48_to_long(smart->retry_buffer_overflow_cnt.raw));
- printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
- smart->pll_lock_loss_cnt.norm,
- int48_to_long(smart->pll_lock_loss_cnt.raw));
- printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
- smart->nand_bytes_written.norm,
- int48_to_long(smart->nand_bytes_written.raw));
- printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
- smart->host_bytes_written.norm,
- int48_to_long(smart->host_bytes_written.raw));
+ printf("ID KEY Normalized Raw\n");
+
+ for (int i = 0; i < num_items; i++, iter++)
+ print_intel_smart_log_items(iter);
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -307,7 +371,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
- sizeof(smart_log), &smart_log);
+ NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (cfg.json)
show_intel_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
@@ -347,7 +411,7 @@ static int get_market_log(int argc, char **argv, struct command *cmd, struct plu
return fd;
err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd, false,
- sizeof(log), log);
+ NVME_NO_LOG_LSP, sizeof(log), log);
if (!err) {
if (!cfg.raw_binary)
printf("Intel Marketing Name Log:\n%s\n", log);
@@ -409,7 +473,7 @@ static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct
return fd;
err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5, false,
- sizeof(stats), &stats);
+ NVME_NO_LOG_LSP, sizeof(stats), &stats);
if (!err) {
if (!cfg.raw_binary)
show_temp_stats(&stats);
@@ -427,6 +491,28 @@ struct intel_lat_stats {
__u32 data[1216];
};
+struct __attribute__((__packed__)) optane_lat_stats {
+ __u16 maj;
+ __u16 min;
+ __u64 data[9];
+};
+
+#define MEDIA_MAJOR_IDX 0
+#define MEDIA_MINOR_IDX 1
+#define MEDIA_MAX_LEN 2
+#define OPTANE_V1000_BUCKET_LEN 8
+
+static struct intel_lat_stats stats;
+static struct optane_lat_stats v1000_stats;
+
+struct v1000_thresholds {
+ __u32 read[OPTANE_V1000_BUCKET_LEN];
+ __u32 write[OPTANE_V1000_BUCKET_LEN];
+};
+
+static struct v1000_thresholds v1000_bucket;
+static __u16 media_version[MEDIA_MAX_LEN] = {0};
+
enum FormatUnit {
US,
MS,
@@ -536,6 +622,28 @@ static void show_lat_stats_bucket(struct intel_lat_stats *stats,
printf("%-*d\n", COL_WIDTH, stats->data[i]);
}
+static void show_optane_lat_stats_bucket(struct optane_lat_stats *stats,
+ __u32 lower_us, enum inf_bound_type start_type,
+ __u32 upper_us, enum inf_bound_type end_type, int i)
+{
+ enum FormatUnit fu = S;
+ char buffer[BUFSIZE];
+
+ init_buffer(buffer, BUFSIZE);
+ printf("%-*d", COL_WIDTH, i);
+
+ fu = get_seconds_magnitude(lower_us);
+ set_unit_string(buffer, lower_us, fu, start_type);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ fu = get_seconds_magnitude(upper_us);
+ set_unit_string(buffer, upper_us, fu, end_type);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ printf("%-*lu\n", COL_WIDTH, (long unsigned int)stats->data[i]);
+}
+
+
static void show_lat_stats_linear(struct intel_lat_stats *stats,
__u32 start_offset, __u32 end_offset, __u32 bytes_per,
__u32 us_step, bool nonzero_print)
@@ -622,6 +730,31 @@ static void json_add_bucket(struct intel_lat_stats *stats,
json_object_add_value_int(bucket, "value", val);
}
+static void json_add_bucket_optane(struct json_object *bucket_list, __u32 id,
+ __u32 lower_us, enum inf_bound_type start_type,
+ __u32 upper_us, enum inf_bound_type end_type, __u32 val)
+{
+ char buffer[BUFSIZE];
+ struct json_object *bucket = json_create_object();
+
+ init_buffer(buffer, BUFSIZE);
+
+ json_object_add_value_object(bucket_list,
+ "bucket", bucket);
+ json_object_add_value_int(bucket, "id", id);
+
+ set_unit_string(buffer, lower_us,
+ get_seconds_magnitude(lower_us), start_type);
+ json_object_add_value_string(bucket, "start", buffer);
+
+ set_unit_string(buffer, upper_us,
+ get_seconds_magnitude(upper_us), end_type);
+ json_object_add_value_string(bucket, "end", buffer);
+
+ json_object_add_value_uint(bucket, "value", val);
+
+}
+
static void json_lat_stats_linear(struct intel_lat_stats *stats,
struct json_object *bucket_list, __u32 start_offset,
__u32 end_offset, __u32 bytes_per,
@@ -714,32 +847,121 @@ static void show_lat_stats_4_0(struct intel_lat_stats *stats)
}
}
-static void json_lat_stats(struct intel_lat_stats *stats, int write)
+static void jason_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
+{
+ int i;
+ struct json_object *root = json_create_object();
+ struct json_object *bucket_list = json_create_object();
+
+ lat_stats_make_json_root(root, bucket_list, write);
+
+ if (write) {
+ for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
+ json_add_bucket_optane(bucket_list, i,
+ v1000_bucket.write[i], NOINF,
+ v1000_bucket.write[i + 1] - 1,
+ NOINF,
+ stats->data[i]);
+
+ json_add_bucket_optane(bucket_list,
+ OPTANE_V1000_BUCKET_LEN - 1,
+ v1000_bucket.write[i],
+ NOINF,
+ v1000_bucket.write[i],
+ POSINF, stats->data[i]);
+ } else {
+ for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
+ json_add_bucket_optane(bucket_list, i,
+ v1000_bucket.read[i], NOINF,
+ v1000_bucket.read[i + 1] - 1,
+ NOINF,
+ stats->data[i]);
+
+ json_add_bucket_optane(bucket_list,
+ OPTANE_V1000_BUCKET_LEN - 1,
+ v1000_bucket.read[i],
+ NOINF,
+ v1000_bucket.read[i],
+ POSINF, stats->data[i]);
+ }
+
+ struct json_object *subroot = json_create_object();
+ json_object_add_value_object(root, "Average latency since last reset", subroot);
+
+ json_object_add_value_uint(subroot, "value in us", stats->data[8]);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+
+}
+
+static void show_lat_stats_v1000_0(struct optane_lat_stats *stats, int write)
+{
+ int i;
+ if (write) {
+ for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
+ show_optane_lat_stats_bucket(stats,
+ v1000_bucket.write[i],
+ NOINF,
+ v1000_bucket.write[i + 1] -1,
+ NOINF, i);
+
+ show_optane_lat_stats_bucket(stats, v1000_bucket.write[i],
+ NOINF, v1000_bucket.write[i],
+ POSINF, i);
+ } else {
+ for (i = 0; i < OPTANE_V1000_BUCKET_LEN - 1; i++)
+ show_optane_lat_stats_bucket(stats,
+ v1000_bucket.read[i],
+ NOINF,
+ v1000_bucket.read[i + 1] -1,
+ NOINF, i);
+
+ show_optane_lat_stats_bucket(stats, v1000_bucket.read[i],
+ NOINF, v1000_bucket.read[i],
+ POSINF, i);
+ }
+
+ printf("Average latency since last reset: %lu us\n", (long unsigned int)stats->data[8]);
+
+}
+
+static void json_lat_stats(int write)
{
- switch (stats->maj) {
+ switch (media_version[MEDIA_MAJOR_IDX]) {
case 3:
- json_lat_stats_3_0(stats, write);
+ json_lat_stats_3_0(&stats, write);
break;
case 4:
- switch (stats->min) {
+ switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
- json_lat_stats_4_0(stats, write);
+ json_lat_stats_4_0(&stats, write);
break;
default:
- printf(("Unsupported minor revision (%u.%u)\n"
- "Defaulting to format for rev4.0"),
- stats->maj, stats->min);
+ printf("Unsupported minor revision (%u.%u)\n",
+ stats.maj, stats.min);
+ break;
+ }
+ break;
+ case 1000:
+ switch (media_version[MEDIA_MINOR_IDX]) {
+ case 0:
+ jason_lat_stats_v1000_0(&v1000_stats, write);
+ break;
+ default:
+ printf("Unsupported minor revision (%u.%u)\n",
+ stats.maj, stats.min);
break;
}
break;
default:
printf("Unsupported revision (%u.%u)\n",
- stats->maj, stats->min);
+ stats.maj, stats.min);
break;
}
printf("\n");
@@ -752,69 +974,79 @@ static void print_dash_separator(int count)
putchar('\n');
}
-static void show_lat_stats(struct intel_lat_stats *stats, int write)
+static void show_lat_stats(int write)
{
static const int separator_length = 50;
printf("Intel IO %s Command Latency Statistics\n",
write ? "Write" : "Read");
printf("Major Revision : %u\nMinor Revision : %u\n",
- stats->maj, stats->min);
+ media_version[MEDIA_MAJOR_IDX], media_version[MEDIA_MINOR_IDX]);
print_dash_separator(separator_length);
printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
print_dash_separator(separator_length);
- switch (stats->maj) {
+ switch (media_version[MEDIA_MAJOR_IDX]) {
case 3:
- show_lat_stats_3_0(stats);
+ show_lat_stats_3_0(&stats);
break;
case 4:
- switch (stats->min) {
+ switch (media_version[MEDIA_MINOR_IDX]) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
- show_lat_stats_4_0(stats);
+ show_lat_stats_4_0(&stats);
break;
default:
- printf(("Unsupported minor revision (%u.%u)\n"
- "Defaulting to format for rev4.0"),
- stats->maj, stats->min);
+ printf("Unsupported minor revision (%u.%u)\n",
+ stats.maj, stats.min);
+ break;
+ }
+ break;
+ case 1000:
+ switch (media_version[MEDIA_MINOR_IDX]) {
+ case 0:
+ show_lat_stats_v1000_0(&v1000_stats, write);
+ break;
+ default:
+ printf("Unsupported minor revision (%u.%u)\n",
+ stats.maj, stats.min);
break;
}
break;
default:
printf("Unsupported revision (%u.%u)\n",
- stats->maj, stats->min);
+ stats.maj, stats.min);
break;
}
}
static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- struct intel_lat_stats stats;
- enum nvme_print_flags flags;
+
int err, fd;
const char *desc = "Get Intel Latency Statistics log and show it.";
- const char *raw = "dump output in binary format";
+ const char *raw = "Dump output in binary format";
+ const char *json= "Dump output in json format";
const char *write = "Get write statistics (read default)";
+
struct config {
- char *output_format;
int raw_binary;
+ int json;
int write;
};
struct config cfg = {
- .output_format = "normal",
};
OPT_ARGS(opts) = {
- OPT_FLAG("write", 'w', &cfg.write, write),
- OPT_FMT("output-format", 'o', &cfg.output_format, "Output format: normal|json|binary"),
- OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("json", 'j', &cfg.json, json),
OPT_END()
};
@@ -822,26 +1054,54 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
if (fd < 0)
return fd;
- err = flags = validate_output_format(cfg.output_format);
- if (flags < 0)
+ /* Query maj and minor version first */
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
+ false, NVME_NO_LOG_LSP, sizeof(media_version),
+ media_version);
+ if (err)
goto close_fd;
- if (cfg.raw_binary)
- flags = BINARY;
+ if (media_version[0] == 1000) {
+ __u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
+ __u32 result;
+
+ err = nvme_get_feature(fd, 0, 0xf7, 0, cfg.write ? 0x1 : 0x0,
+ sizeof(thresholds), thresholds, &result);
+ if (err) {
+ fprintf(stderr, "Quering thresholds failed. NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ goto close_fd;
+ }
+
+ /* Update bucket thresholds to be printed */
+ if (cfg.write) {
+ for (int i = 0; i < OPTANE_V1000_BUCKET_LEN; i++)
+ v1000_bucket.write[i] = thresholds[i];
+ } else {
+ for (int i = 0; i < OPTANE_V1000_BUCKET_LEN; i++)
+ v1000_bucket.read[i] = thresholds[i];
+
+ }
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
+ false, NVME_NO_LOG_LSP, sizeof(v1000_stats),
+ &v1000_stats);
+ } else {
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
+ false, NVME_NO_LOG_LSP, sizeof(stats),
+ &stats);
+ }
- err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
- false, sizeof(stats), &stats);
if (!err) {
- if (flags & JSON)
- json_lat_stats(&stats, cfg.write);
- else if (flags & BINARY)
- d_raw((unsigned char *)&stats, sizeof(stats));
+ if (cfg.json)
+ json_lat_stats(cfg.write);
+ else if (!cfg.raw_binary)
+ show_lat_stats(cfg.write);
else
- show_lat_stats(&stats, cfg.write);
+ d_raw((unsigned char *)&stats, sizeof(stats));
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
-
close_fd:
close(fd);
return err;
@@ -1314,3 +1574,84 @@ static int enable_lat_stats_tracking(int argc, char **argv,
}
return fd;
}
+
+static int set_lat_stats_thresholds(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ int err, fd, num;
+ const char *desc = "Write Intel Bucket Thresholds for Latency Statistics Tracking";
+ const char *bucket_thresholds = "Bucket Threshold List, comma separated list: 0, 10, 20 ...";
+ const char *write = "Set write bucket Thresholds for latency tracking (read default)";
+
+ const __u32 nsid = 0;
+ const __u8 fid = 0xf7;
+ const __u32 cdw12 = 0x0;
+ const __u32 save = 0;
+ __u32 result;
+
+ struct config {
+ int write;
+ char *bucket_thresholds;
+ };
+
+ struct config cfg = {
+ .write = 0,
+ .bucket_thresholds = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_LIST("bucket-thresholds", 't', &cfg.bucket_thresholds,
+ bucket_thresholds),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ return fd;
+
+ /* Query maj and minor version first to figure out the amount of
+ * valid buckets a user is allowed to modify. Read or write doesn't
+ * matter
+ */
+ err = nvme_get_log(fd, NVME_NSID_ALL, 0xc2,
+ false, NVME_NO_LOG_LSP, sizeof(media_version),
+ media_version);
+ if (err) {
+ fprintf(stderr, "Querying media version failed. NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ goto close_fd;
+ }
+
+ if (media_version[0] == 1000) {
+ int thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
+ num = argconfig_parse_comma_sep_array(cfg.bucket_thresholds,
+ thresholds,
+ sizeof(thresholds));
+ if (num == -1) {
+ fprintf(stderr, "ERROR: Bucket list is malformed\n");
+ goto close_fd;
+
+ }
+
+ err = nvme_set_feature(fd, nsid, fid, cfg.write ? 0x1 : 0x0,
+ cdw12, save, OPTANE_V1000_BUCKET_LEN,
+ thresholds, &result);
+
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ }
+ } else {
+ fprintf(stderr, "Unsupported command\n");
+ }
+
+close_fd:
+ close(fd);
+ return err;
+}
+
diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h
index 335e901..b119004 100644
--- a/plugins/intel/intel-nvme.h
+++ b/plugins/intel/intel-nvme.h
@@ -11,6 +11,7 @@ PLUGIN(NAME("intel", "Intel vendor specific extensions"),
ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
ENTRY("internal-log", "Retrieve Intel internal firmware log, save it", get_internal_log)
ENTRY("lat-stats", "Retrieve Intel IO Latency Statistics log, show it", get_lat_stats_log)
+ ENTRY("set-bucket-thresholds", "Set Latency Stats Bucket Values, save it", set_lat_stats_thresholds)
ENTRY("lat-stats-tracking", "Enable and disable Latency Statistics logging.", enable_lat_stats_tracking)
ENTRY("market-name", "Retrieve Intel Marketing Name log, show it", get_market_log)
ENTRY("smart-log-add", "Retrieve Intel SMART Log, show it", get_additional_smart_log)
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
index c75f49c..d330835 100644
--- a/plugins/memblaze/memblaze-nvme.c
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <time.h>
#include "linux/nvme_ioctl.h"
@@ -19,9 +20,23 @@
#include "memblaze-utils.h"
enum {
- MB_FEAT_POWER_MGMT = 0xc6,
+ // feature id
+ MB_FEAT_POWER_MGMT = 0x02,
+ MB_FEAT_HIGH_LATENCY = 0xE1,
+ // log id
+ GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM = 0xC1,
+ GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM = 0xC2,
+ GLP_ID_VU_GET_HIGH_LATENCY_LOG = 0xC3,
+ MB_FEAT_CLEAR_ERRORLOG = 0xF7,
};
+#define LOG_PAGE_SIZE (0x1000)
+#define DO_PRINT_FLAG (1)
+#define NOT_PRINT_FLAG (0)
+#define FID_C1_LOG_FILENAME "log_c1.csv"
+#define FID_C2_LOG_FILENAME "log_c2.csv"
+#define FID_C3_LOG_FILENAME "log_c3.csv"
+
/*
* Return -1 if @fw1 < @fw2
* Return 0 if @fw1 == @fw2
@@ -53,18 +68,26 @@ static int compare_fw_version(const char *fw1, const char *fw2)
#define MEMBLAZE_FORMAT (0)
#define INTEL_FORMAT (1)
-// 2.83 = raisin
-#define IS_RAISIN(str) (!strcmp(str, "2.83"))
// 2.13 = papaya
#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
-#define STR_VER_SIZE 5
+// 2.83 = raisin
+#define IS_RAISIN(str) (!strcmp(str, "2.83"))
+// 2.94 = kumquat
+#define IS_KUMQUAT(str) (!strcmp(str, "2.94"))
+// 0.60 = loquat
+#define IS_LOQUAT(str) (!strcmp(str, "0.60"))
+
+#define STR_VER_SIZE (5)
int getlogpage_format_type(char *fw_ver)
{
char fw_ver_local[STR_VER_SIZE];
strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
*(fw_ver_local + STR_VER_SIZE - 1) = '\0';
- if ( IS_RAISIN(fw_ver_local) )
+ if ( IS_RAISIN(fw_ver_local)
+ || IS_KUMQUAT(fw_ver_local)
+ || IS_LOQUAT(fw_ver_local)
+ )
{
return INTEL_FORMAT;
}
@@ -128,7 +151,7 @@ static __u64 raw_2_u64(const __u8 *buf, size_t len)
#define STR17_04 ", min: "
#define STR17_05 ", curr: "
#define STR18_01 "power_loss_protection"
-#define STR19_01 "read_fail"
+#define STR19_01 "read_fail_count"
#define STR20_01 "thermal_throttle_time"
#define STR21_01 "flash_media_error"
@@ -380,7 +403,42 @@ static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname,
return err;
}
-static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+int parse_params(char *str, int number, ...)
+{
+ va_list argp;
+ int *param;
+ char *c;
+ int value;
+
+ va_start(argp, number);
+
+ while (number > 0) {
+ c = strtok(str, ",");
+ if ( c == NULL) {
+ printf("No enough parameters. abort...\n");
+ exit(EINVAL);
+ }
+
+ if (isalnum(*c) == 0) {
+ printf("%s is not a valid number\n", c);
+ return 1;
+ }
+ value = atoi(c);
+ param = va_arg(argp, int *);
+ *param = value;
+
+ if (str) {
+ str = strchr(str, ',');
+ if (str) { str++; }
+ }
+ number--;
+ }
+ va_end(argp);
+
+ return 0;
+}
+
+static int mb_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
struct nvme_memblaze_smart_log smart_log;
int err, fd;
@@ -408,7 +466,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return fd;
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
- sizeof(smart_log), &smart_log);
+ NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
@@ -423,213 +481,262 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
static char *mb_feature_to_string(int feature)
{
- switch (feature) {
- case MB_FEAT_POWER_MGMT: return "Memblaze power management";
- default: return "Unknown";
- }
+ switch (feature) {
+ case MB_FEAT_POWER_MGMT: return "Memblaze power management";
+ case MB_FEAT_HIGH_LATENCY: return "Memblaze high latency log";
+ case MB_FEAT_CLEAR_ERRORLOG: return "Memblaze clear error log";
+ default: return "Unknown";
+ }
}
-static int get_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_get_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- const char *desc = "Read operating parameters of the "\
- "specified controller. Operating parameters are grouped "\
- "and identified by Feature Identifiers; each Feature "\
- "Identifier contains one or more attributes that may affect "\
- "behaviour of the feature. Each Feature has three possible "\
- "settings: default, saveable, and current. If a Feature is "\
- "saveable, it may be modified by set-feature. Default values "\
- "are vendor-specific and not changeable. Use set-feature to "\
- "change saveable Features.\n\n"\
- "Available additional feature id:\n"\
- "0xc6: Memblaze power management\n"\
- " (value 0 - 25w, 1 - 20w, 2 - 15w)";
- const char *raw = "show feature in binary format";
- const char *namespace_id = "identifier of desired namespace";
- const char *feature_id = "hexadecimal feature name";
- const char *sel = "[0-3]: curr./default/saved/supp.";
- const char *data_len = "buffer len (if) data is returned";
- const char *cdw11 = "dword 11 for interrupt vector config";
- const char *human_readable = "show infos in readable format";
- int err, fd;
- __u32 result;
- void *buf = NULL;
-
- struct config {
- __u32 namespace_id;
- __u32 feature_id;
- __u8 sel;
- __u32 cdw11;
- __u32 data_len;
- int raw_binary;
- int human_readable;
- };
+ const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ int err, fd;
+ __u32 result;
+ __u32 feature_id = MB_FEAT_POWER_MGMT;
- struct config cfg = {
- .namespace_id = 1,
- .feature_id = 0,
- .sel = 0,
- .cdw11 = 0,
- .data_len = 0,
- };
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
- 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("sel", 's', &cfg.sel, sel),
- OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
- OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
- OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
- OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
- OPT_END()
- };
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
- 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);
+ if (err < 0) {
+ perror("get-feature");
+ }
+ if (!err) {
+ printf("get-feature:0x%02x (%s), %s value: %#08x\n", feature_id,
+ mb_feature_to_string(feature_id),
+ nvme_select_to_string(0), result);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ return err;
+}
- if (cfg.sel > 7) {
- fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
- return EINVAL;
- }
- if (!cfg.feature_id) {
- fprintf(stderr, "feature-id required param\n");
- return EINVAL;
- }
- if (cfg.data_len) {
- if (posix_memalign(&buf, getpagesize(), cfg.data_len))
- exit(ENOMEM);
- memset(buf, 0, cfg.data_len);
- }
+static int mb_set_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Set Memblaze power management status\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ const char *value = "new value of feature (required)";
+ const char *save = "specifies that the controller shall save the attribute";
+ int err, fd;
+ __u32 result;
+
+ struct config {
+ __u32 feature_id;
+ __u32 value;
+ int save;
+ };
+
+ struct config cfg = {
+ .feature_id = MB_FEAT_POWER_MGMT,
+ .value = 0,
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ 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);
+ if (err < 0) {
+ perror("set-feature");
+ }
+ if (!err) {
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id), cfg.value);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
- err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
- cfg.data_len, buf, &result);
- if (!err) {
- printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
- mb_feature_to_string(cfg.feature_id),
- nvme_select_to_string(cfg.sel), result);
- if (cfg.human_readable)
- nvme_feature_show_fields(cfg.feature_id, result, buf);
- else {
- if (buf) {
- if (!cfg.raw_binary)
- d(buf, cfg.data_len, 16, 1);
- else
- d_raw(buf, cfg.data_len);
- }
- }
- } else if (err > 0)
- fprintf(stderr, "NVMe Status:%s(%x)\n",
- nvme_status_to_string(err), err);
- if (buf)
- free(buf);
- return err;
+ return err;
}
-static int set_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+#define P2MIN (1)
+#define P2MAX (5000)
+#define MB_FEAT_HIGH_LATENCY_VALUE_SHIFT (15)
+static int mb_set_high_latency_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
- const char *desc = "Modify the saveable or changeable "\
- "current operating parameters of the controller. Operating "\
- "parameters are grouped and identified by Feature "\
- "Identifiers. Feature settings can be applied to the entire "\
- "controller and all associated namespaces, or to only a few "\
- "namespace(s) associated with the controller. Default values "\
- "for each Feature are vendor-specific and may not be modified."\
- "Use get-feature to determine which Features are supported by "\
- "the controller and are saveable/changeable.\n\n"\
- "Available additional feature id:\n"\
- "0xc6: Memblaze power management\n"\
- " (value 0 - 25w, 1 - 20w, 2 - 15w)";
- const char *namespace_id = "desired namespace";
- const char *feature_id = "hex feature name (required)";
- const char *data_len = "buffer length if data required";
- const char *data = "optional file for feature data (default stdin)";
- const char *value = "new value of feature (required)";
- const char *save = "specifies that the controller shall save the attribute";
- int err, fd;
- __u32 result;
- void *buf = NULL;
- int ffd = STDIN_FILENO;
+ const char *desc = "Set Memblaze high latency log\n"\
+ " input parameter p1,p2\n"\
+ " p1 value: 0 is disable, 1 is enable\n"\
+ " p2 value: 1 .. 5000 ms";
+ const char *param = "input parameters";
+ int err, fd;
+ __u32 result;
+ int param1 = 0, param2 = 0;
+
+ struct config {
+ __u32 feature_id;
+ char * param;
+ __u32 value;
+ };
+
+ struct config cfg = {
+ .feature_id = MB_FEAT_HIGH_LATENCY,
+ .param = "0,0",
+ .value = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_LIST("param", 'p', &cfg.param, param),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ if (parse_params(cfg.param, 2, &param1, &param2)) {
+ printf("setfeature: invalid formats %s\n", cfg.param);
+ exit(EINVAL);
+ }
+ if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
+ printf("setfeature: invalid high io latency threshold %d\n", param2);
+ exit(EINVAL);
+ }
+ cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
- struct config {
- char *file;
- __u32 namespace_id;
- __u32 feature_id;
- __u32 value;
- __u32 data_len;
- int save;
- };
+ err = nvme_set_feature(fd, 0, cfg.feature_id, cfg.value, 0, 0, 0, NULL, &result);
+ if (err < 0) {
+ perror("set-feature");
+ }
+ if (!err) {
+ printf("set-feature:0x%02X (%s), value:%#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id), cfg.value);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
- struct config cfg = {
- .file = "",
- .namespace_id = 0,
- .feature_id = 0,
- .value = 0,
- .data_len = 0,
- .save = 0,
- };
+ return err;
+}
- OPT_ARGS(opts) = {
- OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
- OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
- OPT_UINT("value", 'v', &cfg.value, value),
- OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
- OPT_FILE("data", 'd', &cfg.file, data),
- OPT_FLAG("save", 's', &cfg.save, save),
- OPT_END()
- };
+static int glp_high_latency_show_bar(FILE *fdi, int print)
+{
+ fPRINT_PARAM1("Memblaze High Latency Log\n");
+ fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
+ fPRINT_PARAM1("Timestamp Type QID CID NSID StartLBA NumLBA Latency\n");
+ fPRINT_PARAM1("---------------------------------------------------------------------------------------------\n");
+ return 0;
+}
- fd = parse_and_open(argc, argv, desc, opts);
- if (fd < 0)
- return fd;
+/* High latency log page definiton
+ * Total 32 bytes
+ */
+typedef struct
+{
+ __u8 port;
+ __u8 revision;
+ __u16 rsvd;
+ __u8 opcode;
+ __u8 sqe;
+ __u16 cid;
+ __u32 nsid;
+ __u32 latency;
+ __u64 sLBA;
+ __u16 numLBA;
+ __u16 timestampH;
+ __u32 timestampL;
+} log_page_high_latency_t; /* total 32 bytes */
+
+static int find_deadbeef(char *buf)
+{
+ if (((*(buf + 0) & 0xff) == 0xef) && ((*(buf + 1) & 0xff) == 0xbe) && \
+ ((*(buf + 2) & 0xff) == 0xad) && ((*(buf + 3) & 0xff) == 0xde))
+ {
+ return 1;
+ }
+ return 0;
+}
- if (!cfg.feature_id) {
- fprintf(stderr, "feature-id required param\n");
- return EINVAL;
- }
+#define TIME_STR_SIZE (44)
+static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
+{
+ log_page_high_latency_t *logEntry;
+ char string[TIME_STR_SIZE];
+ int i, entrySize;
+ __u64 timestamp;
+ time_t tt = 0;
+ struct tm *t = NULL;
+ int millisec = 0;
+
+ if (find_deadbeef(buf)) return 0;
+
+ entrySize = sizeof(log_page_high_latency_t);
+ for (i = 0; i < buflen; i += entrySize)
+ {
+ logEntry = (log_page_high_latency_t *)(buf + i);
- if (cfg.data_len) {
- if (posix_memalign(&buf, getpagesize(), cfg.data_len))
- exit(ENOMEM);
- memset(buf, 0, cfg.data_len);
- }
+ if (logEntry->latency == 0 && logEntry->revision == 0)
+ {
+ return 1;
+ }
+
+ if (0 == logEntry->timestampH) // generate host time string
+ {
+ snprintf(string, sizeof(string), "%d", logEntry->timestampL);
+ }
+ else // sort
+ {
+ timestamp = logEntry->timestampH - 1;
+ timestamp = timestamp << 32;
+ timestamp += logEntry->timestampL;
+ tt = timestamp / 1000;
+ millisec = timestamp % 1000;
+ t = gmtime(&tt);
+ snprintf(string, sizeof(string), "%4d%02d%02d--%02d:%02d:%02d.%03d UTC",
+ 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, millisec);
+ }
+
+ fprintf(fdi, "%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
+ string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
+ (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
+ if (print)
+ {
+ printf("%-32s %-7x %-6x %-6x %-8x %4x%08x %-8x %-d\n",
+ string, logEntry->opcode, logEntry->sqe, logEntry->cid, logEntry->nsid,
+ (__u32)(logEntry->sLBA >> 32), (__u32)logEntry->sLBA, logEntry->numLBA, logEntry->latency);
+ }
+ }
+ return 1;
+}
- if (buf) {
- if (strlen(cfg.file)) {
- ffd = open(cfg.file, O_RDONLY);
- if (ffd <= 0) {
- fprintf(stderr, "no firmware file provided\n");
- err = EINVAL;
- goto free;
- }
- }
- if (read(ffd, (void *)buf, cfg.data_len) < 0) {
- fprintf(stderr, "failed to read data buffer from input file\n");
- err = EINVAL;
- goto free;
- }
- }
+static int mb_high_latency_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Memblaze high latency log";
+ int err, fd;
+ char buf[LOG_PAGE_SIZE];
+ FILE *fdi = NULL;
+
+ fdi = fopen(FID_C3_LOG_FILENAME, "w+");
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
+ err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
+
+ while ( 1) {
+ if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG)) break;
+ err = nvme_get_log(fd, NVME_NSID_ALL, GLP_ID_VU_GET_HIGH_LATENCY_LOG, 0, NVME_NO_LOG_LSP, sizeof(buf), &buf);
+ if ( err) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ break;
+ }
+ }
- err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
- 0, cfg.save, cfg.data_len, buf, &result);
- if (err < 0) {
- perror("set-feature");
- goto free;
- }
- if (!err) {
- printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
- mb_feature_to_string(cfg.feature_id), cfg.value);
- if (buf)
- d(buf, cfg.data_len, 16, 1);
- } else if (err > 0)
- fprintf(stderr, "NVMe Status:%s(%x)\n",
- nvme_status_to_string(err), err);
-
-free:
- if (buf)
- free(buf);
- return err;
+ if (NULL != fdi) fclose(fdi);
+ return err;
}
+
static int memblaze_fw_commit(int fd, int select)
{
struct nvme_admin_cmd cmd = {
@@ -641,7 +748,7 @@ static int memblaze_fw_commit(int fd, int select)
return nvme_submit_admin_passthru(fd, &cmd);
}
-static int memblaze_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int mb_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
const char *desc =
"This performs a selective firmware download, which allows the user to "
@@ -757,3 +864,287 @@ out:
return err;
}
+static void ioLatencyHistogramOutput(FILE *fd, int index, int start, int end, char *unit0,
+ char *unit1, unsigned int *pHistogram, int print)
+{
+ int len;
+ char string[64], subString0[12], subString1[12];
+
+ len = snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
+ if (end != 0x7FFFFFFF)
+ {
+ len = snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
+ }
+ else
+ {
+ len = snprintf(subString1, sizeof(subString1), "%s", "+INF");
+ }
+ len = snprintf(string, sizeof(string), "%-11d %-11s %-11s %-11u\n", index, subString0, subString1,
+ pHistogram[index]);
+ fwrite(string, 1, len, fd);
+ if (print)
+ {
+ printf("%s", string);
+ }
+}
+
+int io_latency_histogram(char *file, char *buf, int print, int logid)
+{
+ FILE *fdi = fopen(file, "w+");
+ int i, index;
+ char unit[2][3];
+ unsigned int *revision = (unsigned int *)buf;
+
+ if (logid == GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM)
+ {
+ fPRINT_PARAM1("Memblaze IO Read Command Latency Histogram\n");
+ }
+ else if (logid == GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM)
+ {
+ fPRINT_PARAM1("Memblaze IO Write Command Latency Histogram\n");
+ }
+ fPRINT_PARAM2("Major Revision : %d\n", revision[1]);
+ fPRINT_PARAM2("Minor Revision : %d\n", revision[0]);
+ buf += 8;
+
+ if (revision[1] == 1 && revision[0] == 0)
+ {
+ fPRINT_PARAM1("--------------------------------------------------\n");
+ fPRINT_PARAM1("Bucket Start End Value \n");
+ fPRINT_PARAM1("--------------------------------------------------\n");
+ index = 0;
+ strcpy(unit[0], "us");
+ strcpy(unit[1], "us");
+ for (i = 0; i < 32; i++, index++)
+ {
+ if (i == 31)
+ {
+ strcpy(unit[1], "ms");
+ ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
+ print);
+ }
+ }
+
+ strcpy(unit[0], "ms");
+ strcpy(unit[1], "ms");
+ for (i = 1; i < 32; i++, index++)
+ {
+ ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+
+ for (i = 1; i < 32; i++, index++)
+ {
+ if (i == 31)
+ {
+ strcpy(unit[1], "s");
+ ioLatencyHistogramOutput(fdi, index, i * 32, 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ ioLatencyHistogramOutput(fdi, index, i * 32, (i + 1) * 32, unit[0], unit[1], (unsigned int *)buf,
+ print);
+ }
+ }
+
+ strcpy(unit[0], "s");
+ strcpy(unit[1], "s");
+ for (i = 1; i < 4; i++, index++)
+ {
+ ioLatencyHistogramOutput(fdi, index, i, i + 1, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+
+ ioLatencyHistogramOutput(fdi, index, i, 0x7FFFFFFF, unit[0], unit[1], (unsigned int *)buf, print);
+ }
+ else
+ {
+ fPRINT_PARAM1("Unsupported io latency histogram revision\n");
+ }
+
+ fclose(fdi);
+ return 1;
+}
+
+static int mb_lat_stats_log_print(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char stats[LOG_PAGE_SIZE];
+ int err = 0;
+ int fd;
+ char f1[] = FID_C1_LOG_FILENAME;
+ char f2[] = FID_C2_LOG_FILENAME;
+
+ const char *desc = "Get Latency Statistics log and show it.";
+ const char *write = "Get write statistics (read default)";
+
+ struct config {
+ int write;
+ };
+ struct config cfg = {
+ .write = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) return fd;
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1, false, NVME_NO_LOG_LSP, sizeof(stats), &stats);
+ if (!err)
+ io_latency_histogram(cfg.write ? f2 : f1, stats, DO_PRINT_FLAG,
+ cfg.write ? GLP_ID_VU_GET_WRITE_LATENCY_HISTOGRAM : GLP_ID_VU_GET_READ_LATENCY_HISTOGRAM);
+ else
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+ close(fd);
+ return err;
+}
+
+#define OP 0xFC
+#define FID 0x68
+static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err, fd;
+ char *desc = "Clear Memblaze devices error log.";
+
+ //const char *value = "new value of feature (required)";
+ //const char *save = "specifies that the controller shall save the attribute";
+ __u32 result;
+
+ struct config {
+ __u32 feature_id;
+ __u32 value;
+ int save;
+ };
+
+ struct config cfg = {
+ .feature_id = 0xf7,
+ .value = 0x534d0001,
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ 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);
+ if (err < 0) {
+ perror("set-feature");
+ }
+ if (!err) {
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id, mb_feature_to_string(cfg.feature_id), cfg.value);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+/*
+ struct nvme_admin_cmd admin_cmd = {
+ .opcode = OP,
+ .cdw10 = FID,
+ };
+
+ err = nvme_submit_admin_passthru(fd, &admin_cmd);
+
+ if (!err) {
+ printf("OP(0x%2X) FID(0x%2X) Clear error log success.\n", OP, FID);
+ } else {
+ printf("NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+ };
+*/
+ return err;
+}
+
+static int mb_set_lat_stats(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ int err, fd;
+ const char *desc = (
+ "Enable/Disable Latency Statistics Tracking.\n"
+ "No argument prints current status.");
+ const char *enable_desc = "Enable LST";
+ const char *disable_desc = "Disable LST";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xe2;
+ const __u8 sel = 0;
+ const __u32 cdw11 = 0x0;
+ const __u32 cdw12 = 0x0;
+ const __u32 data_len = 32;
+ const __u32 save = 0;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ bool enable, disable;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .disable = false,
+ };
+
+ const struct argconfig_commandline_options command_line_options[] = {
+ {"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc},
+ {"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc},
+ {NULL}
+ };
+
+ fd = parse_and_open(argc, argv, desc, command_line_options);
+
+ enum Option {
+ None = -1,
+ True = 1,
+ False = 0,
+ };
+ enum Option option = None;
+
+ if (cfg.enable && cfg.disable)
+ printf("Cannot enable and disable simultaneously.");
+ else if (cfg.enable || cfg.disable)
+ option = cfg.enable;
+
+ if (fd < 0)
+ return fd;
+ switch (option) {
+ case None:
+ err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf,
+ &result);
+ if (!err) {
+ printf(
+ "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
+ fid, result);
+ } else {
+ printf("Could not read feature id 0xE2.\n");
+ return err;
+ }
+ break;
+ case True:
+ case False:
+ err = nvme_set_feature(fd, nsid, fid, option, cdw12, save,
+ data_len, buf, &result);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set enable bit for FID (0x%X) to %i.\n",
+ fid, option);
+ }
+ break;
+ default:
+ printf("%d not supported.\n", option);
+ return EINVAL;
+ }
+ return fd;
+}
+
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
index 8f7024d..043d0a8 100644
--- a/plugins/memblaze/memblaze-nvme.h
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -14,10 +14,15 @@
PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"),
COMMAND_LIST(
- ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", get_additional_smart_log)
- ENTRY("get-feature-add", "Get Memblaze feature and show the resulting value", get_additional_feature)
- ENTRY("set-feature-add", "Set a Memblaze feature and show the resulting value", set_additional_feature)
- ENTRY("select-download", "Selective Firmware Download", memblaze_selective_download)
+ 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)
+ ENTRY("set-pm-status", "Set Memblaze Power Manager Status", mb_set_powermanager_status)
+ ENTRY("select-download", "Selective Firmware Download", mb_selective_download)
+ ENTRY("lat-stats", "Enable and disable Latency Statistics logging", mb_set_lat_stats)
+ ENTRY("lat-stats-print", "Retrieve IO Latency Statistics log, show it", mb_lat_stats_log_print)
+ ENTRY("lat-log", "Set Memblaze High Latency Log", mb_set_high_latency_log)
+ ENTRY("lat-log-print", "Output Memblaze High Latency Log", mb_high_latency_log_print)
+ ENTRY("clear-error-log", "Clear error log", memblaze_clear_error_log)
)
);
diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h
index a67ee5e..6fdee39 100644
--- a/plugins/memblaze/memblaze-utils.h
+++ b/plugins/memblaze/memblaze-utils.h
@@ -160,5 +160,68 @@ struct nvme_p4_smart_log
u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS];
};
+// base
+#define DD do{ printf("=Memblaze= %s[%d]-%s():\n", __FILE__, __LINE__, __func__); }while(0)
+#define DE(str) do{ printf("===ERROR!=== %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, \
+ str); }while(0)
+// integer
+#define DI(i) do{ printf("=Memblaze= %s[%d]-%s():int=%d\n", __FILE__, __LINE__, __func__, \
+ (int)i); } while(0)
+#define DPI(prompt, i) do{ printf("=Memblaze= %s[%d]-%s():%s=%d\n", __FILE__, __LINE__, __func__, \
+ prompt, i); }while(0)
+#define DAI(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \
+ for(i=0;i<max;i++) printf(" %d:%d", i, arr[i]); \
+ printf("\n"); }while(0)
+// char
+#define DC(c) do{ printf("=Memblaze= %s[%d]-%s():char=%c\n", __FILE__, __LINE__, __func__, c); \
+ }while(0)
+#define DPC(prompt, c) do{ printf("=Memblaze= %s[%d]-%s():%s=%c\n", __FILE__, __LINE__, __func__, \
+ prompt, c); }while(0)
+// address
+#define DA(add) do{ printf("=Memblaze= %s[%d]-%s():address=0x%08X\n", __FILE__, __LINE__, \
+ __func__, add); }while(0)
+#define DPA(prompt, add) do{ printf("=Memblaze= %s[%d]-%s():%s=0x%08X\n", __FILE__, __LINE__, __func__, \
+ prompt, add); }while(0)
+// string
+#define DS(str) do{ printf("=Memblaze= %s[%d]-%s():str=%s\n", __FILE__, __LINE__, __func__, str); \
+ }while(0)
+#define DPS(prompt, str) do{ printf("=Memblaze= %s[%d]-%s():%s=%s\n", __FILE__, __LINE__, __func__, \
+ prompt, str); }while(0)
+#define DAS(prompt, i, arr, max) do{ printf("=Memblaze= %s[%d]-%s():%s", __FILE__, __LINE__, __func__, prompt); \
+ for(i=0;i<max;i++) printf(" %d:%s", i, arr[i]); \
+ printf("\n"); }while(0)
+// array
+#define DR(str, k) do{ int ip; for(ip=0;ip<k;ip++) if(NULL != argv[ip]) \
+ printf("=Memblaze= %s[%d]-%s():%d=%s\n", \
+ __FILE__, __LINE__, __func__, ip, str[ip]); }while(0)
+#define DARG do{ DPI("argc", argc); \
+ int ip; for(ip=0;ip<argc;ip++) if(NULL != argv[ip]) \
+ printf("=Memblaze= %s[%d]-%s():%d=%s\n", \
+ __FILE__, __LINE__, __func__, ip, argv[ip]); }while(0)
+
+#define fPRINT_PARAM1(format) \
+ { \
+ do \
+ { \
+ fprintf(fdi, format);\
+ if (print) \
+ { \
+ printf(format); \
+ } \
+ } while (0); \
+ }
+
+#define fPRINT_PARAM2(format, value) \
+ { \
+ do \
+ { \
+ fprintf(fdi, format, value);\
+ if (print) \
+ { \
+ printf(format, value); \
+ } \
+ } while (0); \
+ }
+
#endif // __MEMBLAZE_UTILS_H__
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
index 165fcf0..f76c015 100644
--- a/plugins/micron/micron-nvme.c
+++ b/plugins/micron/micron-nvme.c
@@ -14,1167 +14,2332 @@
#include "nvme-ioctl.h"
#include <sys/ioctl.h>
#include <limits.h>
-
#define CREATE_CMD
#include "micron-nvme.h"
-#define min(x, y) ((x) > (y) ? (y) : (x))
-#define SensorCount 2
+
+/* Supported Vendor specific feature ids */
+#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS 0xC3
+#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xCE
+#define MICRON_FEATURE_TELEMETRY_CONTROL_OPTION 0xCF
+#define MICRON_FEATURE_SMBUS_OPTION 0xD5
+
+/* Supported Vendor specific log page sizes */
#define C5_log_size (((452 + 16 * 1024) / 4) * 4096)
-#define D0_log_size 256
+#define C0_log_size 512
+#define C2_log_size 4096
+#define D0_log_size 512
+#define FB_log_size 512
#define MaxLogChunk 16 * 1024
#define CommonChunkSize 16 * 4096
+#define min(x, y) ((x) > (y) ? (y) : (x))
+#define SensorCount 2
+
+/* 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";
+
+/* supported models of micron plugin; new models should be added at the end
+ * before UNKNOWN_MODEL. Make sure M5410 is first in the list !
+ */
+typedef enum { M5410 = 0, M51AX, M51BX, M51CX, M5407, M5411, UNKNOWN_MODEL } eDriveModel;
+
+#define MICRON_VENDOR_ID 0x1344
+
+static char *fvendorid1 = "/sys/class/nvme/nvme%d/device/vendor";
+static char *fvendorid2 = "/sys/class/misc/nvme%d/device/vendor";
+static char *fdeviceid1 = "/sys/class/nvme/nvme%d/device/device";
+static char *fdeviceid2 = "/sys/class/misc/nvme%d/device/device";
+static unsigned short vendor_id;
+static unsigned short device_id;
+
typedef struct _LogPageHeader_t {
- unsigned char numDwordsInLogPageHeaderLo;
- unsigned char logPageHeaderFormatVersion;
- unsigned char logPageId;
- unsigned char numDwordsInLogPageHeaderHi;
- unsigned int numValidDwordsInPayload;
- unsigned int numDwordsInEntireLogPage;
+ unsigned char numDwordsInLogPageHeaderLo;
+ unsigned char logPageHeaderFormatVersion;
+ unsigned char logPageId;
+ unsigned char numDwordsInLogPageHeaderHi;
+ unsigned int numValidDwordsInPayload;
+ unsigned int numDwordsInEntireLogPage;
} LogPageHeader_t;
-/*
- * Useful Helper functions
- */
+static void WriteData(__u8 *data, __u32 len, const char *dir, const char *file, const char *msg)
+{
+ char tempFolder[PATH_MAX] = { 0 };
+ FILE *fpOutFile = NULL;
+ sprintf(tempFolder, "%s/%s", dir, file);
+ if ((fpOutFile = fopen(tempFolder, "ab+")) != NULL) {
+ if (fwrite(data, 1, len, fpOutFile) != len) {
+ printf("Failed to write %s data to %s\n", msg, tempFolder);
+ }
+ fclose(fpOutFile);
+ } else {
+ printf("Failed to open %s file to write %s\n", tempFolder, msg);
+ }
+}
-static int micron_fw_commit(int fd, int select)
+static int ReadSysFile(const char *file, unsigned short *id)
{
- struct nvme_admin_cmd cmd = {
- .opcode = nvme_admin_activate_fw,
- .cdw10 = 8,
- .cdw12 = select,
- };
- return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ int ret = 0;
+ char idstr[32] = { '\0' };
+ int fd = open(file, O_RDONLY);
+
+ if (fd > 0) {
+ ret = read(fd, idstr, sizeof(idstr));
+ close(fd);
+ }
+
+ if (fd < 0 || ret < 0)
+ perror(file);
+ else
+ *id = strtol(idstr, NULL, 16);
+
+ return ret;
+}
+static eDriveModel GetDriveModel(int idx)
+{
+ eDriveModel eModel = UNKNOWN_MODEL;
+ char path[512];
+
+ sprintf(path, fvendorid1, idx);
+ if (ReadSysFile(path, &vendor_id) < 0) {
+ sprintf(path, fvendorid2, idx);
+ ReadSysFile(path, &vendor_id);
+ }
+ sprintf(path, fdeviceid1, idx);
+ if (ReadSysFile(path, &device_id) < 0) {
+ sprintf(path, fdeviceid2, idx);
+ ReadSysFile(path, &device_id);
+ }
+ if (vendor_id == MICRON_VENDOR_ID) {
+ switch (device_id) {
+ case 0x51A0:
+ case 0x51A1:
+ case 0x51A2:
+ eModel = M51AX;
+ break;
+ case 0x51B0:
+ case 0x51B1:
+ case 0x51B2:
+ eModel = M51BX;
+ break;
+ case 0x51C0:
+ case 0x51C1:
+ case 0x51C2:
+ case 0x51C3:
+ eModel = M51CX;
+ break;
+ case 0x5405:
+ case 0x5406:
+ case 0x5407:
+ eModel = M5407;
+ break;
+ case 0x5410:
+ eModel = M5410;
+ break;
+ case 0x5411:
+ eModel = M5411;
+ break;
+ default:
+ break;
+ }
+ }
+ return eModel;
}
static int ZipAndRemoveDir(char *strDirName, char *strFileName)
{
- int err = 0;
- char strBuffer[PATH_MAX];
- int nRet;
-
- sprintf(strBuffer, "zip -r \"%s\" \"%s\" >temp.txt 2>&1", strFileName,
- strDirName);
-
- nRet = system(strBuffer);
-
- if (nRet < 0) {
- printf("Unable to create zip package!\n");
- err = EINVAL;
- goto exit_status;
- }
-
- sprintf(strBuffer, "rm -f -R \"%s\" >temp.txt 2>&1", strDirName);
- nRet = system(strBuffer);
- if (nRet < 0) {
- printf("Unable to remove temporary files!\n");
- err = EINVAL;
- goto exit_status;
- }
-
- exit_status:
- err = system("rm -f temp.txt");
- return err;
+ int err = 0;
+ char strBuffer[PATH_MAX];
+ int nRet;
+ bool is_tgz = false;
+ struct stat sb;
+
+ if (strstr(strFileName, ".tar.gz") || strstr(strFileName, ".tgz")) {
+ sprintf(strBuffer, "tar -zcf \"%s\" \"%s\"", strFileName,
+ strDirName);
+ is_tgz = true;
+ } else {
+ sprintf(strBuffer, "zip -r \"%s\" \"%s\" >temp.txt 2>&1", strFileName,
+ strDirName);
+ }
+
+ err = EINVAL;
+ nRet = system(strBuffer);
+
+ /* check if log file is created, if not print error message */
+ if (nRet < 0 || (stat(strFileName, &sb) == -1)) {
+ if (is_tgz)
+ sprintf(strBuffer, "check if tar and gzip commands are installed");
+ else
+ sprintf(strBuffer, "check if zip command is installed");
+
+ fprintf(stderr, "Failed to create log data package, %s!\n", strBuffer);
+ }
+
+ sprintf(strBuffer, "rm -f -R \"%s\" >temp.txt 2>&1", strDirName);
+ nRet = system(strBuffer);
+ if (nRet < 0)
+ printf("Failed to remove temporary files!\n");
+
+ err = system("rm -f temp.txt");
+ return err;
}
static int SetupDebugDataDirectories(char *strSN, char *strFilePath,
- char *strMainDirName, char *strOSDirName,
- char *strCtrlDirName)
+ char *strMainDirName, char *strOSDirName,
+ char *strCtrlDirName)
{
- int err = 0;
- char strAppend[250];
- struct stat st;
- char *fileLocation = NULL;
- char *fileName;
- int length = 0;
- int nIndex = 0;
- char *strTemp = NULL;
- struct stat dirStat;
- int j;
- int k = 0;
- int i = 0;
-
- if (strchr(strFilePath, '/') != NULL) {
- fileName = strrchr(strFilePath, '\\');
- if (fileName == NULL) {
- fileName = strrchr(strFilePath, '/');
- }
-
- if (fileName != NULL) {
- if (!strcmp(fileName, "/")) {
- goto exit_status;
- }
-
- while (strFilePath[nIndex] != '\0') {
- if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) {
- goto exit_status;
- }
- nIndex++;
- }
-
- length = (int)strlen(strFilePath) - (int)strlen(fileName);
-
- if (fileName == strFilePath) {
- length = 1;
- }
-
- fileLocation = (char *)malloc(length + 1);
- strncpy(fileLocation, strFilePath, length);
- fileLocation[length] = '\0';
-
- while (fileLocation[k] != '\0') {
- if (fileLocation[k] == '\\') {
- fileLocation[k] = '/';
- }
- }
-
- length = (int)strlen(fileLocation);
-
- if (':' == fileLocation[length - 1]) {
- strTemp = (char *)malloc(length + 2);
- strcpy(strTemp, fileLocation);
- strcat(strTemp, "/");
- free(fileLocation);
-
- length = (int)strlen(strTemp);
- fileLocation = (char *)malloc(length + 1);
- memcpy(fileLocation, strTemp, length + 1);
- free(strTemp);
- }
-
- if (stat(fileLocation, &st) != 0) {
- free(fileLocation);
- goto exit_status;
- }
- free(fileLocation);
- } else {
- goto exit_status;
- }
- }
-
- nIndex = 0;
- for (i = 0; i < (int)strlen(strSN); i++) {
- if (strSN[i] != ' ' && strSN[i] != '\n' && strSN[i] != '\t' && strSN[i] != '\r') {
- strMainDirName[nIndex++] = strSN[i];
- }
- }
- strMainDirName[nIndex] = '\0';
-
- j = 1;
- while (stat(strMainDirName, &dirStat) == 0) {
- strMainDirName[nIndex] = '\0';
- sprintf(strAppend, "-%d", j);
- strcat(strMainDirName, strAppend);
- j++;
- }
-
- mkdir(strMainDirName, 0777);
-
- if (strOSDirName != NULL) {
- sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
- mkdir(strOSDirName, 0777);
-
- }
- if (strCtrlDirName != NULL) {
- sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller");
- mkdir(strCtrlDirName, 0777);
-
- }
-
- exit_status:
- return err;
+ int err = 0;
+ char strAppend[250];
+ struct stat st;
+ char *fileLocation = NULL;
+ char *fileName;
+ int length = 0;
+ int nIndex = 0;
+ char *strTemp = NULL;
+ struct stat dirStat;
+ int j;
+ int k = 0;
+ int i = 0;
+
+ if (strchr(strFilePath, '/') != NULL) {
+ fileName = strrchr(strFilePath, '\\');
+ if (fileName == NULL) {
+ fileName = strrchr(strFilePath, '/');
+ }
+
+ if (fileName != NULL) {
+ if (!strcmp(fileName, "/")) {
+ goto exit_status;
+ }
+
+ while (strFilePath[nIndex] != '\0') {
+ if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) {
+ goto exit_status;
+ }
+ nIndex++;
+ }
+
+ length = (int)strlen(strFilePath) - (int)strlen(fileName);
+
+ if (fileName == strFilePath) {
+ length = 1;
+ }
+
+ if ((fileLocation = (char *)malloc(length + 1)) == NULL) {
+ goto exit_status;
+ }
+ strncpy(fileLocation, strFilePath, length);
+ fileLocation[length] = '\0';
+
+ while (fileLocation[k] != '\0') {
+ if (fileLocation[k] == '\\') {
+ fileLocation[k] = '/';
+ }
+ k++;
+ }
+
+ length = (int)strlen(fileLocation);
+
+ if (':' == fileLocation[length - 1]) {
+ if ((strTemp = (char *)malloc(length + 2)) == NULL) {
+ goto exit_status;
+ }
+ strcpy(strTemp, fileLocation);
+ strcat(strTemp, "/");
+ free(fileLocation);
+
+ length = (int)strlen(strTemp);
+ if ((fileLocation = (char *)malloc(length + 1)) == NULL) {
+ goto exit_status;
+ }
+
+ memcpy(fileLocation, strTemp, length + 1);
+ free(strTemp);
+ }
+
+ if (stat(fileLocation, &st) != 0) {
+ free(fileLocation);
+ goto exit_status;
+ }
+ free(fileLocation);
+ } else {
+ goto exit_status;
+ }
+ }
+
+ nIndex = 0;
+ for (i = 0; i < (int)strlen(strSN); i++) {
+ if (strSN[i] != ' ' && strSN[i] != '\n' && strSN[i] != '\t' && strSN[i] != '\r') {
+ strMainDirName[nIndex++] = strSN[i];
+ }
+ }
+ strMainDirName[nIndex] = '\0';
+
+ j = 1;
+ while (stat(strMainDirName, &dirStat) == 0) {
+ strMainDirName[nIndex] = '\0';
+ sprintf(strAppend, "-%d", j);
+ strcat(strMainDirName, strAppend);
+ j++;
+ }
+
+ mkdir(strMainDirName, 0777);
+
+ if (strOSDirName != NULL) {
+ sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
+ mkdir(strOSDirName, 0777);
+
+ }
+ if (strCtrlDirName != NULL) {
+ sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller");
+ mkdir(strCtrlDirName, 0777);
+
+ }
+
+exit_status:
+ return err;
}
static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize)
{
- int err = 0;
- struct nvme_admin_cmd cmd;
- unsigned int uiXferDwords = 0;
- unsigned char pTmpBuf[CommonChunkSize] = { 0 };
- LogPageHeader_t *pLogHeader = NULL;
-
- if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) {
- cmd.opcode = 0x02;
- cmd.cdw10 = ucLogID;
- uiXferDwords = (unsigned int)(CommonChunkSize / 4);
- cmd.nsid = 0xFFFFFFFF;
- cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
- cmd.data_len = CommonChunkSize;
- cmd.addr = (__u64) (uintptr_t) & pTmpBuf;
- err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
- if (err == 0) {
- pLogHeader = (LogPageHeader_t *) pTmpBuf;
- LogPageHeader_t *pLogHeader1 = (LogPageHeader_t *) pLogHeader;
- *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4;
- } else {
- printf ("Getting size of log page : 0x%X failed with %d\n", ucLogID, err);
- *nLogSize = 0;
- }
- }
- return err;
+ int err = 0;
+ unsigned char pTmpBuf[CommonChunkSize] = { 0 };
+ LogPageHeader_t *pLogHeader = NULL;
+
+ if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) {
+ err = nvme_get_log(nFD, NVME_NSID_ALL, ucLogID, false, NVME_NO_LOG_LSP,
+ CommonChunkSize, pTmpBuf);
+ if (err == 0) {
+ pLogHeader = (LogPageHeader_t *) pTmpBuf;
+ LogPageHeader_t *pLogHeader1 = (LogPageHeader_t *) pLogHeader;
+ *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4;
+ if (pLogHeader1->logPageHeaderFormatVersion == 0) {
+ printf ("Unsupported log page format version %d of log page : 0x%X\n",
+ ucLogID, err);
+ *nLogSize = 0;
+ err = -1;
+ }
+ } else {
+ printf ("Getting size of log page : 0x%X failed with %d\n", ucLogID, err);
+ *nLogSize = 0;
+ }
+ }
+ return err;
}
static int NVMEGetLogPage(int nFD, unsigned char ucLogID, unsigned char *pBuffer, int nBuffSize)
{
- int err = 0;
- struct nvme_admin_cmd cmd = { 0 };
- unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int);
- unsigned int uiMaxChunk = uiNumDwords;
- unsigned int uiNumChunks = 1;
- unsigned int uiXferDwords = 0;
- unsigned long long ullBytesRead = 0;
- unsigned char *pTempPtr = pBuffer;
- unsigned char ucOpCode = 0x02;
-
- if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
- uiMaxChunk = 4096;
- } else if (uiMaxChunk > 16 * 1024) {
- uiMaxChunk = 16 * 1024;
- }
-
- uiNumChunks = uiNumDwords / uiMaxChunk;
- if (uiNumDwords % uiMaxChunk > 0) {
- uiNumChunks += 1;
- }
-
- for (unsigned int i = 0; i < uiNumChunks; i++) {
- memset(&cmd, 0, sizeof(cmd));
- uiXferDwords = uiMaxChunk;
- if (i == uiNumChunks - 1 && uiNumDwords % uiMaxChunk > 0) {
- uiXferDwords = uiNumDwords % uiMaxChunk;
- }
-
- cmd.opcode = ucOpCode;
- cmd.cdw10 |= ucLogID;
- cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
-
- if (ucLogID == 0x7) {
- cmd.cdw10 |= 0x80;
- }
- if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
- cmd.cdw11 = 1;
- }
- if (ullBytesRead > 0 && !(ucLogID == 0xE6 || ucLogID == 0xE7)) {
- unsigned long long ullOffset = ullBytesRead;
- cmd.cdw12 = ullOffset & 0xFFFFFFFF;
- cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
- }
-
- cmd.addr = (__u64) (uintptr_t) pTempPtr;
- cmd.nsid = 0xFFFFFFFF;
- cmd.data_len = uiXferDwords * 4;
- err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
- ullBytesRead += uiXferDwords * 4;
- pTempPtr = pBuffer + ullBytesRead;
- }
-
- return err;
+ int err = 0;
+ struct nvme_admin_cmd cmd = { 0 };
+ unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int);
+ unsigned int uiMaxChunk = uiNumDwords;
+ unsigned int uiNumChunks = 1;
+ unsigned int uiXferDwords = 0;
+ unsigned long long ullBytesRead = 0;
+ unsigned char *pTempPtr = pBuffer;
+ unsigned char ucOpCode = 0x02;
+
+ if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ uiMaxChunk = 4096;
+ } else if (uiMaxChunk > 16 * 1024) {
+ uiMaxChunk = 16 * 1024;
+ }
+
+ uiNumChunks = uiNumDwords / uiMaxChunk;
+ if (uiNumDwords % uiMaxChunk > 0) {
+ uiNumChunks += 1;
+ }
+
+ for (unsigned int i = 0; i < uiNumChunks; i++) {
+ memset(&cmd, 0, sizeof(cmd));
+ uiXferDwords = uiMaxChunk;
+ if (i == uiNumChunks - 1 && uiNumDwords % uiMaxChunk > 0) {
+ uiXferDwords = uiNumDwords % uiMaxChunk;
+ }
+
+ cmd.opcode = ucOpCode;
+ cmd.cdw10 |= ucLogID;
+ cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
+
+ if (ucLogID == 0x7) {
+ cmd.cdw10 |= 0x80;
+ }
+ if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ cmd.cdw11 = 1;
+ }
+ if (ullBytesRead > 0 && !(ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ unsigned long long ullOffset = ullBytesRead;
+ cmd.cdw12 = ullOffset & 0xFFFFFFFF;
+ cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
+ }
+
+ cmd.addr = (__u64) (uintptr_t) pTempPtr;
+ cmd.nsid = 0xFFFFFFFF;
+ cmd.data_len = uiXferDwords * 4;
+ err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
+ ullBytesRead += uiXferDwords * 4;
+ pTempPtr = pBuffer + ullBytesRead;
+ }
+
+ return err;
}
static int NVMEResetLog(int nFD, unsigned char ucLogID, int nBufferSize,
- long long llMaxSize)
+ long long llMaxSize)
{
- unsigned int *pBuffer = NULL;
- int err = 0;
+ unsigned int *pBuffer = NULL;
+ int err = 0;
- if ((pBuffer = (unsigned int *)calloc(1, nBufferSize)) == NULL)
- return err;
+ if ((pBuffer = (unsigned int *)calloc(1, nBufferSize)) == NULL)
+ return err;
- while (err == 0 && llMaxSize > 0) {
- err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize);
- if (err)
- return err;
+ while (err == 0 && llMaxSize > 0) {
+ err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize);
+ if (err)
+ return err;
- if (pBuffer[0] == 0xdeadbeef)
- break;
+ if (pBuffer[0] == 0xdeadbeef)
+ break;
- llMaxSize = llMaxSize - nBufferSize;
- }
+ llMaxSize = llMaxSize - nBufferSize;
+ }
- free(pBuffer);
- return err;
+ free(pBuffer);
+ return err;
}
-static int GetCommonLogPage(int nFD, unsigned char ucLogID, unsigned char **pBuffer, int nBuffSize)
+static int GetCommonLogPage(int nFD, unsigned char ucLogID,
+ unsigned char **pBuffer, int nBuffSize)
{
- struct nvme_admin_cmd cmd;
- int err = 0;
- unsigned char pTmpBuf[CommonChunkSize] = { 0 };
- unsigned int uiMaxChunk = 0;
- unsigned int uiXferDwords = 0;
- int nBytesRead = 0;
- unsigned char *pTempPtr = NULL;
-
- uiMaxChunk = CommonChunkSize / 4;
- pTempPtr = (unsigned char *)malloc(nBuffSize);
- if (!pTempPtr) {
- goto exit_status;
- }
- memset(pTempPtr, 0, nBuffSize);
-
- while (nBytesRead < nBuffSize) {
- int nBytesRemaining = nBuffSize - nBytesRead;
-
- memset(pTmpBuf, 0, CommonChunkSize);
-
- uiXferDwords = uiMaxChunk;
- memset(&cmd, 0, sizeof(cmd));
- cmd.opcode = 0x02;
- cmd.cdw10 |= ucLogID;
- cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
-
- if (nBytesRead > 0) {
- unsigned long long ullOffset = (unsigned long long)nBytesRead;
- cmd.cdw12 = ullOffset & 0xFFFFFFFF;
- cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
- }
- cmd.nsid = 0xFFFFFFFF;
- cmd.data_len = uiXferDwords * 4;
- cmd.addr = (__u64) (uintptr_t) pTmpBuf;
-
- err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
-
- if (nBytesRemaining >= (int)(uiMaxChunk * 4)) {
- memcpy(&pTempPtr[nBytesRead], pTmpBuf, uiMaxChunk * 4);
- } else {
- memcpy(&pTempPtr[nBytesRead], pTmpBuf, nBytesRemaining);
- }
-
- nBytesRead += (int)uiXferDwords *4;
- }
- *pBuffer = pTempPtr;
-
- exit_status:
- return err;
+ unsigned char *pTempPtr = NULL;
+ int err = 0;
+ pTempPtr = (unsigned char *)malloc(nBuffSize);
+ if (!pTempPtr) {
+ goto exit_status;
+ }
+ memset(pTempPtr, 0, nBuffSize);
+ err = nvme_get_log(nFD, NVME_NSID_ALL, ucLogID, false, NVME_NO_LOG_LSP,
+ nBuffSize, pTempPtr);
+ *pBuffer = pTempPtr;
+
+exit_status:
+ return err;
}
/*
* Plugin Commands
*/
+static int micron_parse_options(int argc, char **argv, const char *desc,
+ const struct argconfig_commandline_options *opts, eDriveModel *modelp)
+{
+ int idx = 0;
+ int fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0) {
+ perror("open");
+ return -1;
+ }
+
+ if (modelp) {
+ sscanf(argv[optind], "/dev/nvme%d", &idx);
+ *modelp = GetDriveModel(idx);
+ }
+
+ return fd;
+}
-static int micron_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int micron_fw_commit(int fd, int select)
{
- const char *desc =
- "This performs a selective firmware download, which allows the user to "
- "select which firmware binary to update for 9200 devices. This requires a power cycle once the "
- "update completes. The options available are: \n\n"
- "OOB - This updates the OOB and main firmware\n"
- "EEP - This updates the eeprom and main firmware\n"
- "ALL - This updates the eeprom, OOB, and main firmware";
- const char *fw = "firmware file (required)";
- const char *select = "FW Select (e.g., --select=ALL)";
- int xfer = 4096;
- void *fw_buf;
- int fd, selectNo, fw_fd, fw_size, err, offset = 0;
- struct stat sb;
-
- struct config {
- char *fw;
- char *select;
- };
-
- struct config cfg = {
- .fw = "",
- .select = "\0",
- };
-
- OPT_ARGS(opts) = {
- OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw),
- OPT_STRING("select", 's', "flag", &cfg.select, select),
- OPT_END()
- };
-
- fd = parse_and_open(argc, argv, desc, opts);
-
- if (fd < 0)
- return fd;
-
- if (strlen(cfg.select) != 3) {
- fprintf(stderr, "Invalid select flag\n");
- err = EINVAL;
- goto out;
- }
-
- for (int i = 0; i < 3; i++) {
- cfg.select[i] = toupper(cfg.select[i]);
- }
-
- if (strncmp(cfg.select, "OOB", 3) == 0) {
- selectNo = 18;
- } else if (strncmp(cfg.select, "EEP", 3) == 0) {
- selectNo = 10;
- } else if (strncmp(cfg.select, "ALL", 3) == 0) {
- selectNo = 26;
- } else {
- fprintf(stderr, "Invalid select flag\n");
- err = EINVAL;
- goto out;
- }
-
- fw_fd = open(cfg.fw, O_RDONLY);
- if (fw_fd < 0) {
- fprintf(stderr, "no firmware file provided\n");
- err = EINVAL;
- goto out;
- }
-
- err = fstat(fw_fd, &sb);
- if (err < 0) {
- perror("fstat");
- err = errno;
- }
-
- fw_size = sb.st_size;
- if (fw_size & 0x3) {
- fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
- err = EINVAL;
- goto out;
- }
-
- if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
- fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
- err = ENOMEM;
- goto out;
- }
-
- if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size)))
- return EIO;
-
- while (fw_size > 0) {
- xfer = min(xfer, fw_size);
-
- err = nvme_fw_download(fd, offset, xfer, fw_buf);
- if (err < 0) {
- perror("fw-download");
- goto out;
- } else if (err != 0) {
- fprintf(stderr, "NVME Admin command error:%s(%x)\n",
- nvme_status_to_string(err), err);
- goto out;
- }
- fw_buf += xfer;
- fw_size -= xfer;
- offset += xfer;
- }
-
- err = micron_fw_commit(fd, selectNo);
-
- if (err == 0x10B || err == 0x20B) {
- err = 0;
- fprintf(stderr,
- "Update successful! Please power cycle for changes to take effect\n");
- }
-
- out:
- return err;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_activate_fw,
+ .cdw10 = 8,
+ .cdw12 = select,
+ };
+ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
}
-static int micron_temp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int micron_selective_download(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
{
+ const char *desc =
+ "This performs a selective firmware download, which allows the user to "
+ "select which firmware binary to update for 9200 devices. This requires "
+ "a power cycle once the update completes. The options available are: \n\n"
+ "OOB - This updates the OOB and main firmware\n"
+ "EEP - This updates the eeprom and main firmware\n"
+ "ALL - This updates the eeprom, OOB, and main firmware";
+ const char *fw = "firmware file (required)";
+ const char *select = "FW Select (e.g., --select=ALL)";
+ int xfer = 4096;
+ void *fw_buf;
+ int fd, selectNo, fw_fd, fw_size, err, offset = 0;
+ struct stat sb;
+
+ struct config {
+ char *fw;
+ char *select;
+ };
+
+ struct config cfg = {
+ .fw = "",
+ .select = "\0",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw),
+ OPT_STRING("select", 's', "flag", &cfg.select, select),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ return fd;
+
+ if (strlen(cfg.select) != 3) {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ cfg.select[i] = toupper(cfg.select[i]);
+ }
+
+ if (strncmp(cfg.select, "OOB", 3) == 0) {
+ selectNo = 18;
+ } else if (strncmp(cfg.select, "EEP", 3) == 0) {
+ selectNo = 10;
+ } else if (strncmp(cfg.select, "ALL", 3) == 0) {
+ selectNo = 26;
+ } else {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ if (fw_fd < 0) {
+ fprintf(stderr, "no firmware file provided\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ err = errno;
+ }
+
+ fw_size = sb.st_size;
+ if (fw_size & 0x3) {
+ fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
+ fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ err = ENOMEM;
+ goto out;
+ }
+
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size)))
+ return EIO;
+
+ while (fw_size > 0) {
+ xfer = min(xfer, fw_size);
+
+ err = nvme_fw_download(fd, offset, xfer, fw_buf);
+ if (err < 0) {
+ perror("fw-download");
+ goto out;
+ } else if (err != 0) {
+ fprintf(stderr, "NVME Admin command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ goto out;
+ }
+ fw_buf += xfer;
+ fw_size -= xfer;
+ offset += xfer;
+ }
+
+ err = micron_fw_commit(fd, selectNo);
+
+ if (err == 0x10B || err == 0x20B) {
+ err = 0;
+ fprintf(stderr,
+ "Update successful! Power cycle for changes to take effect\n");
+ }
+
+out:
+ return err;
+}
- struct nvme_smart_log smart_log;
- unsigned int temperature = 0, i = 0, fd = 0, err = 0;
- unsigned int tempSensors[SensorCount] = { 0 };
- const char *desc = "Retrieve Micron temperature info for the given device ";
-
- OPT_ARGS(opts) = {
- OPT_END()
- };
-
- fd = parse_and_open(argc, argv, desc, opts);
- if (fd < 0) {
- printf("\nDevice not found \n");;
- return -1;
- }
-
- err = nvme_smart_log(fd, 0xffffffff, &smart_log);
- if (!err) {
- printf("Micron temperature information:\n");
- temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
- temperature = temperature ? temperature - 273 : 0;
- for (i = 0; i < SensorCount; i++) {
- tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
- tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
- }
- printf("%-10s : %u C\n", "Current Composite Temperature", temperature);
- for (i = 0; i < SensorCount; i++) {
- printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
- }
- }
- return err;
+static int micron_smbus_option(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ __u32 result = 0;
+ __u32 cdw10 = 0;
+ __u32 cdw11 = 0;
+ const char *desc = "Enable/Disable/Get status of SMBUS option on controller";
+ const char *option = "enable or disable or status";
+ const char *value = "1 - hottest component temperature, 0 - composite "
+ "temperature (default) for enable option, 0 (current), "
+ "1 (default), 2 (saved) for status options";
+ const char *save = "1 - persistent, 0 - non-persistent (default)";
+ int err = 0;
+ int fd = 0;
+ int fid = MICRON_FEATURE_SMBUS_OPTION;
+ eDriveModel model = UNKNOWN_MODEL;
+
+ struct {
+ char *option;
+ int value;
+ int save;
+ int status;
+ } opt = {
+ .option = "disable",
+ .value = 0,
+ .save = 0,
+ .status = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("option", 'o', "option", &opt.option, option),
+ OPT_UINT("value", 'v', &opt.value, value),
+ OPT_UINT("save", 's', &opt.save, save),
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0)
+ return err;
+
+ if (model != M5407 && model != M5411) {
+ printf ("This option is not supported for specified drive\n");
+ close(fd);
+ return err;
+ }
+
+ if (!strcmp(opt.option, "enable")) {
+ cdw11 = opt.value << 1 | 1;
+ err = nvme_set_feature(fd, 1, fid, cdw11, 0, opt.save, 0, 0, &result);
+ if (err == 0) {
+ printf("successfully enabled SMBus on drive\n");
+ } else {
+ printf("Failed to enabled SMBus on drive\n");
+ }
+ }
+ else if (!strcmp(opt.option, "status")) {
+ cdw10 = opt.value;
+ err = nvme_get_feature(fd, 1, fid, cdw10, 0, 0, 0, &result);
+ if (err == 0) {
+ printf("SMBus status on the drive: %s (returns %s temperature) \n",
+ (result & 1) ? "enabled" : "disabled",
+ (result & 2) ? "hottest component" : "composite");
+ } else {
+ printf("Failed to retrieve SMBus status on the drive\n");
+ }
+ }
+ 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);
+ if (err == 0) {
+ printf("Successfully disabled SMBus on drive\n");
+ } else {
+ printf("Failed to disable SMBus on drive\n");
+ }
+ } else {
+ printf("Invalid option %s, valid values are enable, disable or status\n",
+ opt.option);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return err;
}
-static int micron_pcie_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int micron_temp_stats(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
{
- int err = 0, bus = 0, domain = 0, device = 0, function = 0;
- char strTempFile[1024], strTempFile2[1024], command[1024];
- char *businfo = NULL;
- char *devicename = NULL;
- char tdevice[NAME_MAX] = { 0 };
- ssize_t sLinkSize = 0;
- FILE *fp;
- char correctable[8] = { 0 };
- char uncorrectable[8] = { 0 };
- char *res;
-
- if (argc != 2) {
- printf("vs-pcie-stats: Invalid argument\n");
- printf("Usage: nvme micron vs-pcie-stats <device>\n\n");
- goto out;
- }
- if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
- devicename = strrchr(argv[optind], '/');
- } else if (strstr(argv[optind], "/dev/nvme")) {
- devicename = strrchr(argv[optind], '/');
- sprintf(tdevice, "%s%s", devicename, "n1");
- devicename = tdevice;
- } else {
- printf("Invalid device specified!\n");
- goto out;
- }
- sprintf(strTempFile, "/sys/block/%s/device", devicename);
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
- if (sLinkSize < 0) {
- printf("Unable to read device\n");
- goto out;
- }
- if (strstr(strTempFile2, "../../nvme")) {
- sprintf(strTempFile, "/sys/block/%s/device/device", devicename);
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
- if (sLinkSize < 0) {
- printf("Unable to read device\n");
- goto out;
- }
- }
- businfo = strrchr(strTempFile2, '/');
- sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
- sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device,
- function);
- fp = popen(command, "r");
- if (fp == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- res = fgets(correctable, sizeof(correctable), fp);
- if (res == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- pclose(fp);
-
- sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device,
- function);
- fp = popen(command, "r");
- if (fp == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- res = fgets(uncorrectable, sizeof(uncorrectable), fp);
- if (res == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- pclose(fp);
- printf("PCIE Stats:\n");
- printf("Device correctable errors detected: %s\n", correctable);
- printf("Device uncorrectable errors detected: %s\n", uncorrectable);
-
- out:
- return err;
+
+ struct nvme_smart_log smart_log;
+ unsigned int temperature = 0, i = 0, err = 0;
+ unsigned int tempSensors[SensorCount] = { 0 };
+ const char *desc = "Retrieve Micron temperature info for the given device ";
+ const char *fmt = "output format normal|json";
+ struct format {
+ char *fmt;
+ };
+ struct format cfg = {
+ .fmt = "normal",
+ };
+ bool is_json = false;
+ struct json_object *root;
+ struct json_object *logPages;
+ int fd;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ if (strcmp(cfg.fmt, "json") == 0)
+ is_json = true;
+
+ err = nvme_smart_log(fd, 0xffffffff, &smart_log);
+ if (!err) {
+ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
+ temperature = temperature ? temperature - 273 : 0;
+ for (i = 0; i < SensorCount; i++) {
+ tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
+ tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
+ }
+ if (is_json) {
+ struct json_object *stats = json_create_object();
+ char tempstr[64] = { 0 };
+ root = json_create_object();
+ logPages = json_create_array();
+ json_object_add_value_array(root, "Micron temperature information", logPages);
+ sprintf(tempstr, "%u C", temperature);
+ json_object_add_value_string(stats, "Current Composite Temperature", tempstr);
+ for (i = 0; i < SensorCount; i++) {
+ char sensor_str[256] = { 0 };
+ char datastr[64] = { 0 };
+ sprintf(sensor_str, "Temperature Sensor #%d", (i + 1));
+ sprintf(datastr, "%u C", tempSensors[i]);
+ json_object_add_value_string(stats, sensor_str, datastr);
+ }
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ printf("Micron temperature information:\n");
+ printf("%-10s : %u C\n", "Current Composite Temperature", temperature);
+ for (i = 0; i < SensorCount; i++) {
+ printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
+ }
+ }
+ }
+ return err;
}
-static int micron_clear_pcie_correctable_errors(int argc, char **argv,
- struct command *cmd,
- struct plugin *plugin)
+static int micron_pcie_stats(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
{
- int err = 0, bus = 0, domain = 0, device = 0, function = 0;
- char strTempFile[1024], strTempFile2[1024], command[1024];
- char *businfo = NULL;
- char *devicename = NULL;
- char tdevice[PATH_MAX] = { 0 };
- ssize_t sLinkSize = 0;
- FILE *fp;
- char correctable[8] = { 0 };
- char *res;
-
- if (argc != 2) {
- printf("clear-pcie-correctable-errors: Invalid argument\n");
- printf ("Usage: nvme micron clear-pcie-correctable-errors <device>\n\n");
- goto out;
- }
- if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
- devicename = strrchr(argv[optind], '/');
- } else if (strstr(argv[optind], "/dev/nvme")) {
- devicename = strrchr(argv[optind], '/');
- sprintf(tdevice, "%s%s", devicename, "n1");
- devicename = tdevice;
- } else {
- printf("Invalid device specified!\n");
- goto out;
- }
- err = snprintf(strTempFile, sizeof(strTempFile),
- "/sys/block/%s/device", devicename);
- if (err < 0)
- goto out;
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
- if (sLinkSize < 0) {
- printf("Unable to read device\n");
- goto out;
- }
- if (strstr(strTempFile2, "../../nvme")) {
- err = snprintf(strTempFile, sizeof(strTempFile),
- "/sys/block/%s/device/device", devicename);
- if (err < 0)
- goto out;
- sLinkSize = readlink(strTempFile, strTempFile2, 1024);
- if (sLinkSize < 0) {
- printf("Unable to read device\n");
- goto out;
- }
- }
- businfo = strrchr(strTempFile2, '/');
- sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
- sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus,
- device, function);
-
- fp = popen(command, "r");
- if (fp == NULL) {
- printf("Unable to clear error count\n");
- goto out;
- }
- pclose(fp);
-
- sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L", bus, device,
- function);
- fp = popen(command, "r");
- if (fp == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- res = fgets(correctable, sizeof(correctable), fp);
- if (res == NULL) {
- printf("Unable to retrieve error count\n");
- goto out;
- }
- pclose(fp);
- printf("Device correctable errors cleared!\n");
- printf("Device correctable errors detected: %s\n", correctable);
-
- out:
- return err;
+ int i, fd, err = 0, bus = 0, domain = 0, device = 0, function = 0, ctrlIdx;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ char *businfo = NULL;
+ char *devicename = NULL;
+ char tdevice[NAME_MAX] = { 0 };
+ ssize_t sLinkSize = 0;
+ FILE *fp;
+ char correctable[8] = { 0 };
+ char uncorrectable[8] = { 0 };
+ eDriveModel eModel = UNKNOWN_MODEL;
+ char *res;
+ bool is_json = true;
+ struct format {
+ char *fmt;
+ };
+ const char *desc = "Retrieve PCIe event counters";
+ const char *fmt = "output format json|normal";
+ struct format cfg = {
+ .fmt = "json",
+ };
+ struct {
+ char *err;
+ int bit;
+ int val;
+ } pcie_correctable_errors[] = {
+ { "Unsupported Request Error Status (URES)", 20},
+ { "ECRC Error Status (ECRCES)", 19},
+ { "Malformed TLP Status (MTS)", 18},
+ { "Receiver Overflow Status (ROS)", 17},
+ { "Unexpected Completion Status (UCS)", 16},
+ { "Completer Abort Status (CAS)", 15},
+ { "Completion Timeout Stats (CTS)", 14},
+ { "Flow Control Protocol Error Status (FCPES)", 13},
+ { "Poisoned TLP Status (PTS)", 12},
+ { "Data Link Protocol Error Status (DLPES)", 4},
+ },
+ pcie_uncorrectable_errors[] = {
+ { "Advisory Non-Fatal Error Status (ANFES)", 13},
+ { "Replay Timer Timeout Status (RTS)", 12},
+ { "REPLY NUM Rollover Status (RRS)", 8},
+ { "Bad DLLP Status (BDS)", 7},
+ { "Bad TLP Status (BTS)", 6},
+ { "Receiver Error Status (RES)", 0},
+ };
+
+ __u32 correctable_errors;
+ __u32 uncorrectable_errors;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ /* 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-pcie-stats command\n");
+ close(fd);
+ goto out;
+ }
+
+ if (strcmp(cfg.fmt, "normal") == 0)
+ is_json = false;
+
+ if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
+ devicename = strrchr(argv[optind], '/');
+ } else if (strstr(argv[optind], "/dev/nvme")) {
+ devicename = strrchr(argv[optind], '/');
+ sprintf(tdevice, "%s%s", devicename, "n1");
+ devicename = tdevice;
+ } else {
+ printf("Invalid device specified!\n");
+ goto out;
+ }
+ sprintf(strTempFile, "/sys/block/%s/device", devicename);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ if (strstr(strTempFile2, "../../nvme")) {
+ sprintf(strTempFile, "/sys/block/%s/device/device", devicename);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (res == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(uncorrectable, sizeof(uncorrectable), fp);
+ if (res == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+
+ correctable_errors = (__u32)strtol(correctable, NULL, 16);
+ uncorrectable_errors = (__u32)strtol(uncorrectable, NULL, 16);
+
+ if (is_json) {
+
+ struct json_object *root = json_create_object();
+ struct json_object *pcieErrors = json_create_array();
+ struct json_object *stats = json_create_object();
+
+ json_object_add_value_array(root, "PCIE Stats", pcieErrors);
+ for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) {
+ json_object_add_value_int(stats, pcie_correctable_errors[i].err,
+ ((correctable_errors >> pcie_correctable_errors[i].bit) & 1));
+ }
+ for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) {
+ json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err,
+ ((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1));
+ }
+ json_array_add_value_object(pcieErrors, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else if (eModel == M5407 || eModel == M5410) {
+ for (i = 0; i < sizeof(pcie_correctable_errors) / sizeof(pcie_correctable_errors[0]); i++) {
+ printf("%-40s : %-1d\n", pcie_correctable_errors[i].err,
+ ((correctable_errors >> pcie_correctable_errors[i].bit) & 1));
+ }
+ for (i = 0; i < sizeof(pcie_uncorrectable_errors) / sizeof(pcie_uncorrectable_errors[0]); i++) {
+ printf("%-40s : %-1d\n", pcie_uncorrectable_errors[i].err,
+ ((uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1));
+ }
+ } else {
+ printf("PCIE Stats:\n");
+ printf("Device correctable errors detected: %s\n", correctable);
+ printf("Device uncorrectable errors detected: %s\n", uncorrectable);
+ }
+
+out:
+ return err;
}
-static int micron_nand_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+static int micron_clear_pcie_correctable_errors(int argc, char **argv,
+ struct command *cmd,
+ struct plugin *plugin)
{
- const char *desc = "Retrieve Micron NAND stats for the given device ";
- unsigned int extSmartLog[64] = { 0 };
- struct nvme_id_ctrl ctrl;
- int fd, err;
-
- OPT_ARGS(opts) = {
- OPT_END()
- };
-
- fd = parse_and_open(argc, argv, desc, opts);
- if (fd < 0) {
- printf("\nDevice not found \n");;
- return -1;
- }
-
- err = nvme_identify_ctrl(fd, &ctrl);
- if (err)
- goto out;
-
- err = NVMEGetLogPage(fd, 0xD0, (unsigned char *)extSmartLog, D0_log_size);
- if (err)
- goto out;
-
- unsigned long long count = ((unsigned long long)extSmartLog[45] << 32) | extSmartLog[44];
- printf("%-40s : 0x%llx\n", "NAND Writes (Bytes Written)", count);
- printf("%-40s : ", "Program Failure Count");
-
- unsigned long long count_hi = ((unsigned long long)extSmartLog[39] << 32) | extSmartLog[38];
- unsigned long long count_lo = ((unsigned long long)extSmartLog[37] << 32) | extSmartLog[36];
- if (count_hi != 0)
- printf("0x%llx%016llx", count_hi, count_lo);
- else
- printf("0x%llx\n", count_lo);
-
- count = ((unsigned long long)extSmartLog[25] << 32) | extSmartLog[24];
- printf("%-40s : 0x%llx\n", "Erase Failures", count);
- printf("%-40s : 0x%x\n", "Bad Block Count", extSmartLog[3]);
-
- count = (unsigned long long)extSmartLog[3] - (count_lo + count);
- printf("%-40s : 0x%llx\n", "NAND XOR/RAID Recovery Trigger Events", count);
- printf("%-40s : 0x%x\n", "NSZE Change Supported", (ctrl.oacs >> 3) & 0x1);
- printf("%-40s : 0x%x\n", "Number of NSZE Modifications", extSmartLog[1]);
- out:
- close(fd);
- return err;
+ int err = -EINVAL, bus = 0, domain = 0, device = 0, function = 0;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ char *businfo = NULL;
+ char *devicename = NULL;
+ char tdevice[PATH_MAX] = { 0 };
+ ssize_t sLinkSize = 0;
+ eDriveModel model = UNKNOWN_MODEL;
+ char correctable[8] = { 0 };
+ int fd = -1;
+ FILE *fp;
+ char *res;
+ const char *desc = "Clear PCIe Device Correctable Errors";
+ __u32 result = 0;
+ __u8 fid = MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS;
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0)
+ return err;
+
+ /* 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);
+ if (err == 0 && (err = (int)result) == 0)
+ printf("Device correctable errors cleared!\n");
+ else
+ printf("Error clearing Device correctable errors = 0x%x\n", err);
+ goto out;
+ }
+
+ if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
+ devicename = strrchr(argv[optind], '/');
+ } else if (strstr(argv[optind], "/dev/nvme")) {
+ devicename = strrchr(argv[optind], '/');
+ sprintf(tdevice, "%s%s", devicename, "n1");
+ devicename = tdevice;
+ } else {
+ printf("Invalid device specified!\n");
+ goto out;
+ }
+ err = snprintf(strTempFile, sizeof(strTempFile),
+ "/sys/block/%s/device", devicename);
+ if (err < 0)
+ goto out;
+
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ if (strstr(strTempFile2, "../../nvme")) {
+ err = snprintf(strTempFile, sizeof(strTempFile),
+ "/sys/block/%s/device/device", devicename);
+ if (err < 0)
+ goto out;
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus,
+ device, function);
+ err = -1;
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Failed to clear error count\n");
+ goto out;
+ }
+ pclose(fp);
+
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (res == NULL) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+ printf("Device correctable errors cleared!\n");
+ printf("Device correctable errors detected: %s\n", correctable);
+ err = 0;
+out:
+ if (fd > 0)
+ close(fd);
+ return err;
}
-typedef enum { M5410 = 0, M51AX, M51BX, UNKNOWN_MODEL } eDriveModel;
+static struct logpage {
+ const char *field;
+ char datastr[128];
+} d0_log_page[] = {
+ { "NAND Writes (Bytes Written)", { 0 }},
+ { "Program Failure Count", { 0 }},
+ { "Erase Failures", { 0 }},
+ { "Bad Block Count", { 0 }},
+ { "NAND XOR/RAID Recovery Trigger Events", { 0 }},
+ { "NSZE Change Supported", { 0 }},
+ { "Number of NSZE Modifications", { 0 }}
+};
+
+static void init_d0_log_page(__u8 *buf, __u8 nsze)
+{
+ unsigned int logD0[D0_log_size/sizeof(int)] = { 0 };
+ __u64 count_lo, count_hi, count;
-static char *fvendorid1 = "/sys/class/nvme/nvme%d/device/vendor";
-static char *fvendorid2 = "/sys/class/misc/nvme%d/device/vendor";
-static char *fdeviceid1 = "/sys/class/nvme/nvme%d/device/device";
-static char *fdeviceid2 = "/sys/class/misc/nvme%d/device/device";
-static unsigned short vendor_id;
-static unsigned short device_id;
+ memcpy(logD0, buf, sizeof(logD0));
-static int ReadSysFile(const char *file, unsigned short *id)
+
+ count = ((__u64)logD0[45] << 32) | logD0[44];
+ sprintf(d0_log_page[0].datastr, "0x%"PRIx64, le64_to_cpu(count));
+
+ count_hi = ((__u64)logD0[39] << 32) | logD0[38];
+ count_lo = ((__u64)logD0[37] << 32) | logD0[36];
+ if (count_hi != 0)
+ sprintf(d0_log_page[1].datastr, "0x%"PRIx64"%016"PRIx64,
+ le64_to_cpu(count_hi), le64_to_cpu(count_lo));
+ else
+ sprintf(d0_log_page[1].datastr, "0x%"PRIx64, le64_to_cpu(count_lo));
+
+ count = ((__u64)logD0[25] << 32) | logD0[24];
+ sprintf(d0_log_page[2].datastr, "0x%"PRIx64, le64_to_cpu(count));
+
+ sprintf(d0_log_page[3].datastr, "0x%x", logD0[3]);
+
+ count_lo = ((__u64)logD0[37] << 32) | logD0[36];
+ count = ((__u64)logD0[25] << 32) | logD0[24];
+ count = (__u64)logD0[3] - (count_lo + count);
+ sprintf(d0_log_page[4].datastr, "0x%"PRIx64, le64_to_cpu(count));
+
+ sprintf(d0_log_page[5].datastr, "0x%x", nsze);
+ sprintf(d0_log_page[6].datastr, "0x%x", logD0[1]);
+}
+
+/* OCP and Vendor specific log data format */
+struct micron_vs_logpage {
+ char *field;
+ int size;
+}
+/* Smart Health Log information as per OCP spec */
+ocp_c0_log_page[] = {
+ { "Physical Media Units Written", 16 },
+ { "Physical Media Units Read", 16 },
+ { "Raw Bad User NAND Block Count", 6},
+ { "Normalized Bad User NAND Block Count", 2},
+ { "Raw Bad System NAND Block Count", 6},
+ { "Normalized Bad System NAND Block Count", 2},
+ { "XOR Recovery Count", 8},
+ { "Uncorrectable Read Error Count", 8},
+ { "Soft ECC Error Count", 8},
+ { "SSD End to End Detected Counts", 4},
+ { "SSD End to End Corrected Errors", 4},
+ { "System data % life-used", 1},
+ { "Refresh Count", 7},
+ { "Maximum User Data Erase Count", 4},
+ { "Minimum User Data Erase Count", 4},
+ { "Thermal Throttling Count", 1},
+ { "Thermal Throttling Status", 1},
+ { "Reserved", 6},
+ { "PCIe Correctable Error count", 8},
+ { "Incomplete Shutdowns", 4},
+ { "Reserved", 4},
+ { "% Free Blocks", 1},
+ { "Reserved", 7},
+ { "Capacitor Health", 2},
+ { "Reserved", 6},
+ { "Unaligned I/O", 8},
+ { "Security Version Number", 8},
+ { "NUSE", 8},
+ { "PLP Start Count", 16},
+ { "Endurance Estimate", 16},
+ { "Reserved", 302},
+ { "Log Page Version", 2},
+ { "Log Page GUID", 16},
+},
+/* 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}
+};
+
+/* Common function to print Micron VS log pages */
+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 */
+)
{
- int ret = 0;
- char idstr[32] = { '\0' };
- int fd = open(file, O_RDONLY);
+ __u64 lval_lo, lval_hi;
+ __u32 ival;
+ __u16 sval;
+ __u8 cval, lval[8] = { 0 };
+ int field, guid_index;
+ 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]);
+ } else {
+ lval_lo = *((__u64 *)(&buf[offset]));
+ lval_hi = *((__u64 *)(&buf[offset + 8]));
+ if (lval_hi)
+ sprintf(datastr, "0x%"PRIx64"_%"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) {
+ lval_lo = *((__u64 *)(&buf[offset]));
+ sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
+ } else if (log_page[field].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) {
+ 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) {
+ ival = *((__u32 *)(&buf[offset]));
+ sprintf(datastr, "0x%x", le32_to_cpu(ival));
+ } else if (log_page[field].size == 2) {
+ sval = *((__u16 *)(&buf[offset]));
+ sprintf(datastr, "0x%04x", le16_to_cpu(sval));
+ } else if (log_page[field].size == 1) {
+ cval = buf[offset];
+ sprintf(datastr, "0x%02x", cval);
+ } else {
+ sprintf(datastr, "0");
+ }
+ offset += log_page[field].size;
+ /* do not print reserved values */
+ if (strstr(log_page[field].field, "Reserved"))
+ continue;
+ if (stats != NULL) {
+ json_object_add_value_string(stats, log_page[field].field, datastr);
+ } else {
+ printf("%-40s : %-4s\n", log_page[field].field, datastr);
+ }
+ }
+}
- if (fd > 0) {
- ret = read(fd, idstr, sizeof(idstr));
- close(fd);
- }
+static void print_smart_cloud_health_log(__u8 *buf, bool is_json)
+{
+ struct json_object *root;
+ struct json_object *logPages;
+ struct json_object *stats = NULL;
+ int field_count = sizeof(ocp_c0_log_page)/sizeof(ocp_c0_log_page[0]);
+
+ if (is_json) {
+ root = json_create_object();
+ stats = json_create_object();
+ logPages = json_create_array();
+ json_object_add_value_array(root, "OCP SMART Cloud Health Log: 0xC0",
+ logPages);
+ }
+
+ print_micron_vs_logs(buf, ocp_c0_log_page, field_count, stats);
+
+ if (is_json) {
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
- if (fd < 0 || ret < 0)
- perror(file);
- else
- *id = strtol(idstr, NULL, 16);
+static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json)
+{
+ struct json_object *root;
+ struct json_object *logPages;
+ struct json_object *stats = NULL;
+ int field_count = sizeof(fb_log_page)/sizeof(fb_log_page[0]);
+
+ if (is_json) {
+ root = json_create_object();
+ stats = json_create_object();
+ logPages = json_create_array();
+ json_object_add_value_array(root, "Extended Smart Log Page : 0xFB",
+ logPages);
+ }
+
+ print_micron_vs_logs(buf, fb_log_page, field_count, stats);
+
+ /* print last three entries from D0 log page */
+ 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) {
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
- return ret;
+static void print_nand_stats_d0(__u8 *buf, __u8 oacs, bool is_json)
+{
+ init_d0_log_page(buf, oacs);
+
+ if (is_json) {
+ struct json_object *root = json_create_object();
+ struct json_object *stats = json_create_object();
+ struct json_object *logPages = json_create_array();
+
+ json_object_add_value_array(root,
+ "Extended Smart Log Page : 0xD0",
+ logPages);
+
+ for (int i = 0; i < 7; i++) {
+ json_object_add_value_string(stats,
+ d0_log_page[i].field,
+ d0_log_page[i].datastr);
+ }
+
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ for (int i = 0; i < 7; i++) {
+ printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr);
+ }
+ }
}
-static eDriveModel GetDriveModel(int idx)
+static bool nsze_from_oacs = false; /* read nsze for now from idd[4059] */
+
+static int micron_nand_stats(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
{
- eDriveModel eModel = UNKNOWN_MODEL;
- char path[512];
-
- sprintf(path, fvendorid1, idx);
- if (ReadSysFile(path, &vendor_id) < 0) {
- sprintf(path, fvendorid2, idx);
- ReadSysFile(path, &vendor_id);
- }
- sprintf(path, fdeviceid1, idx);
- if (ReadSysFile(path, &device_id) < 0) {
- sprintf(path, fdeviceid2, idx);
- ReadSysFile(path, &device_id);
- }
-
- if (vendor_id == 0x1344) {
- switch (device_id) {
- case 0x5410:
- eModel = M5410;
- break;
- case 0x51A0:
- case 0x51A1:
- case 0x51A2:
- eModel = M51AX;
- break;
- case 0x51B0:
- case 0x51B1:
- case 0x51B2:
- eModel = M51BX;
- break;
- default:
- break;
- }
- }
- return eModel;
+ const char *desc = "Retrieve Micron NAND stats for the given device ";
+ unsigned int extSmartLog[D0_log_size/sizeof(int)] = { 0 };
+ unsigned int logFB[FB_log_size/sizeof(int)] = { 0 };
+ eDriveModel eModel = UNKNOWN_MODEL;
+ struct nvme_id_ctrl ctrl;
+ int fd, err, ctrlIdx;
+ __u8 nsze;
+ bool has_d0_log = true;
+ bool has_fb_log = false;
+ bool is_json = true;
+ struct format {
+ char *fmt;
+ };
+ const char *fmt = "output format json|normal";
+ struct format cfg = {
+ .fmt = "json",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ if (strcmp(cfg.fmt, "normal") == 0)
+ is_json = false;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (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);
+ goto out;
+ }
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, 0xD0, false, NVME_NO_LOG_LSP,
+ D0_log_size, extSmartLog);
+ has_d0_log = (0 == err);
+
+ /* 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, 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)
+ print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json);
+ else {
+ printf("Unable to retrieve extended smart log for the drive\n");
+ err = -ENOTTY;
+ }
+out:
+ close(fd);
+ return err;
}
+
static void GetDriveInfo(const char *strOSDirName, int nFD,
- struct nvme_id_ctrl *ctrlp)
+ struct nvme_id_ctrl *ctrlp)
{
- FILE *fpOutFile = NULL;
- char tempFile[256] = { 0 };
- char strBuffer[1024] = { 0 };
- char model[41] = { 0 };
- char serial[21] = { 0 };
- char fwrev[9] = { 0 };
- char *strPDir = strdup(strOSDirName);
- char *strDest = dirname(strPDir);
-
- sprintf(tempFile, "%s/%s", strDest, "drive-info.txt");
- fpOutFile = fopen(tempFile, "w+");
- if (!fpOutFile) {
- printf("Unable to create %s\n", tempFile);
- free(strPDir);
- return;
- }
-
- strncpy(model, ctrlp->mn, 40);
- strncpy(serial, ctrlp->sn, 20);
- strncpy(fwrev, ctrlp->fr, 8);
-
- sprintf(strBuffer,
- "********************\nDrive Info\n********************\n");
-
- fprintf(fpOutFile, "%s", strBuffer);
- sprintf(strBuffer,
- "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n",
- "Device Name", nFD,
- "Model No", (char *)model,
- "Serial No", (char *)serial, "FW-Rev", (char *)fwrev);
-
- fprintf(fpOutFile, "%s", strBuffer);
-
- sprintf(strBuffer,
- "\n********************\nPCI Info\n********************\n");
-
- fprintf(fpOutFile, "%s", strBuffer);
-
- sprintf(strBuffer,
- "%-22s : %04X\n%-22s : %04X\n",
- "VendorId", vendor_id, "DeviceId", device_id);
- fprintf(fpOutFile, "%s", strBuffer);
- fclose(fpOutFile);
- free(strPDir);
+ FILE *fpOutFile = NULL;
+ char tempFile[256] = { 0 };
+ char strBuffer[1024] = { 0 };
+ char model[41] = { 0 };
+ char serial[21] = { 0 };
+ char fwrev[9] = { 0 };
+ char *strPDir = strdup(strOSDirName);
+ char *strDest = dirname(strPDir);
+
+ sprintf(tempFile, "%s/%s", strDest, "drive-info.txt");
+ fpOutFile = fopen(tempFile, "w+");
+ if (!fpOutFile) {
+ printf("Failed to create %s\n", tempFile);
+ free(strPDir);
+ return;
+ }
+
+ strncpy(model, ctrlp->mn, 40);
+ strncpy(serial, ctrlp->sn, 20);
+ strncpy(fwrev, ctrlp->fr, 8);
+
+ sprintf(strBuffer,
+ "********************\nDrive Info\n********************\n");
+
+ fprintf(fpOutFile, "%s", strBuffer);
+ sprintf(strBuffer,
+ "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n",
+ "Device Name", nFD,
+ "Model No", (char *)model,
+ "Serial No", (char *)serial, "FW-Rev", (char *)fwrev);
+
+ fprintf(fpOutFile, "%s", strBuffer);
+
+ sprintf(strBuffer,
+ "\n********************\nPCI Info\n********************\n");
+
+ fprintf(fpOutFile, "%s", strBuffer);
+
+ sprintf(strBuffer,
+ "%-22s : %04X\n%-22s : %04X\n",
+ "VendorId", vendor_id, "DeviceId", device_id);
+ fprintf(fpOutFile, "%s", strBuffer);
+ fclose(fpOutFile);
+ free(strPDir);
}
static void GetTimestampInfo(const char *strOSDirName)
{
- char outstr[200];
- time_t t;
- struct tm *tmp;
- FILE *fpOutFile = NULL;
- size_t num;
- char tempFolder[256] = { 0 };
- char *strPDir;
- char *strDest;
-
- t = time(NULL);
- tmp = localtime(&t);
- if (tmp == NULL)
- return;
-
- num = strftime(outstr, sizeof(outstr), "Timestamp (UTC): %a, %d %b %Y %T %z", tmp);
- if (num) {
- strPDir = strdup(strOSDirName);
- strDest = dirname(strPDir);
- sprintf(tempFolder, "%s/%s", strDest, "timestamp_info.txt");
- fpOutFile = fopen(tempFolder, "wb");
- if (fwrite(outstr, 1, num, fpOutFile) != num)
- printf("Unable to write to %s file!", tempFolder);
- if (fpOutFile)
- fclose(fpOutFile);
- free(strPDir);
- }
+ __u8 outstr[1024];
+ time_t t;
+ struct tm *tmp;
+ size_t num;
+ char *strPDir;
+ char *strDest;
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (tmp == NULL)
+ return;
+
+ num = strftime((char *)outstr, sizeof(outstr),
+ "Timestamp (UTC): %a, %d %b %Y %T %z", tmp);
+ num += sprintf((char *)(outstr + num), "\nPackage Version: 1.4");
+ if (num) {
+ strPDir = strdup(strOSDirName);
+ strDest = dirname(strPDir);
+ WriteData(outstr, num, strDest, "timestamp_info.txt", "timestamp");
+ free(strPDir);
+ }
}
-static void GetCtrlIDDInfo(const char *strCtrlDirName, struct nvme_id_ctrl *ctrlp)
+static void GetCtrlIDDInfo(const char *dir, struct nvme_id_ctrl *ctrlp)
{
- char tempFolder[PATH_MAX] = { 0 };
- FILE *fpOutFile;
- sprintf(tempFolder, "%s/%s", strCtrlDirName,
- "nvme_controller_identify_data.bin");
- fpOutFile = fopen(tempFolder, "wb");
- if (fwrite(ctrlp, 1, sizeof(*ctrlp), fpOutFile) != sizeof(*ctrlp))
- printf("Unable to write controller data to %s file!", tempFolder);
- if (fpOutFile)
- fclose(fpOutFile);
+ WriteData((__u8*)ctrlp, sizeof(*ctrlp), dir,
+ "nvme_controller_identify_data.bin", "id-ctrl");
}
-static void GetSmartlogData(int fd, const char *strCtrlDirName)
+static void GetSmartlogData(int fd, const char *dir)
{
- char tempFolder[PATH_MAX] = { 0 };
- FILE *fpOutFile = NULL;
- struct nvme_smart_log smart_log;
- if (nvme_smart_log(fd, -1, &smart_log) == 0) {
- sprintf(tempFolder, "%s/%s", strCtrlDirName, "smart_data.bin");
- fpOutFile = fopen(tempFolder, "wb");
- if (fwrite(&smart_log, 1, sizeof(smart_log), fpOutFile) != sizeof(smart_log))
- printf("Unable to write smart log data to %s file!", tempFolder);
- if (fpOutFile)
- fclose(fpOutFile);
- }
+ struct nvme_smart_log smart_log;
+ if (nvme_smart_log(fd, -1, &smart_log) == 0) {
+ WriteData((__u8*)&smart_log, sizeof(smart_log), dir,
+ "smart_data.bin", "smart log");
+ }
}
-static void GetErrorlogData(int fd, int entries, const char *strCtrlDirName)
+static void GetErrorlogData(int fd, int entries, const char *dir)
{
- char tempFolder[PATH_MAX] = { 0 };
- FILE *fpOutFile = NULL;
- int logSize = entries * sizeof(struct nvme_error_log_page);
- struct nvme_error_log_page *error_log = (struct nvme_error_log_page *)calloc(1, logSize);
-
- if (error_log == NULL)
- return;
-
- if (nvme_error_log(fd, entries, error_log) == 0) {
- sprintf(tempFolder, "%s/%s", strCtrlDirName,
- "error_information_log.bin");
- fpOutFile = fopen(tempFolder, "wb");
- if (fwrite(error_log, 1, logSize, fpOutFile) != logSize)
- printf("Unable to write error log to %s file!", tempFolder);
- if (fpOutFile)
- fclose(fpOutFile);
- }
- free(error_log);
+ int logSize = entries * sizeof(struct nvme_error_log_page);
+ struct nvme_error_log_page *error_log =
+ (struct nvme_error_log_page *)calloc(1, logSize);
+
+ if (error_log == NULL)
+ return;
+
+ if (nvme_error_log(fd, entries, error_log) == 0) {
+ WriteData((__u8*)error_log, logSize, dir,
+ "error_information_log.bin", "error log");
+ }
+
+ free(error_log);
}
-static void GetNSIDDInfo(int fd, const char *strCtrlDirName, int nsid)
+static void GetNSIDDInfo(int fd, const char *dir, int nsid)
{
- char tempFolder[256] = { 0 };
- char strFileName[PATH_MAX] = { 0 };
- FILE *fpOutFile = NULL;
- struct nvme_id_ns ns;
- if (nvme_identify_ns(fd, nsid, 0, &ns) == 0) {
- sprintf(tempFolder, "identify_namespace_%d_data.bin.bin", nsid);
- sprintf(strFileName, "%s/%s", strCtrlDirName, tempFolder);
- fpOutFile = fopen(strFileName, "wb");
- if (fwrite(&ns, 1, sizeof(ns), fpOutFile) != sizeof(ns))
- printf("Unable to write controller data to %s file!", tempFolder);
- if (fpOutFile)
- fclose(fpOutFile);
- }
+ char file[PATH_MAX] = { 0 };
+ struct nvme_id_ns ns;
+
+ if (nvme_identify_ns(fd, nsid, 0, &ns) == 0) {
+ sprintf(file, "identify_namespace_%d_data.bin", nsid);
+ WriteData((__u8*)&ns, sizeof(ns), dir, file, "id-ns");
+ }
}
static void GetOSConfig(const char *strOSDirName)
{
- FILE *fpOSConfig = NULL;
- char strBuffer[1024], strTemp[1024];
- char strFileName[PATH_MAX];
- int i;
-
- struct {
- char *strcmdHeader;
- char *strCommand;
- } cmdArray[] = {
- { (char *)"SYSTEM INFORMATION", (char *)"uname -a >> %s" },
- { (char *)"LINUX KERNEL MODULE INFORMATION", (char *)"lsmod >> %s" },
- { (char *)"LINUX SYSTEM MEMORY INFORMATION", (char *)"cat /proc/meminfo >> %s" },
- { (char *)"SYSTEM INTERRUPT INFORMATION", (char *)"cat /proc/interrupts >> %s" },
- { (char *)"CPU INFORMATION", (char *)"cat /proc/cpuinfo >> %s" },
- { (char *)"IO MEMORY MAP INFORMATION", (char *)"cat /proc/iomem >> %s" },
- { (char *)"MAJOR NUMBER AND DEVICE GROUP", (char *)"cat /proc/devices >> %s" },
- { (char *)"KERNEL DMESG", (char *)"dmesg >> %s" },
- { (char *)"/VAR/LOG/MESSAGES", (char *)"cat /var/log/messages >> %s" }
- };
-
- sprintf(strFileName, "%s/%s", strOSDirName, "os_config.txt");
-
- for (i = 0; i < 7; i++) {
- fpOSConfig = fopen(strFileName, "a+");
- fprintf(fpOSConfig,
- "\n\n\n\n%s\n-----------------------------------------------\n",
- cmdArray[i].strcmdHeader);
- if (NULL != fpOSConfig) {
- fclose(fpOSConfig);
- fpOSConfig = NULL;
- }
- strcpy(strTemp, cmdArray[i].strCommand);
- sprintf(strBuffer, strTemp, strFileName);
- if (system(strBuffer))
- fprintf(stderr, "Failed to send \"%s\"\n", strBuffer);
- }
+ FILE *fpOSConfig = NULL;
+ char strBuffer[1024], strTemp[1024];
+ char strFileName[PATH_MAX];
+ int i;
+
+ struct {
+ char *strcmdHeader;
+ char *strCommand;
+ } cmdArray[] = {
+ { (char *)"SYSTEM INFORMATION", (char *)"uname -a >> %s" },
+ { (char *)"LINUX KERNEL MODULE INFORMATION", (char *)"lsmod >> %s" },
+ { (char *)"LINUX SYSTEM MEMORY INFORMATION", (char *)"cat /proc/meminfo >> %s" },
+ { (char *)"SYSTEM INTERRUPT INFORMATION", (char *)"cat /proc/interrupts >> %s" },
+ { (char *)"CPU INFORMATION", (char *)"cat /proc/cpuinfo >> %s" },
+ { (char *)"IO MEMORY MAP INFORMATION", (char *)"cat /proc/iomem >> %s" },
+ { (char *)"MAJOR NUMBER AND DEVICE GROUP", (char *)"cat /proc/devices >> %s" },
+ { (char *)"KERNEL DMESG", (char *)"dmesg >> %s" },
+ { (char *)"/VAR/LOG/MESSAGES", (char *)"cat /var/log/messages >> %s" }
+ };
+
+ sprintf(strFileName, "%s/%s", strOSDirName, "os_config.txt");
+
+ for (i = 0; i < 7; i++) {
+ fpOSConfig = fopen(strFileName, "a+");
+ fprintf(fpOSConfig,
+ "\n\n\n\n%s\n-----------------------------------------------\n",
+ cmdArray[i].strcmdHeader);
+ if (NULL != fpOSConfig) {
+ fclose(fpOSConfig);
+ fpOSConfig = NULL;
+ }
+ strcpy(strTemp, cmdArray[i].strCommand);
+ sprintf(strBuffer, strTemp, strFileName);
+ if (system(strBuffer))
+ fprintf(stderr, "Failed to send \"%s\"\n", strBuffer);
+ }
}
-static int micron_internal_logs(int argc, char **argv, struct command *cmd,
- struct plugin *plugin)
+static int micron_telemetry_log(int fd, __u8 gen, __u8 type, __u8 **data,
+ int *logSize, int da)
+{
+ int err;
+ unsigned short data_area[4];
+ unsigned char ctrl_init = (type == 0x8);
+
+ __u8 *buffer = (unsigned char *)calloc(512, 1);
+ if (buffer == NULL)
+ return -1;
+ err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, 512, 0);
+ if (err != 0) {
+ fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type);
+ if (buffer != NULL) {
+ free(buffer);
+ }
+ 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];
+ 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];
+
+ if (data_area[da] == 0) {
+ fprintf(stderr, "Requested telemetry data for 0x%X is empty\n", type);
+ if (buffer != NULL) {
+ free(buffer);
+ buffer = NULL;
+ }
+ return -1;
+ }
+
+ *logSize = data_area[da] * 512;
+ if ((buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize))) != NULL) {
+ err = nvme_get_telemetry_log(fd, buffer, gen, ctrl_init, *logSize, 0);
+ }
+
+ if (err == 0 && buffer != NULL) {
+ *data = buffer;
+ } else {
+ fprintf(stderr, "Failed to get telemetry data for 0x%x\n", type);
+ if (buffer != NULL)
+ free(buffer);
+ }
+
+ return err;
+}
+
+static int GetTelemetryData(int fd, const char *dir)
+{
+ unsigned char *buffer = NULL;
+ int i, err, logSize = 0;
+ char msg[256] = {0};
+ struct {
+ __u8 log;
+ char *file;
+ } tmap[] = {
+ {0x07, "nvme_host_telemetry.bin"},
+ {0x08, "nvme_cntrl_telemetry.bin"},
+ };
+
+ for(i = 0; i < (int)(sizeof(tmap)/sizeof(tmap[0])); i++) {
+ err = micron_telemetry_log(fd, 0, 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);
+ if (buffer != NULL)
+ free(buffer);
+ }
+ buffer = NULL;
+ logSize = 0;
+ }
+ return err;
+}
+
+static int GetFeatureSettings(int fd, const char *dir)
+{
+ unsigned char *bufp, buf[4096] = { 0 };
+ int i, err, len, errcnt = 0;
+ __u32 attrVal = 0;
+ char msg[256] = { 0 };
+
+ struct features {
+ int id;
+ char *file;
+ } fmap[] = {
+ {0x01, "nvme_feature_setting_arbitration.bin"},
+ {0x02, "nvme_feature_setting_pm.bin"},
+ {0x03, "nvme_feature_setting_lba_range_namespace_1.bin"},
+ {0x04, "nvme_feature_setting_temp_threshold.bin"},
+ {0x05, "nvme_feature_setting_error_recovery.bin"},
+ {0x06, "nvme_feature_setting_volatile_write_cache.bin"},
+ {0x07, "nvme_feature_setting_num_queues.bin"},
+ {0x08, "nvme_feature_setting_interrupt_coalescing.bin"},
+ {0x09, "nvme_feature_setting_interrupt_vec_config.bin"},
+ {0x0A, "nvme_feature_setting_write_atomicity.bin"},
+ {0x0B, "nvme_feature_setting_async_event_config.bin"},
+ {0x80, "nvme_feature_setting_sw_progress_marker.bin"},
+ };
+
+ for (i = 0; i < (int)(sizeof(fmap)/sizeof(fmap[0])); i++) {
+ if (fmap[i].id == 0x03) {
+ len = 4096;
+ bufp = (unsigned char *)(&buf[0]);
+ } else {
+ len = 0;
+ bufp = NULL;
+ }
+
+ err = nvme_get_feature(fd, 1, fmap[i].id, 0, 0x0, len, bufp, &attrVal);
+ if (err == 0) {
+ sprintf(msg, "feature: 0x%X", fmap[i].id);
+ WriteData((__u8*)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg);
+ if (bufp != NULL) {
+ WriteData(bufp, len, dir, fmap[i].file, msg);
+ }
+ } else {
+ printf("Failed to retrieve feature 0x%x data !\n", fmap[i].id);
+ errcnt++;
+ }
+ }
+ return (int)(errcnt == sizeof(fmap)/sizeof(fmap[0]));
+}
+
+static int micron_drive_info(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Get drive HW information";
+ int fd, err = 0;
+ struct nvme_id_ctrl ctrl = { 0 };
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, NULL)) < 0)
+ return err;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR : nvme_identify_ctrl() failed with 0x%x\n", err);
+ return -1;
+ }
+
+ printf("%u.%u\n", ctrl.vs[820], ctrl.vs[821]);
+ return 0;
+}
+
+static int micron_cloud_ssd_plugin_version(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ printf("nvme-cli Micron cloud SSD plugin version: %s.%s\n",
+ __version_major, __version_minor);
+ return 0;
+}
+
+static int micron_plugin_version(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ printf("nvme-cli Micron plugin version: %s.%s.%s\n",
+ __version_major, __version_minor, __version_patch);
+ return 0;
+}
+
+static int micron_logpage_dir(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ printf("This command is not implemented for the drive\n");
+ return 0;
+}
+/* Binary format of firmware activation history entry */
+struct __attribute__((__packed__)) fw_activation_history_entry {
+ __u8 version;
+ __u8 length;
+ __u16 rsvd1;
+ __le16 valid;
+ __le64 power_on_hour;
+ __le64 rsvd2;
+ __le64 power_cycle_count;
+ __u8 previous_fw[8];
+ __u8 activated_fw[8];
+ __u8 slot;
+ __u8 commit_action_type;
+ __le16 result;
+ __u8 rsvd3[14];
+};
+
+
+/* Binary format for firmware activation history table */
+struct __attribute__((__packed__)) micron_fw_activation_history_table {
+ __u8 log_page;
+ __u8 rsvd1[3];
+ __le32 num_entries;
+ struct fw_activation_history_entry entries[20];
+ __u8 rsvd2[2790];
+ __u16 version;
+ __u8 GUID[16];
+};
+
+/* header to be printed field widths = 10 | 12 | 10 | 11 | 12 | 9 | 9 | 9 */
+
+const char *fw_activation_history_table_header = "\
+__________________________________________________________________________________\n\
+ | | | | | | | \n\
+Firmware | Power | Power | Previous | New FW | Slot | Commit | Result \n\
+Activation| On Hour | cycle | firmware | activated | number | Action | \n\
+Counter | | count | | | | Type | \n\
+__________|___________|_________|__________|___________|________|________|________\n";
+
+static int display_fw_activate_entry (
+ int entry_count,
+ struct fw_activation_history_entry *entry,
+ char *formatted_entry,
+ struct json_object *stats
+)
+{
+ time_t timestamp, hours;
+ char buffer[32];
+ __u8 minutes, seconds;
+ char *ca[] = {"000b", "001b", "010b", "011b"};
+ char *ptr = formatted_entry;
+ int index = 0, entry_size = 82;
+
+ if (entry->version != 1 || entry->length != 64) {
+ fprintf(stderr, "unsupported entry ! version: %x with length: %d\n",
+ entry->version, entry->length);
+ return -EINVAL;
+ }
+
+ sprintf(ptr, "%d", entry_count);
+ ptr += 10;
+
+ timestamp = (le64_to_cpu(entry->power_on_hour) & 0x0000FFFFFFFFFFFFUL) / 1000;
+ hours = timestamp / 3600;
+ minutes = (timestamp % 3600) / 60;
+ seconds = (timestamp % 3600) % 60;
+ sprintf(ptr, "|%"PRIu64":%hhu:%hhu", (uint64_t)hours, minutes, seconds);
+ ptr += 12;
+
+ sprintf(ptr, "| %"PRIu64, le64_to_cpu(entry->power_cycle_count));
+ ptr += 10;
+
+ /* firmware details */
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, entry->previous_fw, sizeof(entry->previous_fw));
+ sprintf(ptr, "| %s", buffer);
+ ptr += 11;
+
+ memset(buffer, 0, sizeof(buffer));
+ memcpy(buffer, entry->activated_fw, sizeof(entry->activated_fw));
+ sprintf(ptr, "| %s", buffer);
+ ptr += 12;
+
+ /* firmware slot and commit action*/
+ sprintf(ptr, "| %d", entry->slot);
+ ptr += 9;
+
+ if (entry->commit_action_type <= 3)
+ sprintf(ptr, "| %s", ca[entry->commit_action_type]);
+ else
+ sprintf(ptr, "| xxxb");
+ ptr += 9;
+
+ /* result */
+ if (entry->result) {
+ sprintf(ptr, "| Fail #%d", entry->result);
+ } else {
+ sprintf(ptr, "| pass");
+ }
+
+ /* replace all null charecters with spaces */
+ ptr = formatted_entry;
+ while (index < entry_size) {
+ if (ptr[index] == '\0')
+ ptr[index] = ' ';
+ index++;
+ }
+ return 0;
+}
+
+
+static int micron_fw_activation_history(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Firmware Activation history of the given drive";
+ char formatted_output[100];
+ 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;
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ if (strcmp(cfg.fmt, "normal") != 0) {
+ fprintf (stderr, "only normal format is supported currently\n");
+ close(fd);
+ 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;
+ }
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, 0xC2, false, NVME_NO_LOG_LSP, C2_log_size, logC2);
+ if (err) {
+ fprintf(stderr, "Failed to retrieve fw activation history log, error: %x\n", err);
+ goto out;
+ }
+
+ /* check if we have atleast one entry to print */
+ struct micron_fw_activation_history_table *table =
+ (struct micron_fw_activation_history_table *)logC2;
+
+ /* check version and log page */
+ if (table->version != 2 || table->log_page != 0xC2) {
+ fprintf(stderr, "Unsupported fw activation history page: %x, version: %x\n",
+ table->log_page, table->version);
+ goto out;
+ }
+
+ if (table->num_entries == 0) {
+ fprintf(stderr, "No entries were found in fw activation history log\n");
+ goto out;
+ }
+
+ printf("%s", fw_activation_history_table_header);
+ for(count = 0; count < table->num_entries; count++) {
+ memset(formatted_output, '\0', 100);
+ if (display_fw_activate_entry(count,
+ &table->entries[count],
+ formatted_output, NULL) == 0)
+ {
+ printf("%s\n", formatted_output);
+ }
+ }
+out:
+ if (fd > 0)
+ close(fd);
+ return err;
+}
+
+static int micron_error_reason(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ printf("This command is not implemented for the drive\n");
+ return 0;
+}
+
+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 ";
+ unsigned int logC0[C0_log_size/sizeof(int)] = { 0 };
+ eDriveModel eModel = UNKNOWN_MODEL;
+ struct nvme_id_ctrl ctrl;
+ int fd, err, ctrlIdx;
+ bool is_json = false;
+ struct format {
+ char *fmt;
+ };
+ const char *fmt = "output format normal|json";
+ struct format cfg = {
+ .fmt = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ if (strcmp(cfg.fmt, "json") == 0)
+ is_json = true;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (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-smart-add-log commmand\n");
+ close(fd);
+ 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 {
+ print_smart_cloud_health_log((__u8 *)logC0, is_json);
+ }
+out:
+ close(fd);
+ return err;
+}
+
+static int micron_clr_fw_activation_history(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
{
+ const char *desc = "Clear FW activation history";
+ int fd, err = 0;
+ __u32 result = 0;
+ __u8 fid = MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY;
+ eDriveModel model = UNKNOWN_MODEL;
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0)
+ return err;
+
+ if (model != M51CX) {
+ printf ("This option is not supported for specified drive\n");
+ close(fd);
+ return err;
+ }
+
+ //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);
+ if (err == 0) err = (int)result;
+ return err;
+}
- int err = 0;
- int fd;
- int ctrlIdx;
- FILE *fpOutFile = NULL;
- char strOSDirName[1024];
- char strCtrlDirName[1024];
- char strMainDirName[256];
- char tempFolder[PATH_MAX] = { 0 };
- unsigned int *puiIDDBuf;
- unsigned int uiMask;
- struct nvme_id_ctrl ctrl;
- char sn[20] = { 0 };
-
- struct {
- unsigned char ucLogPage;
- const char *strFileName;
- int nLogSize;
- int nMaxSize;
- } aVendorLogs[32] = {
- { 0xC1, "nvmelog_C1.bin", 0, 0 },
- { 0xC2, "nvmelog_C2.bin", 0, 0 },
- { 0xC4, "nvmelog_C4.bin", 0, 0 },
- { 0xC5, "nvmelog_C5.bin", C5_log_size, 0 },
- { 0xD0, "nvmelog_D0.bin", D0_log_size, 0 },
- { 0xE6, "nvmelog_E6.bin", 0, 0 },
- { 0xE7, "nvmelog_E7.bin", 0, 0 }
- },
- aM51XXLogs[] = {
- { 0xFB, "nvmelog_FB.bin", 4096, 0 }, /* this should be collected first for M51AX */
- { 0xF7, "nvmelog_F7.bin", 4096, 512 * 1024 },
- { 0xF8, "nvmelog_F8.bin", 4096, 512 * 1024 },
- { 0xF9, "nvmelog_F9.bin", 4096, 200 * 1024 * 1024 },
- { 0xFC, "nvmelog_FC.bin", 4096, 200 * 1024 * 1024 },
- { 0xFD, "nvmelog_FD.bin", 4096, 80 * 1024 * 1024 }
- },
- aM51AXLogs[] = {
- { 0xD0, "nvmelog_D0.bin", 512, 0 },
- { 0xCA, "nvmelog_CA.bin", 512, 0 },
- { 0xFA, "nvmelog_FA.bin", 4096, 15232 },
- { 0xFE, "nvmelog_FE.bin", 4096, 512 * 1024 },
- { 0xFF, "nvmelog_FF.bin", 4096, 162 * 1024 },
- { 0x04, "changed_namespace_log.bin", 4096, 0 },
- { 0x05, "command_effects_log.bin", 4096, 0 },
- { 0x06, "drive_self_test.bin", 4096, 0 }
- },
- aM51BXLogs[] = {
- { 0xFA, "nvmelog_FA.bin", 4096, 16376 },
- { 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 },
- { 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 },
- { 0xCA, "nvmelog_CA.bin", 512, 1024 }
- };
-
- eDriveModel eModel;
-
- const char *desc = "This retrieves the micron debug log package";
- const char *package = "Log output package name (required)";
- unsigned char *dataBuffer = NULL;
- int bSize = 0;
- int maxSize = 0;
-
- struct config {
- char *package;
- };
-
- struct config cfg = {
- .package = ""
- };
-
- OPT_ARGS(opts) = {
- OPT_STRING("package", 'p', "FILE", &cfg.package, package),
- OPT_END()
- };
-
- fd = parse_and_open(argc, argv, desc, opts);
-
- if (strlen(cfg.package) == 0) {
- printf ("You must specify an output name for the log package. ie --p=logfiles.zip\n");
- goto out;
- }
-
- if (fd < 0)
- 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-internal-log collection\n");
- close(fd);
- goto out;
- }
-
- printf("Preparing log package. This will take a few seconds...\n");
- err = nvme_identify_ctrl(fd, &ctrl);
- if (err)
- goto out;
-
- // trim spaces out of serial number string */
- int i, j = 0;
- for (i = 0; i < sizeof(ctrl.sn); i++) {
- if (isblank(ctrl.sn[i]))
- continue;
- sn[j++] = ctrl.sn[i];
- }
- sn[j] = '\0';
- strcpy(ctrl.sn, sn);
-
- SetupDebugDataDirectories(ctrl.sn, cfg.package, strMainDirName, strOSDirName, strCtrlDirName);
-
- GetTimestampInfo(strOSDirName);
- GetCtrlIDDInfo(strCtrlDirName, &ctrl);
- GetOSConfig(strOSDirName);
- GetDriveInfo(strOSDirName, ctrlIdx, &ctrl);
-
- for (int i = 1; i <= ctrl.nn; i++)
- GetNSIDDInfo(fd, strCtrlDirName, i);
-
- GetSmartlogData(fd, strCtrlDirName);
- GetErrorlogData(fd, ctrl.elpe, strCtrlDirName);
-
- if (eModel != M5410) {
- memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs));
- if (eModel == M51AX)
- memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs));
- else
- memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51BXLogs, sizeof(aM51BXLogs));
- }
-
- for (int i = 0; i < (int)(sizeof(aVendorLogs) / sizeof(aVendorLogs[0])) && aVendorLogs[i].ucLogPage != 0; i++) {
- err = -1;
- switch (aVendorLogs[i].ucLogPage) {
- case 0xC1:
- case 0xC2:
- case 0xC4:
- err = GetLogPageSize(fd, aVendorLogs[i].ucLogPage, &bSize);
- if (err == 0 && bSize > 0)
- err = GetCommonLogPage(fd, aVendorLogs[i].ucLogPage, &dataBuffer, bSize);
- break;
-
- case 0xE6:
- case 0xE7:
- puiIDDBuf = (unsigned int *)&ctrl;
- uiMask = puiIDDBuf[1015];
- if (uiMask == 0 || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) || (aVendorLogs[i].ucLogPage == 0xE7
- && uiMask == 1)) {
- bSize = 0;
- } else {
- bSize = (int)puiIDDBuf[1015];
- if (bSize % (16 * 1024)) {
- bSize += (16 * 1024) - (bSize % (16 * 1024));
- }
- }
- if (bSize != 0) {
- dataBuffer = (unsigned char *)malloc(bSize);
- memset(dataBuffer, 0, bSize);
- err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
- }
- break;
-
- case 0xF7:
- case 0xF9:
- case 0xFC:
- case 0xFD:
- if (eModel == M51BX)
- (void)NVMEResetLog(fd, aVendorLogs[i].ucLogPage, aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
- default:
- bSize = aVendorLogs[i].nLogSize;
- dataBuffer = (unsigned char *)malloc(bSize);
- memset(dataBuffer, 0, bSize);
- err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
- maxSize = aVendorLogs[i].nMaxSize - bSize;
- while (err == 0 && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
- sprintf(tempFolder, "%s/%s", strCtrlDirName,
- aVendorLogs[i].strFileName);
- fpOutFile = fopen(tempFolder, "ab+");
- if (fwrite(dataBuffer, 1, bSize, fpOutFile) != bSize) {
- printf ("Unable to write log to file %s\n!", aVendorLogs[i].strFileName);
- }
- if (fpOutFile)
- fclose(fpOutFile);
- err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
- if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef))
- break;
- maxSize -= bSize;
- }
- break;
- }
-
- if (err == 0 && dataBuffer != NULL && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
- sprintf(tempFolder, "%s/%s", strCtrlDirName,
- aVendorLogs[i].strFileName);
- fpOutFile = fopen(tempFolder, "ab+");
- if (fwrite(dataBuffer, 1, bSize, fpOutFile) != bSize) {
- printf("Unable to write log to file %s\n!", aVendorLogs[i].strFileName);
- }
- if (fpOutFile)
- fclose(fpOutFile);
- }
-
- if (dataBuffer != NULL) {
- free(dataBuffer);
- dataBuffer = NULL;
- }
- }
-
- ZipAndRemoveDir(strMainDirName, cfg.package);
- out:
- return err;
+static int micron_telemetry_cntrl_option(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ int err = 0;
+ __u32 result = 0;
+ const char *desc = "Enable or Disable Controller telemetry log generation";
+ const char *option = "enable or disable or status";
+ const char *select = "select/save values: enable/disable options"
+ "1 - save (persistent), 0 - non-persistent and for "
+ "status options: 0 - current, 1 - default, 2-saved";
+ int fd = 0;
+ int fid = MICRON_FEATURE_TELEMETRY_CONTROL_OPTION;
+ eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_id_ctrl ctrl = { 0 };
+
+ struct {
+ char *option;
+ int select;
+ } opt = {
+ .option = "disable",
+ .select= 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("option", 'o', "option", &opt.option, option),
+ OPT_UINT("select", 's', &opt.select, select),
+ OPT_END()
+ };
+
+ if ((fd = micron_parse_options(argc, argv, desc, opts, &model)) < 0) {
+ return -1;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if ((ctrl.lpa & 0x8) != 0x8) {
+ printf("drive doesn't support host/controller generated telemetry logs\n");
+ close(fd);
+ return err;
+ }
+
+ if (!strcmp(opt.option, "enable")) {
+ err = nvme_set_feature(fd, 1, fid, 1, 0, (opt.select & 0x1), 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);
+ if (err == 0) {
+ printf("successfully disabled controller telemetry option\n");
+ } else {
+ printf("Failed to disable controller telemetry option\n");
+ }
+ } else if (!strcmp(opt.option, "status")) {
+ opt.select &= 0x3;
+ err = nvme_get_feature(fd, 1, fid, opt.select, 0, 0, 0, &result);
+ if (err == 0) {
+ printf("Controller telemetry option : %s\n",
+ (result) ? "enabled" : "disabled");
+ } else {
+ printf("Failed to retrieve controller telemetry option\n");
+ }
+ } else {
+ printf("invalid option %s, valid values are enable,disable or status\n", opt.option);
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return err;
+}
+
+static int micron_internal_logs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = -EINVAL;
+ int fd = 0;
+ int ctrlIdx, telemetry_option = 0;
+ char strOSDirName[1024];
+ char strCtrlDirName[1024];
+ char strMainDirName[256];
+ unsigned int *puiIDDBuf;
+ unsigned int uiMask;
+ struct nvme_id_ctrl ctrl;
+ char sn[20] = { 0 };
+ char msg[256] = { 0 };
+
+ struct {
+ unsigned char ucLogPage;
+ const char *strFileName;
+ int nLogSize;
+ int nMaxSize;
+ } aVendorLogs[32] = {
+ { 0x03, "firmware_slot_info_log.bin", 512, 0 },
+ { 0xC1, "nvmelog_C1.bin", 0, 0 },
+ { 0xC2, "nvmelog_C2.bin", 0, 0 },
+ { 0xC4, "nvmelog_C4.bin", 0, 0 },
+ { 0xC5, "nvmelog_C5.bin", C5_log_size, 0 },
+ { 0xD0, "nvmelog_D0.bin", D0_log_size, 0 },
+ { 0xE6, "nvmelog_E6.bin", 0, 0 },
+ { 0xE7, "nvmelog_E7.bin", 0, 0 }
+ },
+ aM51XXLogs[] = {
+ { 0xFB, "nvmelog_FB.bin", 4096, 0 }, /* this should be collected first for M51AX */
+ { 0xD0, "nvmelog_D0.bin", 512, 0 },
+ { 0x03, "firmware_slot_info_log.bin", 512, 0},
+ { 0xF7, "nvmelog_F7.bin", 4096, 512 * 1024 },
+ { 0xF8, "nvmelog_F8.bin", 4096, 512 * 1024 },
+ { 0xF9, "nvmelog_F9.bin", 4096, 200 * 1024 * 1024 },
+ { 0xFC, "nvmelog_FC.bin", 4096, 200 * 1024 * 1024 },
+ { 0xFD, "nvmelog_FD.bin", 4096, 80 * 1024 * 1024 }
+ },
+ aM51AXLogs[] = {
+ { 0xCA, "nvmelog_CA.bin", 512, 0 },
+ { 0xFA, "nvmelog_FA.bin", 4096, 15232 },
+ { 0xF6, "nvmelog_F6.bin", 4096, 512 * 1024 },
+ { 0xFE, "nvmelog_FE.bin", 4096, 512 * 1024 },
+ { 0xFF, "nvmelog_FF.bin", 4096, 162 * 1024 },
+ { 0x04, "changed_namespace_log.bin", 4096, 0 },
+ { 0x05, "command_effects_log.bin", 4096, 0 },
+ { 0x06, "drive_self_test.bin", 4096, 0 }
+ },
+ aM51BXLogs[] = {
+ { 0xFA, "nvmelog_FA.bin", 4096, 16376 },
+ { 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 },
+ { 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 },
+ { 0xCA, "nvmelog_CA.bin", 512, 1024 }
+ };
+
+ eDriveModel eModel;
+
+ const char *desc = "This retrieves the micron debug log package";
+ const char *package = "Log output data file name (required)";
+ const char *type = "telemetry log type - host or controller";
+ const char *data_area = "telemetry log data area 1, 2 or 3";
+ unsigned char *dataBuffer = NULL;
+ int bSize = 0;
+ int maxSize = 0;
+
+ struct config {
+ char *type;
+ char *package;
+ int data_area;
+ int log;
+ };
+
+ struct config cfg = {
+ .type = "",
+ .package = "",
+ .data_area = -1,
+ .log = 0x07,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("type", 't', "log type", &cfg.type, type),
+ OPT_STRING("package", 'p', "FILE", &cfg.package, package),
+ OPT_UINT("data_area", 'd', &cfg.data_area, data_area),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ goto out;
+
+ /* if telemetry type is specified, check for data area */
+ if (strlen(cfg.type) != 0) {
+ if (!strcmp(cfg.type, "controller")) {
+ cfg.log = 0x08;
+ } else if (strcmp(cfg.type, "host")) {
+ printf ("telemetry type (host or controller) should be specified i.e. -t=host\n");
+ close(fd);
+ goto out;
+ }
+
+ if (cfg.data_area <= 0 || cfg.data_area > 3) {
+ printf ("data area must be selected using -d option ie --d=1,2,3\n");
+ close(fd);
+ goto out;
+ }
+ telemetry_option = 1;
+ } else if (cfg.data_area > 0) {
+ printf ("data area option is valid only for telemetry option (i.e --type=host|controller)\n");
+ close(fd);
+ goto out;
+ }
+
+ if (strlen(cfg.package) == 0) {
+ if (telemetry_option)
+ printf ("Log data file must be specified. ie -p=logfile.bin\n");
+ else
+ printf ("Log data file must be specified. ie -p=logfile.zip or -p=logfile.tgz|logfile.tar.gz\n");
+ 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-internal-log collection\n");
+ close(fd);
+ goto out;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ goto out;
+
+ err = -EINVAL;
+ if (telemetry_option) {
+ if ((ctrl.lpa & 0x8) != 0x8) {
+ printf("telemetry option is not supported for specified drive\n");
+ close(fd);
+ goto out;
+ }
+ int logSize = 0; __u8 *buffer = NULL; const char *dir = ".";
+ err = micron_telemetry_log(fd, 0, cfg.log, &buffer, &logSize, cfg.data_area);
+ if (err == 0 && logSize > 0 && buffer != NULL) {
+ sprintf(msg, "telemetry log: 0x%X", cfg.log);
+ WriteData(buffer, logSize, dir, cfg.package, msg);
+ free(buffer);
+ }
+ close(fd);
+ goto out;
+ }
+
+ printf("Preparing log package. This will take a few seconds...\n");
+
+ // trim spaces out of serial number string */
+ int i, j = 0;
+ for (i = 0; i < sizeof(ctrl.sn); i++) {
+ if (isblank(ctrl.sn[i]))
+ continue;
+ sn[j++] = ctrl.sn[i];
+ }
+ sn[j] = '\0';
+ strcpy(ctrl.sn, sn);
+
+ SetupDebugDataDirectories(ctrl.sn, cfg.package, strMainDirName, strOSDirName, strCtrlDirName);
+
+ GetTimestampInfo(strOSDirName);
+ GetCtrlIDDInfo(strCtrlDirName, &ctrl);
+ GetOSConfig(strOSDirName);
+ GetDriveInfo(strOSDirName, ctrlIdx, &ctrl);
+
+ for (int i = 1; i <= ctrl.nn; i++)
+ GetNSIDDInfo(fd, strCtrlDirName, i);
+
+ GetSmartlogData(fd, strCtrlDirName);
+ GetErrorlogData(fd, ctrl.elpe, strCtrlDirName);
+
+ // pull if telemetry log data is supported
+ if ((ctrl.lpa & 0x8) == 0x8)
+ GetTelemetryData(fd, strCtrlDirName);
+
+ GetFeatureSettings(fd, strCtrlDirName);
+
+ if (eModel != M5410) {
+ memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs));
+ if (eModel == M51AX)
+ memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs));
+ else
+ memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51BXLogs, sizeof(aM51BXLogs));
+ }
+
+ for (int i = 0; i < (int)(sizeof(aVendorLogs) / sizeof(aVendorLogs[0])) &&
+ aVendorLogs[i].ucLogPage != 0; i++) {
+ err = -1;
+ switch (aVendorLogs[i].ucLogPage) {
+ case 0xC1:
+ case 0xC2:
+ case 0xC4:
+ err = GetLogPageSize(fd, aVendorLogs[i].ucLogPage, &bSize);
+ if (err == 0 && bSize > 0)
+ err = GetCommonLogPage(fd, aVendorLogs[i].ucLogPage, &dataBuffer, bSize);
+ break;
+
+ case 0xE6:
+ case 0xE7:
+ puiIDDBuf = (unsigned int *)&ctrl;
+ uiMask = puiIDDBuf[1015];
+ if (uiMask == 0 || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) ||
+ (aVendorLogs[i].ucLogPage == 0xE7 && uiMask == 1)) {
+ bSize = 0;
+ } else {
+ bSize = (int)puiIDDBuf[1023];
+ if (bSize % (16 * 1024)) {
+ bSize += (16 * 1024) - (bSize % (16 * 1024));
+ }
+ }
+ if (bSize != 0 && (dataBuffer = (unsigned char *)malloc(bSize)) != NULL) {
+ memset(dataBuffer, 0, bSize);
+ if (eModel == M5410 || eModel == M5407)
+ err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
+ else
+ err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage,
+ false, NVME_NO_LOG_LSP, bSize, dataBuffer);
+ }
+ break;
+
+ case 0xF7:
+ case 0xF9:
+ case 0xFC:
+ case 0xFD:
+ if (eModel == M51BX)
+ (void)NVMEResetLog(fd, aVendorLogs[i].ucLogPage,
+ aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
+ default:
+ bSize = aVendorLogs[i].nLogSize;
+ dataBuffer = (unsigned char *)malloc(bSize);
+ if (dataBuffer == NULL) {
+ break;
+ }
+ memset(dataBuffer, 0, bSize);
+ err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage,
+ false, NVME_NO_LOG_LSP, bSize, dataBuffer);
+ maxSize = aVendorLogs[i].nMaxSize - bSize;
+ while (err == 0 && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
+ sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage);
+ WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg);
+ err = nvme_get_log(fd, NVME_NSID_ALL, aVendorLogs[i].ucLogPage,
+ false, NVME_NO_LOG_LSP, bSize, dataBuffer);
+ if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef))
+ break;
+ maxSize -= bSize;
+ }
+ break;
+ }
+
+ if (err == 0 && dataBuffer != NULL && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
+ sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage);
+ WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg);
+ }
+
+ if (dataBuffer != NULL) {
+ free(dataBuffer);
+ dataBuffer = NULL;
+ }
+ }
+
+ err = ZipAndRemoveDir(strMainDirName, cfg.package);
+out:
+ return err;
}
diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h
index add36e4..118f8cd 100644
--- a/plugins/micron/micron-nvme.h
+++ b/plugins/micron/micron-nvme.h
@@ -12,7 +12,17 @@ PLUGIN(NAME("micron", "Micron vendor specific extensions"),
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)
ENTRY("vs-internal-log", "Retrieve Micron logs", micron_internal_logs)
+ ENTRY("vs-telemetry-controller-option", "Enable/Disable controller telemetry log generation", micron_telemetry_cntrl_option)
ENTRY("vs-nand-stats", "Retrieve NAND Stats", micron_nand_stats)
+ ENTRY("vs-drive-info", "Retrieve Drive information", micron_drive_info)
+ ENTRY("plugin-version", "Display plugin version info", micron_plugin_version)
+ ENTRY("cloud-SSD-plugin-version", "Display plugin version info", micron_cloud_ssd_plugin_version)
+ ENTRY("log-page-directory", "Retrieve log page directory", micron_logpage_dir)
+ ENTRY("vs-fw-activate-history", "Display FW activation history", micron_fw_activation_history)
+ ENTRY("vs-error-reason-identifier", "Retrieve Error reason", micron_error_reason)
+ ENTRY("vs-smart-add-log", "Retrieve extended SMART data", micron_ocp_smart_health_logs)
+ ENTRY("clear-fw-activate-history", "Clear FW activation history", micron_clr_fw_activation_history)
+ ENTRY("vs-smbus-option", "Enable/Disable SMBUS on the drive", micron_smbus_option)
)
);
diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c
index a942f57..15c3923 100644
--- a/plugins/netapp/netapp-nvme.c
+++ b/plugins/netapp/netapp-nvme.c
@@ -25,7 +25,6 @@
#include "nvme.h"
#include "nvme-ioctl.h"
-#include "json.h"
#include "suffix.h"
@@ -197,7 +196,7 @@ static void netapp_get_ontap_labels(char *vsname, char *nspath,
vol_name, "/", ns_name);
}
-static void netapp_smdevice_json(struct json_array *devices, char *devname,
+static void netapp_smdevice_json(struct json_object *devices, char *devname,
char *arrayname, char *volname, int nsid, char *nguid,
char *ctrl, char *astate, char *size, long long lba,
long long nsze)
@@ -219,7 +218,7 @@ static void netapp_smdevice_json(struct json_array *devices, char *devname,
json_array_add_value_object(devices, device_attrs);
}
-static void netapp_ontapdevice_json(struct json_array *devices, char *devname,
+static void netapp_ontapdevice_json(struct json_object *devices, char *devname,
char *vsname, char *nspath, int nsid, char *uuid,
char *size, long long lba, long long nsze)
{
@@ -241,7 +240,7 @@ static void netapp_ontapdevice_json(struct json_array *devices, char *devname,
static void netapp_smdevices_print(struct smdevice_info *devices, int count, int format)
{
struct json_object *root = NULL;
- struct json_array *json_devices = NULL;
+ struct json_object *json_devices = NULL;
int i, slta;
char array_label[ARRAY_LABEL_LEN / 2 + 1];
char volume_label[VOLUME_LABEL_LEN / 2 + 1];
@@ -266,7 +265,7 @@ static void netapp_smdevices_print(struct smdevice_info *devices, int count, int
else if (format == NJSON) {
/* prepare for json output */
root = json_create_object();
- json_devices = json_create_array();
+ json_devices = json_create_object();
}
for (i = 0; i < count; i++) {
@@ -304,7 +303,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
int count, int format)
{
struct json_object *root = NULL;
- struct json_array *json_devices = NULL;
+ struct json_object *json_devices = NULL;
char vsname[ONTAP_LABEL_LEN] = " ";
char nspath[ONTAP_NS_PATHLEN] = " ";
long long lba;
@@ -332,7 +331,7 @@ static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
} else if (format == NJSON) {
/* prepare for json output */
root = json_create_object();
- json_devices = json_create_array();
+ json_devices = json_create_object();
}
for (i = 0; i < count; i++) {
diff --git a/plugins/nvidia/nvidia-nvme.c b/plugins/nvidia/nvidia-nvme.c
new file mode 100644
index 0000000..cdf51ab
--- /dev/null
+++ b/plugins/nvidia/nvidia-nvme.c
@@ -0,0 +1,58 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "nvidia-nvme.h"
+
+struct nvme_vu_id_ctrl_field {
+ __u16 json_rpc_2_0_mjr;
+ __u16 json_rpc_2_0_mnr;
+ __u16 json_rpc_2_0_ter;
+ __u8 reserved0[1018];
+};
+
+static void json_nvidia_id_ctrl(struct nvme_vu_id_ctrl_field *id,
+ char *json_rpc_2_0_ver, struct json_object *root)
+{
+ json_object_add_value_string(root, "json_rpc_2_0_ver",
+ json_rpc_2_0_ver);
+}
+
+static void nvidia_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
+ char json_rpc_2_0_ver[16] = { 0 };
+
+ snprintf(json_rpc_2_0_ver, sizeof(json_rpc_2_0_ver), "0x%04x%04x%04x",
+ le16_to_cpu(id->json_rpc_2_0_mjr),
+ le16_to_cpu(id->json_rpc_2_0_mnr),
+ le16_to_cpu(id->json_rpc_2_0_ter));
+
+ if (root) {
+ json_nvidia_id_ctrl(id, json_rpc_2_0_ver, root);
+ return;
+ }
+
+ printf("json_rpc_2_0_ver : %s\n", json_rpc_2_0_ver);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, nvidia_id_ctrl);
+}
diff --git a/plugins/nvidia/nvidia-nvme.h b/plugins/nvidia/nvidia-nvme.h
new file mode 100644
index 0000000..bf562b9
--- /dev/null
+++ b/plugins/nvidia/nvidia-nvme.h
@@ -0,0 +1,17 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/nvidia/nvidia-nvme
+
+#if !defined(NVIDIA_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define NVIDIA_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("nvidia", "NVIDIA vendor specific extensions"),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c
index 846ca77..df7f9a3 100644
--- a/plugins/scaleflux/sfx-nvme.c
+++ b/plugins/scaleflux/sfx-nvme.c
@@ -8,6 +8,8 @@
#include <asm/byteorder.h>
#include <sys/ioctl.h>
#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "linux/nvme_ioctl.h"
@@ -15,7 +17,6 @@
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "nvme-status.h"
-#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@@ -28,36 +29,40 @@
#define SECTOR_SHIFT 9
#define SFX_GET_FREESPACE _IOWR('N', 0x240, struct sfx_freespace_ctx)
-#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
+#define NVME_IOCTL_CLR_CARD _IO('N', 0x47)
+#define IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
+#define IDEMA_CAP2GB(exp_sector) (((__u64)exp_sector - 97696368ULL) / 1953504ULL + 50ULL)
enum {
SFX_LOG_LATENCY_READ_STATS = 0xc1,
SFX_LOG_SMART = 0xc2,
- SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
+ SFX_LOG_LATENCY_WRITE_STATS = 0xc3,
SFX_LOG_QUAL = 0xc4,
SFX_LOG_MISMATCHLBA = 0xc5,
SFX_LOG_MEDIA = 0xc6,
SFX_LOG_BBT = 0xc7,
SFX_LOG_IDENTIFY = 0xcc,
SFX_FEAT_ATOMIC = 0x01,
+ SFX_FEAT_UP_P_CAP = 0xac,
+ SFX_FEAT_CLR_CARD = 0xdc,
};
enum sfx_nvme_admin_opcode {
nvme_admin_query_cap_info = 0xd3,
nvme_admin_change_cap = 0xd4,
- nvme_admin_sfx_set_features = 0xd5,
- nvme_admin_sfx_get_features = 0xd6,
+ nvme_admin_sfx_set_features = 0xd5,
+ nvme_admin_sfx_get_features = 0xd6,
};
struct sfx_freespace_ctx
{
__u64 free_space;
- __u64 phy_cap; /* physical capacity, in unit of sector */
- __u64 phy_space; /* physical space considering OP, in unit of sector */
- __u64 user_space; /* user required space, in unit of sector*/
- __u64 hw_used; /* hw space used in 4K */
- __u64 app_written; /* app data written in 4K */
+ __u64 phy_cap; /* physical capacity, in unit of sector */
+ __u64 phy_space; /* physical space considering OP, in unit of sector */
+ __u64 user_space; /* user required space, in unit of sector*/
+ __u64 hw_used; /* hw space used in 4K */
+ __u64 app_written; /* app data written in 4K */
};
struct nvme_capacity_info {
@@ -66,7 +71,7 @@ struct nvme_capacity_info {
__u64 used_space;
__u64 free_space;
};
-struct __attribute__((packed)) nvme_additional_smart_log_item {
+struct __attribute__((packed)) nvme_additional_smart_log_item {
uint8_t key;
uint8_t _kp[2];
uint8_t norm;
@@ -112,11 +117,10 @@ int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
struct nvme_admin_cmd cmd = {
.opcode = nvme_admin_change_cap,
.nsid = nsid,
- .cdw10 = (capacity & 0xffffffff),
- .cdw11 = (capacity >> 32),
+ .cdw10 = (capacity & 0xffffffff),
+ .cdw11 = (capacity >> 32),
};
-
return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd);
}
@@ -267,65 +271,65 @@ static void show_sfx_smart_log(struct nvme_additional_smart_log *smart,
unsigned int nsid, const char *devname)
{
printf("Additional Smart Log for ScaleFlux device:%s namespace-id:%x\n",
- devname, nsid);
- printf("key normalized raw\n");
- printf("program_fail_count : %3d%% %"PRIu64"\n",
- smart->program_fail_cnt.norm,
- int48_to_long(smart->program_fail_cnt.raw));
- printf("erase_fail_count : %3d%% %"PRIu64"\n",
- smart->erase_fail_cnt.norm,
- int48_to_long(smart->erase_fail_cnt.raw));
- printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
- smart->wear_leveling_cnt.norm,
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
- le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
- printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
- smart->e2e_err_cnt.norm,
- int48_to_long(smart->e2e_err_cnt.raw));
- printf("crc_error_count : %3d%% %"PRIu64"\n",
- smart->crc_err_cnt.norm,
- int48_to_long(smart->crc_err_cnt.raw));
- printf("timed_workload_media_wear : %3d%% %.3f%%\n",
- smart->timed_workload_media_wear.norm,
- ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
- printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
- smart->timed_workload_host_reads.norm,
- int48_to_long(smart->timed_workload_host_reads.raw));
- printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
- smart->timed_workload_timer.norm,
- int48_to_long(smart->timed_workload_timer.raw));
- printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
- smart->thermal_throttle_status.norm,
- smart->thermal_throttle_status.thermal_throttle.pct,
- smart->thermal_throttle_status.thermal_throttle.count);
- printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
- smart->retry_buffer_overflow_cnt.norm,
- int48_to_long(smart->retry_buffer_overflow_cnt.raw));
- printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
- smart->pll_lock_loss_cnt.norm,
- int48_to_long(smart->pll_lock_loss_cnt.raw));
- printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
- smart->nand_bytes_written.norm,
- int48_to_long(smart->nand_bytes_written.raw));
- printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
- smart->host_bytes_written.norm,
- int48_to_long(smart->host_bytes_written.raw));
- printf("raid_recover_cnt : %3d%% %"PRIu64"\n",
- smart->raid_recover_cnt.norm,
- int48_to_long(smart->raid_recover_cnt.raw));
- printf("read_ecc_cnt : %3d%% %"PRIu64"\n",
- smart->read_ecc_cnt.norm,
- int48_to_long(smart->read_ecc_cnt.raw));
- printf("prog_timeout_cnt : %3d%% %"PRIu64"\n",
- smart->prog_timeout_cnt.norm,
- int48_to_long(smart->prog_timeout_cnt.raw));
- printf("erase_timeout_cnt : %3d%% %"PRIu64"\n",
- smart->erase_timeout_cnt.norm,
- int48_to_long(smart->erase_timeout_cnt.raw));
- printf("read_timeout_cnt : %3d%% %"PRIu64"\n",
- smart->read_timeout_cnt.norm,
- int48_to_long(smart->read_timeout_cnt.raw));
+ devname, nsid);
+ printf("key normalized raw\n");
+ printf("program_fail_count : %3d%% %"PRIu64"\n",
+ smart->program_fail_cnt.norm,
+ int48_to_long(smart->program_fail_cnt.raw));
+ printf("erase_fail_count : %3d%% %"PRIu64"\n",
+ smart->erase_fail_cnt.norm,
+ int48_to_long(smart->erase_fail_cnt.raw));
+ printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
+ smart->wear_leveling_cnt.norm,
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.min),
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.max),
+ le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
+ printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
+ smart->e2e_err_cnt.norm,
+ int48_to_long(smart->e2e_err_cnt.raw));
+ printf("crc_error_count : %3d%% %"PRIu64"\n",
+ smart->crc_err_cnt.norm,
+ int48_to_long(smart->crc_err_cnt.raw));
+ printf("timed_workload_media_wear : %3d%% %.3f%%\n",
+ smart->timed_workload_media_wear.norm,
+ ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
+ printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
+ smart->timed_workload_host_reads.norm,
+ int48_to_long(smart->timed_workload_host_reads.raw));
+ printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
+ smart->timed_workload_timer.norm,
+ int48_to_long(smart->timed_workload_timer.raw));
+ printf("thermal_throttle_status : %3d%% %u%%, cnt: %u\n",
+ smart->thermal_throttle_status.norm,
+ smart->thermal_throttle_status.thermal_throttle.pct,
+ smart->thermal_throttle_status.thermal_throttle.count);
+ printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
+ smart->retry_buffer_overflow_cnt.norm,
+ int48_to_long(smart->retry_buffer_overflow_cnt.raw));
+ printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
+ smart->pll_lock_loss_cnt.norm,
+ int48_to_long(smart->pll_lock_loss_cnt.raw));
+ printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
+ smart->nand_bytes_written.norm,
+ int48_to_long(smart->nand_bytes_written.raw));
+ printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
+ smart->host_bytes_written.norm,
+ int48_to_long(smart->host_bytes_written.raw));
+ printf("raid_recover_cnt : %3d%% %"PRIu64"\n",
+ smart->raid_recover_cnt.norm,
+ int48_to_long(smart->raid_recover_cnt.raw));
+ printf("read_ecc_cnt : %3d%% %"PRIu64"\n",
+ smart->read_ecc_cnt.norm,
+ int48_to_long(smart->read_ecc_cnt.raw));
+ printf("prog_timeout_cnt : %3d%% %"PRIu64"\n",
+ smart->prog_timeout_cnt.norm,
+ int48_to_long(smart->prog_timeout_cnt.raw));
+ printf("erase_timeout_cnt : %3d%% %"PRIu64"\n",
+ smart->erase_timeout_cnt.norm,
+ int48_to_long(smart->erase_timeout_cnt.raw));
+ printf("read_timeout_cnt : %3d%% %"PRIu64"\n",
+ smart->read_timeout_cnt.norm,
+ int48_to_long(smart->read_timeout_cnt.raw));
}
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -357,8 +361,8 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
- err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, sizeof(smart_log),
- (void *)&smart_log);
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, NVME_NO_LOG_LSP,
+ sizeof(smart_log), (void *)&smart_log);
if (!err) {
if (cfg.json)
show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
@@ -373,7 +377,6 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
return err;
}
-
struct sfx_lat_stats {
__u16 maj;
__u16 min;
@@ -440,7 +443,8 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
fd = parse_and_open(argc, argv, desc, opts);
- err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, sizeof(stats), (void *)&stats);
+ err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, NVME_NO_LOG_LSP,
+ sizeof(stats), (void *)&stats);
if (!err) {
if (!cfg.raw_binary)
show_lat_stats(&stats, cfg.write);
@@ -448,7 +452,7 @@ static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct
d_raw((unsigned char *)&stats, sizeof(stats));
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
- nvme_status_to_string(err), err);
+ nvme_status_to_string(err), err);
return err;
}
@@ -517,16 +521,16 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size)
bb_elem = (__u64 *)(bd_table + 5 * sizeof(__u32));
printf("Bad Block Table \n");
- printf("MF_BB_COUNT: %u\n", mf_bb_count);
- printf("GROWN_BB_COUNT: %u\n", grown_bb_count);
- printf("TOTAL_BB_COUNT: %u\n", total_bb_count);
- printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count);
- printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count);
+ printf("MF_BB_COUNT: %u\n", mf_bb_count);
+ printf("GROWN_BB_COUNT: %u\n", grown_bb_count);
+ printf("TOTAL_BB_COUNT: %u\n", total_bb_count);
+ printf("REMAP_MFBB_COUNT: %u\n", remap_mfbb_count);
+ printf("REMAP_GBB_COUNT: %u\n", remap_gbb_count);
printf("REMAP_MFBB_TABLE [");
i = 0;
while (bb_elem < elem_end && i < remap_mfbb_count) {
- printf(" 0x%llx", *(bb_elem++));
+ printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
i++;
}
printf(" ]\n");
@@ -534,14 +538,14 @@ static void bd_table_show(unsigned char *bd_table, __u64 table_size)
printf("REMAP_GBB_TABLE [");
i = 0;
while (bb_elem < elem_end && i < remap_gbb_count) {
- printf(" 0x%llx",*(bb_elem++));
+ printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
i++;
}
printf(" ]\n");
}
/**
- * @brief "hooks of sfx get-bad-block"
+ * @brief "hooks of sfx get-bad-block"
*
* @param argc
* @param argv
@@ -592,10 +596,16 @@ static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct
static void show_cap_info(struct sfx_freespace_ctx *ctx)
{
- printf("user sectors: %#llx\n", ctx->user_space);
- printf("totl physical sectors: %#llx\n", ctx->phy_space);
- printf("free physical sectors: %#llx\n", ctx->free_space);
- printf("used physical sectors: %#llx\n", ctx->phy_space - ctx->free_space);
+
+ printf("logic capacity:%5lluGB(0x%"PRIx64")\n",
+ IDEMA_CAP2GB(ctx->user_space), (uint64_t)ctx->user_space);
+ printf("provisioned capacity:%5lluGB(0x%"PRIx64")\n",
+ IDEMA_CAP2GB(ctx->phy_space), (uint64_t)ctx->phy_space);
+ printf("free provisioned capacity:%5lluGB(0x%"PRIx64")\n",
+ IDEMA_CAP2GB(ctx->free_space), (uint64_t)ctx->free_space);
+ printf("used provisioned capacity:%5lluGB(0x%"PRIx64")\n",
+ IDEMA_CAP2GB(ctx->phy_space) - IDEMA_CAP2GB(ctx->free_space),
+ (uint64_t)(ctx->phy_space - ctx->free_space));
}
static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
@@ -631,42 +641,94 @@ static int query_cap_info(int argc, char **argv, struct command *cmd, struct plu
return err;
}
-static int change_cap_mem_check(int fd, __u64 trg_in_4k)
+static int change_sanity_check(int fd, __u64 trg_in_4k, int *shrink)
{
struct sfx_freespace_ctx freespace_ctx = { 0 };
struct sysinfo s_info;
__u64 mem_need = 0;
__u64 cur_in_4k = 0;
+ __u64 provisoned_cap_4k = 0;
__u32 cnt_ms = 0;
+ int extend = 0;
while (ioctl(fd, SFX_GET_FREESPACE, &freespace_ctx)) {
if (cnt_ms++ > 600) {//1min
- fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno);
return -1;
}
usleep(100000);
}
- cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT);
- if (cur_in_4k > trg_in_4k) {
- return 0;
+ /*
+ * capacity illegal check
+ */
+ provisoned_cap_4k = freespace_ctx.phy_space >>
+ (SFX_PAGE_SHIFT - SECTOR_SHIFT);
+ if (trg_in_4k < provisoned_cap_4k ||
+ trg_in_4k > ((__u64)provisoned_cap_4k * 4)) {
+ fprintf(stderr,
+ "WARNING: Only support 1.0~4.0 x provisoned capacity!\n");
+ if (trg_in_4k < provisoned_cap_4k) {
+ fprintf(stderr,
+ "WARNING: The target capacity is less than 1.0 x provisioned capacity!\n");
+ } else {
+ fprintf(stderr,
+ "WARNING: The target capacity is larger than 4.0 x provisioned capacity!\n");
+ }
+ return -1;
}
-
- if (sysinfo(&s_info) < 0) {
- printf("change-cap query mem info fail\n");
+ if (trg_in_4k > ((__u64)provisoned_cap_4k*4)) {
+ fprintf(stderr, "WARNING: the target capacity is too large\n");
return -1;
}
- mem_need = (trg_in_4k - cur_in_4k) * 8;
- if (s_info.freeram <= 10 || mem_need > s_info.freeram) {
- fprintf(stderr, "WARNING: mem needed is %llu, free mem is %lu\n"
- "Insufficient memory, please drop cache or add free memory and retry\n",
- mem_need, s_info.freeram);
- return -1;
+ /*
+ * check whether mem enough if extend
+ * */
+ cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT);
+ extend = (cur_in_4k <= trg_in_4k);
+ if (extend) {
+ if (sysinfo(&s_info) < 0) {
+ printf("change-cap query mem info fail\n");
+ return -1;
+ }
+ mem_need = (trg_in_4k - cur_in_4k) * 8;
+ if (s_info.freeram <= 10 || mem_need > s_info.freeram) {
+ fprintf(stderr,
+ "WARNING: Free memory is not enough! "
+ "Please drop cache or extend more memory and retry\n"
+ "WARNING: Memory needed is %"PRIu64", free memory is %"PRIu64"\n",
+ (uint64_t)mem_need, (uint64_t)s_info.freeram);
+ return -1;
+ }
}
+ *shrink = !extend;
+
return 0;
}
+/**
+ * @brief prompt and get user confirm input
+ *
+ * @param str, prompt string
+ *
+ * @return 0, cancled; 1 confirmed
+ */
+static int sfx_confirm_change(const char *str)
+{
+ char confirm;
+ fprintf(stderr, "WARNING: %s.\n"
+ "Use the force [--force] option to suppress this warning.\n", str);
+
+ fprintf(stderr, "Confirm Y/y, Others cancel:\n");
+ confirm = fgetc(stdin);
+ if (confirm != 'y' && confirm != 'Y') {
+ fprintf(stderr, "Cancled.\n");
+ return 0;
+ }
+ fprintf(stderr, "Sending operation ... \n");
+ return 1;
+}
+
static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
{
int err = -1, fd;
@@ -678,6 +740,8 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
__u64 cap_in_4k = 0;
__u64 cap_in_sec = 0;
+ int shrink = 0;
+
struct config {
__u64 cap_in_byte;
__u32 capacity_in_gb;
@@ -694,7 +758,7 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
OPT_ARGS(opts) = {
OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb),
- OPT_UINT("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
+ OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
OPT_FLAG("force", 'f', &cfg.force, force),
OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
OPT_FLAG("json", 'j', &cfg.json, json),
@@ -706,22 +770,21 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
return fd;
}
- if (!cfg.force) {
- fprintf(stderr, "WARNING: Changing capacity may irrevocably delete user data.\n"
- "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"
- "Use the force [--force|-f] option to suppress this warning.\n");
- sleep(10);
- fprintf(stderr, "Sending operation ... \n");
- }
-
cap_in_sec = IDEMA_CAP(cfg.capacity_in_gb);
cap_in_4k = cap_in_sec >> 3;
if (cfg.cap_in_byte)
cap_in_4k = cfg.cap_in_byte >> 12;
- printf("%dG %lluB %llu 4K\n",
- cfg.capacity_in_gb, cfg.cap_in_byte, cap_in_4k);
- if (change_cap_mem_check(fd, cap_in_4k))
+ printf("%dG %"PRIu64"B %"PRIu64" 4K\n",
+ cfg.capacity_in_gb, (uint64_t)cfg.cap_in_byte, (uint64_t)cap_in_4k);
+
+ if (change_sanity_check(fd, cap_in_4k, &shrink)) {
+ printf("ScaleFlux change-capacity: fail\n");
return err;
+ }
+
+ if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) {
+ return 0;
+ }
err = nvme_change_cap(fd, 0xffffffff, cap_in_4k);
if (err < 0)
@@ -731,20 +794,54 @@ static int change_cap(int argc, char **argv, struct command *cmd, struct plugin
nvme_status_to_string(err), err);
else {
printf("ScaleFlux change-capacity: success\n");
- if(ioctl(fd, BLKRRPART) < 0) {
- fprintf(stderr, "failed to re-read partition table\n");
- err = EFAULT;
- }
+ ioctl(fd, BLKRRPART);
}
return err;
}
+static int sfx_verify_chr(int fd)
+{
+ static struct stat nvme_stat;
+ int err = fstat(fd, &nvme_stat);
+
+ if (err < 0) {
+ perror("fstat");
+ return errno;
+ }
+ if (!S_ISCHR(nvme_stat.st_mode)) {
+ fprintf(stderr,
+ "Error: requesting clean card on non-controller handle\n");
+ return ENOTBLK;
+ }
+ return 0;
+}
+
+static int sfx_clean_card(int fd)
+{
+ int ret;
+
+ ret = sfx_verify_chr(fd);
+ if (ret)
+ return ret;
+ ret = ioctl(fd, NVME_IOCTL_CLR_CARD);
+ if (ret)
+ perror("Ioctl Fail.");
+ else
+ printf("ScaleFlux clean card success\n");
+
+ return ret;
+}
+
char *sfx_feature_to_string(int feature)
{
switch (feature) {
- case SFX_FEAT_ATOMIC: return "ATOMIC";
+ case SFX_FEAT_ATOMIC:
+ return "ATOMIC";
+ case SFX_FEAT_UP_P_CAP:
+ return "UPDATE_PROVISION_CAPACITY";
- default: return "Unknown";
+ default:
+ return "Unknown";
}
}
@@ -752,27 +849,34 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
{
int err = 0, fd;
char *desc = "ScaleFlux internal set features\n"
- "feature id 1: ATOMIC";
+ "feature id 1: ATOMIC\n"
+ "value 0: Disable atomic write\n"
+ " 1: Enable atomic write";
const char *value = "new value of feature (required)";
const char *feature_id = "hex feature name (required)";
const char *namespace_id = "desired namespace";
+ const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
+
struct nvme_id_ns ns;
struct config {
__u32 namespace_id;
__u32 feature_id;
__u32 value;
+ __u32 force;
};
struct config cfg = {
.namespace_id = 1,
.feature_id = 0,
.value = 0,
+ .force = 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_UINT("value", 'v', &cfg.value, value),
+ OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_FLAG("force", 's', &cfg.force, force),
OPT_END()
};
@@ -786,7 +890,17 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
return EINVAL;
}
- if (cfg.feature_id == SFX_FEAT_ATOMIC) {
+ if (cfg.feature_id == SFX_FEAT_CLR_CARD) {
+ /*Warning for clean card*/
+ if (!cfg.force && !sfx_confirm_change("Going to clean device's data, confirm umount fs and try again")) {
+ return 0;
+ } else {
+ return sfx_clean_card(fd);
+ }
+
+ }
+
+ if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value != 0) {
if (cfg.namespace_id != 0xffffffff) {
err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns);
if (err) {
@@ -806,14 +920,25 @@ static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct pl
return EFAULT;
}
}
+ } else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) {
+ if (cfg.value <= 0) {
+ fprintf(stderr, "Invalid Param\n");
+ return EINVAL;
+ }
+
+ /*Warning for change pacp by GB*/
+ if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) {
+ return 0;
+ }
}
err = nvme_sfx_set_features(fd, cfg.namespace_id, cfg.feature_id, cfg.value);
+
if (err < 0) {
perror("ScaleFlux-set-feature");
return errno;
} else if (!err) {
- printf("ScaleFlux set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ printf("ScaleFlux set-feature:%#02x (%s), value:%d\n", cfg.feature_id,
sfx_feature_to_string(cfg.feature_id), cfg.value);
} else if (err > 0)
fprintf(stderr, "NVMe Status:%s(%x)\n",
diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h
index daf9c33..8f14501 100644
--- a/plugins/scaleflux/sfx-nvme.h
+++ b/plugins/scaleflux/sfx-nvme.h
@@ -14,12 +14,10 @@ PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions"),
ENTRY("query-cap", "Query current capacity info", query_cap_info)
ENTRY("change-cap", "Dynamic change capacity", change_cap)
ENTRY("set-feature", "Set a feature", sfx_set_feature)
- ENTRY("get-feature", "get a feature", sfx_get_feature)
+ ENTRY("get-feature", "Get a feature", sfx_get_feature)
)
);
#endif
#include "define_cmd.h"
-
-
diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c
index 7ba14f8..d5ef32b 100644
--- a/plugins/seagate/seagate-nvme.c
+++ b/plugins/seagate/seagate-nvme.c
@@ -36,7 +36,6 @@
#include "plugin.h"
#include "argconfig.h"
#include "suffix.h"
-#include "json.h"
#define CREATE_CMD
@@ -132,7 +131,7 @@ static char *log_pages_supp_print(__u32 pageID)
static void json_log_pages_supp(log_page_map *logPageMap)
{
struct json_object *root;
- struct json_array *logPages;
+ struct json_object *logPages;
__u32 i = 0;
root = json_create_object();
@@ -177,7 +176,8 @@ static int log_pages_supp(int argc, char **argv, struct command *cmd,
};
fd = parse_and_open(argc, argv, desc, opts);
- err = nvme_get_log(fd, 1, 0xc5, false, sizeof(logPageMap), &logPageMap);
+ err = nvme_get_log(fd, 1, 0xc5, false, NVME_NO_LOG_LSP,
+ sizeof(logPageMap), &logPageMap);
if (!err) {
if (strcmp(cfg.output_format,"json")) {
printf ("Seagate Supported Log-pages count :%d\n",
@@ -312,7 +312,7 @@ static char *print_ext_smart_id(__u8 attrId)
return "RAIS_ECC_CORRECT_ERR_COUNT";
break;
case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
- return "Uncorrectable read error count";/*VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS*/
+ return "Uncorrectable RAISE error count";/*VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS*/
break;
case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
return "DRIVE_LIFE_PROTECTION_STATUS";
@@ -493,7 +493,7 @@ static void json_print_smart_log(struct json_object *root,
EXTENDED_SMART_INFO_T *ExtdSMARTInfo )
{
/*struct json_object *root; */
- struct json_array *lbafs;
+ struct json_object *lbafs;
int index = 0;
static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
@@ -650,7 +650,7 @@ static void json_print_smart_log_CF(struct json_object *root,
vendor_log_page_CF *pLogPageCF)
{
/*struct json_object *root;*/
- struct json_array *logPages;
+ struct json_object *logPages;
unsigned int currentTemp, maxTemp;
char buf[40];
@@ -715,11 +715,9 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
EXTENDED_SMART_INFO_T ExtdSMARTInfo;
vendor_log_page_CF logPageCF;
int fd;
- struct json_object *root;
- struct json_array *lbafs;
+ struct json_object *root = json_create_object();
+ struct json_object *lbafs = json_create_array();
struct json_object *lbafs_ExtSmart, *lbafs_DramSmart;
- root = json_create_object();
- lbafs = json_create_array();
const char *desc = "Retrieve Seagate Extended SMART information for the given device ";
const char *output_format = "output in binary format";
@@ -741,7 +739,8 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
if (strcmp(cfg.output_format,"json"))
printf("Seagate Extended SMART Information :\n");
- err = nvme_get_log(fd, 1, 0xC4, false, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
+ err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP,
+ sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
if (strcmp(cfg.output_format,"json")) {
printf("%-39s %-15s %-19s \n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
@@ -763,7 +762,8 @@ static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugi
* Next get Log Page 0xCF
*/
- err = nvme_get_log(fd, 1, 0xCF, false, sizeof(logPageCF), &logPageCF);
+ err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP,
+ sizeof(logPageCF), &logPageCF);
if (!err) {
if(strcmp(cfg.output_format,"json")) {
/*printf("Seagate DRAM Supercap SMART Attributes :\n");*/
@@ -860,7 +860,8 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
}
/* STEP-2 : Get Max temperature form Ext SMART-id 194 */
- err = nvme_get_log(fd, 1, 0xC4, false, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
+ err = nvme_get_log(fd, 1, 0xC4, false, NVME_NO_LOG_LSP,
+ sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
if (!err) {
for(index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_LIFE_TEMPERATURE) {
@@ -882,7 +883,8 @@ static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin
fprintf(stderr, "NVMe Status:%s(%x)\n",
nvme_status_to_string(err), err);
- cf_err = nvme_get_log(fd, 1, 0xCF, false, sizeof(ExtdSMARTInfo), &logPageCF);
+ cf_err = nvme_get_log(fd, 1, 0xCF, false, NVME_NO_LOG_LSP,
+ sizeof(ExtdSMARTInfo), &logPageCF);
if(!cf_err) {
scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature;
@@ -1011,7 +1013,8 @@ static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct
if(strcmp(cfg.output_format,"json"))
printf("Seagate PCIe error counters Information :\n");
- err = nvme_get_log(fd, 1, 0xCB, false, sizeof(pcieErrorLog), &pcieErrorLog);
+ err = nvme_get_log(fd, 1, 0xCB, false, NVME_NO_LOG_LSP,
+ sizeof(pcieErrorLog), &pcieErrorLog);
if (!err) {
if(strcmp(cfg.output_format,"json")) {
print_vs_pcie_error_log(pcieErrorLog);
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
index 3aa6f8a..588f4f3 100644
--- a/plugins/shannon/shannon-nvme.c
+++ b/plugins/shannon/shannon-nvme.c
@@ -11,7 +11,6 @@
#include "nvme.h"
#include "nvme-print.h"
#include "nvme-ioctl.h"
-#include "json.h"
#include "plugin.h"
#include "argconfig.h"
@@ -143,7 +142,7 @@ static int get_additional_smart_log(int argc, char **argv, struct command *cmd,
fd = parse_and_open(argc, argv, desc, opts);
err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
- sizeof(smart_log), &smart_log);
+ NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
if (!err) {
if (!cfg.raw_binary)
show_shannon_smart_log(&smart_log, cfg.namespace_id, devicename);
@@ -182,7 +181,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
struct config {
__u32 namespace_id;
- __u32 feature_id;
+ enum nvme_feat feature_id;
__u8 sel;
__u32 cdw11;
__u32 data_len;
@@ -192,7 +191,7 @@ static int get_additional_feature(int argc, char **argv, struct command *cmd, st
struct config cfg = {
.namespace_id = 1,
- .feature_id = 0,
+ .feature_id = NVME_FEAT_NONE,
.sel = 0,
.cdw11 = 0,
.data_len = 0,
diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c
index c067ce8..53d54bc 100644
--- a/plugins/toshiba/toshiba-nvme.c
+++ b/plugins/toshiba/toshiba-nvme.c
@@ -393,7 +393,7 @@ static int nvme_get_vendor_log(int fd, __u32 namespace_id, int log_page,
goto end;
}
err = nvme_get_log(fd, namespace_id, log_page, false,
- log_len, log);
+ NVME_NO_LOG_LSP, log_len, log);
if (err) {
fprintf(stderr, "%s: couldn't get log 0x%x\n", __func__,
log_page);
diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c
index 47b0fdc..a194a5f 100644
--- a/plugins/virtium/virtium-nvme.c
+++ b/plugins/virtium/virtium-nvme.c
@@ -633,7 +633,7 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
const char *VWCtable[2] = {"0 = a volatile write cache is not present",
"1 = a volatile write cache is present"};
- const char *NVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific",
+ const char *ICSVSCCtable[2] = {"0 = the format of all NVM Vendor Specific Commands are vendor specific",
"1 = all NVM Vendor Specific Commands use the format defined in NVM Express specification"};
const char *SGLSSubtable[4] = {"00b = SGLs are not supported",
@@ -883,11 +883,11 @@ static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
vt_convert_data_buffer_to_hex_string(&buf[528], 2, true, s);
printf(" \"Atomic Write Unit Power Fail\":\"%sh\",\n", s);
- temp = ctrl->nvscc;
+ temp = ctrl->icsvscc;
printf(" \"NVM Vendor Specific Command Configuration\":{\n");
vt_convert_data_buffer_to_hex_string(&buf[530], 1, true, s);
printf(" \"Value\":\"%sh\",\n", s);
- vt_build_identify_lv2(temp, 0, 1, NVSCCtable, true);
+ vt_build_identify_lv2(temp, 0, 1, ICSVSCCtable, true);
vt_convert_data_buffer_to_hex_string(&buf[532], 2, true, s);
printf(" \"Atomic Compare 0 Write Unit\":\"%sh\",\n", s);
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c
index 0cebe3f..f7a5b31 100644
--- a/plugins/wdc/wdc-nvme.c
+++ b/plugins/wdc/wdc-nvme.c
@@ -19,6 +19,7 @@
* Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>,
* Dong Ho <dong.ho@hgst.com>,
* Jeff Lien <jeff.lien@wdc.com>
+ * Brandon Paupore <brandon.paupore@wdc.com>
*/
#include <stdio.h>
#include <string.h>
@@ -36,7 +37,7 @@
#include "nvme-print.h"
#include "nvme-ioctl.h"
#include "plugin.h"
-#include "json.h"
+#include "nvme-status.h"
#include "argconfig.h"
#include "suffix.h"
@@ -52,6 +53,11 @@
#define WDC_NVME_LOG_SIZE_DATA_LEN 0x08
#define WDC_NVME_LOG_SIZE_HDR_LEN 0x08
+/* Enclosure */
+#define WDC_OPENFLEX_MI_DEVICE_MODEL "OpenFlex"
+#define WDC_RESULT_MORE_DATA 0x80000000
+#define WDC_RESULT_NOT_AVAILABLE 0x7FFFFFFF
+
/* Device Config */
#define WDC_NVME_VID 0x1c58
#define WDC_NVME_VID_2 0x1b96
@@ -66,12 +72,13 @@
#define WDC_NVME_SN640_DEV_ID 0x2400
#define WDC_NVME_SN640_DEV_ID_1 0x2401
#define WDC_NVME_SN640_DEV_ID_2 0x2402
-#define WDC_NVME_SN640_DEV_ID_3 0x2404
-#define WDC_NVME_ZN440_DEV_ID 0x2600
-#define WDC_NVME_SN440_DEV_ID 0x2610
-#define WDC_NVME_SN7GC_DEV_ID 0x2700
-#define WDC_NVME_SN7GC_DEV_ID_1 0x2701
-#define WDC_NVME_SN7GC_DEV_ID_2 0x2702
+#define WDC_NVME_SN640_DEV_ID_3 0x2404
+#define WDC_NVME_ZN540_DEV_ID 0x2600
+#define WDC_NVME_SN540_DEV_ID 0x2610
+#define WDC_NVME_SN650_DEV_ID 0x2700
+#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_SXSLCL_DEV_ID 0x2001
#define WDC_NVME_SN520_DEV_ID 0x5003
#define WDC_NVME_SN520_DEV_ID_1 0x5004
@@ -81,6 +88,8 @@
#define WDC_NVME_SN730B_DEV_ID 0x3714
#define WDC_NVME_SN730B_DEV_ID_1 0x3734
#define WDC_NVME_SN340_DEV_ID 0x500d
+#define WDC_NVME_ZN350_DEV_ID 0x5010
+#define WDC_NVME_ZN350_DEV_ID_1 0x5018
#define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001
#define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002
@@ -92,9 +101,9 @@
#define WDC_DRIVE_CAP_CLEAR_PCIE 0x0000000000000080
#define WDC_DRIVE_CAP_RESIZE 0x0000000000000100
#define WDC_DRIVE_CAP_NAND_STATS 0x0000000000000200
-#define WDC_DRIVE_CAP_DRIVE_LOG 0x0000000000000400
-#define WDC_DRIVE_CAP_CRASH_DUMP 0x0000000000000800
-#define WDC_DRIVE_CAP_PFAIL_DUMP 0x0000000000001000
+#define WDC_DRIVE_CAP_DRIVE_LOG 0x0000000000000400
+#define WDC_DRIVE_CAP_CRASH_DUMP 0x0000000000000800
+#define WDC_DRIVE_CAP_PFAIL_DUMP 0x0000000000001000
#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY 0x0000000000002000
#define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY 0x0000000000004000
#define WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG 0x0000000000008000
@@ -102,14 +111,31 @@
#define WDC_DRIVE_CAP_LOG_PAGE_DIR 0x0000000000020000
#define WDC_DRIVE_CAP_NS_RESIZE 0x0000000000040000
#define WDC_DRIVE_CAP_INFO 0x0000000000080000
+#define WDC_DRIVE_CAP_C0_LOG_PAGE 0x0000000000100000
+#define WDC_DRIVE_CAP_TEMP_STATS 0x0000000000200000
+#define WDC_DRIVE_CAP_VUC_CLEAR_PCIE 0x0000000000400000
+#define WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE 0x0000000000800000
+#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 0x0000000001000000
+#define WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY 0x0000000002000000
+#define WDC_DRIVE_CAP_CLOUD_SSD_VERSION 0x0000000004000000
+#define WDC_DRIVE_CAP_PCIE_STATS 0x0000000008000000
+#define WDC_DRIVE_CAP_INFO_2 0x0000000010000000
#define WDC_DRIVE_CAP_DRIVE_ESSENTIALS 0x0000000100000000
#define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000
#define WDC_SN730B_CAP_VUC_LOG 0x0000000400000000
-#define WDC_DRIVE_CAP_SN340_DUI 0x0000000800000000
-#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C1_LOG_PAGE | WDC_DRIVE_CAP_CA_LOG_PAGE | \
- WDC_DRIVE_CAP_D0_LOG_PAGE)
-
+#define WDC_DRIVE_CAP_DUI 0x0000000800000000
+#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 | \
+ WDC_DRIVE_CAP_VUC_CLEAR_PCIE | \
+ WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE)
+#define WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK (WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | \
+ WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2)
+#define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | \
+ WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY)
+#define WDC_DRIVE_CAP_INTERNAL_LOG_MASK (WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_DUI | \
+ WDC_DRIVE_CAP_DUI_DATA | WDC_SN730B_CAP_VUC_LOG)
/* SN730 Get Log Capabilities */
#define SN730_NVME_GET_LOG_OPCODE 0xc2
#define SN730_GET_FULL_LOG_LENGTH 0x00080009
@@ -126,9 +152,20 @@
/* Customer ID's */
#define WDC_CUSTOMER_ID_GN 0x0001
#define WDC_CUSTOMER_ID_GD 0x0101
-#define WDC_CUSTOMER_ID_0x1004 0x1004
+#define WDC_CUSTOMER_ID_BD 0x1009
+
#define WDC_CUSTOMER_ID_0x1005 0x1005
+#define WDC_CUSTOMER_ID_0x1004 0x1004
+#define WDC_CUSTOMER_ID_0x1008 0x1008
+#define WDC_CUSTOMER_ID_0x1304 0x1304
+
+#define WDC_ALL_PAGE_MASK 0xFFFF
+#define WDC_C0_PAGE_MASK 0x0001
+#define WDC_C1_PAGE_MASK 0x0002
+#define WDC_CA_PAGE_MASK 0x0004
+#define WDC_D0_PAGE_MASK 0x0008
+
/* Drive Resize */
#define WDC_NVME_DRIVE_RESIZE_OPCODE 0xCC
#define WDC_NVME_DRIVE_RESIZE_CMD 0x03
@@ -142,6 +179,9 @@
#define WDC_NVME_DRIVE_INFO_CMD 0x22
#define WDC_NVME_DRIVE_INFO_SUBCMD 0x06
+/* VS PCIE Stats */
+#define WDC_NVME_PCIE_STATS_OPCODE 0xD1
+
/* Capture Diagnostics */
#define WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE WDC_NVME_LOG_SIZE_DATA_LEN
#define WDC_NVME_CAP_DIAG_OPCODE 0xE6
@@ -160,6 +200,7 @@
#define WDC_NVME_DUI_MAX_SECTION_V2 0x26
#define WDC_NVME_DUI_MAX_SECTION_V3 0x23
#define WDC_NVME_DUI_MAX_DATA_AREA 0x05
+#define WDC_NVME_SN730_SECTOR_SIZE 512
/* Telemtery types for vs-internal-log command */
#define WDC_TELEMETRY_TYPE_NONE 0x0
@@ -224,6 +265,7 @@
#define WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE 0xC6
#define WDC_NVME_CLEAR_FW_ACT_HIST_CMD 0x23
#define WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD 0x05
+#define WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID 0xC1
/* Additional Smart Log */
#define WDC_ADD_LOG_BUF_LEN 0x4000
@@ -233,6 +275,7 @@
/* C2 Log Page */
#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE 0xC2
+#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 0xC8
#define WDC_C2_LOG_BUF_LEN 0x1000
#define WDC_C2_LOG_PAGES_SUPPORTED_ID 0x08
#define WDC_C2_CUSTOMER_ID_ID 0x15
@@ -262,11 +305,20 @@
/* C0 EOL Status Log Page */
#define WDC_NVME_GET_EOL_STATUS_LOG_OPCODE 0xC0
#define WDC_NVME_EOL_STATUS_LOG_LEN 0x200
+#define WDC_NVME_SMART_CLOUD_ATTR_LEN 0x200
+
+/* C0 SMART Cloud Attributes Log Page*/
+#define WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE 0xC0
/* CB - FW Activate History Log Page */
#define WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID 0xCB
#define WDC_FW_ACT_HISTORY_LOG_BUF_LEN 0x3d0
+/* C2 - FW Activation History Log Page */
+#define WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID 0xC2
+#define WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN 0x1000
+#define WDC_MAX_NUM_ACT_HIST_ENTRIES 20
+
/* D0 Smart Log Page */
#define WDC_NVME_GET_VU_SMART_LOG_OPCODE 0xD0
#define WDC_NVME_VU_SMART_LOG_LEN 0x200
@@ -274,13 +326,16 @@
/* Log Page Directory defines */
#define NVME_LOG_PERSISTENT_EVENT 0x0D
#define WDC_LOG_ID_C0 0xC0
+#define WDC_LOG_ID_C1 0xC1
#define WDC_LOG_ID_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE
#define WDC_LOG_ID_C4 0xC4
#define WDC_LOG_ID_C5 0xC5
#define WDC_LOG_ID_C6 0xC6
+#define WDC_LOG_ID_C8 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8
#define WDC_LOG_ID_CA WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE
#define WDC_LOG_ID_CB WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID
#define WDC_LOG_ID_D0 WDC_NVME_GET_VU_SMART_LOG_OPCODE
+#define WDC_LOG_ID_D1 0xD1
#define WDC_LOG_ID_D6 0xD6
#define WDC_LOG_ID_D7 0xD7
#define WDC_LOG_ID_D8 0xD8
@@ -291,10 +346,11 @@
#define WDC_LOG_ID_FA 0xFA
/* Clear PCIe Correctable Errors */
-#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
-#define WDC_NVME_CLEAR_PCIE_CORR_CMD 0x22
-#define WDC_NVME_CLEAR_PCIE_CORR_SUBCMD 0x04
-
+#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
+#define WDC_NVME_CLEAR_PCIE_CORR_CMD 0x22
+#define WDC_NVME_CLEAR_PCIE_CORR_SUBCMD 0x04
+#define WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC 0xD2
+#define WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID 0xC3
/* Clear Assert Dump Status */
#define WDC_NVME_CLEAR_ASSERT_DUMP_OPCODE 0xD8
#define WDC_NVME_CLEAR_ASSERT_DUMP_CMD 0x03
@@ -319,6 +375,8 @@
/* VU Opcodes */
#define WDC_DE_VU_READ_SIZE_OPCODE 0xC0
#define WDC_DE_VU_READ_BUFFER_OPCODE 0xC2
+#define WDC_NVME_ADMIN_ENC_MGMT_SND 0xC9
+#define WDC_NVME_ADMIN_ENC_MGMT_RCV 0xCA
#define WDC_DE_FILE_HEADER_SIZE 4
#define WDC_DE_FILE_OFFSET_SIZE 2
@@ -332,6 +390,21 @@
#define WDC_DE_DESTN_SPI 1
#define WDC_DE_DUMPTRACE_DESTINATION 6
+#define NVME_ID_CTRL_MODEL_NUMBER_SIZE 40
+#define NVME_ID_CTRL_SERIAL_NUMBER_SIZE 20
+
+/* Enclosure log */
+#define WDC_NVME_ENC_LOG_SIZE_CHUNK 0x1000
+#define WDC_NVME_ENC_NIC_LOG_SIZE 0x400000
+
+/* Enclosure nic crash dump get-log id */
+#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 0xD1
+#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2 0xD2
+#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 0xD3
+#define WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4 0xD4
+#define WDC_ENC_CRASH_DUMP_ID 0xE4
+#define WDC_ENC_LOG_DUMP_ID 0xE2
+
typedef enum _NVME_FEATURES_SELECT
{
FS_CURRENT = 0,
@@ -392,6 +465,62 @@ typedef enum
WDC_DE_TYPE_ALL = 0xFFFFFFF,
} WDC_DRIVE_ESSENTIAL_TYPE;
+typedef enum
+{
+ SCAO_PMUW = 0, /* Physical media units written */
+ SCAO_PMUR = 16, /* Physical media units read */
+ SCAO_BUNBR = 32, /* Bad user nand blocks raw */
+ SCAO_BUNBN = 38, /* Bad user nand blocks normalized */
+ SCAO_BSNBR = 40, /* Bad system nand blocks raw */
+ SCAO_BSNBN = 46, /* Bad system nand blocks normalized */
+ SCAO_XRC = 48, /* XOR recovery count */
+ SCAO_UREC = 56, /* Uncorrectable read error count */
+ SCAO_SEEC = 64, /* Soft ecc error count */
+ SCAO_EECE = 72, /* End to end corrected errors */
+ SCAO_EEDC = 76, /* End to end detected errors */
+ SCAO_SDPU = 80, /* System data percent used */
+ SCAO_RFSC = 81, /* Refresh counts */
+ SCAO_MXUDEC = 88, /* Max User data erase counts */
+ SCAO_MNUDEC = 92, /* Min User data erase counts */
+ SCAO_NTTE = 96, /* Number of Thermal throttling events */
+ SCAO_CTS = 97, /* Current throttling status */
+ SCAO_EVF = 98, /* Errata Version Field */
+ SCAO_PVF = 99, /* Point Version Field */
+ SCAO_MIVF = 101, /* Minor Version Field */
+ SCAO_MAVF = 103, /* Major Version Field */
+ SCAO_PCEC = 104, /* PCIe correctable error count */
+ SCAO_ICS = 112, /* Incomplete shutdowns */
+ SCAO_PFB = 120, /* Percent free blocks */
+ SCAO_CPH = 128, /* Capacitor health */
+ SCAO_NEV = 130, /* NVMe Errata Version */
+ SCAO_UIO = 136, /* Unaligned I/O */
+ SCAO_SVN = 144, /* Security Version Number */
+ SCAO_NUSE = 152, /* NUSE - Namespace utilization */
+ SCAO_PSC = 160, /* PLP start count */
+ SCAO_EEST = 176, /* Endurance estimate */
+ SCAO_PLRC = 192, /* PCIe Link Retraining Count */
+ SCAO_LPV = 494, /* Log page version */
+ SCAO_LPG = 496, /* Log page GUID */
+} SMART_CLOUD_ATTRIBUTE_OFFSETS;
+
+#define WDC_C2_GUID_LENGTH 16
+
+static __u8 scao_guid[WDC_C2_GUID_LENGTH] = { 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
+ 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF };
+
+typedef enum
+{
+ EOL_RBC = 76, /* Realloc Block Count */
+ EOL_ECCR = 80, /* ECC Rate */
+ EOL_WRA = 84, /* Write Amp */
+ EOL_PLR = 88, /* Percent Life Remaining */
+ EOL_RSVBC = 92, /* Reserved Block Count */
+ EOL_PFC = 96, /* Program Fail Count */
+ EOL_EFC = 100, /* Erase Fail Count */
+ EOL_RRER = 108, /* Raw Read Error Rate */
+} EOL_LOG_PAGE_C0_OFFSETS;
+
+
typedef struct __attribute__((__packed__)) _WDC_DE_VU_FILE_META_DATA
{
__u8 fileName[WDC_DE_FILE_NAME_SIZE];
@@ -517,6 +646,12 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
static int wdc_do_drive_info(int fd, __u32 *result);
static int wdc_vs_drive_info(int argc, char **argv, struct command *command,
struct plugin *plugin);
+static int wdc_vs_temperature_stats(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static __u64 wdc_get_enc_drive_capabilities(int fd);
+static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_len, FILE *out);
+static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, FILE *out, int data_id, int cdw14, int cdw15);
+static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data);
/* Drive log data size */
struct wdc_log_size {
@@ -543,6 +678,14 @@ struct __attribute__((__packed__)) wdc_dui_log_section_v2 {
__le64 section_size;
};
+/* DUI log header V4 */
+struct wdc_dui_log_section_v4 {
+ __le16 section_type;
+ __u8 data_area_id;
+ __u8 reserved;
+ __le32 section_size_sectors;
+};
+
struct wdc_dui_log_hdr {
__u8 telemetry_hdr[512];
__le16 hdr_version;
@@ -573,6 +716,16 @@ struct __attribute__((__packed__)) wdc_dui_log_hdr_v3 {
__u8 log_data[40];
};
+struct __attribute__((__packed__)) wdc_dui_log_hdr_v4 {
+ __u8 telemetry_hdr[512];
+ __u8 hdr_version;
+ __u8 product_id;
+ __le16 section_count;
+ __le32 log_size_sectors;
+ struct wdc_dui_log_section_v4 log_section[WDC_NVME_DUI_MAX_SECTION];
+ __u8 log_data[40];
+};
+
/* Purge monitor response */
struct wdc_nvme_purge_monitor_data {
__le16 rsvd1;
@@ -706,7 +859,57 @@ struct __attribute__((__packed__)) wdc_nand_stats {
__le64 nand_rec_trigger_event;
__le64 e2e_error_counter;
__le64 successful_ns_resize_event;
- __u8 rsvd[444];
+ __u8 rsvd[442];
+ __u16 log_page_version;
+};
+
+struct __attribute__((__packed__)) wdc_nand_stats_V3 {
+ __u8 nand_write_tlc[16];
+ __u8 nand_write_slc[16];
+ __u8 bad_nand_block_count[8];
+ __le64 xor_recovery_count;
+ __le64 uecc_read_error_count;
+ __u8 ssd_correction_counts[16];
+ __u8 percent_life_used;
+ __le64 user_data_erase_counts[4];
+ __u8 program_fail_count[8];
+ __u8 erase_fail_count[8];
+ __le64 correctable_error_count;
+ __u8 percent_free_blocks_user;
+ __le64 security_version_number;
+ __u8 percent_free_blocks_system;
+ __u8 trim_completions[25];
+ __u8 back_pressure_guage;
+ __le64 soft_ecc_error_count;
+ __le64 refresh_count;
+ __u8 bad_sys_nand_block_count[8];
+ __u8 endurance_estimate[16];
+ __u8 thermal_throttling_st_ct[2];
+ __le64 unaligned_IO;
+ __u8 physical_media_units[16];
+ __u8 reserved[279];
+ __u16 log_page_version;
+};
+
+struct wdc_vs_pcie_stats
+{
+ __le64 unsupportedRequestErrorCount;
+ __le64 ecrcErrorStatusCount;
+ __le64 malformedTlpStatusCount;
+ __le64 receiverOverflowStatusCount;
+ __le64 unexpectedCmpltnStatusCount;
+ __le64 completeAbortStatusCount;
+ __le64 cmpltnTimoutStatusCount;
+ __le64 flowControlErrorStatusCount;
+ __le64 poisonedTlpStatusCount;
+ __le64 dLinkPrtclErrorStatusCount;
+ __le64 advsryNFatalErrStatusCount;
+ __le64 replayTimerToStatusCount;
+ __le64 replayNumRolloverStCount;
+ __le64 badDllpStatusCount;
+ __le64 badTlpStatusCount;
+ __le64 receiverErrStatusCount;
+ __u8 reserved1[384];
};
struct wdc_fw_act_history_log_hdr {
@@ -731,6 +934,32 @@ struct wdc_fw_act_history_log_entry {
__u8 reserved[12];
};
+struct __attribute__((__packed__)) wdc_fw_act_history_log_entry_c2 {
+ __u8 entry_version_num;
+ __u8 entry_len;
+ __le16 reserved;
+ __le16 fw_act_hist_entries;
+ __le64 timestamp;
+ __u8 reserved2[8];
+ __le64 power_cycle_count;
+ __le64 previous_fw_version;
+ __le64 current_fw_version;
+ __u8 slot_number;
+ __u8 commit_action_type;
+ __le16 result;
+ __u8 reserved3[14];
+};
+
+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];
+ __u8 reserved2[2790];
+ __le16 log_page_version;
+ __u8 log_page_guid[WDC_C2_GUID_LENGTH];
+};
+
#define WDC_REASON_INDEX_MAX 16
#define WDC_REASON_ID_ENTRY_LEN 128
#define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli"
@@ -835,15 +1064,63 @@ free_id:
return ret;
}
+static int wdc_get_vendor_id(int fd, uint32_t *vendor_id)
+{
+ int ret;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(fd, &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed "
+ "0x%x\n", ret);
+ return -1;
+ }
+
+ *vendor_id = (uint32_t) ctrl.vid;
+
+ return ret;
+}
+
+static bool wdc_check_power_of_2(int num)
+{
+ return (num && ( !(num & (num-1))));
+}
+
+static int wdc_get_model_number(int fd, char *model)
+{
+ int ret,i;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(fd, &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed "
+ "0x%x\n", ret);
+ return -1;
+ }
+
+ memcpy(model,ctrl.mn,NVME_ID_CTRL_MODEL_NUMBER_SIZE);
+ /* get rid of the padded spaces */
+ i = NVME_ID_CTRL_MODEL_NUMBER_SIZE-1;
+ while (model[i] == ' ') i--;
+ model[i+1]=0;
+
+ return ret;
+}
+
static bool wdc_check_device(int fd)
{
int ret;
bool supported;
- uint32_t read_device_id, read_vendor_id;
+ uint32_t read_device_id = -1, read_vendor_id = -1;
ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
- if (ret < 0)
- return false;
+ if (ret < 0) {
+ /* Use the identify nvme command to get vendor id due to NVMeOF device. */
+ if (wdc_get_vendor_id(fd, &read_vendor_id) < 0)
+ return false;
+ }
supported = false;
@@ -858,14 +1135,46 @@ static bool wdc_check_device(int fd)
return supported;
}
+static bool wdc_enc_check_model(int fd)
+{
+ int ret;
+ bool supported;
+ char model[NVME_ID_CTRL_MODEL_NUMBER_SIZE+1];
+
+ ret = wdc_get_model_number(fd, model);
+ if (ret < 0)
+ return false;
+
+ supported = false;
+ model[NVME_ID_CTRL_MODEL_NUMBER_SIZE] = 0; /* forced termination */
+ if (strstr(model,WDC_OPENFLEX_MI_DEVICE_MODEL) != NULL)
+ supported = true;
+ else
+ fprintf(stderr, "ERROR : WDC: unsupported WDC enclosure, Model = %s\n",model);
+
+ return supported;
+}
+
static __u64 wdc_get_drive_capabilities(int fd) {
int ret;
- uint32_t read_device_id, read_vendor_id;
+ uint32_t read_device_id = -1, read_vendor_id = -1;
__u64 capabilities = 0;
+ __u8 *data;
+ __u32 *cust_id;
ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
if (ret < 0)
+ {
+ if (wdc_get_vendor_id(fd, &read_vendor_id) < 0)
+ return capabilities;
+ }
+
+ /* below check condition is added due in NVMeOF device we dont have device_id so we need to use only vendor_id*/
+ if (read_device_id == -1 && read_vendor_id != -1)
+ {
+ capabilities = wdc_get_enc_drive_capabilities(fd);
return capabilities;
+ }
switch (read_vendor_id) {
case WDC_NVME_VID:
@@ -912,25 +1221,59 @@ static __u64 wdc_get_drive_capabilities(int fd) {
/* FALLTHRU */
case WDC_NVME_SN640_DEV_ID_2:
/* FALLTHRU */
- case WDC_NVME_SN640_DEV_ID_3:
- /* FALLTHRU */
+ case WDC_NVME_SN640_DEV_ID_3:
+ /* 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;
+ }
+
+ capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
+ WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
+ WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY |
+ WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID |
+ WDC_DRIVE_CAP_LOG_PAGE_DIR);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+
+ if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) {
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID);
+ return -1;
+ }
+
+ cust_id = (__u32*)data;
+
+ if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) ||
+ (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304))
+ capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
+ WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION);
+ else
+ capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE);
+
+ break;
case WDC_NVME_SN840_DEV_ID:
/* FALLTHRU */
case WDC_NVME_SN840_DEV_ID_1:
+ /* 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;
+ }
/* FALLTHRU */
- case WDC_NVME_ZN440_DEV_ID:
+ case WDC_NVME_ZN540_DEV_ID:
/* FALLTHRU */
- case WDC_NVME_SN440_DEV_ID:
- /* FALLTHRU */
- case WDC_NVME_SN7GC_DEV_ID:
- case WDC_NVME_SN7GC_DEV_ID_1:
- case WDC_NVME_SN7GC_DEV_ID_2:
- capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
+ case WDC_NVME_SN540_DEV_ID:
+ /* FALLTHRU */
+ capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE |
WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY |
WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID |
- WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_INFO);
+ WDC_DRIVE_CAP_LOG_PAGE_DIR );
/* verify the 0xCA log page is supported */
if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
@@ -940,6 +1283,24 @@ static __u64 wdc_get_drive_capabilities(int fd) {
if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
break;
+ case WDC_NVME_SN650_DEV_ID:
+ case WDC_NVME_SN650_DEV_ID_1:
+ case WDC_NVME_SN650_DEV_ID_2:
+ case WDC_NVME_SN650_DEV_ID_3:
+ /* 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;
+ }
+
+ capabilities |= (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
+ WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
+ WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
+ WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY |
+ WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID |
+ WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_INFO |
+ WDC_DRIVE_CAP_CLOUD_SSD_VERSION);
+
+ break;
case WDC_NVME_SN730B_DEV_ID:
/* FALLTHRU */
case WDC_NVME_SN730B_DEV_ID_1:
@@ -965,10 +1326,18 @@ static __u64 wdc_get_drive_capabilities(int fd) {
capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_NS_RESIZE;
break;
case WDC_NVME_SN730A_DEV_ID:
- capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS;
+ capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS | WDC_DRIVE_CAP_INFO_2
+ | WDC_DRIVE_CAP_TEMP_STATS | WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS;
break;
case WDC_NVME_SN340_DEV_ID:
- capabilities = WDC_DRIVE_CAP_SN340_DUI;
+ capabilities = WDC_DRIVE_CAP_DUI;
+ break;
+ case WDC_NVME_ZN350_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_ZN350_DEV_ID_1:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_C0_LOG_PAGE |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 |
+ WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_CLOUD_SSD_VERSION | WDC_DRIVE_CAP_LOG_PAGE_DIR;
break;
default:
capabilities = 0;
@@ -981,6 +1350,71 @@ static __u64 wdc_get_drive_capabilities(int fd) {
return capabilities;
}
+static __u64 wdc_get_enc_drive_capabilities(int fd) {
+ int ret;
+ uint32_t read_vendor_id;
+ __u64 capabilities = 0;
+ __u8 *data;
+ __u32 *cust_id;
+
+ ret = wdc_get_vendor_id(fd, &read_vendor_id);
+ if (ret < 0)
+ return capabilities;
+
+ switch (read_vendor_id) {
+ case WDC_NVME_VID:
+ 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);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xC1 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_ADD_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE;
+ break;
+ case WDC_NVME_VID_2:
+ capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
+ WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
+ WDC_DRIVE_CAP_RESIZE);
+
+ /* verify the 0xCB log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == true)
+ capabilities |= WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY;
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+
+ if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) {
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID);
+ return -1;
+ }
+
+ cust_id = (__u32*)data;
+
+ if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) ||
+ (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304))
+ capabilities |= (WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE);
+ else
+ capabilities |= (WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY | WDC_DRIVE_CAP_CLEAR_PCIE);
+
+ break;
+ case WDC_NVME_SNDK_VID:
+ capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS;
+ break;
+ default:
+ capabilities = 0;
+ }
+
+ return capabilities;
+}
+
static int wdc_get_serial_name(int fd, char *file, size_t len, const char *suffix)
{
int i;
@@ -1060,6 +1494,99 @@ static int wdc_create_log_file(char *file, __u8 *drive_log_data,
return 0;
}
+bool wdc_get_dev_mng_log_entry(__u32 log_length,
+ __u32 entry_id,
+ struct wdc_c2_log_page_header* p_log_hdr,
+ struct wdc_c2_log_subpage_header **p_p_found_log_entry)
+{
+ __u32 remaining_len = 0;
+ __u32 log_entry_hdr_size = sizeof(struct wdc_c2_log_subpage_header) - 1;
+ __u32 log_entry_size = 0;
+ __u32 size = 0;
+ bool valid_log;
+ __u32 current_data_offset = 0;
+ struct wdc_c2_log_subpage_header *p_next_log_entry = NULL;
+
+ if (*p_p_found_log_entry == NULL) {
+ fprintf(stderr, "ERROR : WDC - wdc_get_dev_mng_log_entry: No ppLogEntry pointer.\n");
+ return false;
+ }
+
+ *p_p_found_log_entry = NULL;
+
+ /* Ensure log data is large enough for common header */
+ if (log_length < sizeof(struct wdc_c2_log_page_header)) {
+ fprintf(stderr, "ERROR : WDC - wdc_get_dev_mng_log_entry: \
+ Buffer is not large enough for the common header. BufSize: 0x%x HdrSize: %"PRIxPTR"\n",
+ log_length, sizeof(struct wdc_c2_log_page_header));
+ return false;
+ }
+
+ /* Get pointer to first log Entry */
+ size = sizeof(struct wdc_c2_log_page_header);
+ current_data_offset = size;
+ p_next_log_entry = (struct wdc_c2_log_subpage_header *)((__u8*)p_log_hdr + current_data_offset);
+ remaining_len = log_length - size;
+ valid_log = false;
+
+ /* Walk the entire structure. Perform a sanity check to make sure this is a
+ standard version of the structure. This means making sure each entry looks
+ valid. But allow for the data to overflow the allocated
+ buffer (we don't want a false negative because of a FW formatting error) */
+
+ /* Proceed only if there is at least enough data to read an entry header */
+ while (remaining_len >= log_entry_hdr_size) {
+ /* Get size of the next entry */
+ log_entry_size = p_next_log_entry->length;
+
+ /* If log entry size is 0 or the log entry goes past the end
+ of the data, we must be at the end of the data */
+ if ((log_entry_size == 0) ||
+ (log_entry_size > remaining_len)) {
+ fprintf(stderr, "ERROR : WDC: wdc_get_dev_mng_log_entry: \
+ Detected unaligned end of the data. Data Offset: 0x%x \
+ Entry Size: 0x%x, Remaining Log Length: 0x%x Entry Id: 0x%x\n",
+ current_data_offset, log_entry_size, remaining_len, p_next_log_entry->entry_id);
+
+ /* Force the loop to end */
+ remaining_len = 0;
+ } else if ((p_next_log_entry->entry_id == 0) ||
+ (p_next_log_entry->entry_id > 200)) {
+ /* Invalid entry - fail the search */
+ fprintf(stderr, "ERROR : WDC: wdc_get_dev_mng_log_entry: \
+ Invalid entry found at offset: 0x%x Entry Size: 0x%x, \
+ Remaining Log Length: 0x%x Entry Id: 0x%x\n",
+ current_data_offset, log_entry_size, remaining_len, p_next_log_entry->entry_id);
+
+ /* Force the loop to end */
+ remaining_len = 0;
+ valid_log = false;
+
+ /* The struture is invalid, so any match that was found is invalid. */
+ *p_p_found_log_entry = NULL;
+ } else {
+ /* Structure must have at least one valid entry to be considered valid */
+ valid_log = true;
+ if (p_next_log_entry->entry_id == entry_id) {
+ /* A potential match. */
+ *p_p_found_log_entry = p_next_log_entry;
+ }
+
+ remaining_len -= log_entry_size;
+
+ if (remaining_len > 0) {
+ /* Increment the offset counter */
+ current_data_offset += log_entry_size;
+
+ /* Get the next entry */
+ p_next_log_entry = (struct wdc_c2_log_subpage_header *)(((__u8*)p_log_hdr) + current_data_offset);
+ }
+ }
+ }
+
+ return valid_log;
+}
+
static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data)
{
int ret = -1;
@@ -1068,8 +1595,17 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data)
struct wdc_c2_log_subpage_header *sph;
__u32 length = 0;
bool found = false;
-
+ __u8 uuid_ix = 1;
+ __u8 lid = 0;
*cbs_data = NULL;
+ __u32 device_id, read_vendor_id;
+
+ ret = wdc_get_pci_ids(&device_id, &read_vendor_id);
+ if(device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) {
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8;
+ uuid_ix = 0;
+ } else
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE;
if ((data = (__u8*) malloc(sizeof (__u8) * WDC_C2_LOG_BUF_LEN)) == NULL) {
fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
@@ -1078,10 +1614,9 @@ 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_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE,
- false, WDC_C2_LOG_BUF_LEN, data);
+ ret = nvme_get_log14(fd, 0xFFFFFFFF, lid, NVME_NO_LOG_LSP, 0, 0, false, uuid_ix, WDC_C2_LOG_BUF_LEN, data);
if (ret) {
- fprintf(stderr, "ERROR : WDC : Unable to get C2 Log Page length, ret = 0x%x\n", ret);
+ fprintf(stderr, "ERROR : WDC : Unable to get 0x%x Log Page length, ret = 0x%x\n", lid, ret);
goto end;
}
@@ -1097,28 +1632,37 @@ static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data)
}
}
- ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE,
- false, le32_to_cpu(hdr_ptr->length), data);
- /* parse the data until the List of log page ID's is found */
+ /* 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);
if (ret) {
- fprintf(stderr, "ERROR : WDC : Unable to read C2 Log Page data, ret = 0x%x\n", ret);
+ fprintf(stderr, "ERROR : WDC : Unable to read 0x%x Log Page data, ret = 0x%x\n", lid, ret);
goto end;
}
+ /* Check the log data to see if the WD version of log page ID's is found */
+
length = sizeof(struct wdc_c2_log_page_header);
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);
- while (length < le32_to_cpu(hdr_ptr->length)) {
+ if (found) {
+ *cbs_data = (void *)&sph->data;
+ } else {
+ /* 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);
+ hdr_ptr = (struct wdc_c2_log_page_header *)data;
sph = (struct wdc_c2_log_subpage_header *)(data + length);
-
- if (le32_to_cpu(sph->entry_id) == log_id) {
+ found = wdc_get_dev_mng_log_entry(hdr_ptr->length, log_id, hdr_ptr, &sph);
+ if (found) {
*cbs_data = (void *)&sph->data;
- found = true;
- break;
+ } else {
+ /* WD version not found */
+ fprintf(stderr, "ERROR : WDC : Unable to find correct version of page 0x%x, entry id = %d\n", lid, log_id);
}
- length += le32_to_cpu(sph->length);
}
-
end:
free(data);
return found;
@@ -1270,6 +1814,7 @@ static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dum
{
int ret;
struct nvme_admin_cmd admin_cmd;
+ __u64 offset_lo, offset_hi;
memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE;
@@ -1277,8 +1822,11 @@ static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dum
admin_cmd.addr = (__u64)(uintptr_t)dump_data;
admin_cmd.data_len = dataLen;
admin_cmd.cdw10 = ((dataLen >> 2) - 1);
- admin_cmd.cdw12 = (__u32)(offset & 0x00000000FFFFFFFF);
- admin_cmd.cdw13 = (__u32)(offset >> 32);
+ offset_lo = offset & 0x00000000FFFFFFFF;
+ offset_hi = ((offset & 0xFFFFFFFF00000000) >> 32);
+ admin_cmd.cdw12 = (__u32)offset_lo;
+ admin_cmd.cdw13 = (__u32)offset_hi;
+
if (last_xfer)
admin_cmd.cdw14 = 0;
else
@@ -1609,6 +2157,7 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
struct wdc_dui_log_hdr_v3 *log_hdr_v3;
__u32 cap_dui_length;
__u64 cap_dui_length_v3;
+ __u64 cap_dui_length_v4;
__u8 *dump_data = NULL;
__u8 *buffer_addr;
__s64 total_size = 0;
@@ -1634,7 +2183,100 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
}
/* Check the Log Header version */
- if (((log_hdr->hdr_version & 0xFF) == 0x02) ||
+ if ((log_hdr->hdr_version & 0xFF) == 0x00 ||
+ (log_hdr->hdr_version & 0xFF) == 0x01) {
+ __s32 log_size = 0;
+ __u32 curr_data_offset = 0;
+
+ cap_dui_length = le32_to_cpu(log_hdr->log_size);
+
+ if (verbose) {
+ fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log, data area = %d\n", data_area);
+ fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr->hdr_version);
+ }
+
+ if (cap_dui_length == 0) {
+ fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log is empty\n");
+ } else {
+ /* parse log header for all sections up to specified data area inclusively */
+ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) {
+ for(j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) {
+ if (log_hdr->log_section[j].data_area_id <= data_area &&
+ log_hdr->log_section[j].data_area_id != 0) {
+ log_size += log_hdr->log_section[j].section_size;
+ if (verbose)
+ fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%x\n",
+ __func__, log_hdr->log_section[j].data_area_id, (unsigned int)log_hdr->log_section[j].section_size, (unsigned int)log_size);
+
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, "%s: break, total size = 0x%x\n", __func__, (unsigned int)log_size);
+ break;
+ }
+ }
+ } else
+ log_size = cap_dui_length;
+
+ total_size = log_size;
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size);
+ if (dump_data == NULL) {
+ fprintf(stderr, "%s: ERROR : dump data V1 malloc failed : status %s, size = 0x%x\n",
+ __func__, strerror(errno), (unsigned int)xfer_size);
+ ret = -1;
+ goto out;
+ }
+ memset(dump_data, 0, sizeof (__u8) * xfer_size);
+
+ output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ fprintf(stderr, "%s: Failed to open output file %s: %s!\n",
+ __func__, file, strerror(errno));
+ ret = output;
+ goto free_mem;
+ }
+
+ /* write the telemetry and log headers into the dump_file */
+ err = write(output, (void *)log_hdr, WDC_NVME_CAP_DUI_HEADER_SIZE);
+ if (err != WDC_NVME_CAP_DUI_HEADER_SIZE) {
+ fprintf(stderr, "%s: Failed to flush header data to file!\n", __func__);
+ goto free_mem;
+ }
+
+ log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE;
+ curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE;
+ i = 0;
+ buffer_addr = dump_data;
+
+ for(; log_size > 0; log_size -= xfer_size) {
+ xfer_size = min(xfer_size, log_size);
+
+ if (log_size <= xfer_size)
+ last_xfer = true;
+
+ ret = wdc_dump_dui_data(fd, xfer_size, curr_data_offset, buffer_addr, last_xfer);
+ if (ret != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%x, addr = %p\n",
+ __func__, i, (uint64_t)log_size, curr_data_offset, buffer_addr);
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ break;
+ }
+
+ /* write the dump data into the file */
+ err = write(output, (void *)buffer_addr, xfer_size);
+ if (err != xfer_size) {
+ fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%x\n",
+ __func__, i, err, xfer_size);
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size;
+ i++;
+ }
+ }
+ }
+ else if (((log_hdr->hdr_version & 0xFF) == 0x02) ||
((log_hdr->hdr_version & 0xFF) == 0x03)) { /* Process Version 2 or 3 header */
__s64 log_size = 0;
__u64 curr_data_offset = 0;
@@ -1648,8 +2290,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
fprintf(stderr, "INFO : WDC : Capture V2 or V3 Device Unit Info log, data area = %d\n", data_area);
fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr_v3->hdr_version);
- if (log_hdr_v3->hdr_version >= 0x03)
- fprintf(stderr, "INFO : WDC : DUI Product ID = %c\n", log_hdr_v3->product_id);
+ if ((log_hdr->hdr_version & 0xFF) == 0x03)
+ fprintf(stderr, "INFO : WDC : DUI Product ID = 0x%x/%c\n", log_hdr_v3->product_id, log_hdr_v3->product_id);
}
if (cap_dui_length_v3 == 0) {
@@ -1662,12 +2304,12 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
log_hdr_v3->log_section[j].data_area_id != 0) {
log_size += log_hdr_v3->log_section[j].section_size;
if (verbose)
- fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%lx\n",
- __func__, log_hdr_v3->log_section[j].data_area_id, (unsigned int)log_hdr_v3->log_section[j].section_size, (long unsigned int)log_size);
+ fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%"PRIx64"\n",
+ __func__, log_hdr_v3->log_section[j].data_area_id, (unsigned int)log_hdr_v3->log_section[j].section_size, (uint64_t)log_size);
}
else {
if (verbose)
- fprintf(stderr, "%s: break, total size = 0x%lx\n", __func__, (long unsigned int)log_size);
+ fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", __func__, (uint64_t)log_size);
break;
}
}
@@ -1684,8 +2326,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size_long);
if (dump_data == NULL) {
- fprintf(stderr, "%s: ERROR : dump data v3 malloc failed : status %s, size = 0x%lx\n",
- __func__, strerror(errno), (long unsigned int)xfer_size_long);
+ fprintf(stderr, "%s: ERROR : dump data v3 malloc failed : status %s, size = 0x%"PRIx64"\n",
+ __func__, strerror(errno), (uint64_t)xfer_size_long);
ret = -1;
goto out;
}
@@ -1727,8 +2369,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr, last_xfer);
if (ret != 0) {
- fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%lx, addr = 0x%lx\n",
- __func__, i, (long unsigned int)total_size, (long unsigned int)curr_data_offset, (long unsigned int)buffer_addr);
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n",
+ __func__, i, (uint64_t)total_size, (uint64_t)curr_data_offset, buffer_addr);
fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
break;
}
@@ -1736,8 +2378,8 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
/* write the dump data into the file */
err = write(output, (void *)buffer_addr, xfer_size_long);
if (err != xfer_size_long) {
- fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%lx\n",
- __func__, i, err, (long unsigned int)xfer_size_long);
+ fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%"PRIx64"\n",
+ __func__, i, err, (uint64_t)xfer_size_long);
goto free_mem;
}
@@ -1745,50 +2387,65 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
i++;
}
}
- } else {
- __s32 log_size = 0;
- __u32 curr_data_offset = 0;
+ }
+ else if ((log_hdr->hdr_version & 0xFF) == 0x04) {
+ __s64 log_size = 0;
+ __u64 curr_data_offset = 0;
+ struct wdc_dui_log_hdr_v4 *log_hdr_v4;
+ log_hdr_v4 = (struct wdc_dui_log_hdr_v4 *)log_hdr;
+ __s64 xfer_size_long = (__s64)xfer_size;
+ __s64 section_size_bytes = 0;
- cap_dui_length = le32_to_cpu(log_hdr->log_size);
+ cap_dui_length_v4 = le64_to_cpu(log_hdr_v4->log_size_sectors) * WDC_NVME_SN730_SECTOR_SIZE;
if (verbose) {
- fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log, data area = %d\n", data_area);
- fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr->hdr_version);
+ fprintf(stderr, "INFO : WDC : Capture V4 Device Unit Info log, data area = %d\n", data_area);
+ fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr_v4->hdr_version);
+ fprintf(stderr, "INFO : WDC : DUI Product ID = 0x%x/%c\n", log_hdr_v4->product_id, log_hdr_v4->product_id);
+ fprintf(stderr, "INFO : WDC : DUI log size sectors = 0x%x\n", log_hdr_v4->log_size_sectors);
+ fprintf(stderr, "INFO : WDC : DUI cap_dui_length = 0x%"PRIx64"\n", (uint64_t)cap_dui_length_v4);
}
- if (cap_dui_length == 0) {
- fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log is empty\n");
+ if (cap_dui_length_v4 == 0) {
+ fprintf(stderr, "INFO : WDC : Capture V4 Device Unit Info log is empty\n");
} else {
/* parse log header for all sections up to specified data area inclusively */
if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) {
for(j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) {
- if (log_hdr->log_section[j].data_area_id <= data_area &&
- log_hdr->log_section[j].data_area_id != 0) {
- log_size += log_hdr->log_section[j].section_size;
+ if (log_hdr_v4->log_section[j].data_area_id <= data_area &&
+ log_hdr_v4->log_section[j].data_area_id != 0) {
+ section_size_bytes = ((__s64)log_hdr_v4->log_section[j].section_size_sectors * WDC_NVME_SN730_SECTOR_SIZE);
+ log_size += section_size_bytes;
if (verbose)
- fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%x\n",
- __func__, log_hdr->log_section[j].data_area_id, (unsigned int)log_hdr->log_section[j].section_size, (unsigned int)log_size);
-
+ fprintf(stderr, "%s: Data area ID %d : section size 0x%x sectors, section size 0x%"PRIx64" bytes, total size = 0x%"PRIx64"\n",
+ __func__, log_hdr_v4->log_section[j].data_area_id, log_hdr_v4->log_section[j].section_size_sectors, (uint64_t)section_size_bytes,
+ (uint64_t)log_size);
}
else {
if (verbose)
- fprintf(stderr, "%s: break, total size = 0x%x\n", __func__, (unsigned int)log_size);
+ fprintf(stderr, "%s: break, total size = 0x%"PRIx64"\n", __func__, (uint64_t)log_size);
break;
}
}
} else
- log_size = cap_dui_length;
+ log_size = cap_dui_length_v4;
total_size = log_size;
- dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size);
+ if (offset >= total_size) {
+ fprintf(stderr, "%s: INFO : WDC : Offset 0x%"PRIx64" exceeds total size 0x%"PRIx64", no data retrieved\n",
+ __func__, (uint64_t)offset, (uint64_t)total_size);
+ goto out;
+ }
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size_long);
if (dump_data == NULL) {
- fprintf(stderr, "%s: ERROR : dump data V1 malloc failed : status %s, size = 0x%x\n",
- __func__, strerror(errno), (unsigned int)xfer_size);
+ fprintf(stderr, "%s: ERROR : dump data V4 malloc failed : status %s, size = 0x%x\n",
+ __func__, strerror(errno), (unsigned int)xfer_size_long);
ret = -1;
goto out;
}
- memset(dump_data, 0, sizeof (__u8) * xfer_size);
+ memset(dump_data, 0, sizeof (__u8) * xfer_size_long);
output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (output < 0) {
@@ -1798,49 +2455,62 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, in
goto free_mem;
}
- /* write the telemetry and log headers into the dump_file */
- err = write(output, (void *)log_hdr, WDC_NVME_CAP_DUI_HEADER_SIZE);
- if (err != WDC_NVME_CAP_DUI_HEADER_SIZE) {
- fprintf(stderr, "%s: Failed to flush header data to file!\n", __func__);
- goto free_mem;
+ curr_data_offset = 0;
+
+ if (file_size != 0) {
+ /* Write the DUI data based on the passed in file size */
+ if ((offset + file_size) > total_size)
+ log_size = min((total_size - offset), file_size);
+ else
+ log_size = min(total_size, file_size);
+
+ if (verbose)
+ fprintf(stderr, "%s: INFO : WDC : Offset 0x%"PRIx64", file size 0x%"PRIx64", total size 0x%"PRIx64", log size 0x%"PRIx64"\n",
+ __func__, (uint64_t)offset, (uint64_t)file_size, (uint64_t)total_size, (uint64_t)log_size);
+
+ curr_data_offset = offset;
+
}
- log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE;
- curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE;
i = 0;
buffer_addr = dump_data;
- for(; log_size > 0; log_size -= xfer_size) {
- xfer_size = min(xfer_size, log_size);
+ for(; log_size > 0; log_size -= xfer_size_long) {
+ xfer_size_long = min(xfer_size_long, log_size);
- if (log_size <= xfer_size)
+ if (log_size <= xfer_size_long)
last_xfer = true;
- ret = wdc_dump_dui_data(fd, xfer_size, curr_data_offset, buffer_addr, last_xfer);
+ ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr, last_xfer);
if (ret != 0) {
- fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%x, addr = %p\n",
- __func__, i, (long unsigned int)log_size, curr_data_offset, buffer_addr);
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%"PRIx64", offset = 0x%"PRIx64", addr = %p\n",
+ __func__, i, (uint64_t)log_size, (uint64_t)curr_data_offset, buffer_addr);
fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
break;
}
/* write the dump data into the file */
- err = write(output, (void *)buffer_addr, xfer_size);
- if (err != xfer_size) {
- fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%x\n",
- __func__, i, err, xfer_size);
+ err = write(output, (void *)buffer_addr, xfer_size_long);
+ if (err != xfer_size_long) {
+ fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size_long = 0x%"PRIx64"\n",
+ __func__, i, err, (uint64_t)xfer_size_long);
goto free_mem;
}
- curr_data_offset += xfer_size;
+ curr_data_offset += xfer_size_long;
i++;
}
}
}
+ else {
+ fprintf(stderr, "INFO : WDC : Unsupported header version = 0x%x\n", log_hdr->hdr_version);
+ goto out;
+ }
+
fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
if (verbose)
- fprintf(stderr, "INFO : WDC : Capture Device Unit Info log, length = 0x%lx\n", (long unsigned int)total_size);
+ fprintf(stderr, "INFO : WDC : Capture Device Unit Info log, length = 0x%"PRIx64"\n", (uint64_t)total_size);
free_mem:
close(output);
@@ -2137,7 +2807,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
char *desc = "Internal Firmware Log.";
char *file = "Output file pathname.";
char *size = "Data retrieval transfer size.";
- char *data_area = "Data area to retrieve up to. Currently only supported on the SN340, SN640, and SN840 devices.";
+ char *data_area = "Data area to retrieve up to. Currently only supported on the SN340, SN640, SN730, and SN840 devices.";
char *file_size = "Output file size. Currently only supported on the SN340 device.";
char *offset = "Output file data offset. Currently only supported on the SN340 device.";
char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN640 and SN840 devices.";
@@ -2164,7 +2834,7 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
struct config cfg = {
.file = NULL,
.xfer_size = 0x10000,
- .data_area = 3,
+ .data_area = 0,
.file_size = 0,
.offset = 0,
.type = NULL,
@@ -2224,13 +2894,18 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
fprintf(stderr, "%s: filename = %s\n", __func__, f);
- if (cfg.data_area > 5 || cfg.data_area == 0) {
- fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n");
- return -1;
+ if (cfg.data_area) {
+ if (cfg.data_area > 5 || cfg.data_area < 1) {
+ fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n");
+ return -1;
+ }
}
capabilities = wdc_get_drive_capabilities(fd);
if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) {
+ if (cfg.data_area == 0)
+ cfg.data_area = 3; /* Set the default DA to 3 if not specified */
+
if ((cfg.type == NULL) ||
(!strcmp(cfg.type, "NONE")) ||
(!strcmp(cfg.type, "none"))) {
@@ -2251,7 +2926,11 @@ static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command
return wdc_do_cap_diag(fd, f, xfer_size, telemetry_type, telemetry_data_area);
}
- if ((capabilities & WDC_DRIVE_CAP_SN340_DUI) == WDC_DRIVE_CAP_SN340_DUI) {
+ if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) {
+ if (cfg.data_area == 0) {
+ cfg.data_area = 1;
+ }
+
/* FW requirement - xfer size must be 256k for data area 4 */
if (cfg.data_area >= 4)
xfer_size = 0x40000;
@@ -2924,119 +3603,112 @@ static void wdc_print_bd_ca_log_normal(void *data)
{
struct wdc_bd_ca_log_format *bd_data = (struct wdc_bd_ca_log_format *)data;
__u64 *raw;
- __u16 *word_raw;
+ __u16 *word_raw1, *word_raw2, *word_raw3;
__u32 *dword_raw;
__u8 *byte_raw;
if (bd_data->field_id == 0x00) {
raw = (__u64*)bd_data->raw_value;
- printf(" CA Log Page values :- \n");
- printf(" Program fail counts %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
- printf(" %% Remaining of allowable program fails %3"PRIu8"\n",
- bd_data->normalized_value);
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
+ devicename, WDC_DE_GLOBAL_NSID);
+ printf("key normalized raw\n");
+ printf("program_fail_count : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x01) {
raw = (__u64*)bd_data->raw_value;
- printf(" Erase fail count %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
- printf(" %% Remaining of allowable erase fails %3"PRIu8"\n",
- bd_data->normalized_value);
+ printf("erase_fail_count : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x02) {
- word_raw = (__u16*)bd_data->raw_value;
- printf(" Min erase cycles %10"PRIu16"\n",
- le16_to_cpu(*word_raw));
- word_raw = (__u16*)&bd_data->raw_value[2];
- printf(" Max erase cycles %10"PRIu16"\n",
- le16_to_cpu(*word_raw));
- word_raw = (__u16*)&bd_data->raw_value[4];
- printf(" Ave erase cycles %10"PRIu16"\n",
- le16_to_cpu(*word_raw));
- printf(" Wear Leveling Normalized %3"PRIu8"\n",
- bd_data->normalized_value);
-
+ word_raw1 = (__u16*)bd_data->raw_value;
+ word_raw2 = (__u16*)&bd_data->raw_value[2];
+ word_raw3 = (__u16*)&bd_data->raw_value[4];
+ printf("wear_leveling : %3"PRIu8"%% min: %"PRIu16", max: %"PRIu16", avg: %"PRIu16"\n",
+ bd_data->normalized_value,
+ le16_to_cpu(*word_raw1),
+ le16_to_cpu(*word_raw2),
+ le16_to_cpu(*word_raw3));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x03) {
raw = (__u64*)bd_data->raw_value;
- printf(" End to end error detection count %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf("end_to_end_error_detection_count: %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x04) {
raw = (__u64*)bd_data->raw_value;
- printf(" Crc error count %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf("crc_error_count : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x05) {
raw = (__u64*)bd_data->raw_value;
- printf(" Timed workload media error %20.3f\n",
- safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
+ printf("timed_workload_media_wear : %3"PRIu8"%% %-.3f%%\n",
+ bd_data->normalized_value,
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x06) {
raw = (__u64*)bd_data->raw_value;
- printf(" Timed workload host reads %% %3"PRIu64"\n",
- le64_to_cpu(*raw & 0x00000000000000FF));
+ printf("timed_workload_host_reads : %3"PRIu8"%% %"PRIu64"%%\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x07) {
raw = (__u64*)bd_data->raw_value;
- printf(" Timed workload timer %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf("timed_workload_timer : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x08) {
byte_raw = (__u8*)bd_data->raw_value;
- printf(" Throttle status %% %10"PRIu16"\n",
- *byte_raw);
dword_raw = (__u32*)&bd_data->raw_value[1];
- printf(" Throttling event counter %10"PRIu16"\n",
- le32_to_cpu(*dword_raw));
+ printf("thermal_throttle_status : %3"PRIu8"%% %"PRIu16"%%, cnt: %"PRIu16"\n",
+ bd_data->normalized_value, *byte_raw, le32_to_cpu(*dword_raw));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x09) {
raw = (__u64*)bd_data->raw_value;
- printf(" Retry buffer overflow count %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf("retry_buffer_overflow_count : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x0A) {
raw = (__u64*)bd_data->raw_value;
- printf(" Pll lock loss count %20"PRIu64"\n",
- le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf("pll_lock_loss_count : %3"PRIu8"%% %"PRIu64"\n",
+ bd_data->normalized_value, le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x0B) {
raw = (__u64*)bd_data->raw_value;
- printf(" Nand bytes written (32mb) %20.0f\n",
- safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n",
+ bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
raw = (__u64*)bd_data->raw_value;
} else {
goto invalid_id;
@@ -3044,8 +3716,8 @@ static void wdc_print_bd_ca_log_normal(void *data)
bd_data++;
if (bd_data->field_id == 0x0C) {
raw = (__u64*)bd_data->raw_value;
- printf(" Host bytes written (32mb) %20.0f\n",
- safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n",
+ bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
raw = (__u64*)bd_data->raw_value;
} else {
goto invalid_id;
@@ -3073,9 +3745,9 @@ static void wdc_print_bd_ca_log_json(void *data)
root = json_create_object();
if (bd_data->field_id == 0x00) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Program fail counts",
+ json_object_add_value_int(root, "program_fail_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
- json_object_add_value_int(root, "% Remaining of allowable program fails",
+ json_object_add_value_int(root, "normalized",
bd_data->normalized_value);
} else {
goto invalid_id;
@@ -3083,9 +3755,9 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x01) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Erase fail count",
+ json_object_add_value_int(root, "erase_fail_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
- json_object_add_value_int(root, "% Remaining of allowable erase fails",
+ json_object_add_value_int(root, "normalized",
bd_data->normalized_value);
} else {
goto invalid_id;
@@ -3093,19 +3765,19 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x02) {
word_raw = (__u16*)bd_data->raw_value;
- json_object_add_value_int(root, "Min erase cycles", le16_to_cpu(*word_raw));
+ json_object_add_value_int(root, "min", le16_to_cpu(*word_raw));
word_raw = (__u16*)&bd_data->raw_value[2];
- json_object_add_value_int(root, "Max erase cycles", le16_to_cpu(*word_raw));
+ json_object_add_value_int(root, "max", le16_to_cpu(*word_raw));
word_raw = (__u16*)&bd_data->raw_value[4];
- json_object_add_value_int(root, "Ave erase cycles", le16_to_cpu(*word_raw));
- json_object_add_value_int(root, "Wear Leveling Normalized", bd_data->normalized_value);
+ json_object_add_value_int(root, "avg", le16_to_cpu(*word_raw));
+ json_object_add_value_int(root, "wear_leveling-normalized", bd_data->normalized_value);
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x03) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "End to end error detection count",
+ json_object_add_value_int(root, "end_to_end_error_detection_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
@@ -3113,7 +3785,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x04) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Crc error count",
+ json_object_add_value_int(root, "crc_error_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
@@ -3121,7 +3793,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x05) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_float(root, "Timed workload media error",
+ json_object_add_value_float(root, "timed_workload_media_wear",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
} else {
goto invalid_id;
@@ -3129,7 +3801,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x06) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Timed workload host reads %",
+ json_object_add_value_int(root, "timed_workload_host_reads",
le64_to_cpu(*raw & 0x00000000000000FF));
} else {
goto invalid_id;
@@ -3137,7 +3809,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x07) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Timed workload timer",
+ json_object_add_value_int(root, "timed_workload_timer",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
@@ -3145,16 +3817,16 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x08) {
byte_raw = (__u8*)bd_data->raw_value;
- json_object_add_value_int(root, "Throttle status %", *byte_raw);
+ json_object_add_value_int(root, "thermal_throttle_status", *byte_raw);
dword_raw = (__u32*)&bd_data->raw_value[1];
- json_object_add_value_int(root, "Throttling event counter", le32_to_cpu(*dword_raw));
+ json_object_add_value_int(root, "cnt", le32_to_cpu(*dword_raw));
} else {
goto invalid_id;
}
bd_data++;
if (bd_data->field_id == 0x09) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Retry buffer overflow count",
+ json_object_add_value_int(root, "retry_buffer_overflow_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
@@ -3162,7 +3834,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x0A) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_int(root, "Pll lock loss count",
+ json_object_add_value_int(root, "pll_lock_loss_count",
le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
} else {
goto invalid_id;
@@ -3170,7 +3842,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x0B) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_float(root, "Nand bytes written (32mb)",
+ json_object_add_value_float(root, "nand_bytes_written",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
} else {
goto invalid_id;
@@ -3178,7 +3850,7 @@ static void wdc_print_bd_ca_log_json(void *data)
bd_data++;
if (bd_data->field_id == 0x0C) {
raw = (__u64*)bd_data->raw_value;
- json_object_add_value_float(root, "Host bytes written (32mb)",
+ json_object_add_value_float(root, "host_bytes_written",
safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
raw = (__u64*)bd_data->raw_value;
} else {
@@ -3334,61 +4006,162 @@ static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin)
}
-static void wdc_print_fw_act_history_log_normal(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
- int num_entries)
+static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries, __u32 cust_id)
{
int i;
char previous_fw[9];
char new_fw[9];
char commit_action_bin[8];
- memset((void *)previous_fw, 0, 9);
- memset((void *)new_fw, 0, 9);
- memset((void *)commit_action_bin, 0, 8);
+ char time_str[11];
+ __u16 oldestEntryIdx = 0, entryIdx = 0;
char *null_fw = "--------";
-
-
- printf(" Firmware Activate History Log \n");
- printf(" Power on Hour Power Cycle Previous New \n");
- printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
- printf(" ----- -------------- ------------ ---------- ---------- ----- ------ -------\n");
-
- for (i = 0; i < num_entries; i++) {
- memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
- if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
- memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
- else
- memcpy(new_fw, null_fw, 8);
-
- printf("%5"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->entry_num));
- printf(" ");
- printf("%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
- (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
- printf(" ");
- printf("%8"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->power_cycle_count));
- printf(" ");
- printf("%s", (char *)previous_fw);
- printf(" ");
- printf("%s", (char *)new_fw);
- printf(" ");
- printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->slot_number);
- printf(" ");
- wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
- printf(" %s", (char *)commit_action_bin);
- printf(" ");
- if (le16_to_cpu(fw_act_history_entry->result) == 0)
- printf("pass");
+ memset((void *)time_str, 0, 11);
+
+ 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) {
+ printf(" Power on Hour Power Cycle Previous New \n");
+ printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
+ printf(" ----- ----------------- ----------------- --------- --------- ----- ------ -------\n");
+ } else {
+ printf(" Power Cycle Previous New \n");
+ 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++) {
+ 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;
+ break;
+ }
+ }
+ }
+ if (oldestEntryIdx == WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
else
- printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->result));
+ entryIdx = oldestEntryIdx;
+
+ for (i = 0; i < num_entries; i++) {
+ memset((void *)previous_fw, 0, 9);
+ memset((void *)new_fw, 0, 9);
+ memset((void *)commit_action_bin, 0, 8);
+
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ printf("%5"PRIu16"", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
+ if (cust_id == WDC_CUSTOMER_ID_0x1005) {
+ printf(" ");
+ memset((void *)time_str, 0, 9);
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%3600)/60)),
+ (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%60)));
+
+ printf("%s", time_str);
+ printf(" ");
+ } else {
+ printf(" ");
+ uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
+ printf("%16"PRIu64"", timestamp);
+ printf(" ");
+ }
- printf("\n");
+ printf("%16"PRIu64"", (uint64_t)le64_to_cpu(fw_act_history_entry->entry[entryIdx].power_cycle_count));
+ printf(" ");
+ printf("%s", (char *)previous_fw);
+ printf(" ");
+ printf("%s", (char *)new_fw);
+ printf(" ");
+ printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->entry[entryIdx].slot_number);
+ printf(" ");
+ wdc_get_commit_action_bin(fw_act_history_entry->entry[entryIdx].commit_action_type,(char *)&commit_action_bin);
+ printf(" %s", (char *)commit_action_bin);
+ printf(" ");
+ if (le16_to_cpu(fw_act_history_entry->entry[entryIdx].result) == 0)
+ printf("pass");
+ else
+ printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->entry[entryIdx].result));
+ printf("\n");
+
+ entryIdx++;
+ if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ }
+ }
+ else
+ {
+ printf(" Firmware Activate History Log \n");
+ printf(" Power on Hour Power Cycle Previous New \n");
+ printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
+ printf(" ----- -------------- -------------------- ---------- ---------- ----- ------ -------\n");
+
+ struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+
+ if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
+ /* find lowest/oldest entry */
+ for (i = 0; i < num_entries; i++) {
+ if (le32_to_cpu(fw_act_history_entry[i].entry_num) > le32_to_cpu(fw_act_history_entry[i+1].entry_num)) {
+ oldestEntryIdx = i+1;
+ break;
+ }
+ }
+ }
- fw_act_history_entry++;
+ if (oldestEntryIdx == WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ else
+ entryIdx = oldestEntryIdx;
+
+ for (i = 0; i < num_entries; i++) {
+ memset((void *)previous_fw, 0, 9);
+ memset((void *)new_fw, 0, 9);
+ memset((void *)commit_action_bin, 0, 8);
+
+ memcpy(previous_fw, (char *)&(fw_act_history_entry[entryIdx].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry[entryIdx].new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry[entryIdx].new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ printf("%5"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry[entryIdx].entry_num));
+ printf(" ");
+ printf("%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)%60));
+ printf(" ");
+ printf("%16"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry[entryIdx].power_cycle_count));
+ printf(" ");
+ printf("%s", (char *)previous_fw);
+ printf(" ");
+ printf("%s", (char *)new_fw);
+ printf(" ");
+ printf("%2"PRIu8"", (uint8_t)fw_act_history_entry[entryIdx].slot_number);
+ printf(" ");
+ wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type,(char *)&commit_action_bin);
+ printf(" %s", (char *)commit_action_bin);
+ printf(" ");
+ if (le16_to_cpu(fw_act_history_entry[entryIdx].result) == 0)
+ printf("pass");
+ else
+ printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry[entryIdx].result));
+
+ printf("\n");
+
+ entryIdx++;
+ if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ }
}
}
-static void wdc_print_fw_act_history_log_json(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
- int num_entries)
+static void wdc_print_fw_act_history_log_json(__u8 *data, int num_entries, __u32 cust_id)
{
struct json_object *root;
int i;
@@ -3396,59 +4169,569 @@ static void wdc_print_fw_act_history_log_json(struct wdc_fw_act_history_log_entr
char new_fw[9];
char commit_action_bin[8];
char fail_str[32];
- char time_str[9];
+ char time_str[11];
memset((void *)previous_fw, 0, 9);
memset((void *)new_fw, 0, 9);
memset((void *)commit_action_bin, 0, 8);
- memset((void *)time_str, 0, 9);
+ memset((void *)time_str, 0, 11);
memset((void *)fail_str, 0, 11);
char *null_fw = "--------";
+ __u16 oldestEntryIdx = 0, entryIdx = 0;
root = json_create_object();
- for (i = 0; i < num_entries; i++) {
- memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
- if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
- memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
+ if(data[0] == WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID) {
+ 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++) {
+ 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;
+ break;
+ }
+ }
+ }
+ if (oldestEntryIdx == WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
else
- memcpy(new_fw, null_fw, 8);
-
- json_object_add_value_int(root, "Entry",
- le32_to_cpu(fw_act_history_entry->entry_num));
-
- sprintf((char *)time_str, "%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
- (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
- (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
- json_object_add_value_string(root, "Power on Hour", time_str);
-
- json_object_add_value_int(root, "Power Cycle Count",
- le32_to_cpu(fw_act_history_entry->power_cycle_count));
- json_object_add_value_string(root, "Previous Firmware",
- previous_fw);
- json_object_add_value_string(root, "New Firmware",
- new_fw);
- json_object_add_value_int(root, "Slot",
- fw_act_history_entry->slot_number);
-
- wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
- json_object_add_value_string(root, "Action", commit_action_bin);
-
- if (le16_to_cpu(fw_act_history_entry->result) == 0)
- json_object_add_value_string(root, "Result", "pass");
- else {
- sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->result)));
- json_object_add_value_string(root, "Result", fail_str);
+ entryIdx = oldestEntryIdx;
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->entry[entryIdx].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->entry[entryIdx].current_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ json_object_add_value_int(root, "Entry",
+ le16_to_cpu(fw_act_history_entry->entry[entryIdx].fw_act_hist_entries));
+
+ if (cust_id == WDC_CUSTOMER_ID_0x1005) {
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%3600)/60)),
+ (int)(le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp%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);
+ }
+
+ json_object_add_value_int(root, "Power Cycle Count",
+ le64_to_cpu(fw_act_history_entry->entry[entryIdx].power_cycle_count));
+ json_object_add_value_string(root, "Previous Firmware",
+ previous_fw);
+ json_object_add_value_string(root, "New Firmware",
+ new_fw);
+ json_object_add_value_int(root, "Slot",
+ fw_act_history_entry->entry[entryIdx].slot_number);
+
+ wdc_get_commit_action_bin(fw_act_history_entry->entry[entryIdx].commit_action_type,(char *)&commit_action_bin);
+ json_object_add_value_string(root, "Action", commit_action_bin);
+
+ if (le16_to_cpu(fw_act_history_entry->entry[entryIdx].result) == 0)
+ json_object_add_value_string(root, "Result", "pass");
+ else {
+ sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->entry[entryIdx].result)));
+ json_object_add_value_string(root, "Result", fail_str);
+ }
+
+ entryIdx++;
+ if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ }
+ }
+ else {
+ struct wdc_fw_act_history_log_entry *fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+
+ if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
+ /* find lowest/oldest entry */
+ for (i = 0; i < num_entries; i++) {
+ if (le32_to_cpu(fw_act_history_entry[i].entry_num) > le32_to_cpu(fw_act_history_entry[i+1].entry_num)) {
+ oldestEntryIdx = i+1;
+ break;
+ }
+ }
+ }
+ if (oldestEntryIdx == WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ else
+ entryIdx = oldestEntryIdx;
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry[entryIdx].previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry[entryIdx].new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry[entryIdx].new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ json_object_add_value_int(root, "Entry",
+ le32_to_cpu(fw_act_history_entry[entryIdx].entry_num));
+
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry[entryIdx].power_on_seconds)%60));
+ json_object_add_value_string(root, "Power on Hour", time_str);
+
+ json_object_add_value_int(root, "Power Cycle Count",
+ le32_to_cpu(fw_act_history_entry[entryIdx].power_cycle_count));
+ json_object_add_value_string(root, "Previous Firmware",
+ previous_fw);
+ json_object_add_value_string(root, "New Firmware",
+ new_fw);
+ json_object_add_value_int(root, "Slot",
+ fw_act_history_entry[entryIdx].slot_number);
+
+ wdc_get_commit_action_bin(fw_act_history_entry[entryIdx].commit_action_type,(char *)&commit_action_bin);
+ json_object_add_value_string(root, "Action", commit_action_bin);
+
+ if (le16_to_cpu(fw_act_history_entry[entryIdx].result) == 0)
+ json_object_add_value_string(root, "Result", "pass");
+ else {
+ sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry[entryIdx].result)));
+ json_object_add_value_string(root, "Result", fail_str);
+ }
+
+ entryIdx++;
+ if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
}
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
- fw_act_history_entry++;
+static void wdc_print_smart_cloud_attr_C0_normal(void *data)
+{
+ __u8 *log_data = (__u8*)data;
+ uint16_t smart_log_ver = 0;
+
+ printf(" SMART Cloud Attributes :- \n");
+
+ printf(" Physical media units written %.0Lf\n",
+ int128_to_double(&log_data[SCAO_PMUW]));
+ printf(" Physical media units Read %.0Lf\n",
+ int128_to_double(&log_data[SCAO_PMUR]));
+ printf(" Bad user nand blocks - Raw %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
+ printf(" Bad user nand blocks - Normalized %d\n",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
+ printf(" Bad system nand blocks - Raw %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
+ printf(" Bad system nand blocks - Normalized %d\n",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
+ printf(" XOR recovery count %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
+ printf(" Uncorrectable read error count %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
+ printf(" Soft ecc error count %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
+ printf(" End to end corrected errors %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
+ printf(" End to end detected errors %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
+ printf(" System data percent used %d\n",
+ (__u8)log_data[SCAO_SDPU]);
+ printf(" Refresh counts %"PRIu64"\n",
+ (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF));
+ printf(" Max User data erase counts %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
+ printf(" Min User data erase counts %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
+ printf(" Number of Thermal throttling events %d\n",
+ (__u8)log_data[SCAO_NTTE]);
+ printf(" Current throttling status 0x%x\n",
+ (__u8)log_data[SCAO_CTS]);
+ printf(" PCIe correctable error count %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
+ printf(" Incomplete shutdowns %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
+ printf(" Percent free blocks %d\n",
+ (__u8)log_data[SCAO_PFB]);
+ printf(" Capacitor health %"PRIu16"\n",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
+ printf(" Unaligned I/O %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
+ printf(" Security Version Number %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
+ printf(" NUSE - Namespace utilization %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
+ printf(" PLP start count %.0Lf\n",
+ int128_to_double(&log_data[SCAO_PSC]));
+ printf(" Endurance estimate %.0Lf\n",
+ int128_to_double(&log_data[SCAO_EEST]));
+ 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]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
+ if(smart_log_ver > 2) {
+ printf(" Errata Version Field %d\n",
+ (__u8)log_data[SCAO_EVF]);
+ printf(" Point Version Field %"PRIu16"\n",
+ (uint16_t)log_data[SCAO_PVF]);
+ printf(" Minor Version Field %"PRIu16"\n",
+ (uint16_t)log_data[SCAO_MIVF]);
+ printf(" Major Version Field %d\n",
+ (__u8)log_data[SCAO_MAVF]);
+ printf(" NVMe Errata Version %d\n",
+ (__u8)log_data[SCAO_NEV]);
+ printf(" PCIe Link Retraining Count %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
}
+ printf("\n");
+}
+static void wdc_print_smart_cloud_attr_C0_json(void *data)
+{
+ __u8 *log_data = (__u8*)data;
+ struct json_object *root;
+ uint16_t smart_log_ver = 0;
+
+ root = json_create_object();
+ json_object_add_value_float(root, "Physical media units written",
+ int128_to_double(&log_data[SCAO_PMUW]));
+ json_object_add_value_int(root, "Physical media units Read",
+ int128_to_double(&log_data[SCAO_PMUR]));
+ json_object_add_value_uint(root, "Bad user nand blocks - Raw",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BUNBR] & 0x0000FFFFFFFFFFFF));
+ json_object_add_value_uint(root, "Bad user nand blocks - Normalized",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BUNBN]));
+ json_object_add_value_uint(root, "Bad system nand blocks - Raw",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_BSNBR] & 0x0000FFFFFFFFFFFF));
+ json_object_add_value_uint(root, "Bad system nand blocks - Normalized",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_BSNBN]));
+ json_object_add_value_uint(root, "XOR recovery count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
+ json_object_add_value_uint(root, "Uncorrectable read error count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
+ json_object_add_value_uint(root, "Soft ecc error count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SEEC]));
+ json_object_add_value_uint(root, "End to end corrected errors",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
+ json_object_add_value_uint(root, "End to end detected errors",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
+ json_object_add_value_uint(root, "System data percent used",
+ (__u8)log_data[SCAO_SDPU]);
+ json_object_add_value_uint(root, "Refresh counts",
+ (uint64_t)(le64_to_cpu(*(uint64_t *)&log_data[SCAO_RFSC])& 0x00FFFFFFFFFFFFFF));
+ json_object_add_value_uint(root, "Max User data erase counts",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MXUDEC]));
+ json_object_add_value_uint(root, "Min User data erase counts",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_MNUDEC]));
+ json_object_add_value_uint(root, "Number of Thermal throttling events",
+ (__u8)log_data[SCAO_NTTE]);
+ json_object_add_value_uint(root, "Current throttling status",
+ (__u8)log_data[SCAO_CTS]);
+ json_object_add_value_uint(root, "PCIe correctable error count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PCEC]));
+ json_object_add_value_uint(root, "Incomplete shutdowns",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_ICS]));
+ json_object_add_value_uint(root, "Percent free blocks",
+ (__u8)log_data[SCAO_PFB]);
+ json_object_add_value_uint(root, "Capacitor health",
+ (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_CPH]));
+ json_object_add_value_uint(root, "Unaligned I/O",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
+ json_object_add_value_uint(root, "Security Version Number",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
+ json_object_add_value_uint(root, "NUSE - Namespace utilization",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
+ json_object_add_value_uint(root, "PLP start count",
+ int128_to_double(&log_data[SCAO_PSC]));
+ json_object_add_value_uint(root, "Endurance estimate",
+ int128_to_double(&log_data[SCAO_EEST]));
+ smart_log_ver = (uint16_t)le16_to_cpu(*(uint16_t *)&log_data[SCAO_LPV]);
+ 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]),
+ (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",
+ (__u8)log_data[SCAO_EVF]);
+ json_object_add_value_uint(root, "Point Version Field",
+ (uint16_t)log_data[SCAO_PVF]);
+ json_object_add_value_uint(root, "Minor Version Field",
+ (uint16_t)log_data[SCAO_MIVF]);
+ json_object_add_value_uint(root, "Major Version Field",
+ (__u8)log_data[SCAO_MAVF]);
+ json_object_add_value_uint(root, "NVMe Errata Version",
+ (__u8)log_data[SCAO_NEV]);
+ json_object_add_value_uint(root, "PCIe Link Retraining Count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
+ }
json_print_object(root, NULL);
printf("\n");
+ json_free_object(root);
+}
+
+static void wdc_print_eol_c0_normal(void *data)
+{
+ __u8 *log_data = (__u8*)data;
+
+ printf(" End of Life Log Page 0xC0 :- \n");
+
+ printf(" Realloc Block Count %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_RBC]));
+ printf(" ECC Rate %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_ECCR]));
+ printf(" Write Amp %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_WRA]));
+ printf(" Percent Life Remaining %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_PLR]));
+ printf(" Program Fail Count %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_PFC]));
+ printf(" Erase Fail Count %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_EFC]));
+ printf(" Raw Read Error Rate %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(log_data[EOL_RRER]));
+
+}
+
+static void wdc_print_eol_c0_json(void *data)
+{
+ __u8 *log_data = (__u8*)data;
+ struct json_object *root;
+
+ root = json_create_object();
+
+ json_object_add_value_uint(root, "Realloc Block Count",
+ (uint32_t)le32_to_cpu(log_data[EOL_RBC]));
+ json_object_add_value_uint(root, "ECC Rate",
+ (uint32_t)le32_to_cpu(log_data[EOL_ECCR]));
+ json_object_add_value_uint(root, "Write Amp",
+ (uint32_t)le32_to_cpu(log_data[EOL_WRA]));
+ json_object_add_value_uint(root, "Percent Life Remaining",
+ (uint32_t)le32_to_cpu(log_data[EOL_PLR]));
+ json_object_add_value_uint(root, "Program Fail Count",
+ (uint32_t)le32_to_cpu(log_data[EOL_PFC]));
+ json_object_add_value_uint(root, "Erase Fail Count",
+ (uint32_t)le32_to_cpu(log_data[EOL_EFC]));
+ json_object_add_value_uint(root, "Raw Read Error Rate",
+ (uint32_t)le32_to_cpu(log_data[EOL_RRER]));
+
+ json_print_object(root, NULL);
+ printf("\n");
json_free_object(root);
}
+static int wdc_print_c0_cloud_attr_log(void *data, int fmt)
+{
+ if (!data) {
+ fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 log\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_smart_cloud_attr_C0_normal(data);
+ break;
+ case JSON:
+ wdc_print_smart_cloud_attr_C0_json(data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_c0_eol_log(void *data, int fmt)
+{
+ if (!data) {
+ fprintf(stderr, "ERROR : WDC : Invalid buffer to read 0xC0 log\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_eol_c0_normal(data);
+ break;
+ case JSON:
+ wdc_print_eol_c0_json(data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_get_c0_log_page(int fd, char *format, int uuid_index)
+{
+ int ret = 0;
+ int fmt = -1;
+ int i = 0;
+ __u8 *data;
+ __u32 *cust_id;
+ uint32_t device_id, read_vendor_id;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ ret = wdc_get_pci_ids(&device_id, &read_vendor_id);
+
+ switch (device_id) {
+
+ case WDC_NVME_SN640_DEV_ID:
+ case WDC_NVME_SN640_DEV_ID_1:
+ case WDC_NVME_SN640_DEV_ID_2:
+ case WDC_NVME_SN640_DEV_ID_3:
+ case WDC_NVME_SN840_DEV_ID:
+ case WDC_NVME_SN840_DEV_ID_1:
+ if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) {
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID);
+ return -1;
+ }
+
+ cust_id = (__u32*)data;
+
+ if ((*cust_id == WDC_CUSTOMER_ID_0x1004) || (*cust_id == WDC_CUSTOMER_ID_0x1008) ||
+ (*cust_id == WDC_CUSTOMER_ID_0x1005) || (*cust_id == WDC_CUSTOMER_ID_0x1304))
+ {
+ if (uuid_index == 0)
+ {
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* 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);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+
+ /* Verify GUID matches */
+ for (i=0; i<16; i++) {
+ if (scao_guid[i] != data[SCAO_LPG + i]) {
+ fprintf(stderr, "ERROR : WDC : Unknown GUID in C0 Log Page data\n");
+ int j;
+ fprintf(stderr, "ERROR : WDC : Expected GUID: 0x");
+ for (j = 0; j<16; j++) {
+ fprintf(stderr, "%x", scao_guid[j]);
+ }
+ fprintf(stderr, "\nERROR : WDC : Actual GUID: 0x");
+ for (j = 0; j<16; j++) {
+ fprintf(stderr, "%x", data[SCAO_LPG + j]);
+ }
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+
+ if (ret == 0) {
+
+ /* parse the data */
+ wdc_print_c0_cloud_attr_log(data, fmt);
+ }
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ } else if (uuid_index == 1) {
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_EOL_STATUS_LOG_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* 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);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ wdc_print_c0_eol_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unknown uuid index\n");
+ ret = -1;
+ }
+ }
+ else {
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_EOL_STATUS_LOG_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
+ false, NVME_NO_LOG_LSP, WDC_NVME_EOL_STATUS_LOG_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ wdc_print_c0_eol_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ }
+ break;
+
+ case WDC_NVME_ZN350_DEV_ID:
+ case WDC_NVME_ZN350_DEV_ID_1:
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_OPCODE,
+ false, NVME_NO_LOG_LSP, WDC_NVME_SMART_CLOUD_ATTR_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ wdc_print_c0_cloud_attr_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read C0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ break;
+
+ default:
+ fprintf(stderr, "ERROR : WDC : Unknown device id - 0x%x\n", device_id);
+
+ ret = -1;
+ break;
+
+ }
+
+ return ret;
+}
+
static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
{
if (!perf) {
@@ -3500,21 +4783,19 @@ 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(struct wdc_fw_act_history_log_entry *fw_act_history_entries,
- int num_entries,
- int fmt)
+static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt, __u32 cust_id)
{
- if (!fw_act_history_entries) {
+ if (!data) {
fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n");
return -1;
}
switch (fmt) {
case NORMAL:
- wdc_print_fw_act_history_log_normal(fw_act_history_entries, num_entries);
+ wdc_print_fw_act_history_log_normal(data, num_entries, cust_id);
break;
case JSON:
- wdc_print_fw_act_history_log_json(fw_act_history_entries, num_entries);
+ wdc_print_fw_act_history_log_json(data, num_entries, cust_id);
break;
}
return 0;
@@ -3566,7 +4847,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN);
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
- false, WDC_FB_CA_LOG_BUF_LEN, data);
+ false, NVME_NO_LOG_LSP, WDC_FB_CA_LOG_BUF_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
@@ -3580,7 +4861,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
}
} else {
- fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = %d\n", *cust_id);
+ fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", *cust_id);
return -1;
}
break;
@@ -3588,7 +4869,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
case WDC_NVME_SN640_DEV_ID:
case WDC_NVME_SN640_DEV_ID_1:
case WDC_NVME_SN640_DEV_ID_2:
- case WDC_NVME_SN640_DEV_ID_3:
+ case WDC_NVME_SN640_DEV_ID_3:
case WDC_NVME_SN840_DEV_ID:
case WDC_NVME_SN840_DEV_ID_1:
@@ -3602,7 +4883,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
memset(data, 0, sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN);
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
- false, WDC_FB_CA_LOG_BUF_LEN, data);
+ false, NVME_NO_LOG_LSP, WDC_FB_CA_LOG_BUF_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
@@ -3614,7 +4895,8 @@ static int wdc_get_ca_log_page(int fd, char *format)
fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
ret = -1;
}
- } else if ((*cust_id == WDC_CUSTOMER_ID_GN) || (*cust_id == WDC_CUSTOMER_ID_GD)) {
+ } else if ((*cust_id == WDC_CUSTOMER_ID_GN) || (*cust_id == WDC_CUSTOMER_ID_GD) ||
+ (*cust_id == WDC_CUSTOMER_ID_BD)) {
if ((data = (__u8*) malloc(sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN)) == NULL) {
fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
@@ -3623,7 +4905,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
memset(data, 0, sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN);
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
- false, WDC_BD_CA_LOG_BUF_LEN, data);
+ false, NVME_NO_LOG_LSP, WDC_BD_CA_LOG_BUF_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
@@ -3638,7 +4920,7 @@ static int wdc_get_ca_log_page(int fd, char *format)
break;
} else {
- fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = %d\n", *cust_id);
+ fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = 0x%x\n", *cust_id);
return -1;
}
break;
@@ -3687,7 +4969,7 @@ static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval)
memset(data, 0, sizeof (__u8) * WDC_ADD_LOG_BUF_LEN);
ret = nvme_get_log(fd, 0x01, WDC_NVME_ADD_LOG_OPCODE, false,
- WDC_ADD_LOG_BUF_LEN, data);
+ NVME_NO_LOG_LSP, WDC_ADD_LOG_BUF_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
if (ret == 0) {
@@ -3740,7 +5022,7 @@ static int wdc_get_d0_log_page(int fd, char *format)
memset(data, 0, sizeof (__u8) * WDC_NVME_VU_SMART_LOG_LEN);
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_VU_SMART_LOG_OPCODE,
- false, WDC_NVME_VU_SMART_LOG_LEN, data);
+ false, NVME_NO_LOG_LSP, WDC_NVME_VU_SMART_LOG_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
@@ -3763,23 +5045,33 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
const char *desc = "Retrieve additional performance statistics.";
const char *interval = "Interval to read the statistics from [1, 15].";
int fd;
+ const char *log_page_version = "Log Page Version: 0 = vendor, 1 = WDC";
+ const char *log_page_mask = "Log Page Mask, comma separated list: 0xC0, 0xC1, 0xCA, 0xD0";
int ret = 0;
+ int uuid_index = 0;
+ int page_mask = 0, num, i;
+ int log_page_list[16];
__u64 capabilities = 0;
struct config {
uint8_t interval;
- int vendor_specific;
char *output_format;
+ __u8 log_page_version;
+ char *log_page_mask;
};
struct config cfg = {
.interval = 14,
.output_format = "normal",
+ .log_page_version = 0,
+ .log_page_mask = "",
};
OPT_ARGS(opts) = {
- OPT_UINT("interval", 'i', &cfg.interval, interval),
- OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("interval", 'i', &cfg.interval, interval),
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_BYTE("log-page-version", 'l', &cfg.log_page_version, log_page_version),
+ OPT_LIST("log-page-mask", 'p', &cfg.log_page_mask, log_page_mask),
OPT_END()
};
@@ -3787,6 +5079,50 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
if (fd < 0)
return fd;
+ if (cfg.log_page_version == 0) {
+ uuid_index = 0;
+ } else if (cfg.log_page_version == 1) {
+ uuid_index = 1;
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported log page version for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ num = argconfig_parse_comma_sep_array(cfg.log_page_mask, log_page_list, 16);
+
+ if (num == -1) {
+ fprintf(stderr, "ERROR: WDC: log page list is malformed\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (num == 0)
+ {
+ page_mask |= WDC_ALL_PAGE_MASK;
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ if (log_page_list[i] == 0xc0) {
+ page_mask |= WDC_C0_PAGE_MASK;
+ }
+ if (log_page_list[i] == 0xc1) {
+ page_mask |= WDC_C1_PAGE_MASK;
+ }
+ if (log_page_list[i] == 0xca) {
+ page_mask |= WDC_CA_PAGE_MASK;
+ }
+ if (log_page_list[i] == 0xd0) {
+ page_mask |= WDC_D0_PAGE_MASK;
+ }
+ }
+ }
+ if (page_mask == 0)
+ fprintf(stderr, "ERROR : WDC: Unknown log page mask - %s\n", cfg.log_page_mask);
+
+
capabilities = wdc_get_drive_capabilities(fd);
if ((capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK) == 0) {
@@ -3795,25 +5131,78 @@ static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
goto out;
}
- if ((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) {
+ if (((capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE) == WDC_DRIVE_CAP_C0_LOG_PAGE) &&
+ (page_mask & WDC_C0_PAGE_MASK)) {
+ /* Get 0xC0 log page if possible. */
+ ret = wdc_get_c0_log_page(fd, cfg.output_format, uuid_index);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the C0 Log Page, ret = %d\n", ret);
+ }
+ if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) &&
+ (page_mask & WDC_CA_PAGE_MASK)) {
/* Get the CA Log Page */
ret = wdc_get_ca_log_page(fd, cfg.output_format);
if (ret)
fprintf(stderr, "ERROR : WDC : Failure reading the CA Log Page, ret = %d\n", ret);
}
- if ((capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE) == WDC_DRIVE_CAP_C1_LOG_PAGE) {
+ if (((capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE) == WDC_DRIVE_CAP_C1_LOG_PAGE) &&
+ (page_mask & WDC_C1_PAGE_MASK)) {
/* Get the C1 Log Page */
ret = wdc_get_c1_log_page(fd, cfg.output_format, cfg.interval);
if (ret)
fprintf(stderr, "ERROR : WDC : Failure reading the C1 Log Page, ret = %d\n", ret);
}
- if ((capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE) == WDC_DRIVE_CAP_D0_LOG_PAGE) {
+ if (((capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE) == WDC_DRIVE_CAP_D0_LOG_PAGE) &&
+ (page_mask & WDC_D0_PAGE_MASK)) {
/* Get the D0 Log Page */
ret = wdc_get_d0_log_page(fd, cfg.output_format);
if (ret)
fprintf(stderr, "ERROR : WDC : Failure reading the D0 Log Page, ret = %d\n", ret);
}
+
out:
+
+ return ret;
+}
+
+static int wdc_do_clear_pcie_correctable_errors(int fd)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_PCIE_CORR_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_PCIE_CORR_CMD);
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ return ret;
+}
+
+static int wdc_do_clear_pcie_correctable_errors_vuc(int fd)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE_VUC;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ return ret;
+}
+
+static int wdc_do_clear_pcie_correctable_errors_fid(int fd)
+{
+ int ret;
+ __u32 result;
+ __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);
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
return ret;
}
@@ -3823,7 +5212,6 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma
char *desc = "Clear PCIE Correctable Errors.";
int fd, ret;
__u64 capabilities = 0;
- struct nvme_passthru_cmd admin_cmd;
OPT_ARGS(opts) = {
OPT_END()
@@ -3839,28 +5227,32 @@ static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct comma
}
capabilities = wdc_get_drive_capabilities(fd);
- if ((capabilities & WDC_DRIVE_CAP_CLEAR_PCIE) == 0) {
+ if ((capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK) == 0) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
goto out;
}
+
+ if (capabilities & WDC_DRIVE_CAP_CLEAR_PCIE) {
+ ret = wdc_do_clear_pcie_correctable_errors(fd);
+ }
+ else if (capabilities & WDC_DRIVE_CAP_VUC_CLEAR_PCIE) {
+ ret = wdc_do_clear_pcie_correctable_errors_vuc(fd);
+ }
+ else {
+ ret = wdc_do_clear_pcie_correctable_errors_fid(fd);
+ }
- memset(&admin_cmd, 0, sizeof (admin_cmd));
- admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE;
- admin_cmd.cdw12 = ((WDC_NVME_CLEAR_PCIE_CORR_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
- WDC_NVME_CLEAR_PCIE_CORR_CMD);
-
- ret = nvme_submit_admin_passthru(fd, &admin_cmd);
- fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
out:
return ret;
}
+
static int wdc_drive_status(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
char *desc = "Get Drive Status.";
int fd;
- int ret = -1;
+ int ret = 0;
__le32 system_eol_state;
__le32 user_eol_state;
__le32 format_corrupt_reason = cpu_to_le32(0xFFFFFFFF);
@@ -4022,7 +5414,6 @@ static int wdc_get_fw_act_history(int fd, char *format)
int fmt = -1;
__u8 *data;
struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
- struct wdc_fw_act_history_log_entry *fw_act_history_entry;
if (!wdc_check_device(fd))
return -1;
@@ -4047,7 +5438,7 @@ static int wdc_get_fw_act_history(int fd, char *format)
memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN);
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID,
- false, WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data);
+ false, NVME_NO_LOG_LSP, WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data);
if (strcmp(format, "json"))
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
@@ -4055,17 +5446,85 @@ static int wdc_get_fw_act_history(int fd, char *format)
if (ret == 0) {
/* parse the data */
fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data);
- fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
- if (fw_act_history_hdr->num_entries > 0)
- ret = wdc_print_fw_act_history_log(fw_act_history_entry, fw_act_history_hdr->num_entries, fmt);
- else
- fprintf(stderr, "INFO : WDC : No entries found in FW Activate History Log Page\n");
+ 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);
+ else if (fw_act_history_hdr->num_entries == 0) {
+ 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", fw_act_history_hdr->num_entries);
+ ret = -1;
+ }
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ return ret;
+}
+
+static int wdc_get_fw_act_history_C2(int fd, char *format)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ __u32 *cust_id;
+ struct wdc_fw_act_history_log_format_c2 *fw_act_history_log;
+ __u32 num_entries = 0;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof (__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
+
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID,
+ false, NVME_NO_LOG_LSP, WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ 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);
+
+ if ((num_entries > 0) && (num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) {
+ /* 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) {
+ 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;
}
+freeData:
free(data);
return ret;
}
@@ -4098,16 +5557,86 @@ static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *com
return fd;
capabilities = wdc_get_drive_capabilities(fd);
-
- if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) == WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
- ret = wdc_get_fw_act_history(fd, cfg.output_format);
- if (ret)
- fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
- } else {
+ if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK) == 0) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
+ goto out;
}
+ if (capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
+ int uuid_index = 0;
+ bool c0GuidMatch = false;
+ __u8 *data;
+ int i;
+
+ /* check for the GUID in the 0xC0 log page to determine which log page to use to */
+ /* to retrieve fw activate history data */
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN)) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* 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);
+
+ if (ret == 0) {
+ /* Verify GUID matches */
+ for (i=0; i<16; i++) {
+ if (scao_guid[i] != data[SCAO_LPG + i]) {
+ c0GuidMatch = false;
+ break;
+ }
+ }
+
+ if (i == 16) {
+ c0GuidMatch = true;
+ }
+ }
+
+ free(data);
+ if (c0GuidMatch) {
+ ret = wdc_get_fw_act_history_C2(fd, cfg.output_format);
+ }
+ else {
+ ret = wdc_get_fw_act_history(fd, cfg.output_format);
+ }
+ } else {
+ ret = wdc_get_fw_act_history_C2(fd, cfg.output_format);
+ }
+
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
+out:
+ return ret;
+}
+
+static int wdc_do_clear_fw_activate_history_vuc(int fd)
+{
+ int ret = -1;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_FW_ACT_HIST_CMD);
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ return ret;
+}
+
+static int wdc_do_clear_fw_activate_history_fid(int fd)
+{
+ int ret = -1;
+ __u32 result;
+ __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);
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
return ret;
}
@@ -4118,7 +5647,6 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command *
int fd;
int ret = -1;
__u64 capabilities = 0;
- struct nvme_passthru_cmd admin_cmd;
OPT_ARGS(opts) = {
OPT_END()
@@ -4129,19 +5657,18 @@ static int wdc_clear_fw_activate_history(int argc, char **argv, struct command *
return fd;
capabilities = wdc_get_drive_capabilities(fd);
- if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) != WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK) == 0) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
goto out;
}
- memset(&admin_cmd, 0, sizeof (admin_cmd));
- admin_cmd.opcode = WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE;
- admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
- WDC_NVME_CLEAR_FW_ACT_HIST_CMD);
-
- ret = nvme_submit_admin_passthru(fd, &admin_cmd);
- fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ ret = wdc_do_clear_fw_activate_history_vuc(fd);
+ }
+ else {
+ ret = wdc_do_clear_fw_activate_history_fid(fd);
+ }
out:
return ret;
@@ -4811,7 +6338,7 @@ static int wdc_do_drive_essentials(int fd, char *dir, char *key)
memset(dataBuffer, 0, dataBufferSize);
ret = nvme_get_log(fd, WDC_DE_GLOBAL_NSID, deVULogPagesList[vuLogIdx].logPageId,
- false, dataBufferSize, dataBuffer);
+ false, NVME_NO_LOG_LSP, dataBufferSize, dataBuffer);
if (ret) {
fprintf(stderr, "ERROR : WDC : nvme_get_log() for log page 0x%x failed, ret = %d\n",
deVULogPagesList[vuLogIdx].logPageId, ret);
@@ -5025,7 +6552,6 @@ static int wdc_do_drive_info(int fd, __u32 *result)
return ret;
}
-
static int wdc_drive_resize(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
@@ -5230,13 +6756,16 @@ static const char *nvme_log_id_to_string(__u8 log_id)
case NVME_LOG_SANITIZE: return "Sanitize Status Log ID";
case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C1: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C8: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_CA: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_CB: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_D0: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_D1: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_D6: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_D7: return "WDC Vendor Unique Log ID";
case WDC_LOG_ID_D8: return "WDC Vendor Unique Log ID";
@@ -5258,7 +6787,9 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
int ret = 0;
__u64 capabilities = 0;
struct wdc_c2_cbs_data *cbs_data = NULL;
- int i;
+ int i;
+ __u8 log_id = 0;
+ __u32 device_id, read_vendor_id;
struct config {
char *output_format;
@@ -5288,10 +6819,14 @@ static int wdc_log_page_directory(int argc, char **argv, struct command *command
if ((capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR) == 0) {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
ret = -1;
- } else {
+ }
+ else {
+ ret = wdc_get_pci_ids(&device_id, &read_vendor_id);
+ log_id = (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) ?
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE_C8 : WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE;
/* verify the 0xC2 Device Manageability log page is supported */
- if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) {
- fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page not supported\n", __func__);
+ if (wdc_nvme_check_supported_log_page(fd, log_id) == false) {
+ fprintf(stderr, "%s: ERROR : WDC : 0x%x Log Page not supported\n", __func__, log_id);
ret = -1;
goto out;
}
@@ -5491,51 +7026,349 @@ static int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log_
return ret;
}
-static void wdc_print_nand_stats_normal(struct wdc_nand_stats *data)
-{
- printf(" NAND Statistics :- \n");
- printf(" NAND Writes TLC (Bytes) %.0Lf\n",
- int128_to_double(data->nand_write_tlc));
- printf(" NAND Writes SLC (Bytes) %.0Lf\n",
- int128_to_double(data->nand_write_slc));
- printf(" NAND Program Failures %"PRIu32"\n",
- (uint32_t)le32_to_cpu(data->nand_prog_failure));
- printf(" NAND Erase Failures %"PRIu32"\n",
- (uint32_t)le32_to_cpu(data->nand_erase_failure));
- printf(" Bad Block Count %"PRIu32"\n",
- (uint32_t)le32_to_cpu(data->bad_block_count));
- printf(" NAND XOR/RAID Recovery Trigger Events %"PRIu64"\n",
- le64_to_cpu(data->nand_rec_trigger_event));
- printf(" E2E Error Counter %"PRIu64"\n",
- le64_to_cpu(data->e2e_error_counter));
- printf(" Number Successful NS Resizing Events %"PRIu64"\n",
- le64_to_cpu(data->successful_ns_resize_event));
+static void wdc_print_nand_stats_normal(__u16 version, void *data)
+{
+ struct wdc_nand_stats *nand_stats = (struct wdc_nand_stats *)(data);
+ struct wdc_nand_stats_V3 *nand_stats_v3 = (struct wdc_nand_stats_V3 *)(data);
+ __u64 temp_raw;
+ __u16 temp_norm;
+ __u64 *temp_ptr = NULL;
+
+ switch (version)
+ {
+ case 0:
+ printf(" NAND Statistics :- \n");
+ printf(" NAND Writes TLC (Bytes) %.0Lf\n",
+ int128_to_double(nand_stats->nand_write_tlc));
+ printf(" NAND Writes SLC (Bytes) %.0Lf\n",
+ int128_to_double(nand_stats->nand_write_slc));
+ printf(" NAND Program Failures %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(nand_stats->nand_prog_failure));
+ printf(" NAND Erase Failures %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(nand_stats->nand_erase_failure));
+ printf(" Bad Block Count %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(nand_stats->bad_block_count));
+ printf(" NAND XOR/RAID Recovery Trigger Events %"PRIu64"\n",
+ le64_to_cpu(nand_stats->nand_rec_trigger_event));
+ printf(" E2E Error Counter %"PRIu64"\n",
+ le64_to_cpu(nand_stats->e2e_error_counter));
+ printf(" Number Successful NS Resizing Events %"PRIu64"\n",
+ le64_to_cpu(nand_stats->successful_ns_resize_event));
+ printf(" log page version %"PRIu16"\n",
+ le16_to_cpu(nand_stats->log_page_version));
+ break;
+ case 3:
+ printf(" NAND Statistics V3:- \n");
+ printf(" TLC Units Written %.0Lf\n",
+ int128_to_double(nand_stats_v3->nand_write_tlc));
+ printf(" SLC Units Written %.0Lf\n",
+ int128_to_double(nand_stats_v3->nand_write_slc));
+ temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ printf(" Bad NAND Blocks Count - Normalized %"PRIu16"\n",
+ le16_to_cpu(temp_norm));
+ printf(" Bad NAND Blocks Count - Raw %"PRIu64"\n",
+ le64_to_cpu(temp_raw));
+ printf(" NAND XOR Recovery count %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->xor_recovery_count));
+ printf(" UECC Read Error count %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->uecc_read_error_count));
+ printf(" SSD End to End corrected errors %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->ssd_correction_counts[0]));
+ printf(" SSD End to End detected errors %"PRIu32"\n",
+ le32_to_cpu(nand_stats_v3->ssd_correction_counts[8]));
+ printf(" SSD End to End uncorrected E2E errors %"PRIu32"\n",
+ le32_to_cpu(nand_stats_v3->ssd_correction_counts[12]));
+ printf(" System data %% life-used %u\n",
+ nand_stats_v3->percent_life_used);
+ printf(" User Data Erase Counts - TLC Min %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[0]));
+ printf(" User Data Erase Counts - TLC Max %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[1]));
+ printf(" User Data Erase Counts - SLC Min %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[2]));
+ printf(" User Data Erase Counts - SLC Max %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[3]));
+ temp_ptr = (__u64 *)nand_stats_v3->program_fail_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ printf(" Program Fail Count - Normalized %"PRIu16"\n",
+ le16_to_cpu(temp_norm));
+ printf(" Program Fail Count - Raw %"PRIu64"\n",
+ le64_to_cpu(temp_raw));
+ temp_ptr = (__u64 *)nand_stats_v3->erase_fail_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ printf(" Erase Fail Count - Normalized %"PRIu16"\n",
+ le16_to_cpu(temp_norm));
+ printf(" Erase Fail Count - Raw %"PRIu64"\n",
+ le64_to_cpu(temp_raw));
+ printf(" PCIe Correctable Error Count %"PRIu16"\n",
+ le16_to_cpu(nand_stats_v3->correctable_error_count));
+ printf(" %% Free Blocks (User) %u\n",
+ nand_stats_v3->percent_free_blocks_user);
+ printf(" Security Version Number %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->security_version_number));
+ printf(" %% Free Blocks (System) %u\n",
+ nand_stats_v3->percent_free_blocks_system);
+ printf(" Data Set Management Commands %.0Lf\n",
+ int128_to_double(nand_stats_v3->trim_completions));
+ printf(" Estimate of Incomplete Trim Data %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->trim_completions[16]));
+ printf(" %% of completed trim %u\n",
+ nand_stats_v3->trim_completions[24]);
+ printf(" Background Back-Pressure-Guage %u\n",
+ nand_stats_v3->back_pressure_guage);
+ printf(" Soft ECC Error Count %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->soft_ecc_error_count));
+ printf(" Refresh Count %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->refresh_count));
+ temp_ptr = (__u64 *)nand_stats_v3->bad_sys_nand_block_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ printf(" Bad System Nand Block Count - Normalized %"PRIu16"\n",
+ le16_to_cpu(temp_norm));
+ printf(" Bad System Nand Block Count - Raw %"PRIu64"\n",
+ le64_to_cpu(temp_raw));
+ printf(" Endurance Estimate %.0Lf\n",
+ int128_to_double(nand_stats_v3->endurance_estimate));
+ printf(" Thermal Throttling Count %u\n",
+ nand_stats_v3->thermal_throttling_st_ct[0]);
+ printf(" Thermal Throttling Status %u\n",
+ nand_stats_v3->thermal_throttling_st_ct[1]);
+ printf(" Unaligned I/O %"PRIu64"\n",
+ le64_to_cpu(nand_stats_v3->unaligned_IO));
+ printf(" Physical Media Units Read %.0Lf\n",
+ int128_to_double(nand_stats_v3->physical_media_units));
+ printf(" log page version %"PRIu16"\n",
+ le16_to_cpu(nand_stats_v3->log_page_version));
+ break;
+
+ default:
+ fprintf(stderr, "WDC: Nand Stats ERROR : Invalid version\n");
+ break;
+
+ }
}
-static void wdc_print_nand_stats_json(struct wdc_nand_stats *data)
+static void wdc_print_nand_stats_json(__u16 version, void *data)
{
+ struct wdc_nand_stats *nand_stats = (struct wdc_nand_stats *)(data);
+ struct wdc_nand_stats_V3 *nand_stats_v3 = (struct wdc_nand_stats_V3 *)(data);
struct json_object *root;
+ root = json_create_object();
+ __u64 temp_raw;
+ __u16 temp_norm;
+ __u64 *temp_ptr = NULL;
+
+ switch (version)
+ {
+
+ case 0:
+
+ json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
+ int128_to_double(nand_stats->nand_write_tlc));
+ json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
+ int128_to_double(nand_stats->nand_write_slc));
+ json_object_add_value_uint(root, "NAND Program Failures",
+ le32_to_cpu(nand_stats->nand_prog_failure));
+ json_object_add_value_uint(root, "NAND Erase Failures",
+ le32_to_cpu(nand_stats->nand_erase_failure));
+ json_object_add_value_uint(root, "Bad Block Count",
+ le32_to_cpu(nand_stats->bad_block_count));
+ json_object_add_value_uint(root, "NAND XOR/RAID Recovery Trigger Events",
+ le64_to_cpu(nand_stats->nand_rec_trigger_event));
+ json_object_add_value_uint(root, "E2E Error Counter",
+ le64_to_cpu(nand_stats->e2e_error_counter));
+ json_object_add_value_uint(root, "Number Successful NS Resizing Events",
+ le64_to_cpu(nand_stats->successful_ns_resize_event));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ break;
+
+ case 3:
+
+ json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
+ int128_to_double(nand_stats_v3->nand_write_tlc));
+ json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
+ int128_to_double(nand_stats_v3->nand_write_slc));
+ temp_ptr = (__u64 *)nand_stats_v3->bad_nand_block_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ json_object_add_value_uint(root, "Bad NAND Blocks Count - Normalized",
+ le16_to_cpu(temp_norm));
+ json_object_add_value_uint(root, "Bad NAND Blocks Count - Raw",
+ le64_to_cpu(temp_raw));
+ json_object_add_value_uint(root, "NAND XOR Recovery count",
+ le64_to_cpu(nand_stats_v3->xor_recovery_count));
+ json_object_add_value_uint(root, "UECC Read Error count",
+ le64_to_cpu(nand_stats_v3->uecc_read_error_count));
+ json_object_add_value_uint(root, "SSD End to End corrected errors",
+ le64_to_cpu(nand_stats_v3->ssd_correction_counts[0]));
+ json_object_add_value_uint(root, "SSD End to End detected errors",
+ le32_to_cpu(nand_stats_v3->ssd_correction_counts[8]));
+ json_object_add_value_uint(root, "SSD End to End uncorrected E2E errors",
+ le32_to_cpu(nand_stats_v3->ssd_correction_counts[12]));
+ json_object_add_value_uint(root, "System data % life-used",
+ nand_stats_v3->percent_life_used);
+ json_object_add_value_uint(root, "User Data Erase Counts - SLC Min",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[0]));
+ json_object_add_value_uint(root, "User Data Erase Counts - SLC Max",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[1]));
+ json_object_add_value_uint(root, "User Data Erase Counts - TLC Min",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[2]));
+ json_object_add_value_uint(root, "User Data Erase Counts - TLC Max",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[3]));
+ temp_ptr = (__u64 *)nand_stats_v3->program_fail_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ json_object_add_value_uint(root, "Program Fail Count - Normalized",
+ le16_to_cpu(temp_norm));
+ json_object_add_value_uint(root, "Program Fail Count - Raw",
+ le64_to_cpu(temp_raw));
+ temp_ptr = (__u64 *)nand_stats_v3->erase_fail_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ json_object_add_value_uint(root, "Erase Fail Count - Normalized",
+ le16_to_cpu(temp_norm));
+ json_object_add_value_uint(root, "Erase Fail Count - Raw",
+ le64_to_cpu(temp_raw));
+ json_object_add_value_uint(root, "PCIe Correctable Error Count",
+ le16_to_cpu(nand_stats_v3->correctable_error_count));
+ json_object_add_value_uint(root, "% Free Blocks (User)",
+ nand_stats_v3->percent_free_blocks_user);
+ json_object_add_value_uint(root, "Security Version Number",
+ le64_to_cpu(nand_stats_v3->security_version_number));
+ json_object_add_value_uint(root, "% Free Blocks (System)",
+ nand_stats_v3->percent_free_blocks_system);
+ json_object_add_value_float(root, "Data Set Management Commands",
+ int128_to_double(nand_stats_v3->trim_completions));
+ json_object_add_value_uint(root, "Estimate of Incomplete Trim Data",
+ le64_to_cpu(nand_stats_v3->trim_completions[16]));
+ json_object_add_value_uint(root, "%% of completed trim",
+ nand_stats_v3->trim_completions[24]);
+ json_object_add_value_uint(root, "Background Back-Pressure-Guage",
+ nand_stats_v3->back_pressure_guage);
+ json_object_add_value_uint(root, "Soft ECC Error Count",
+ le64_to_cpu(nand_stats_v3->soft_ecc_error_count));
+ json_object_add_value_uint(root, "Refresh Count",
+ le64_to_cpu(nand_stats_v3->refresh_count));
+ temp_ptr = (__u64 *)nand_stats_v3->bad_sys_nand_block_count;
+ temp_norm = (__u16)(*temp_ptr & 0x000000000000FFFF);
+ temp_raw = ((*temp_ptr & 0xFFFFFFFFFFFF0000) >> 16);
+ json_object_add_value_uint(root, "Bad System Nand Block Count - Normalized",
+ le16_to_cpu(temp_norm));
+ json_object_add_value_uint(root, "Bad System Nand Block Count - Raw",
+ le64_to_cpu(temp_raw));
+ json_object_add_value_float(root, "Endurance Estimate",
+ int128_to_double(nand_stats_v3->endurance_estimate));
+ json_object_add_value_uint(root, "Thermal Throttling Status",
+ nand_stats_v3->thermal_throttling_st_ct[0]);
+ json_object_add_value_uint(root, "Thermal Throttling Count",
+ nand_stats_v3->thermal_throttling_st_ct[1]);
+ json_object_add_value_uint(root, "Unaligned I/O",
+ le64_to_cpu(nand_stats_v3->unaligned_IO));
+ json_object_add_value_float(root, "Physical Media Units Read",
+ int128_to_double(nand_stats_v3->physical_media_units));
+ json_object_add_value_uint(root, "log page version",
+ le16_to_cpu(nand_stats_v3->log_page_version));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ break;
+
+ default:
+ printf("%s: Invalid Stats Version = %d\n", __func__, version);
+ break;
+
+ }
+
+ json_free_object(root);
+
+}
+
+static void wdc_print_pcie_stats_normal(struct wdc_vs_pcie_stats *pcie_stats)
+{
+ printf(" PCIE Statistics :- \n");
+ printf(" Unsupported Request Error Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->unsupportedRequestErrorCount));
+ printf(" ECRC Error Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->ecrcErrorStatusCount));
+ printf(" Malformed TLP Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->malformedTlpStatusCount));
+ printf(" Receiver Overflow Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->receiverOverflowStatusCount));
+ printf(" Unexpected Completion Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->unexpectedCmpltnStatusCount));
+ printf(" Complete Abort Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->completeAbortStatusCount));
+ printf(" Completion Timeout Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->cmpltnTimoutStatusCount));
+ printf(" Flow Control Error Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->flowControlErrorStatusCount));
+ printf(" Poisoned TLP Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->poisonedTlpStatusCount));
+ printf(" Dlink Protocol Error Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->dLinkPrtclErrorStatusCount));
+ printf(" Advisory Non Fatal Error Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->advsryNFatalErrStatusCount));
+ printf(" Replay Timer TO Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->replayTimerToStatusCount));
+ printf(" Replay Number Rollover Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->replayNumRolloverStCount));
+ printf(" Bad DLLP Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->badDllpStatusCount));
+ printf(" Bad TLP Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->badTlpStatusCount));
+ printf(" Receiver Error Status Counter %20"PRIu64"\n",
+ le64_to_cpu(pcie_stats->receiverErrStatusCount));
+
+}
+static void wdc_print_pcie_stats_json(struct wdc_vs_pcie_stats *pcie_stats)
+{
+ struct json_object *root;
root = json_create_object();
- json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
- int128_to_double(data->nand_write_tlc));
- json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
- int128_to_double(data->nand_write_slc));
- json_object_add_value_uint(root, "NAND Program Failures",
- le32_to_cpu(data->nand_prog_failure));
- json_object_add_value_uint(root, "NAND Erase Failures",
- le32_to_cpu(data->nand_erase_failure));
- json_object_add_value_uint(root, "Bad Block Count",
- le32_to_cpu(data->bad_block_count));
- json_object_add_value_uint(root, "NAND XOR/RAID Recovery Trigger Events",
- le64_to_cpu(data->nand_rec_trigger_event));
- json_object_add_value_uint(root, "E2E Error Counter",
- le64_to_cpu(data->e2e_error_counter));
- json_object_add_value_uint(root, "Number Successful NS Resizing Events",
- le64_to_cpu(data->successful_ns_resize_event));
+
+ json_object_add_value_uint(root, "Unsupported Request Error Counter",
+ le64_to_cpu(pcie_stats->unsupportedRequestErrorCount));
+ json_object_add_value_uint(root, "ECRC Error Status Counter",
+ le64_to_cpu(pcie_stats->ecrcErrorStatusCount));
+ json_object_add_value_uint(root, "Malformed TLP Status Counter",
+ le64_to_cpu(pcie_stats->malformedTlpStatusCount));
+
+ json_object_add_value_uint(root, "Receiver Overflow Status Counter",
+ le64_to_cpu(pcie_stats->receiverOverflowStatusCount));
+ json_object_add_value_uint(root, "Unexpected Completion Status Counter",
+ le64_to_cpu(pcie_stats->unexpectedCmpltnStatusCount));
+ json_object_add_value_uint(root, "Complete Abort Status Counter",
+ le64_to_cpu(pcie_stats->completeAbortStatusCount));
+ json_object_add_value_uint(root, "Completion Timeout Status Counter",
+ le64_to_cpu(pcie_stats->cmpltnTimoutStatusCount));
+ json_object_add_value_uint(root, "Flow Control Error Status Counter",
+ le64_to_cpu(pcie_stats->flowControlErrorStatusCount));
+ json_object_add_value_uint(root, "Poisoned TLP Status Counter",
+ le64_to_cpu(pcie_stats->poisonedTlpStatusCount));
+ json_object_add_value_uint(root, "Dlink Protocol Error Status Counter",
+ le64_to_cpu(pcie_stats->dLinkPrtclErrorStatusCount));
+ json_object_add_value_uint(root, "Advisory Non Fatal Error Status Counter",
+ le64_to_cpu(pcie_stats->advsryNFatalErrStatusCount));
+ json_object_add_value_uint(root, "Replay Timer TO Status Counter",
+ le64_to_cpu(pcie_stats->replayTimerToStatusCount));
+ json_object_add_value_uint(root, "Replay Number Rollover Status Counter",
+ le64_to_cpu(pcie_stats->replayNumRolloverStCount));
+ json_object_add_value_uint(root, "Bad DLLP Status Counter",
+ le64_to_cpu(pcie_stats->badDllpStatusCount));
+ json_object_add_value_uint(root, "Bad TLP Status Counter",
+ le64_to_cpu(pcie_stats->badTlpStatusCount));
+ json_object_add_value_uint(root, "Receiver Error Status Counter",
+ le64_to_cpu(pcie_stats->receiverErrStatusCount));
json_print_object(root, NULL);
printf("\n");
+
json_free_object(root);
}
@@ -5544,7 +7377,7 @@ static int wdc_do_vs_nand_stats(int fd, char *format)
int ret;
int fmt = -1;
uint8_t *output = NULL;
- struct wdc_nand_stats *nand_stats;
+ __u16 version = 0;
if ((output = (uint8_t*)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t))) == NULL) {
fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno));
@@ -5553,7 +7386,7 @@ static int wdc_do_vs_nand_stats(int fd, char *format)
}
ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_NAND_STATS_LOG_ID,
- false, WDC_NVME_NAND_STATS_SIZE, (void*)output);
+ false, NVME_NO_LOG_LSP, WDC_NVME_NAND_STATS_SIZE, (void*)output);
if (ret) {
fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__);
goto out;
@@ -5565,14 +7398,15 @@ static int wdc_do_vs_nand_stats(int fd, char *format)
goto out;
}
+ version = output[WDC_NVME_NAND_STATS_SIZE - 2];
+
/* parse the data */
- nand_stats = (struct wdc_nand_stats *)(output);
switch (fmt) {
case NORMAL:
- wdc_print_nand_stats_normal(nand_stats);
+ wdc_print_nand_stats_normal(version, output);
break;
case JSON:
- wdc_print_nand_stats_json(nand_stats);
+ wdc_print_nand_stats_json(version, output);
break;
}
}
@@ -5586,6 +7420,7 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command,
struct plugin *plugin)
{
const char *desc = "Retrieve NAND statistics.";
+
int fd;
int ret = 0;
__u64 capabilities = 0;
@@ -5621,6 +7456,97 @@ static int wdc_vs_nand_stats(int argc, char **argv, struct command *command,
return ret;
}
+static int wdc_do_vs_pcie_stats(int fd,
+ struct wdc_vs_pcie_stats *pcieStatsPtr)
+{
+ int ret;
+ struct nvme_admin_cmd admin_cmd;
+ int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats);
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ admin_cmd.opcode = WDC_NVME_PCIE_STATS_OPCODE;
+ admin_cmd.addr = (__u64)(uintptr_t)pcieStatsPtr;
+ admin_cmd.data_len = pcie_stats_size;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+
+ return ret;
+}
+
+static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve PCIE statistics.";
+
+ int fd;
+ int ret = 0;
+ __u64 capabilities = 0;
+ int fmt = -1;
+ struct wdc_vs_pcie_stats *pcieStatsPtr = NULL;
+ int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats);
+ bool huge;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ ret = fmt;
+ goto out;
+ }
+
+ pcieStatsPtr = nvme_alloc(pcie_stats_size, &huge);
+ if (pcieStatsPtr == NULL) {
+ fprintf(stderr, "ERROR : WDC : PCIE Stats alloc : %s\n", strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ memset((void *)pcieStatsPtr, 0, pcie_stats_size);
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_PCIE_STATS) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_do_vs_pcie_stats(fd, pcieStatsPtr);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading PCIE statistics, ret = 0x%x\n", ret);
+ else {
+ /* parse the data */
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_pcie_stats_normal(pcieStatsPtr);
+ break;
+ case JSON:
+ wdc_print_pcie_stats_json(pcieStatsPtr);
+ break;
+ }
+ }
+ }
+
+ nvme_free(pcieStatsPtr, huge);
+
+out:
+ return ret;
+}
+
static int wdc_vs_drive_info(int argc, char **argv,
struct command *command, struct plugin *plugin)
{
@@ -5630,8 +7556,24 @@ static int wdc_vs_drive_info(int argc, char **argv,
__le32 result;
__u16 size;
double rev;
+ struct nvme_id_ctrl ctrl;
+ char vsData[32] = {0};
+ char major_rev = 0, minor_rev = 0;
+ int fmt = -1;
+ struct json_object *root = NULL;
+ char formatter[41] = { 0 };
+ char rev_str[8] = { 0 };
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
OPT_END()
};
@@ -5639,25 +7581,558 @@ static int wdc_vs_drive_info(int argc, char **argv,
if (fd < 0)
return fd;
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC %s invalid output format\n", __func__);
+ return fmt;
+ }
+
+ /* get the id ctrl data used to fill in drive info below */
+ ret = nvme_identify_ctrl(fd, &ctrl);
+
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC %s: Identify Controller failed\n", __func__);
+ return ret;
+ }
+
wdc_check_device(fd);
capabilities = wdc_get_drive_capabilities(fd);
if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) {
ret = wdc_do_drive_info(fd, &result);
+
+ if (!ret) {
+ size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
+ rev = (double)(cpu_to_le32(result) & 0x0000ffff);
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revison: %4.1f\n", (.1 * rev));
+ printf("FTL Unit Size: 0x%x KB\n", size);
+ printf("Customer SN: %-.*s\n", (int)sizeof(ctrl.sn), &ctrl.sn[0]);
+ }
+ else if (fmt == JSON) {
+ root = json_create_object();
+ sprintf(rev_str, "%4.1f", (.1 * rev));
+ json_object_add_value_string(root, "Drive HW Revison", rev_str);
+
+ json_object_add_value_int(root, "FTL Unit Size", le16_to_cpu(size));
+ wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], sizeof(ctrl.sn));
+ json_object_add_value_string(root, "Customer SN", formatter);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+ }
+ }
+ else if ((capabilities & WDC_DRIVE_CAP_INFO_2) == WDC_DRIVE_CAP_INFO_2) {
+ memcpy(vsData, &ctrl.vs[0], 32);
+
+ major_rev = ctrl.sn[12];
+ minor_rev = ctrl.sn[13];
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revision: %c.%c \n", major_rev, minor_rev);
+ printf("Customer SN: %-.*s\n", 14, &ctrl.sn[0]);
+ }
+ else if (fmt == JSON) {
+ root = json_create_object();
+ sprintf(rev_str, "%c.%c", major_rev, minor_rev);
+ json_object_add_value_string(root, "Drive HW Revison", rev_str);
+ wdc_StrFormat(formatter, sizeof(formatter), &ctrl.sn[0], 14);
+ json_object_add_value_string(root, "Customer SN", formatter);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
} else {
fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
- ret = -1;
+ return -1;
}
- if (!ret) {
- size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
- rev = (double)(cpu_to_le32(result) & 0x0000ffff);
- printf("Drive HW Revison: %4.1f\n", (.1 * rev));
- printf("FTL Unit Size: 0x%x KB\n", size);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ return ret;
+}
+
+static int wdc_vs_temperature_stats(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a vs-temperature-stats command.";
+ struct nvme_smart_log smart_log;
+ struct nvme_id_ctrl id_ctrl;
+ uint64_t capabilities = 0;
+ __u32 hctm_tmt;
+ int fd, ret;
+ int temperature, temp_tmt1, temp_tmt2;
+ int fmt = -1;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ ret = fmt;
+ goto END;
}
+ /* check if command is supported */
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_TEMP_STATS) != WDC_DRIVE_CAP_TEMP_STATS) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ return -1;
+ }
+
+ /* get the temperature stats or report errors */
+ ret = nvme_identify_ctrl(fd, &id_ctrl);
+ if (ret != 0)
+ goto END;
+ ret = nvme_smart_log(fd, NVME_NSID_ALL, &smart_log);
+ if (ret != 0)
+ goto END;
+
+ /* convert from Kelvin to degrees Celsius */
+ 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);
+ temp_tmt1 = ((hctm_tmt >> 16) & 0xffff) ? ((hctm_tmt >> 16) & 0xffff) - 273 : 0;
+ temp_tmt2 = (hctm_tmt & 0xffff) ? (hctm_tmt & 0xffff) - 273 : 0;
+
+ if (fmt == NORMAL) {
+ /* print the temperature stats */
+ printf("Temperature Stats for NVME device:%s namespace-id:%x\n",
+ devicename, WDC_DE_GLOBAL_NSID);
+
+ printf("Current Composite Temperature : %d °C\n", temperature);
+ printf("WCTEMP : %"PRIu16" °C\n", id_ctrl.wctemp - 273);
+ printf("CCTEMP : %"PRIu16" °C\n", id_ctrl.cctemp - 273);
+ printf("DITT support : 0\n");
+ printf("HCTM support : %"PRIu16"\n", id_ctrl.hctma);
+
+ printf("HCTM Light (TMT1) : %"PRIu16" °C\n", temp_tmt1);
+ printf("TMT1 Transition Counter : %"PRIu32"\n", smart_log.thm_temp1_trans_count);
+ printf("TMT1 Total Time : %"PRIu32"\n", smart_log.thm_temp1_total_time);
+
+ printf("HCTM Heavy (TMT2) : %"PRIu16" °C\n", temp_tmt2);
+ printf("TMT2 Transition Counter : %"PRIu32"\n", smart_log.thm_temp2_trans_count);
+ printf("TMT2 Total Time : %"PRIu32"\n", smart_log.thm_temp2_total_time);
+ printf("Thermal Shutdown Threshold : 95 °C\n");
+ }
+ else if (fmt == JSON) {
+ struct json_object *root;
+ root = json_create_object();
+
+ json_object_add_value_int(root, "Current Composite Temperature", le32_to_cpu(temperature));
+ json_object_add_value_int(root, "WCTEMP", le16_to_cpu(id_ctrl.wctemp - 273));
+ json_object_add_value_int(root, "CCTEMP", le16_to_cpu(id_ctrl.cctemp - 273));
+ json_object_add_value_int(root, "DITT support", 0);
+ json_object_add_value_int(root, "HCTM support", le16_to_cpu(id_ctrl.hctma));
+
+ json_object_add_value_int(root, "HCTM Light (TMT1)", le16_to_cpu(temp_tmt1));
+ json_object_add_value_int(root, "TMT1 Transition Counter", le32_to_cpu(smart_log.thm_temp1_trans_count));
+ json_object_add_value_int(root, "TMT1 Total Time", le32_to_cpu(smart_log.thm_temp1_total_time));
+
+ json_object_add_value_int(root, "HCTM Light (TMT2)", le16_to_cpu(temp_tmt2));
+ json_object_add_value_int(root, "TMT2 Transition Counter", le32_to_cpu(smart_log.thm_temp2_trans_count));
+ json_object_add_value_int(root, "TMT2 Total Time", le32_to_cpu(smart_log.thm_temp2_total_time));
+ json_object_add_value_int(root, "Thermal Shutdown Threshold", 95);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+ else
+ printf("%s: Invalid format\n", __func__);
+
+END:
fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
return ret;
}
+static int wdc_capabilities(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a capabilities command.";
+ uint64_t capabilities = 0;
+ int fd;
+
+ OPT_ARGS(opts) =
+ {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ /* get capabilities */
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ /* print command and supported status */
+ printf("WDC Plugin Capabilities for NVME device:%s\n", devicename);
+ printf("cap-diag : %s\n",
+ capabilities & WDC_DRIVE_CAP_CAP_DIAG ? "Supported" : "Not Supported");
+ printf("drive-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_DRIVE_LOG ? "Supported" : "Not Supported");
+ printf("get-crash-dump : %s\n",
+ capabilities & WDC_DRIVE_CAP_CRASH_DUMP ? "Supported" : "Not Supported");
+ 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("vs-internal-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported");
+ printf("vs-nand-stats : %s\n",
+ capabilities & WDC_DRIVE_CAP_NAND_STATS ? "Supported" : "Not Supported");
+ printf("vs-smart-add-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK ? "Supported" : "Not Supported");
+ printf("--C0 Log Page : %s\n",
+ capabilities & WDC_DRIVE_CAP_C0_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("--C1 Log Page : %s\n",
+ capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("--CA Log Page : %s\n",
+ capabilities & WDC_DRIVE_CAP_CA_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("--D0 Log Page : %s\n",
+ capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("clear-pcie-correctable-errors : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK ? "Supported" : "Not Supported");
+ printf("drive-essentials : %s\n",
+ capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS ? "Supported" : "Not Supported");
+ printf("get-drive-status : %s\n",
+ capabilities & WDC_DRIVE_CAP_DRIVE_STATUS ? "Supported" : "Not Supported");
+ printf("clear-assert-dump : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT ? "Supported" : "Not Supported");
+ printf("drive-resize : %s\n",
+ capabilities & WDC_DRIVE_CAP_RESIZE ? "Supported" : "Not Supported");
+ printf("vs-fw-activate-history : %s\n",
+ capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK ? "Supported" : "Not Supported");
+ printf("clear-fw-activate-history : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK ? "Supported" : "Not Supported");
+ printf("vs-telemetry-controller-option: %s\n",
+ capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG ? "Supported" : "Not Supported");
+ printf("vs-error-reason-identifier : %s\n",
+ capabilities & WDC_DRIVE_CAP_REASON_ID ? "Supported" : "Not Supported");
+ printf("log-page-directory : %s\n",
+ capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR ? "Supported" : "Not Supported");
+ printf("namespace-resize : %s\n",
+ capabilities & WDC_DRIVE_CAP_NS_RESIZE ? "Supported" : "Not Supported");
+ printf("vs-drive-info : %s\n",
+ capabilities & (WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_INFO_2) ? "Supported" : "Not Supported");
+ printf("vs-temperature-stats : %s\n",
+ capabilities & WDC_DRIVE_CAP_TEMP_STATS ? "Supported" : "Not Supported");
+ printf("cloud-SSD-plugin-version : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION ? "Supported" : "Not Supported");
+ printf("vs-pcie-stats : %s\n",
+ capabilities & WDC_DRIVE_CAP_PCIE_STATS ? "Supported" : "Not Supported");
+ printf("capabilities : Supported\n");
+ return 0;
+}
+
+static int wdc_cloud_ssd_plugin_version(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Get Cloud SSD Plugin Version command.";
+ uint64_t capabilities = 0;
+ int fd;
+
+ OPT_ARGS(opts) =
+ {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ /* get capabilities */
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_CLOUD_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_SSD_VERSION) {
+ /* print command and supported status */
+ printf("WDC Cloud SSD Plugin Version: 1.0\n");
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ }
+
+ return 0;
+}
+
+static int wdc_enc_get_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Get Enclosure Log.";
+ char *file = "Output file pathname.";
+ char *size = "Data retrieval transfer size.";
+ char *log = "Enclosure Log Page ID.";
+ FILE *output_fd;
+ int xfer_size = 0;
+ int fd;
+ int len;
+ int err;
+
+ struct config {
+ char *file;
+ __u32 xfer_size;
+ __u32 log_id;
+ };
+
+ struct config cfg = {
+ .file = NULL,
+ .xfer_size = 0,
+ .log_id = 0xffffffff,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_UINT("transfer-size", 's', &cfg.xfer_size, size),
+ OPT_UINT("log-id", 'l', &cfg.log_id, log),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ goto ret;
+ }
+
+ if (!wdc_enc_check_model(fd)) {
+ err = -EINVAL;
+ goto closed_fd;
+ }
+
+ if (cfg.log_id > 0xff) {
+ fprintf(stderr, "Invalid log identifier: %d. Valid 0xd1, 0xd2, 0xd3, 0xd4, 0xe2, 0xe4\n", cfg.log_id);
+ goto closed_fd;
+ }
+
+ if (cfg.xfer_size != 0) {
+ xfer_size = cfg.xfer_size;
+ if (!wdc_check_power_of_2(cfg.xfer_size)) {
+ fprintf(stderr, "%s: ERROR : xfer-size (%d) must be a power of 2\n", __func__, cfg.xfer_size);
+ err = -EINVAL;
+ goto closed_fd;
+ }
+ }
+
+ /* Log IDs are only for specific enclosures */
+ if (cfg.log_id) {
+ xfer_size = (xfer_size) ? xfer_size : WDC_NVME_ENC_LOG_SIZE_CHUNK;
+ len = cfg.file==NULL?0:strlen(cfg.file);
+ if (len > 0) {
+ output_fd = fopen(cfg.file,"wb");
+ if (output_fd == 0) {
+ fprintf(stderr, "%s: ERROR : opening:%s : %s\n", __func__,cfg.file, strerror(errno));
+ err = -EINVAL;
+ goto closed_fd;
+ }
+ } else {
+ output_fd = stdout;
+ }
+ if (cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_1 || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_2
+ || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_3 || cfg.log_id == WDC_ENC_NIC_CRASH_DUMP_ID_SLOT_4) {
+ fprintf(stderr, "args - sz:%x logid:%x of:%s\n",xfer_size,cfg.log_id,cfg.file);
+ err = wdc_enc_get_nic_log(fd, cfg.log_id, xfer_size, WDC_NVME_ENC_NIC_LOG_SIZE, output_fd);
+ } else {
+ fprintf(stderr, "args - sz:%x logid:%x of:%s\n",xfer_size,cfg.log_id,cfg.file);
+ err = wdc_enc_submit_move_data(fd, NULL, 0, xfer_size, output_fd, cfg.log_id, 0, 0);
+ }
+
+ if (err == WDC_RESULT_NOT_AVAILABLE) {
+ fprintf(stderr, "No Log/Crashdump available\n");
+ err = 0;
+ } else if (err) {
+ fprintf(stderr, "ERROR:0x%x Failed to collect log-id:%x \n",err, cfg.log_id);
+ }
+ }
+closed_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int wdc_enc_submit_move_data(int fd, char *cmd, int len, int xfer_size, FILE *out, int log_id, int cdw14, int cdw15)
+{
+ struct timespec time;
+ uint32_t response_size, more;
+ int err;
+ int handle;
+ uint32_t offset = 0;
+ char *buf;
+
+ buf = (char *)malloc(sizeof(__u8) * xfer_size);
+ if (buf == NULL) {
+ fprintf(stderr, "%s: ERROR : malloc : %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ /* send something no matter what */
+ cmd = (len) ? cmd : buf;
+ len = (len) ? len : 0x20;
+
+ struct nvme_admin_cmd nvme_cmd = {
+ .opcode = WDC_NVME_ADMIN_ENC_MGMT_SND,
+ .nsid = 0,
+ .addr = (__u64)(uintptr_t) cmd,
+ .data_len = ((len + sizeof(uint32_t) - 1)/sizeof(uint32_t)) * sizeof(uint32_t),
+ .cdw10 = len,
+ .cdw12 = log_id,
+ .cdw13 = 0,
+ .cdw14 = cdw14,
+ .cdw15 = cdw15,
+ };
+
+ clock_gettime(CLOCK_REALTIME, &time);
+ srand(time.tv_nsec);
+ handle = random(); /* Handle to associate send request with receive request */
+ nvme_cmd.cdw11 = handle;
+
+#ifdef WDC_NVME_CLI_DEBUG
+ unsigned char *d = (unsigned char*) nvme_cmd.addr;
+ unsigned char *md = (unsigned char*) nvme_cmd.metadata;
+ printf("NVME_ADMIN_COMMAND:\n" \
+ "opcode: 0x%02x, flags: 0x%02x, rsvd: 0x%04x, nsid: 0x%08x, cdw2: 0x%08x, cdw3: 0x%08x, " \
+ "metadata_len: 0x%08x, data_len: 0x%08x, cdw10: 0x%08x, cdw11: 0x%08x, cdw12: 0x%08x, " \
+ "cdw13: 0x%08x, cdw14: 0x%08x, cdw15: 0x%08x, timeout_ms: 0x%08x, result: 0x%08x, " \
+ "metadata: %s, " \
+ "data: %s\n", \
+ nvme_cmd.opcode, nvme_cmd.flags, nvme_cmd.rsvd1, nvme_cmd.nsid, nvme_cmd.cdw2, nvme_cmd.cdw3, \
+ nvme_cmd.metadata_len, nvme_cmd.data_len, nvme_cmd.cdw10, nvme_cmd.cdw11, nvme_cmd.cdw12, \
+ nvme_cmd.cdw13, nvme_cmd.cdw14, nvme_cmd.cdw15, nvme_cmd.timeout_ms, nvme_cmd.result,
+ md, \
+ d);
+#endif
+ nvme_cmd.result = 0;
+ err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
+ if (err == NVME_SC_INTERNAL) {
+ fprintf(stderr, "%s: WARNING : WDC : No log ID:x%x available\n",
+ __func__, log_id);
+ }
+ else if (err != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Snd Mgmt Status:%s(x%x)\n",
+ __func__, nvme_status_to_string(err), err );
+ } else {
+ if (nvme_cmd.result == WDC_RESULT_NOT_AVAILABLE)
+ {
+ free(buf);
+ return WDC_RESULT_NOT_AVAILABLE;
+ }
+
+ do {
+ /* Sent request, now go retrieve response */
+ nvme_cmd.flags = 0;
+ nvme_cmd.opcode = WDC_NVME_ADMIN_ENC_MGMT_RCV;
+ nvme_cmd.addr = (__u64)(uintptr_t) buf;
+ nvme_cmd.data_len = xfer_size;
+ nvme_cmd.cdw10 = xfer_size / sizeof(uint32_t);
+ nvme_cmd.cdw11 = handle;
+ nvme_cmd.cdw12 = log_id;
+ nvme_cmd.cdw13 = offset / sizeof(uint32_t);
+ nvme_cmd.cdw14 = cdw14;
+ nvme_cmd.cdw15 = cdw15;
+ nvme_cmd.result = 0; /* returned result !=0 indicates more data available */
+ err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd);
+ if (err != 0) {
+ more = 0;
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt Status:%s(x%x)\n",
+ __func__, nvme_status_to_string(err), err);
+ } else {
+ more = nvme_cmd.result & WDC_RESULT_MORE_DATA;
+ response_size = nvme_cmd.result & ~WDC_RESULT_MORE_DATA;
+ fwrite(buf, response_size, 1, out);
+ offset += response_size;
+ if (more && (response_size & (sizeof(uint32_t)-1))) {
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Rcv Mgmt response size:x%x not LW aligned\n",
+ __func__, response_size);
+ }
+ }
+ } while (more);
+ free(buf);
+ }
+
+ return err;
+}
+
+static int wdc_enc_get_nic_log(int fd, __u8 log_id, __u32 xfer_size, __u32 data_len, FILE *out)
+{
+ __u8 *dump_data;
+ __u32 curr_data_offset, curr_data_len;
+ int i, ret;
+ struct nvme_admin_cmd admin_cmd;
+ __u32 dump_length = data_len;
+ __u32 numd;
+ __u16 numdu, numdl;
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * dump_length);
+ if (dump_data == NULL) {
+ fprintf(stderr, "%s: ERROR : malloc : %s\n",__func__, strerror(errno));
+ return -1;
+ }
+ memset(dump_data, 0, sizeof (__u8) * dump_length);
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ curr_data_offset = 0;
+ curr_data_len = xfer_size;
+ i = 0;
+
+ numd = (curr_data_len >> 2) - 1;
+ numdu = numd >> 16;
+ numdl = numd & 0xffff;
+ admin_cmd.opcode = nvme_admin_get_log_page;
+ admin_cmd.nsid = curr_data_offset;
+ admin_cmd.addr = (__u64)(uintptr_t) dump_data;
+ admin_cmd.data_len = curr_data_len;
+ admin_cmd.cdw10 = log_id | (numdl << 16);
+ admin_cmd.cdw11 = numdu;
+ while (curr_data_offset < data_len) {
+#ifdef WDC_NVME_CLI_DEBUG
+ fprintf(stderr, "nsid 0x%08x addr 0x%08llx, data_len 0x%08x, cdw10 0x%08x, cdw11 0x%08x, cdw12 0x%08x, cdw13 0x%08x, cdw14 0x%08x \n", admin_cmd.nsid, admin_cmd.addr, admin_cmd.data_len, admin_cmd.cdw10, admin_cmd.cdw11, admin_cmd.cdw12, admin_cmd.cdw13, admin_cmd.cdw14);
+#endif
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ if (ret !=0 ) {
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n",__func__, nvme_status_to_string(ret), ret);
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n",
+ __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr);
+ break;
+ }
+
+ if ((curr_data_offset + xfer_size) <= data_len)
+ curr_data_len = xfer_size;
+ else
+ curr_data_len = data_len - curr_data_offset; /* last transfer */
+
+ curr_data_offset += curr_data_len;
+ numd = (curr_data_len >> 2) - 1;
+ numdu = numd >> 16;
+ numdl = numd & 0xffff;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data + (__u64)curr_data_offset;
+ admin_cmd.nsid = curr_data_offset;
+ admin_cmd.data_len = curr_data_len;
+ admin_cmd.cdw10 = log_id | (numdl << 16);
+ admin_cmd.cdw11 = numdu;
+ i++;
+ }
+ fwrite(dump_data, data_len, 1, out);
+ free(dump_data);
+ return ret;
+}
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
index c6b2d3f..de6affa 100644
--- a/plugins/wdc/wdc-nvme.h
+++ b/plugins/wdc/wdc-nvme.h
@@ -25,11 +25,16 @@ PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"),
ENTRY("drive-resize", "WDC Drive Resize", wdc_drive_resize)
ENTRY("vs-fw-activate-history", "WDC Get FW Activate History", wdc_vs_fw_activate_history)
ENTRY("clear-fw-activate-history", "WDC Clear FW Activate History", wdc_clear_fw_activate_history)
+ ENTRY("enc-get-log", "WDC Get Enclosure Log", wdc_enc_get_log)
ENTRY("vs-telemetry-controller-option", "WDC Enable/Disable Controller Initiated Telemetry Log", wdc_vs_telemetry_controller_option)
ENTRY("vs-error-reason-identifier", "WDC Telemetry Reason Identifier", wdc_reason_identifier)
ENTRY("log-page-directory", "WDC Get Log Page Directory", wdc_log_page_directory)
ENTRY("namespace-resize", "WDC NamespaceDrive Resize", wdc_namespace_resize)
ENTRY("vs-drive-info", "WDC Get Drive Info", wdc_vs_drive_info)
+ ENTRY("vs-temperature-stats", "WDC Get Temperature Stats", wdc_vs_temperature_stats)
+ ENTRY("capabilities", "WDC Device Capabilities", wdc_capabilities)
+ ENTRY("cloud-SSD-plugin-version", "WDC Cloud SSD Plugin Version", wdc_cloud_ssd_plugin_version)
+ ENTRY("vs-pcie-stats", "WDC VS PCIE Statistics", wdc_vs_pcie_stats)
)
);
diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c
index 80d9955..2740181 100644
--- a/plugins/wdc/wdc-utils.c
+++ b/plugins/wdc/wdc-utils.c
@@ -144,3 +144,18 @@ int wdc_UtilsStrCompare(char *pcSrc, char *pcDst)
return *pcSrc - *pcDst;
}
+void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz)
+{
+
+ fmt_sz = snprintf(formatter,fmt_sz, "%-*.*s",
+ (int)tofmtsz, (int)tofmtsz, tofmt);
+ /* trim() the obnoxious trailing white lines */
+ while (fmt_sz) {
+ if (formatter[fmt_sz - 1] != ' ' && formatter[fmt_sz - 1] != '\0') {
+ formatter[fmt_sz] = '\0';
+ break;
+ }
+ fmt_sz--;
+ }
+}
+
diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h
index 251339f..04d4b83 100644
--- a/plugins/wdc/wdc-utils.h
+++ b/plugins/wdc/wdc-utils.h
@@ -74,4 +74,5 @@ int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo);
int wdc_UtilsStrCompare(char *pcSrc, char *pcDst);
int wdc_UtilsCreateDir(char *path);
int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen);
+void wdc_StrFormat(char *formatter, size_t fmt_sz, char *tofmt, size_t tofmtsz);
diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c
new file mode 100644
index 0000000..91e52be
--- /dev/null
+++ b/plugins/ymtc/ymtc-nvme.c
@@ -0,0 +1,148 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "ymtc-nvme.h"
+#include "ymtc-utils.h"
+
+static void get_ymtc_smart_info(struct nvme_ymtc_smart_log *smart, int index, u8 *nm_val, u8 *raw_val)
+{
+ memcpy(nm_val, smart->itemArr[index].nmVal, NM_SIZE);
+ memcpy(raw_val, smart->itemArr[index].rawVal, RAW_SIZE);
+}
+
+static int show_ymtc_smart_log(int fd, __u32 nsid, const char *devname,
+ struct nvme_ymtc_smart_log *smart)
+{
+ struct nvme_id_ctrl ctrl;
+ char fw_ver[10];
+ int err = 0;
+
+ u8 *nm = malloc(NM_SIZE * sizeof(u8));
+ u8 *raw = malloc(RAW_SIZE * sizeof(u8));
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ return err;
+
+ snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c",
+ ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3],
+ ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]);
+
+ /* Table Title */
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
+ /* Clumn Name*/
+ printf("key normalized raw\n");
+ /* 00 SI_VD_PROGRAM_FAIL */
+ get_ymtc_smart_info(smart, SI_VD_PROGRAM_FAIL, nm, raw);
+ printf("program_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 01 SI_VD_ERASE_FAIL */
+ get_ymtc_smart_info(smart, SI_VD_ERASE_FAIL, nm, raw);
+ printf("erase_fail_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 02 SI_VD_WEARLEVELING_COUNT */
+ get_ymtc_smart_info(smart, SI_VD_WEARLEVELING_COUNT, nm, raw);
+ printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n", *nm,
+ *raw, *(raw+2), *(raw+4));
+ /* 03 SI_VD_E2E_DECTECTION_COUNT */
+ get_ymtc_smart_info(smart, SI_VD_E2E_DECTECTION_COUNT, nm, raw);
+ printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 04 SI_VD_PCIE_CRC_ERR_COUNT */
+ get_ymtc_smart_info(smart, SI_VD_PCIE_CRC_ERR_COUNT, nm, raw);
+ printf("crc_error_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 08 SI_VD_THERMAL_THROTTLE_STATUS */
+ get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
+ printf("thermal_throttle_status : %3d%% %"PRIu64"%%, cnt: %"PRIu64"\n", *nm,
+ int48_to_long(raw), int48_to_long(raw+1));
+ /* 11 SI_VD_TOTAL_WRITE */
+ get_ymtc_smart_info(smart, SI_VD_TOTAL_WRITE, nm, raw);
+ printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 12 SI_VD_HOST_WRITE */
+ get_ymtc_smart_info(smart, SI_VD_HOST_WRITE, nm, raw);
+ printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 14 SI_VD_TOTAL_READ */
+ get_ymtc_smart_info(smart, SI_VD_TOTAL_READ, nm, raw);
+ printf("nand_bytes_read : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 15 SI_VD_TEMPT_SINCE_BORN */
+ get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BORN, nm, raw);
+ printf("tempt_since_born : %3d%% max: %u, min: %u, curr: %u\n", *nm,
+ *raw, *(raw+2), *(raw+4));
+ /* 16 SI_VD_POWER_CONSUMPTION */
+ get_ymtc_smart_info(smart, SI_VD_POWER_CONSUMPTION, nm, raw);
+ printf("power_consumption : %3d%% max: %u, min: %u, curr: %u\n", *nm,
+ *raw, *(raw+2), *(raw+4));
+ /* 17 SI_VD_TEMPT_SINCE_BOOTUP */
+ get_ymtc_smart_info(smart, SI_VD_TEMPT_SINCE_BOOTUP, nm, raw);
+ printf("tempt_since_bootup : %3d%% max: %u, min: %u, curr: %u\n", *nm, *raw,
+ *(raw+2), *(raw+4));
+ /* 18 SI_VD_POWER_LOSS_PROTECTION */
+ get_ymtc_smart_info(smart, SI_VD_POWER_LOSS_PROTECTION, nm, raw);
+ printf("power_loss_protection : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 19 SI_VD_READ_FAIL */
+ get_ymtc_smart_info(smart, SI_VD_READ_FAIL, nm, raw);
+ printf("read_fail : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 20 SI_VD_THERMAL_THROTTLE_TIME */
+ get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_TIME, nm, raw);
+ printf("thermal_throttle_time : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+ /* 21 SI_VD_FLASH_MEDIA_ERROR */
+ get_ymtc_smart_info(smart, SI_VD_FLASH_MEDIA_ERROR, nm, raw);
+ printf("flash_error_media_count : %3d%% %"PRIu64"\n", *nm, int48_to_long(raw));
+
+ free(nm);
+ free(raw);
+
+ return err;
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_ymtc_smart_log smart_log;
+ int err, fd;
+ char *desc = "Get Ymtc vendor specific additional smart log (optionally, "\
+ "for the specified namespace), and show it.";
+ const char *namespace = "(optional) desired namespace";
+ const char *raw = "dump output in binary format";
+ struct config {
+ __u32 namespace_id;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
+ NVME_NO_LOG_LSP, sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ err = show_ymtc_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+ return err;
+}
diff --git a/plugins/ymtc/ymtc-nvme.h b/plugins/ymtc/ymtc-nvme.h
new file mode 100644
index 0000000..739fd37
--- /dev/null
+++ b/plugins/ymtc/ymtc-nvme.h
@@ -0,0 +1,24 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/ymtc/ymtc-nvme
+
+#if !defined(YMTC_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define YMTC_NVME
+
+#include "cmd.h"
+#include "common.h"
+
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+PLUGIN(NAME("ymtc", "Ymtc vendor specific extensions"),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Ymtc SMART Log, show it", get_additional_smart_log)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
+
diff --git a/plugins/ymtc/ymtc-utils.h b/plugins/ymtc/ymtc-utils.h
new file mode 100644
index 0000000..700c764
--- /dev/null
+++ b/plugins/ymtc/ymtc-utils.h
@@ -0,0 +1,80 @@
+#ifndef __YMTC_UTILS_H__
+#define __YMTC_UTILS_H__
+
+#define SMART_INFO_SIZE 4096
+
+#define ID_SIZE 3
+#define NM_SIZE 2
+#define RAW_SIZE 7
+
+typedef unsigned char u8;
+
+/* Additional smart external ID */
+#define SI_VD_PROGRAM_FAIL_ID 0xAB
+#define SI_VD_ERASE_FAIL_ID 0xAC
+#define SI_VD_WEARLEVELING_COUNT_ID 0xAD
+#define SI_VD_E2E_DECTECTION_COUNT_ID 0xB8
+#define SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7
+#define SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2
+#define SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3
+#define SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4
+#define SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA
+#define SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0
+#define SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3
+#define SI_VD_TOTAL_WRITE_ID 0xF4
+#define SI_VD_HOST_WRITE_ID 0xF5
+#define SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6
+#define SI_VD_TOTAL_READ_ID 0xFA
+#define SI_VD_TEMPT_SINCE_BORN_ID 0xE7
+#define SI_VD_POWER_CONSUMPTION_ID 0xE8
+#define SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF
+#define SI_VD_POWER_LOSS_PROTECTION_ID 0xEC
+#define SI_VD_READ_FAIL_ID 0xF2
+#define SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
+#define SI_VD_FLASH_MEDIA_ERROR_ID 0xED
+
+/* Addtional smart internal ID */
+typedef enum
+{
+ /* smart attr following intel */
+ SI_VD_PROGRAM_FAIL = 0, /* 0xAB */
+ SI_VD_ERASE_FAIL = 1, /* 0xAC */
+ SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */
+ SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */
+ SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */
+ SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */
+ SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */
+ SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */
+ SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */
+
+ /* smart attr self defined */
+ SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */
+ SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */
+ SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */
+ SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */
+ SI_VD_READ_FAIL = 19, /* 0xF2 */
+ SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */
+ SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */
+ NR_SMART_ITEMS,
+} si_vendor_smart_item_e;
+
+// Intel Format
+struct nvme_ymtc_smart_log_item
+{
+ /* Item identifier */
+ u8 id[ID_SIZE];
+ /* Normalized value or percentage. In the range from 0 to 100. */
+ u8 nmVal[NM_SIZE];
+ /* raw value */
+ u8 rawVal[RAW_SIZE];
+};
+
+struct nvme_ymtc_smart_log
+{
+ struct nvme_ymtc_smart_log_item itemArr[NR_SMART_ITEMS];
+
+ u8 resv[SMART_INFO_SIZE - sizeof(struct nvme_ymtc_smart_log_item) * NR_SMART_ITEMS];
+};
+
+#endif // __YMTC_UTILS_H__
+
diff --git a/plugins/zns/zns.c b/plugins/zns/zns.c
new file mode 100644
index 0000000..7f6f52e
--- /dev/null
+++ b/plugins/zns/zns.c
@@ -0,0 +1,923 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "nvme.h"
+#include "nvme-ioctl.h"
+#include "nvme-print.h"
+#include "nvme-status.h"
+
+#define CREATE_CMD
+#include "zns.h"
+
+static const char *namespace_id = "Namespace identifier to use";
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an ZNS specific Identify Controller command to "\
+ "the given device and report information about the specified "\
+ "controller in various formats.";
+
+ enum nvme_print_flags flags;
+ struct nvme_zns_id_ctrl ctrl;
+ int fd, err = -1;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_zns_identify_ctrl(fd, &ctrl);
+ if (!err)
+ nvme_show_zns_id_ctrl(&ctrl, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns identify controller");
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an ZNS specific Identify Namespace command to "\
+ "the given device and report information about the specified "\
+ "namespace in varios formats.";
+ const char *vendor_specific = "dump binary vendor fields";
+ const char *human_readable = "show identify in readable format";
+
+ enum nvme_print_flags flags;
+ struct nvme_zns_id_ns ns;
+ struct nvme_id_ns id_ns;
+ int fd, err = -1;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ int human_readable;
+ int vendor_specific;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.vendor_specific)
+ flags |= VS;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ err = nvme_identify_ns(fd, cfg.namespace_id, false, &id_ns);
+ if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ err = nvme_zns_identify_ns(fd, cfg.namespace_id, &ns);
+ if (!err)
+ nvme_show_zns_id_ns(&ns, &id_ns, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns identify namespace");
+close_fd:
+ 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)
+{
+ int err;
+
+ err = nvme_zns_mgmt_send(fd, namespace_id, zslba, select_all, zsa,
+ data_len, buf);
+ close(fd);
+ return err;
+}
+
+static int zns_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin,
+ const char *desc, enum nvme_zns_send_action zsa)
+{
+ const char *zslba = "starting LBA of the zone for this command";
+ const char *select_all = "send command to all zones";
+
+ int err, fd;
+ char *command;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ bool select_all;
+ };
+
+ 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_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ err = asprintf(&command, "%s-%s", plugin->name, cmd->name);
+ if (err < 0)
+ goto close_fd;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto free;
+ }
+ }
+
+ err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba,
+ cfg.select_all, 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,
+ cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror(desc);
+free:
+ free(command);
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_zdes_bytes(int fd, __u32 nsid)
+{
+ struct nvme_zns_id_ns ns;
+ struct nvme_id_ns id_ns;
+ __u8 lbaf;
+ int err;
+
+ err = nvme_identify_ns(fd, nsid, false, &id_ns);
+ if (err > 0){
+ nvme_show_status(err);
+ return err;
+ }
+ else if (err < 0){
+ perror("identify namespace");
+ return err;
+ }
+
+ err = nvme_zns_identify_ns(fd, nsid, &ns);
+ if (err > 0){
+ nvme_show_status(err);
+ return err;
+ }
+ else if (err < 0){
+ perror("zns identify namespace");
+ return err;
+ }
+
+ lbaf = id_ns.flbas & NVME_NS_FLBAS_LBA_MASK;
+ return ns.lbafe[lbaf].zdes << 6;
+}
+
+static int zone_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Zone Management Send";
+ const char *zslba = "starting LBA of the zone for this command";
+ const char *select_all = "send command to all zones";
+ const char *zsa = "zone send action";
+ const char *data_len = "buffer length if data required";
+ const char *data = "optional file for data (default stdin)";
+
+ int fd, ffd = STDIN_FILENO, err = -1;
+ void *buf = NULL;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ bool select_all;
+ __u8 zsa;
+ int data_len;
+ char *file;
+ };
+
+ 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_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ if (!cfg.zsa) {
+ fprintf(stderr, "zone send action must be specified\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ 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) {
+ fprintf(stderr,
+ "Zone Descriptor Extensions are not supported\n");
+ goto close_fd;
+ } else if (cfg.data_len < 0) {
+ err = cfg.data_len;
+ goto close_fd;
+ }
+ }
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ goto close_fd;
+ }
+ memset(buf, 0, cfg.data_len);
+
+ if (cfg.file) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd < 0) {
+ perror(cfg.file);
+ goto free;
+ }
+ }
+
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ perror("read");
+ goto close_ffd;
+ }
+ } else {
+ if (cfg.file || cfg.data_len) {
+ fprintf(stderr,
+ "data, data_len only valid with set extended descriptor\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ }
+
+ err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, cfg.select_all,
+ cfg.zsa, cfg.data_len, buf);
+ if (!err)
+ printf("zone-mgmt-send: Success, action:%d zone:%"PRIx64" "
+ "all:%d nsid:%d\n",
+ cfg.zsa, (uint64_t)cfg.zslba, (int)cfg.select_all,
+ cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns zone-mgmt-send");
+
+close_ffd:
+ if (cfg.file)
+ close(ffd);
+free:
+ free(buf);
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int close_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Close zones\n";
+
+ return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_CLOSE);
+}
+
+static int finish_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Finish zones\n";
+
+ return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_FINISH);
+}
+
+static int open_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Open zones\n";
+
+ return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OPEN);
+}
+
+static int reset_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Reset zones\n";
+
+ return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_RESET);
+}
+
+static int offline_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Offline zones\n";
+
+ return zns_mgmt_send(argc, argv, cmd, plugin, desc, NVME_ZNS_ZSA_OFFLINE);
+}
+
+static int set_zone_desc(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ 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)";
+
+ int fd, ffd = STDIN_FILENO, err;
+ void *buf = NULL;
+ __u32 data_len;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ char *file;
+ };
+
+ 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_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ data_len = get_zdes_bytes(fd, cfg.namespace_id);
+
+ if (!data_len) {
+ fprintf(stderr,
+ "zone format does not provide descriptor extention\n");
+ errno = EINVAL;
+ err = -1;
+ goto close_fd;
+ }
+
+ buf = calloc(1, data_len);
+ if (!buf) {
+ perror("could not alloc memory for zone desc");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ if (cfg.file) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd < 0) {
+ perror(cfg.file);
+ err = -1;
+ goto free;
+ }
+ }
+
+ err = read(ffd, (void *)buf, data_len);
+ if (err < 0) {
+ perror("read");
+ goto close_ffd;
+ }
+
+ err = __zns_mgmt_send(fd, cfg.namespace_id, cfg.zslba, 0,
+ NVME_ZNS_ZSA_SET_DESC_EXT, data_len, buf);
+ if (!err)
+ printf("set-zone-desc: Success, zone:%"PRIx64" nsid:%d\n",
+ (uint64_t)cfg.zslba, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns set-zone-desc");
+close_ffd:
+ if (cfg.file)
+ close(ffd);
+free:
+ free(buf);
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int zone_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Zone Management Receive";
+ const char *zslba = "starting LBA of the zone";
+ const char *zra = "Zone Receive Action";
+ const char *zrasf = "Zone Receive Action Specific Field(Reporting Options)";
+ const char *partial = "Zone Receive Action Specific Features(Partial Report)";
+ const char *data_len = "length of data in bytes";
+
+ enum nvme_print_flags flags;
+ int fd, err = -1;
+ void *data = NULL;
+
+ struct config {
+ char *output_format;
+ __u64 zslba;
+ __u32 namespace_id;
+ __u8 zra;
+ __u8 zrasf;
+ bool partial;
+ __u32 data_len;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
+ OPT_BYTE("zra", 'z', &cfg.zra, zra),
+ OPT_BYTE("zrasf", 'S', &cfg.zrasf, zrasf),
+ OPT_FLAG("partial", 'p', &cfg.partial, partial),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ if (cfg.zra == NVME_ZNS_ZRA_REPORT_ZONES && !cfg.data_len) {
+ fprintf(stderr, "error: data len is needed for NVME_ZRA_ZONE_REPORT\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.data_len) {
+ data = calloc(1, cfg.data_len);
+ if (!data) {
+ perror("could not alloc memory for zone mgmt receive data");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_zns_mgmt_recv(fd, cfg.namespace_id, cfg.zslba, cfg.zra,
+ cfg.zrasf, cfg.partial, cfg.data_len, data);
+ if (!err)
+ printf("zone-mgmt-recv: Success, action:%d zone:%"PRIx64" nsid:%d\n",
+ cfg.zra, (uint64_t)cfg.zslba, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns zone-mgmt-recv");
+
+ free(data);
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int report_zones(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve the Report Zones data structure";
+ const char *zslba = "starting LBA of the zone";
+ const char *num_descs = "number of descriptors to retrieve (default: all of them)";
+ const char *state = "state of zones to list";
+ const char *ext = "set to use the extended report zones";
+ const char *part = "set to use the partial report";
+ const char *human_readable = "show report zones in readable format";
+
+ enum nvme_print_flags flags;
+ int fd, zdes = 0, err = -1;
+ __u32 report_size;
+ void *report;
+ bool huge = false;
+
+ struct config {
+ char *output_format;
+ __u64 zslba;
+ __u32 namespace_id;
+ int num_descs;
+ int state;
+ int human_readable;
+ bool extended;
+ bool partial;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .num_descs = -1,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
+ OPT_UINT("descs", 'd', &cfg.num_descs, num_descs),
+ OPT_UINT("state", 'S', &cfg.state, state),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_FLAG("extended", 'e', &cfg.extended, ext),
+ OPT_FLAG("partial", 'p', &cfg.partial, part),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ if (cfg.extended) {
+ zdes = get_zdes_bytes(fd, cfg.namespace_id);
+ if (zdes < 0) {
+ err = zdes;
+ goto close_fd;
+ }
+ }
+
+ if (cfg.num_descs == -1) {
+ struct nvme_zone_report r;
+
+ err = nvme_zns_report_zones(fd, cfg.namespace_id, 0,
+ 0, cfg.state, 0, sizeof(r), &r);
+ if (err > 0) {
+ nvme_show_status(err);
+ goto close_fd;
+ } else if (err < 0) {
+ perror("zns report-zones");
+ goto close_fd;
+ }
+ cfg.num_descs = le64_to_cpu(r.nr_zones);
+ }
+
+ report_size = sizeof(struct nvme_zone_report) + cfg.num_descs *
+ (sizeof(struct nvme_zns_desc) + cfg.num_descs * zdes);
+
+ report = nvme_alloc(report_size, &huge);
+ if (!report) {
+ perror("alloc");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_zns_report_zones(fd, cfg.namespace_id, cfg.zslba,
+ cfg.extended, cfg.state, cfg.partial, report_size, report);
+ if (!err)
+ nvme_show_zns_report_zones(report, cfg.num_descs, zdes,
+ report_size, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns report-zones");
+
+ nvme_free(report, huge);
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int zone_append(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The zone append command is used to write to a zone "\
+ "using the slba of the zone, and the write will be appended from the "\
+ "write pointer of the zone";
+ const char *zslba = "starting LBA of the zone";
+ const char *data = "file containing data to write";
+ const char *metadata = "file with metadata to be written";
+ const char *limited_retry = "limit media access attempts";
+ const char *fua = "force unit access";
+ const char *prinfo = "protection information action and checks field";
+ const char *piremap = "protection information remap (for type 1 PI)";
+ const char *ref_tag = "reference tag (for end to end PI)";
+ const char *lbat = "logical block application tag (for end to end PI)";
+ const char *lbatm = "logical block application tag mask (for end to end PI)";
+ const char *metadata_size = "size of metadata in bytes";
+ const char *data_size = "size of data in bytes";
+ const char *latency = "output latency statistics";
+
+ int err = -1, fd, dfd = STDIN_FILENO, mfd = STDIN_FILENO;
+ unsigned int lba_size, meta_size;
+ void *buf = NULL, *mbuf = NULL;
+ __u16 nblocks, control = 0;
+ __u64 result;
+ struct timeval start_time, end_time;
+
+ struct nvme_id_ns ns;
+
+ struct config {
+ char *data;
+ char *metadata;
+ __u64 zslba;
+ __u64 data_size;
+ __u64 metadata_size;
+ int limited_retry;
+ int fua;
+ __u32 namespace_id;
+ __u32 ref_tag;
+ __u16 lbat;
+ __u16 lbatm;
+ __u8 prinfo;
+ int piremap;
+ int latency;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("zslba", 's', &cfg.zslba, zslba),
+ OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size),
+ OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size),
+ OPT_FILE("data", 'd', &cfg.data, data),
+ OPT_FILE("metadata", 'M', &cfg.metadata, metadata),
+ OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
+ OPT_FLAG("force-unit-access", 'f', &cfg.fua, fua),
+ OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.lbatm, lbatm),
+ OPT_SHRT("app-tag", 'a', &cfg.lbat, lbat),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_FLAG("piremap", 'P', &cfg.piremap, piremap),
+ OPT_FLAG("latency", 't', &cfg.latency, latency),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ if (!cfg.data_size) {
+ fprintf(stderr, "Append size not provided\n");
+ errno = EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ err = nvme_identify_ns(fd, cfg.namespace_id, false, &ns);
+ if (err) {
+ nvme_show_status(err);
+ goto close_fd;
+ }
+
+ lba_size = 1 << ns.lbaf[(ns.flbas & 0x0f)].ds;
+ if (cfg.data_size & (lba_size - 1)) {
+ fprintf(stderr,
+ "Data size:%#"PRIx64" not aligned to lba size:%#x\n",
+ (uint64_t)cfg.data_size, lba_size);
+ errno = EINVAL;
+ goto close_ns;
+ }
+
+ meta_size = ns.lbaf[(ns.flbas & 0x0f)].ms;
+ if (meta_size && !(meta_size == 8 && (cfg.prinfo & 0x8)) &&
+ (!cfg.metadata_size || cfg.metadata_size % meta_size)) {
+ fprintf(stderr,
+ "Metadata size:%#"PRIx64" not aligned to metadata size:%#x\n",
+ (uint64_t)cfg.metadata_size, meta_size);
+ errno = EINVAL;
+ goto close_ns;
+ }
+
+ if (cfg.prinfo > 0xf) {
+ fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
+ errno = EINVAL;
+ goto close_ns;
+ }
+
+ if (cfg.data) {
+ dfd = open(cfg.data, O_RDONLY);
+ if (dfd < 0) {
+ perror(cfg.data);
+ goto close_ns;
+ }
+ }
+
+ if (posix_memalign(&buf, getpagesize(), cfg.data_size)) {
+ fprintf(stderr, "No memory for data size:%"PRIx64"\n",
+ (uint64_t)cfg.data_size);
+ goto close_dfd;
+ }
+
+ memset(buf, 0, cfg.data_size);
+ err = read(dfd, buf, cfg.data_size);
+ if (err < 0) {
+ perror("read-data");
+ goto free_data;
+ }
+
+ if (cfg.metadata) {
+ mfd = open(cfg.metadata, O_RDONLY);
+ if (mfd < 0) {
+ perror(cfg.metadata);
+ err = -1;
+ goto close_dfd;
+ }
+ }
+
+ if (cfg.metadata_size) {
+ if (posix_memalign(&mbuf, getpagesize(), meta_size)) {
+ fprintf(stderr, "No memory for metadata size:%d\n",
+ meta_size);
+ err = -1;
+ goto close_mfd;
+ }
+
+ memset(mbuf, 0, cfg.metadata_size);
+ err = read(mfd, mbuf, cfg.metadata_size);
+ if (err < 0) {
+ perror("read-metadata");
+ goto free_meta;
+ }
+ }
+
+ nblocks = (cfg.data_size / lba_size) - 1;
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_RW_LR;
+ if (cfg.fua)
+ control |= NVME_RW_FUA;
+ if (cfg.piremap)
+ control |= NVME_RW_PIREMAP;
+
+ gettimeofday(&start_time, NULL);
+ err = nvme_zns_append(fd, cfg.namespace_id, cfg.zslba, nblocks,
+ control, cfg.ref_tag, cfg.lbat, cfg.lbatm,
+ cfg.data_size, buf, cfg.metadata_size, mbuf,
+ &result);
+ gettimeofday(&end_time, NULL);
+ if (cfg.latency)
+ printf(" latency: zone append: %llu us\n",
+ elapsed_utime(start_time, end_time));
+
+ if (!err)
+ printf("Success appended data to LBA %"PRIx64"\n", (uint64_t)result);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns zone-append");
+
+free_meta:
+ free(mbuf);
+close_mfd:
+ if (cfg.metadata)
+ close(mfd);
+free_data:
+ free(buf);
+close_dfd:
+ if (cfg.data)
+ close(dfd);
+close_ns:
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
+
+static int changed_zone_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Changed Zone log for the given device";
+ const char *rae = "retain an asynchronous event";
+
+ struct nvme_zns_changed_zone_log log;
+ enum nvme_print_flags flags;
+ int fd, err = -1;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ bool rae;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return errno;
+
+ flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(fd);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_fd;
+ }
+ }
+
+ err = nvme_get_log(fd, cfg.namespace_id, NVME_LOG_ZONE_CHANGED_LIST,
+ cfg.rae, NVME_NO_LOG_LSP, sizeof(log), &log);
+ if (!err)
+ nvme_show_zns_changed(&log, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns changed-zone-list");
+
+close_fd:
+ close(fd);
+ return nvme_status_to_errno(err, false);
+}
diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h
new file mode 100644
index 0000000..a92de69
--- /dev/null
+++ b/plugins/zns/zns.h
@@ -0,0 +1,30 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/zns/zns
+
+#if !defined(ZNS_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define ZNS_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("zns", "Zoned Namespace Command Set"),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Retrieve ZNS controller identification", id_ctrl)
+ ENTRY("id-ns", "Retrieve ZNS namespace identification", id_ns)
+ ENTRY("zone-mgmt-recv", "Sends the zone management receive command", zone_mgmt_recv)
+ ENTRY("zone-mgmt-send", "Sends the zone management send command", zone_mgmt_send)
+ ENTRY("report-zones", "Retrieve the Report Zones report", report_zones)
+ ENTRY("close-zone", "Closes one or more zones", close_zone)
+ ENTRY("finish-zone", "Finishes one or more zones", finish_zone)
+ ENTRY("open-zone", "Opens one or more zones", open_zone)
+ ENTRY("reset-zone", "Resets one or more zones", reset_zone)
+ ENTRY("offline-zone", "Offlines one or more zones", offline_zone)
+ ENTRY("set-zone-desc", "Attaches zone descriptor extension data", set_zone_desc)
+ ENTRY("zone-append", "Writes data and metadata (if applicable), appended to the end of the requested zone", zone_append)
+ ENTRY("changed-zone-list", "Retrieves the changed zone list log", changed_zone_list)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
+
diff --git a/scripts/gen-hostnqn.sh b/scripts/gen-hostnqn.sh
index d8783cf..5138f0c 100644
--- a/scripts/gen-hostnqn.sh
+++ b/scripts/gen-hostnqn.sh
@@ -2,7 +2,11 @@
LC_ALL=C
-UUID=$(dmidecode -s system-uuid | tr -d '[:space:]')
+if [ -e "/proc/device-tree/ibm,partition-uuid" ] ; then
+ UUID=$(tr -d '\0' < /proc/device-tree/ibm,partition-uuid)
+else
+ UUID=$(dmidecode -s system-uuid | tr -d '[:space:]')
+fi
if [ -z "$UUID" ] ; then
>&2 echo "No UUID found, can't determine hostnqn."
diff --git a/tests/nvme_get_features_test.py b/tests/nvme_get_features_test.py
index 94ed865..2e407ef 100644
--- a/tests/nvme_get_features_test.py
+++ b/tests/nvme_get_features_test.py
@@ -54,7 +54,8 @@ class TestNVMeGetMandatoryFeatures(TestNVMe):
self.setup_log_dir(self.__class__.__name__)
self.feature_id_list = ["0x01", "0x02", "0x04", "0x05", "0x07",
"0x08", "0x09", "0x0A", "0x0B"]
- get_vector_list_cmd = "cat /proc/interrupts | grep nvme |" \
+ device = self.ctrl.split('/')[-1]
+ get_vector_list_cmd = "grep " + device + "q /proc/interrupts |" \
" cut -d : -f 1 | tr -d ' ' | tr '\n' ' '"
proc = subprocess.Popen(get_vector_list_cmd,
shell=True,
@@ -80,7 +81,7 @@ class TestNVMeGetMandatoryFeatures(TestNVMe):
for vector in range(self.vector_list_len):
get_feat_cmd = "nvme get-feature " + self.ctrl + \
" --feature-id=" + str(feature_id) + \
- " --cdw11=" + str(vector)
+ " --cdw11=" + str(vector) + " -H"
proc = subprocess.Popen(get_feat_cmd,
shell=True,
stdout=subprocess.PIPE,
@@ -90,7 +91,7 @@ class TestNVMeGetMandatoryFeatures(TestNVMe):
assert_equal(proc.wait(), 0)
else:
get_feat_cmd = "nvme get-feature " + self.ctrl + \
- " --feature-id=" + str(feature_id)
+ " --feature-id=" + str(feature_id) + " -H"
proc = subprocess.Popen(get_feat_cmd,
shell=True,
stdout=subprocess.PIPE,
diff --git a/util/argconfig.c b/util/argconfig.c
index f647448..341a049 100644
--- a/util/argconfig.c
+++ b/util/argconfig.c
@@ -31,13 +31,14 @@
#include "argconfig.h"
#include "suffix.h"
-#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
#include <getopt.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
#include <stdarg.h>
-#include <inttypes.h>
+#include <string.h>
static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL };
@@ -450,10 +451,11 @@ int argconfig_parse_subopt_string(char *string, char **options,
return 0;
}
-unsigned argconfig_parse_comma_sep_array(char *string, int *val,
+int argconfig_parse_comma_sep_array(char *string, int *val,
unsigned max_length)
{
- unsigned ret = 0;
+ int ret = 0;
+ unsigned long v;
char *tmp;
char *p;
@@ -464,9 +466,14 @@ unsigned argconfig_parse_comma_sep_array(char *string, int *val,
if (!tmp)
return 0;
- val[ret] = strtol(tmp, &p, 0);
+ v = strtoul(tmp, &p, 0);
if (*p != 0)
return -1;
+ if (v > UINT_MAX) {
+ fprintf(stderr, "%s out of range\n", tmp);
+ return -1;
+ }
+ val[ret] = v;
ret++;
while (1) {
@@ -478,19 +485,23 @@ unsigned argconfig_parse_comma_sep_array(char *string, int *val,
if (ret >= max_length)
return -1;
- val[ret] = strtol(tmp, &p, 0);
-
+ v = strtoul(tmp, &p, 0);
if (*p != 0)
return -1;
+ if (v > UINT_MAX) {
+ fprintf(stderr, "%s out of range\n", tmp);
+ return -1;
+ }
+ val[ret] = v;
ret++;
}
}
-unsigned argconfig_parse_comma_sep_array_long(char *string,
+int argconfig_parse_comma_sep_array_long(char *string,
unsigned long long *val,
unsigned max_length)
{
- unsigned ret = 0;
+ int ret = 0;
char *tmp;
char *p;
diff --git a/util/argconfig.h b/util/argconfig.h
index 623b832..3147277 100644
--- a/util/argconfig.h
+++ b/util/argconfig.h
@@ -119,9 +119,9 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc,
const struct argconfig_commandline_options *options);
int argconfig_parse_subopt_string(char *string, char **options,
size_t max_options);
-unsigned argconfig_parse_comma_sep_array(char *string, int *ret,
+int argconfig_parse_comma_sep_array(char *string, int *ret,
unsigned max_length);
-unsigned argconfig_parse_comma_sep_array_long(char *string,
+int argconfig_parse_comma_sep_array_long(char *string,
unsigned long long *ret,
unsigned max_length);
void argconfig_register_help_func(argconfig_help_func * f);
diff --git a/util/cleanup.c b/util/cleanup.c
new file mode 100644
index 0000000..0d5d910
--- /dev/null
+++ b/util/cleanup.c
@@ -0,0 +1,4 @@
+#include <stdlib.h>
+#include "cleanup.h"
+
+DEFINE_CLEANUP_FUNC(cleanup_charp, char *, free);
diff --git a/util/cleanup.h b/util/cleanup.h
new file mode 100644
index 0000000..89a4984
--- /dev/null
+++ b/util/cleanup.h
@@ -0,0 +1,18 @@
+#ifndef __CLEANUP_H
+#define __CLEANUP_H
+
+#define __cleanup__(fn) __attribute__((cleanup(fn)))
+
+#define DECLARE_CLEANUP_FUNC(name, type) \
+ void name(type *__p)
+
+#define DEFINE_CLEANUP_FUNC(name, type, free_fn)\
+DECLARE_CLEANUP_FUNC(name, type) \
+{ \
+ if (*__p) \
+ free_fn(*__p); \
+}
+
+DECLARE_CLEANUP_FUNC(cleanup_charp, char *);
+
+#endif
diff --git a/util/json.c b/util/json.c
index 2978410..df0aefb 100644
--- a/util/json.c
+++ b/util/json.c
@@ -19,9 +19,9 @@ struct json_object *json_create_object(void)
return test;
}
-struct json_array *json_create_array(void)
+struct json_object *json_create_array(void)
{
- void *test = calloc(1, sizeof(struct json_array));
+ void *test = calloc(1, sizeof(struct json_object));
if (!test)
fail_and_notify();
return test;
@@ -146,7 +146,7 @@ static struct json_value *json_create_value_object(struct json_object *obj)
return value;
}
-static struct json_value *json_create_value_array(struct json_array *array)
+static struct json_value *json_create_value_array(struct json_object *array)
{
struct json_value *value = malloc(sizeof(struct json_value));
@@ -173,7 +173,7 @@ void json_free_object(struct json_object *obj)
free(obj);
}
-void json_free_array(struct json_array *array)
+void json_free_array(struct json_object *array)
{
int i;
@@ -206,7 +206,7 @@ static void json_free_value(struct json_value *value)
free(value);
}
-static int json_array_add_value(struct json_array *array, struct json_value *value)
+static int json_array_add_value(struct json_object *array, struct json_value *value)
{
struct json_value **values = realloc(array->values,
sizeof(struct json_value *) * (array->value_cnt + 1));
@@ -255,7 +255,7 @@ int json_object_add_value_type(struct json_object *obj, const char *name, int ty
else if (type == JSON_TYPE_OBJECT)
value = json_create_value_object(va_arg(args, struct json_object *));
else
- value = json_create_value_array(va_arg(args, struct json_array *));
+ value = json_create_value_array(va_arg(args, struct json_object *));
va_end(args);
if (!value)
@@ -274,8 +274,8 @@ int json_object_add_value_type(struct json_object *obj, const char *name, int ty
return 0;
}
-static void json_print_array(struct json_array *array, void *);
-int json_array_add_value_type(struct json_array *array, int type, ...)
+static void json_print_array(struct json_object *array, void *);
+int json_array_add_value_type(struct json_object *array, int type, ...)
{
struct json_value *value;
va_list args;
@@ -293,7 +293,7 @@ int json_array_add_value_type(struct json_array *array, int type, ...)
else if (type == JSON_TYPE_OBJECT)
value = json_create_value_object(va_arg(args, struct json_object *));
else
- value = json_create_value_array(va_arg(args, struct json_array *));
+ value = json_create_value_array(va_arg(args, struct json_object *));
va_end(args);
if (!value)
@@ -309,7 +309,7 @@ int json_array_add_value_type(struct json_array *array, int type, ...)
static int json_value_level(struct json_value *value);
static int json_pair_level(struct json_pair *pair);
-static int json_array_level(struct json_array *array);
+static int json_array_level(struct json_object *array);
static int json_object_level(struct json_object *object)
{
if (object->parent == NULL)
@@ -322,7 +322,7 @@ static int json_pair_level(struct json_pair *pair)
return json_object_level(pair->parent) + 1;
}
-static int json_array_level(struct json_array *array)
+static int json_array_level(struct json_object *array)
{
return json_value_level(array->parent);
}
@@ -342,7 +342,7 @@ static void json_print_level(int level, void *out)
}
static void json_print_pair(struct json_pair *pair, void *);
-static void json_print_array(struct json_array *array, void *);
+static void json_print_array(struct json_object *array, void *);
static void json_print_value(struct json_value *value, void *);
void json_print_object(struct json_object *obj, void *out)
{
@@ -366,7 +366,7 @@ static void json_print_pair(struct json_pair *pair, void *out)
json_print_value(pair->value, out);
}
-static void json_print_array(struct json_array *array, void *out)
+static void json_print_array(struct json_object *array, void *out)
{
int i;
diff --git a/util/json.h b/util/json.h
index d78d3db..666c78d 100644
--- a/util/json.h
+++ b/util/json.h
@@ -2,7 +2,6 @@
#define __JSON__H
struct json_object;
-struct json_array;
struct json_pair;
#define JSON_TYPE_STRING 0
@@ -21,22 +20,18 @@ struct json_value {
long double float_number;
char *string;
struct json_object *object;
- struct json_array *array;
+ struct json_object *array;
};
int parent_type;
union {
struct json_pair *parent_pair;
- struct json_array *parent_array;
+ struct json_object *parent_array;
};
};
-struct json_array {
+struct json_object {
struct json_value **values;
int value_cnt;
- struct json_value *parent;
-};
-
-struct json_object {
struct json_pair **pairs;
int pair_cnt;
struct json_value *parent;
@@ -49,10 +44,10 @@ struct json_pair {
};
struct json_object *json_create_object(void);
-struct json_array *json_create_array(void);
+struct json_object *json_create_array(void);
void json_free_object(struct json_object *obj);
-void json_free_array(struct json_array *array);
+void json_free_array(struct json_object *array);
int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...);
#define json_object_add_value_int(obj, name, val) \
@@ -67,7 +62,7 @@ int json_object_add_value_type(struct json_object *obj, const char *name, int ty
json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val))
#define json_object_add_value_array(obj, name, val) \
json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val))
-int json_array_add_value_type(struct json_array *array, int type, ...);
+int json_array_add_value_type(struct json_object *array, int type, ...);
#define json_array_add_value_int(obj, val) \
json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val))
#define json_array_add_value_uint(obj, val) \
diff --git a/util/log.c b/util/log.c
new file mode 100644
index 0000000..4a22354
--- /dev/null
+++ b/util/log.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 SUSE LLC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file implements basic logging functionality.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <time.h>
+#define LOG_FUNCNAME 1
+#include "log.h"
+#include "cleanup.h"
+
+#ifndef LOG_CLOCK
+#define LOG_CLOCK CLOCK_MONOTONIC
+#endif
+
+int log_level = DEFAULT_LOGLEVEL;
+bool log_timestamp;
+bool log_pid;
+
+void __attribute__((format(printf, 3, 4)))
+__msg(int lvl, const char *func, const char *format, ...)
+{
+ va_list ap;
+ char pidbuf[16];
+ char timebuf[32];
+ static const char *const formats[] = {
+ "%s%s%s",
+ "%s%s%s: ",
+ "%s<%s>%s ",
+ "%s<%s> %s: ",
+ "[%s] %s%s ",
+ "[%s]%s %s: ",
+ "[%s] <%s>%s ",
+ "[%s] <%s> %s: ",
+ };
+ char *header __cleanup__(cleanup_charp) = NULL;
+ char *message __cleanup__(cleanup_charp) = NULL;
+ int idx;
+
+ if (lvl > log_level)
+ return;
+
+ if (log_timestamp) {
+ struct timespec now;
+
+ clock_gettime(LOG_CLOCK, &now);
+ snprintf(timebuf, sizeof(timebuf), "%6ld.%06ld",
+ (long)now.tv_sec, now.tv_nsec / 1000);
+ } else
+ *timebuf = '\0';
+
+ if (log_pid)
+ snprintf(pidbuf, sizeof(pidbuf), "%ld", (long)getpid());
+ else
+ *pidbuf = '\0';
+
+ idx = ((log_timestamp ? 1 : 0) << 2) |
+ ((log_pid ? 1 : 0) << 1) | (func ? 1 : 0);
+
+ if (asprintf(&header, formats[idx], timebuf, pidbuf, func ? func : "")
+ == -1)
+ header = NULL;
+
+ va_start(ap, format);
+ if (vasprintf(&message, format, ap) == -1)
+ message = NULL;
+ va_end(ap);
+
+ fprintf(stderr, "%s%s", header ? header : "<error>",
+ message ? message : "<error>");
+
+}
diff --git a/util/log.h b/util/log.h
new file mode 100644
index 0000000..15107a5
--- /dev/null
+++ b/util/log.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 Martin Wilck, SUSE LLC
+ * SPDX-License-Identifier: LGPL-2.1-or-newer
+ */
+#ifndef _LOG_H
+#define _LOG_H
+
+#ifndef MAX_LOGLEVEL
+# define MAX_LOGLEVEL LOG_DEBUG
+#endif
+#ifndef DEFAULT_LOGLEVEL
+# define DEFAULT_LOGLEVEL LOG_NOTICE
+#endif
+
+#if (LOG_FUNCNAME == 1)
+#define _log_func __func__
+#else
+#define _log_func NULL
+#endif
+
+extern int log_level;
+extern bool log_timestamp;
+extern bool log_pid;
+
+void __attribute__((format(printf, 3, 4)))
+__msg(int lvl, const char *func, const char *format, ...);
+
+#define msg(lvl, format, ...) \
+ do { \
+ if ((lvl) <= MAX_LOGLEVEL) \
+ __msg(lvl, _log_func, format, ##__VA_ARGS__); \
+ } while (0)
+
+#endif /* _LOG_H */