summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 19:41:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 19:41:32 +0000
commitf26f66d866ba1a9f3204e6fdfe2b07e67b5492ad (patch)
treec953c007cbe4f60a147ab62f97937d58abb2e9ca
parentInitial commit. (diff)
downloadnvme-cli-f26f66d866ba1a9f3204e6fdfe2b07e67b5492ad.tar.xz
nvme-cli-f26f66d866ba1a9f3204e6fdfe2b07e67b5492ad.zip
Adding upstream version 2.8.upstream/2.8upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.github/AppImageBuilder.yml57
-rw-r--r--.github/azure-pipelines.yml38
-rw-r--r--.github/codeql/codeql-config.yml3
-rw-r--r--.github/cross/ubuntu-cross-armhf.txt18
-rw-r--r--.github/cross/ubuntu-cross-ppc64le.txt18
-rw-r--r--.github/cross/ubuntu-cross-s390x.txt18
-rw-r--r--.github/dependabot.yml7
-rw-r--r--.github/workflows/appimage.yml56
-rw-r--r--.github/workflows/build.yml101
-rw-r--r--.github/workflows/checkpatch.yml15
-rw-r--r--.github/workflows/codeql.yml71
-rw-r--r--.github/workflows/coverage.yml22
-rw-r--r--.github/workflows/release.yml20
-rw-r--r--.gitignore20
-rw-r--r--.gitmodules0
-rw-r--r--.mailmap1
-rw-r--r--CONTRIBUTING.md24
-rw-r--r--Documentation/asciidoc.conf91
-rw-r--r--Documentation/asciidoctor-extensions.rb29
-rw-r--r--Documentation/cmd-plugins.txt203
-rw-r--r--Documentation/cmds-main.txt275
-rwxr-xr-xDocumentation/install-webdoc.sh39
-rw-r--r--Documentation/manpage-base.xsl35
-rw-r--r--Documentation/manpage-normal.xsl13
-rw-r--r--Documentation/meson.build293
-rw-r--r--Documentation/nvme-admin-passthru.1194
-rw-r--r--Documentation/nvme-admin-passthru.html1034
-rw-r--r--Documentation/nvme-admin-passthru.txt146
-rw-r--r--Documentation/nvme-ana-log.189
-rw-r--r--Documentation/nvme-ana-log.html842
-rw-r--r--Documentation/nvme-ana-log.txt50
-rw-r--r--Documentation/nvme-attach-ns.190
-rw-r--r--Documentation/nvme-attach-ns.html848
-rw-r--r--Documentation/nvme-attach-ns.txt49
-rw-r--r--Documentation/nvme-boot-part-log.195
-rw-r--r--Documentation/nvme-boot-part-log.html853
-rw-r--r--Documentation/nvme-boot-part-log.txt55
-rw-r--r--Documentation/nvme-capacity-mgmt.186
-rw-r--r--Documentation/nvme-capacity-mgmt.html870
-rw-r--r--Documentation/nvme-capacity-mgmt.txt64
-rw-r--r--Documentation/nvme-changed-ns-list-log.1112
-rw-r--r--Documentation/nvme-changed-ns-list-log.html853
-rw-r--r--Documentation/nvme-changed-ns-list-log.txt62
-rw-r--r--Documentation/nvme-check-dhchap-key.151
-rw-r--r--Documentation/nvme-check-dhchap-key.html800
-rw-r--r--Documentation/nvme-check-dhchap-key.txt41
-rw-r--r--Documentation/nvme-check-tls-key.txt79
-rw-r--r--Documentation/nvme-cmdset-ind-id-ns.1147
-rw-r--r--Documentation/nvme-cmdset-ind-id-ns.html896
-rw-r--r--Documentation/nvme-cmdset-ind-id-ns.txt88
-rw-r--r--Documentation/nvme-compare.1229
-rw-r--r--Documentation/nvme-compare.html1123
-rw-r--r--Documentation/nvme-compare.txt172
-rw-r--r--Documentation/nvme-config.txt213
-rw-r--r--Documentation/nvme-connect-all.1385
-rw-r--r--Documentation/nvme-connect-all.html1283
-rw-r--r--Documentation/nvme-connect-all.txt267
-rw-r--r--Documentation/nvme-connect.1304
-rw-r--r--Documentation/nvme-connect.html1226
-rw-r--r--Documentation/nvme-connect.txt221
-rw-r--r--Documentation/nvme-copy.1168
-rw-r--r--Documentation/nvme-copy.html1037
-rw-r--r--Documentation/nvme-copy.txt131
-rw-r--r--Documentation/nvme-create-ns.1197
-rw-r--r--Documentation/nvme-create-ns.html1078
-rw-r--r--Documentation/nvme-create-ns.txt160
-rw-r--r--Documentation/nvme-delete-ns.168
-rw-r--r--Documentation/nvme-delete-ns.html830
-rw-r--r--Documentation/nvme-delete-ns.txt44
-rw-r--r--Documentation/nvme-dera-stat.171
-rw-r--r--Documentation/nvme-dera-stat.html804
-rw-r--r--Documentation/nvme-dera-stat.txt37
-rw-r--r--Documentation/nvme-detach-ns.172
-rw-r--r--Documentation/nvme-detach-ns.html841
-rw-r--r--Documentation/nvme-detach-ns.txt47
-rw-r--r--Documentation/nvme-device-self-test.1121
-rw-r--r--Documentation/nvme-device-self-test.html879
-rw-r--r--Documentation/nvme-device-self-test.txt72
-rw-r--r--Documentation/nvme-dim.1126
-rw-r--r--Documentation/nvme-dim.html892
-rw-r--r--Documentation/nvme-dim.txt84
-rw-r--r--Documentation/nvme-dir-receive.1235
-rw-r--r--Documentation/nvme-dir-receive.html996
-rw-r--r--Documentation/nvme-dir-receive.txt126
-rw-r--r--Documentation/nvme-dir-send.1241
-rw-r--r--Documentation/nvme-dir-send.html1009
-rw-r--r--Documentation/nvme-dir-send.txt132
-rw-r--r--Documentation/nvme-disconnect-all.184
-rw-r--r--Documentation/nvme-disconnect-all.html832
-rw-r--r--Documentation/nvme-disconnect-all.txt45
-rw-r--r--Documentation/nvme-disconnect.1115
-rw-r--r--Documentation/nvme-disconnect.html869
-rw-r--r--Documentation/nvme-disconnect.txt64
-rw-r--r--Documentation/nvme-discover.1414
-rw-r--r--Documentation/nvme-discover.html1332
-rw-r--r--Documentation/nvme-discover.txt301
-rw-r--r--Documentation/nvme-dsm.1113
-rw-r--r--Documentation/nvme-dsm.html925
-rw-r--r--Documentation/nvme-dsm.txt92
-rw-r--r--Documentation/nvme-effects-log.1116
-rw-r--r--Documentation/nvme-effects-log.html864
-rw-r--r--Documentation/nvme-effects-log.txt66
-rw-r--r--Documentation/nvme-endurance-event-agg-log.1118
-rw-r--r--Documentation/nvme-endurance-event-agg-log.html869
-rw-r--r--Documentation/nvme-endurance-event-agg-log.txt70
-rw-r--r--Documentation/nvme-endurance-log.1112
-rw-r--r--Documentation/nvme-endurance-log.html852
-rw-r--r--Documentation/nvme-endurance-log.txt60
-rw-r--r--Documentation/nvme-error-log.1118
-rw-r--r--Documentation/nvme-error-log.html867
-rw-r--r--Documentation/nvme-error-log.txt68
-rw-r--r--Documentation/nvme-fdp-configs.168
-rw-r--r--Documentation/nvme-fdp-configs.html833
-rw-r--r--Documentation/nvme-fdp-configs.txt41
-rw-r--r--Documentation/nvme-fdp-events.167
-rw-r--r--Documentation/nvme-fdp-events.html832
-rw-r--r--Documentation/nvme-fdp-events.txt40
-rw-r--r--Documentation/nvme-fdp-set-events.163
-rw-r--r--Documentation/nvme-fdp-set-events.html823
-rw-r--r--Documentation/nvme-fdp-set-events.txt38
-rw-r--r--Documentation/nvme-fdp-stats.162
-rw-r--r--Documentation/nvme-fdp-stats.html821
-rw-r--r--Documentation/nvme-fdp-stats.txt36
-rw-r--r--Documentation/nvme-fdp-status.162
-rw-r--r--Documentation/nvme-fdp-status.html821
-rw-r--r--Documentation/nvme-fdp-status.txt36
-rw-r--r--Documentation/nvme-fdp-update.154
-rw-r--r--Documentation/nvme-fdp-update.html809
-rw-r--r--Documentation/nvme-fdp-update.txt31
-rw-r--r--Documentation/nvme-fdp-usage.162
-rw-r--r--Documentation/nvme-fdp-usage.html822
-rw-r--r--Documentation/nvme-fdp-usage.txt37
-rw-r--r--Documentation/nvme-fid-support-effects-log.169
-rw-r--r--Documentation/nvme-fid-support-effects-log.html832
-rw-r--r--Documentation/nvme-fid-support-effects-log.txt47
-rw-r--r--Documentation/nvme-flush.166
-rw-r--r--Documentation/nvme-flush.html831
-rw-r--r--Documentation/nvme-flush.txt44
-rw-r--r--Documentation/nvme-format.1237
-rw-r--r--Documentation/nvme-format.html1063
-rw-r--r--Documentation/nvme-format.txt163
-rw-r--r--Documentation/nvme-fw-commit.1162
-rw-r--r--Documentation/nvme-fw-commit.html936
-rw-r--r--Documentation/nvme-fw-commit.txt103
-rw-r--r--Documentation/nvme-fw-download.1103
-rw-r--r--Documentation/nvme-fw-download.html883
-rw-r--r--Documentation/nvme-fw-download.txt78
-rw-r--r--Documentation/nvme-fw-log.1112
-rw-r--r--Documentation/nvme-fw-log.html853
-rw-r--r--Documentation/nvme-fw-log.txt61
-rw-r--r--Documentation/nvme-gen-dhchap-key.169
-rw-r--r--Documentation/nvme-gen-dhchap-key.html842
-rw-r--r--Documentation/nvme-gen-dhchap-key.txt62
-rw-r--r--Documentation/nvme-gen-hostnqn.160
-rw-r--r--Documentation/nvme-gen-hostnqn.html816
-rw-r--r--Documentation/nvme-gen-hostnqn.txt36
-rw-r--r--Documentation/nvme-gen-tls-key.txt99
-rw-r--r--Documentation/nvme-get-feature.1247
-rw-r--r--Documentation/nvme-get-feature.html1008
-rw-r--r--Documentation/nvme-get-feature.txt137
-rw-r--r--Documentation/nvme-get-lba-status.1140
-rw-r--r--Documentation/nvme-get-lba-status.html914
-rw-r--r--Documentation/nvme-get-lba-status.txt86
-rw-r--r--Documentation/nvme-get-log.1181
-rw-r--r--Documentation/nvme-get-log.html1004
-rw-r--r--Documentation/nvme-get-log.txt137
-rw-r--r--Documentation/nvme-get-ns-id.179
-rw-r--r--Documentation/nvme-get-ns-id.html825
-rw-r--r--Documentation/nvme-get-ns-id.txt39
-rw-r--r--Documentation/nvme-get-property.1138
-rw-r--r--Documentation/nvme-get-property.html874
-rw-r--r--Documentation/nvme-get-property.txt68
-rw-r--r--Documentation/nvme-help.169
-rw-r--r--Documentation/nvme-help.html801
-rw-r--r--Documentation/nvme-help.txt33
-rw-r--r--Documentation/nvme-huawei-id-ctrl.197
-rw-r--r--Documentation/nvme-huawei-id-ctrl.html862
-rw-r--r--Documentation/nvme-huawei-id-ctrl.txt66
-rw-r--r--Documentation/nvme-huawei-list.154
-rw-r--r--Documentation/nvme-huawei-list.html804
-rw-r--r--Documentation/nvme-huawei-list.txt31
-rw-r--r--Documentation/nvme-id-ctrl.1202
-rw-r--r--Documentation/nvme-id-ctrl.html928
-rw-r--r--Documentation/nvme-id-ctrl.txt117
-rw-r--r--Documentation/nvme-id-domain.168
-rw-r--r--Documentation/nvme-id-domain.html830
-rw-r--r--Documentation/nvme-id-domain.txt44
-rw-r--r--Documentation/nvme-id-iocs.1113
-rw-r--r--Documentation/nvme-id-iocs.html862
-rw-r--r--Documentation/nvme-id-iocs.txt58
-rwxr-xr-xDocumentation/nvme-id-ns-granularity.txt46
-rw-r--r--Documentation/nvme-id-ns-lba-format.1172
-rw-r--r--Documentation/nvme-id-ns-lba-format.html901
-rw-r--r--Documentation/nvme-id-ns-lba-format.txt102
-rw-r--r--Documentation/nvme-id-ns.1235
-rw-r--r--Documentation/nvme-id-ns.html973
-rw-r--r--Documentation/nvme-id-ns.txt148
-rw-r--r--Documentation/nvme-id-nvmset.1148
-rw-r--r--Documentation/nvme-id-nvmset.html869
-rw-r--r--Documentation/nvme-id-nvmset.txt77
-rwxr-xr-xDocumentation/nvme-id-uuid.txt55
-rw-r--r--Documentation/nvme-inspur-nvme-vendor-log.171
-rw-r--r--Documentation/nvme-inspur-nvme-vendor-log.html803
-rw-r--r--Documentation/nvme-inspur-nvme-vendor-log.txt36
-rw-r--r--Documentation/nvme-intel-id-ctrl.195
-rw-r--r--Documentation/nvme-intel-id-ctrl.html860
-rw-r--r--Documentation/nvme-intel-id-ctrl.txt63
-rw-r--r--Documentation/nvme-intel-internal-log.1120
-rw-r--r--Documentation/nvme-intel-internal-log.html880
-rw-r--r--Documentation/nvme-intel-internal-log.txt73
-rw-r--r--Documentation/nvme-intel-lat-stats.1100
-rw-r--r--Documentation/nvme-intel-lat-stats.html839
-rw-r--r--Documentation/nvme-intel-lat-stats.txt53
-rw-r--r--Documentation/nvme-intel-market-name.174
-rw-r--r--Documentation/nvme-intel-market-name.html820
-rw-r--r--Documentation/nvme-intel-market-name.txt43
-rw-r--r--Documentation/nvme-intel-smart-log-add.1108
-rw-r--r--Documentation/nvme-intel-smart-log-add.html856
-rw-r--r--Documentation/nvme-intel-smart-log-add.txt65
-rw-r--r--Documentation/nvme-intel-temp-stats.197
-rw-r--r--Documentation/nvme-intel-temp-stats.html829
-rw-r--r--Documentation/nvme-intel-temp-stats.txt51
-rw-r--r--Documentation/nvme-io-mgmt-recv.186
-rw-r--r--Documentation/nvme-io-mgmt-recv.html876
-rw-r--r--Documentation/nvme-io-mgmt-recv.txt63
-rw-r--r--Documentation/nvme-io-mgmt-send.186
-rw-r--r--Documentation/nvme-io-mgmt-send.html875
-rw-r--r--Documentation/nvme-io-mgmt-send.txt62
-rw-r--r--Documentation/nvme-io-passthru.1158
-rw-r--r--Documentation/nvme-io-passthru.html1022
-rw-r--r--Documentation/nvme-io-passthru.txt138
-rw-r--r--Documentation/nvme-lba-status-log.1112
-rw-r--r--Documentation/nvme-lba-status-log.html850
-rw-r--r--Documentation/nvme-lba-status-log.txt59
-rw-r--r--Documentation/nvme-list-ctrl.176
-rw-r--r--Documentation/nvme-list-ctrl.html849
-rw-r--r--Documentation/nvme-list-ctrl.txt57
-rw-r--r--Documentation/nvme-list-endgrp.168
-rw-r--r--Documentation/nvme-list-endgrp.html833
-rw-r--r--Documentation/nvme-list-endgrp.txt48
-rw-r--r--Documentation/nvme-list-ns.1122
-rw-r--r--Documentation/nvme-list-ns.html878
-rw-r--r--Documentation/nvme-list-ns.txt70
-rwxr-xr-xDocumentation/nvme-list-secondary.txt54
-rw-r--r--Documentation/nvme-list-subsys.1132
-rw-r--r--Documentation/nvme-list-subsys.html872
-rw-r--r--Documentation/nvme-list-subsys.txt89
-rw-r--r--Documentation/nvme-list.163
-rw-r--r--Documentation/nvme-list.html823
-rw-r--r--Documentation/nvme-list.txt41
-rw-r--r--Documentation/nvme-lockdown.190
-rw-r--r--Documentation/nvme-lockdown.html881
-rw-r--r--Documentation/nvme-lockdown.txt65
-rw-r--r--Documentation/nvme-media-unit-stat-log.167
-rw-r--r--Documentation/nvme-media-unit-stat-log.html831
-rw-r--r--Documentation/nvme-media-unit-stat-log.txt47
-rw-r--r--Documentation/nvme-mi-cmd-support-effects-log.170
-rw-r--r--Documentation/nvme-mi-cmd-support-effects-log.html833
-rw-r--r--Documentation/nvme-mi-cmd-support-effects-log.txt49
-rw-r--r--Documentation/nvme-micron-clear-pcie-errors.171
-rw-r--r--Documentation/nvme-micron-clear-pcie-errors.html805
-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.html821
-rw-r--r--Documentation/nvme-micron-internal-log.txt45
-rw-r--r--Documentation/nvme-micron-nand-stats.171
-rw-r--r--Documentation/nvme-micron-nand-stats.html806
-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.html806
-rw-r--r--Documentation/nvme-micron-pcie-stats.txt40
-rw-r--r--Documentation/nvme-micron-selective-download.1140
-rw-r--r--Documentation/nvme-micron-selective-download.html876
-rw-r--r--Documentation/nvme-micron-selective-download.txt66
-rw-r--r--Documentation/nvme-micron-smart-add-log.190
-rw-r--r--Documentation/nvme-micron-smart-add-log.html824
-rw-r--r--Documentation/nvme-micron-smart-add-log.txt54
-rw-r--r--Documentation/nvme-micron-temperature-stats.171
-rw-r--r--Documentation/nvme-micron-temperature-stats.html806
-rw-r--r--Documentation/nvme-micron-temperature-stats.txt40
-rw-r--r--Documentation/nvme-netapp-ontapdevices.174
-rw-r--r--Documentation/nvme-netapp-ontapdevices.html814
-rw-r--r--Documentation/nvme-netapp-ontapdevices.txt35
-rw-r--r--Documentation/nvme-netapp-smdevices.174
-rw-r--r--Documentation/nvme-netapp-smdevices.html816
-rw-r--r--Documentation/nvme-netapp-smdevices.txt37
-rw-r--r--Documentation/nvme-ns-descs.1120
-rw-r--r--Documentation/nvme-ns-descs.html874
-rw-r--r--Documentation/nvme-ns-descs.txt76
-rw-r--r--Documentation/nvme-ns-rescan.179
-rw-r--r--Documentation/nvme-ns-rescan.html825
-rw-r--r--Documentation/nvme-ns-rescan.txt39
-rw-r--r--Documentation/nvme-nvm-id-ctrl.1104
-rw-r--r--Documentation/nvme-nvm-id-ctrl.html839
-rw-r--r--Documentation/nvme-nvm-id-ctrl.txt53
-rw-r--r--Documentation/nvme-nvm-id-ns-lba-format.1117
-rw-r--r--Documentation/nvme-nvm-id-ns-lba-format.html863
-rw-r--r--Documentation/nvme-nvm-id-ns-lba-format.txt66
-rw-r--r--Documentation/nvme-nvm-id-ns.1162
-rw-r--r--Documentation/nvme-nvm-id-ns.html881
-rw-r--r--Documentation/nvme-nvm-id-ns.txt82
-rw-r--r--Documentation/nvme-nvme-mi-recv.1124
-rw-r--r--Documentation/nvme-nvme-mi-recv.html912
-rwxr-xr-xDocumentation/nvme-nvme-mi-recv.txt79
-rw-r--r--Documentation/nvme-nvme-mi-send.1124
-rw-r--r--Documentation/nvme-nvme-mi-send.html912
-rwxr-xr-xDocumentation/nvme-nvme-mi-send.txt79
-rw-r--r--Documentation/nvme-ocp-clear-fw-activate-history.178
-rw-r--r--Documentation/nvme-ocp-clear-fw-activate-history.html824
-rw-r--r--Documentation/nvme-ocp-clear-fw-activate-history.txt49
-rw-r--r--Documentation/nvme-ocp-clear-pcie-correctable-error-counters.178
-rw-r--r--Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html824
-rw-r--r--Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt49
-rw-r--r--Documentation/nvme-ocp-device-capability-log.txt42
-rw-r--r--Documentation/nvme-ocp-eol-plp-failure-mode.1137
-rw-r--r--Documentation/nvme-ocp-eol-plp-failure-mode.html893
-rw-r--r--Documentation/nvme-ocp-eol-plp-failure-mode.txt72
-rw-r--r--Documentation/nvme-ocp-error-recovery-log.txt42
-rw-r--r--Documentation/nvme-ocp-get-plp-health-check-interval.txt54
-rw-r--r--Documentation/nvme-ocp-latency-monitor-log.179
-rw-r--r--Documentation/nvme-ocp-latency-monitor-log.html818
-rw-r--r--Documentation/nvme-ocp-latency-monitor-log.txt44
-rw-r--r--Documentation/nvme-ocp-set-dssd-power-state-feature.txt43
-rw-r--r--Documentation/nvme-ocp-set-plp-health-check-interval.txt53
-rw-r--r--Documentation/nvme-ocp-smart-add-log.179
-rw-r--r--Documentation/nvme-ocp-smart-add-log.html819
-rw-r--r--Documentation/nvme-ocp-smart-add-log.txt44
-rw-r--r--Documentation/nvme-ocp-telemetry-string-log-page.txt43
-rw-r--r--Documentation/nvme-ocp-unsupported-reqs-log-pages.txt45
-rw-r--r--Documentation/nvme-persistent-event-log.1123
-rw-r--r--Documentation/nvme-persistent-event-log.html884
-rw-r--r--Documentation/nvme-persistent-event-log.txt79
-rw-r--r--Documentation/nvme-phy-rx-eom-log.txt68
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.1118
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.html871
-rw-r--r--Documentation/nvme-pred-lat-event-agg-log.txt73
-rw-r--r--Documentation/nvme-predictable-lat-log.1118
-rw-r--r--Documentation/nvme-predictable-lat-log.html868
-rw-r--r--Documentation/nvme-predictable-lat-log.txt70
-rw-r--r--Documentation/nvme-primary-ctrl-caps.1110
-rw-r--r--Documentation/nvme-primary-ctrl-caps.html853
-rw-r--r--Documentation/nvme-primary-ctrl-caps.txt57
-rw-r--r--Documentation/nvme-read.1214
-rw-r--r--Documentation/nvme-read.html1094
-rw-r--r--Documentation/nvme-read.txt158
-rw-r--r--Documentation/nvme-reset.179
-rw-r--r--Documentation/nvme-reset.html825
-rw-r--r--Documentation/nvme-reset.txt39
-rw-r--r--Documentation/nvme-resv-acquire.1191
-rw-r--r--Documentation/nvme-resv-acquire.html978
-rw-r--r--Documentation/nvme-resv-acquire.txt101
-rw-r--r--Documentation/nvme-resv-notif-log.1104
-rw-r--r--Documentation/nvme-resv-notif-log.html840
-rw-r--r--Documentation/nvme-resv-notif-log.txt55
-rw-r--r--Documentation/nvme-resv-register.1167
-rw-r--r--Documentation/nvme-resv-register.html967
-rw-r--r--Documentation/nvme-resv-register.txt102
-rw-r--r--Documentation/nvme-resv-release.1179
-rw-r--r--Documentation/nvme-resv-release.html960
-rw-r--r--Documentation/nvme-resv-release.txt93
-rw-r--r--Documentation/nvme-resv-report.186
-rw-r--r--Documentation/nvme-resv-report.html872
-rw-r--r--Documentation/nvme-resv-report.txt65
-rw-r--r--Documentation/nvme-rpmb.1340
-rw-r--r--Documentation/nvme-rpmb.html1031
-rw-r--r--Documentation/nvme-rpmb.txt158
-rw-r--r--Documentation/nvme-sanitize-log.1155
-rw-r--r--Documentation/nvme-sanitize-log.html910
-rw-r--r--Documentation/nvme-sanitize-log.txt90
-rw-r--r--Documentation/nvme-sanitize.1169
-rw-r--r--Documentation/nvme-sanitize.html967
-rw-r--r--Documentation/nvme-sanitize.txt112
-rw-r--r--Documentation/nvme-seagate-clear-fw-activate-history.160
-rw-r--r--Documentation/nvme-seagate-clear-fw-activate-history.html799
-rw-r--r--Documentation/nvme-seagate-clear-fw-activate-history.txt37
-rw-r--r--Documentation/nvme-seagate-clear-pcie-correctable-errors.163
-rw-r--r--Documentation/nvme-seagate-clear-pcie-correctable-errors.html809
-rw-r--r--Documentation/nvme-seagate-clear-pcie-correctable-errors.txt38
-rw-r--r--Documentation/nvme-seagate-cloud-SSD-plugin-version.158
-rw-r--r--Documentation/nvme-seagate-cloud-SSD-plugin-version.html794
-rw-r--r--Documentation/nvme-seagate-cloud-SSD-plugin-version.txt31
-rw-r--r--Documentation/nvme-seagate-get-ctrl-tele.168
-rw-r--r--Documentation/nvme-seagate-get-ctrl-tele.html820
-rw-r--r--Documentation/nvme-seagate-get-ctrl-tele.txt42
-rw-r--r--Documentation/nvme-seagate-get-host-tele.173
-rw-r--r--Documentation/nvme-seagate-get-host-tele.html833
-rw-r--r--Documentation/nvme-seagate-get-host-tele.txt48
-rw-r--r--Documentation/nvme-seagate-help.185
-rw-r--r--Documentation/nvme-seagate-help.html819
-rw-r--r--Documentation/nvme-seagate-help.txt49
-rw-r--r--Documentation/nvme-seagate-plugin-version.158
-rw-r--r--Documentation/nvme-seagate-plugin-version.html794
-rw-r--r--Documentation/nvme-seagate-plugin-version.txt31
-rw-r--r--Documentation/nvme-seagate-version.158
-rw-r--r--Documentation/nvme-seagate-version.html794
-rw-r--r--Documentation/nvme-seagate-version.txt31
-rw-r--r--Documentation/nvme-seagate-vs-fw-activate-history.168
-rw-r--r--Documentation/nvme-seagate-vs-fw-activate-history.html820
-rw-r--r--Documentation/nvme-seagate-vs-fw-activate-history.txt42
-rw-r--r--Documentation/nvme-seagate-vs-internal-log.168
-rw-r--r--Documentation/nvme-seagate-vs-internal-log.html821
-rw-r--r--Documentation/nvme-seagate-vs-internal-log.txt43
-rw-r--r--Documentation/nvme-seagate-vs-log-page-sup.175
-rw-r--r--Documentation/nvme-seagate-vs-log-page-sup.html821
-rw-r--r--Documentation/nvme-seagate-vs-log-page-sup.txt50
-rw-r--r--Documentation/nvme-seagate-vs-pcie-stats.163
-rw-r--r--Documentation/nvme-seagate-vs-pcie-stats.html809
-rw-r--r--Documentation/nvme-seagate-vs-pcie-stats.txt38
-rw-r--r--Documentation/nvme-seagate-vs-smart-add-log.179
-rw-r--r--Documentation/nvme-seagate-vs-smart-add-log.html837
-rw-r--r--Documentation/nvme-seagate-vs-smart-add-log.txt55
-rw-r--r--Documentation/nvme-seagate-vs-temperature-stats.163
-rw-r--r--Documentation/nvme-seagate-vs-temperature-stats.html809
-rw-r--r--Documentation/nvme-seagate-vs-temperature-stats.txt38
-rw-r--r--Documentation/nvme-security-recv.1105
-rw-r--r--Documentation/nvme-security-recv.html916
-rw-r--r--Documentation/nvme-security-recv.txt89
-rw-r--r--Documentation/nvme-security-send.198
-rw-r--r--Documentation/nvme-security-send.html903
-rw-r--r--Documentation/nvme-security-send.txt82
-rw-r--r--Documentation/nvme-self-test-log.1133
-rw-r--r--Documentation/nvme-self-test-log.html865
-rw-r--r--Documentation/nvme-self-test-log.txt71
-rw-r--r--Documentation/nvme-set-feature.1146
-rw-r--r--Documentation/nvme-set-feature.html929
-rw-r--r--Documentation/nvme-set-feature.txt95
-rw-r--r--Documentation/nvme-set-property.172
-rw-r--r--Documentation/nvme-set-property.html836
-rw-r--r--Documentation/nvme-set-property.txt45
-rw-r--r--Documentation/nvme-show-hostnqn.160
-rw-r--r--Documentation/nvme-show-hostnqn.html816
-rw-r--r--Documentation/nvme-show-hostnqn.txt36
-rw-r--r--Documentation/nvme-show-regs.1129
-rw-r--r--Documentation/nvme-show-regs.html866
-rw-r--r--Documentation/nvme-show-regs.txt67
-rw-r--r--Documentation/nvme-show-topology.184
-rw-r--r--Documentation/nvme-show-topology.html852
-rw-r--r--Documentation/nvme-show-topology.txt51
-rw-r--r--Documentation/nvme-smart-log.1118
-rw-r--r--Documentation/nvme-smart-log.html868
-rw-r--r--Documentation/nvme-smart-log.txt69
-rw-r--r--Documentation/nvme-subsystem-reset.180
-rw-r--r--Documentation/nvme-subsystem-reset.html826
-rw-r--r--Documentation/nvme-subsystem-reset.txt40
-rw-r--r--Documentation/nvme-supported-cap-config-log.txt52
-rw-r--r--Documentation/nvme-supported-log-pages.164
-rw-r--r--Documentation/nvme-supported-log-pages.html820
-rw-r--r--Documentation/nvme-supported-log-pages.txt43
-rw-r--r--Documentation/nvme-telemetry-log.1102
-rw-r--r--Documentation/nvme-telemetry-log.html869
-rw-r--r--Documentation/nvme-telemetry-log.txt64
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.166
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.html798
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt32
-rw-r--r--Documentation/nvme-toshiba-vs-internal-log.1108
-rw-r--r--Documentation/nvme-toshiba-vs-internal-log.html844
-rw-r--r--Documentation/nvme-toshiba-vs-internal-log.txt62
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.1106
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.html848
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.txt63
-rw-r--r--Documentation/nvme-transcend-badblock.171
-rw-r--r--Documentation/nvme-transcend-badblock.html803
-rw-r--r--Documentation/nvme-transcend-badblock.txt36
-rw-r--r--Documentation/nvme-transcend-healthvalue.171
-rw-r--r--Documentation/nvme-transcend-healthvalue.html804
-rw-r--r--Documentation/nvme-transcend-healthvalue.txt38
-rw-r--r--Documentation/nvme-verify.1165
-rw-r--r--Documentation/nvme-verify.html983
-rw-r--r--Documentation/nvme-verify.txt101
-rwxr-xr-xDocumentation/nvme-virt-mgmt.txt70
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.1138
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.html885
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.txt86
-rw-r--r--Documentation/nvme-virtium-show-identify.171
-rw-r--r--Documentation/nvme-virtium-show-identify.html805
-rw-r--r--Documentation/nvme-virtium-show-identify.txt38
-rw-r--r--Documentation/nvme-wdc-cap-diag.1163
-rw-r--r--Documentation/nvme-wdc-cap-diag.html863
-rw-r--r--Documentation/nvme-wdc-cap-diag.txt64
-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.171
-rw-r--r--Documentation/nvme-wdc-clear-assert-dump.html805
-rw-r--r--Documentation/nvme-wdc-clear-assert-dump.txt38
-rw-r--r--Documentation/nvme-wdc-clear-fw-activate-history.171
-rw-r--r--Documentation/nvme-wdc-clear-fw-activate-history.html804
-rw-r--r--Documentation/nvme-wdc-clear-fw-activate-history.txt37
-rw-r--r--Documentation/nvme-wdc-clear-pcie-corr.171
-rw-r--r--Documentation/nvme-wdc-clear-pcie-corr.html806
-rw-r--r--Documentation/nvme-wdc-clear-pcie-correctable-errors.171
-rw-r--r--Documentation/nvme-wdc-clear-pcie-correctable-errors.html806
-rw-r--r--Documentation/nvme-wdc-clear-pcie-correctable-errors.txt39
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.168
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.html797
-rw-r--r--Documentation/nvme-wdc-cloud-SSD-plugin-version.txt33
-rw-r--r--Documentation/nvme-wdc-cloud-boot-SSD-version.168
-rw-r--r--Documentation/nvme-wdc-cloud-boot-SSD-version.html797
-rw-r--r--Documentation/nvme-wdc-cloud-boot-SSD-version.txt33
-rw-r--r--Documentation/nvme-wdc-drive-essentials.195
-rw-r--r--Documentation/nvme-wdc-drive-essentials.html829
-rw-r--r--Documentation/nvme-wdc-drive-essentials.txt50
-rw-r--r--Documentation/nvme-wdc-drive-log.1116
-rw-r--r--Documentation/nvme-wdc-drive-log.html836
-rw-r--r--Documentation/nvme-wdc-drive-log.txt51
-rw-r--r--Documentation/nvme-wdc-drive-resize.176
-rw-r--r--Documentation/nvme-wdc-drive-resize.html817
-rw-r--r--Documentation/nvme-wdc-drive-resize.txt42
-rw-r--r--Documentation/nvme-wdc-enc-get-log.1106
-rw-r--r--Documentation/nvme-wdc-enc-get-log.html844
-rw-r--r--Documentation/nvme-wdc-enc-get-log.txt60
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.1116
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.html837
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.txt52
-rw-r--r--Documentation/nvme-wdc-get-dev-capabilities-log.178
-rw-r--r--Documentation/nvme-wdc-get-dev-capabilities-log.html822
-rw-r--r--Documentation/nvme-wdc-get-dev-capabilities-log.txt47
-rw-r--r--Documentation/nvme-wdc-get-drive-status.1122
-rw-r--r--Documentation/nvme-wdc-get-drive-status.html843
-rw-r--r--Documentation/nvme-wdc-get-drive-status.txt60
-rw-r--r--Documentation/nvme-wdc-get-error-recovery-log.179
-rw-r--r--Documentation/nvme-wdc-get-error-recovery-log.html823
-rw-r--r--Documentation/nvme-wdc-get-error-recovery-log.txt48
-rw-r--r--Documentation/nvme-wdc-get-latency-monitor-log.179
-rw-r--r--Documentation/nvme-wdc-get-latency-monitor-log.html817
-rw-r--r--Documentation/nvme-wdc-get-latency-monitor-log.txt42
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.1116
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.html839
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.txt54
-rw-r--r--Documentation/nvme-wdc-get-unsupported-reqs-log.179
-rw-r--r--Documentation/nvme-wdc-get-unsupported-reqs-log.html823
-rw-r--r--Documentation/nvme-wdc-get-unsupported-reqs-log.txt48
-rw-r--r--Documentation/nvme-wdc-id-ctrl.198
-rw-r--r--Documentation/nvme-wdc-id-ctrl.html863
-rw-r--r--Documentation/nvme-wdc-id-ctrl.txt67
-rw-r--r--Documentation/nvme-wdc-log-page-directory.179
-rw-r--r--Documentation/nvme-wdc-log-page-directory.html819
-rw-r--r--Documentation/nvme-wdc-log-page-directory.txt43
-rw-r--r--Documentation/nvme-wdc-namespace-resize.1101
-rw-r--r--Documentation/nvme-wdc-namespace-resize.html843
-rw-r--r--Documentation/nvme-wdc-namespace-resize.txt56
-rw-r--r--Documentation/nvme-wdc-purge-monitor.1126
-rw-r--r--Documentation/nvme-wdc-purge-monitor.html844
-rw-r--r--Documentation/nvme-wdc-purge-monitor.txt62
-rw-r--r--Documentation/nvme-wdc-purge.173
-rw-r--r--Documentation/nvme-wdc-purge.html806
-rw-r--r--Documentation/nvme-wdc-purge.txt40
-rw-r--r--Documentation/nvme-wdc-set-latency-monitor-feature.txt118
-rw-r--r--Documentation/nvme-wdc-smart-add-log.1496
-rw-r--r--Documentation/nvme-wdc-smart-add-log.html1139
-rw-r--r--Documentation/nvme-wdc-vs-cloud-log.184
-rw-r--r--Documentation/nvme-wdc-vs-cloud-log.html835
-rw-r--r--Documentation/nvme-wdc-vs-cloud-log.txt52
-rw-r--r--Documentation/nvme-wdc-vs-device-waf.184
-rw-r--r--Documentation/nvme-wdc-vs-device-waf.html835
-rw-r--r--Documentation/nvme-wdc-vs-device-waf.txt53
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.164
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.html802
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.txt47
-rw-r--r--Documentation/nvme-wdc-vs-error-reason-identifier.1102
-rw-r--r--Documentation/nvme-wdc-vs-error-reason-identifier.html843
-rw-r--r--Documentation/nvme-wdc-vs-error-reason-identifier.txt56
-rw-r--r--Documentation/nvme-wdc-vs-fw-activate-history.1154
-rw-r--r--Documentation/nvme-wdc-vs-fw-activate-history.html875
-rw-r--r--Documentation/nvme-wdc-vs-fw-activate-history.txt75
-rw-r--r--Documentation/nvme-wdc-vs-hw-rev-log.184
-rw-r--r--Documentation/nvme-wdc-vs-hw-rev-log.html834
-rw-r--r--Documentation/nvme-wdc-vs-hw-rev-log.txt51
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.1258
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.html965
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.txt119
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.178
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.html821
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.txt45
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.1197
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.html935
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.txt107
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.1130
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.html862
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.txt65
-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.190
-rw-r--r--Documentation/nvme-write-uncor.html875
-rw-r--r--Documentation/nvme-write-uncor.txt60
-rw-r--r--Documentation/nvme-write-zeroes.1182
-rw-r--r--Documentation/nvme-write-zeroes.html1018
-rw-r--r--Documentation/nvme-write-zeroes.txt115
-rw-r--r--Documentation/nvme-write.1224
-rw-r--r--Documentation/nvme-write.html1116
-rw-r--r--Documentation/nvme-write.txt166
-rw-r--r--Documentation/nvme-zns-changed-zone-list.1104
-rw-r--r--Documentation/nvme-zns-changed-zone-list.html839
-rw-r--r--Documentation/nvme-zns-changed-zone-list.txt53
-rw-r--r--Documentation/nvme-zns-close-zone.190
-rw-r--r--Documentation/nvme-zns-close-zone.html853
-rw-r--r--Documentation/nvme-zns-close-zone.txt54
-rw-r--r--Documentation/nvme-zns-finish-zone.190
-rw-r--r--Documentation/nvme-zns-finish-zone.html854
-rw-r--r--Documentation/nvme-zns-finish-zone.txt55
-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.1109
-rw-r--r--Documentation/nvme-zns-id-ns.html853
-rw-r--r--Documentation/nvme-zns-id-ns.txt61
-rw-r--r--Documentation/nvme-zns-offline-zone.190
-rw-r--r--Documentation/nvme-zns-offline-zone.html853
-rw-r--r--Documentation/nvme-zns-offline-zone.txt54
-rw-r--r--Documentation/nvme-zns-open-zone.194
-rw-r--r--Documentation/nvme-zns-open-zone.html863
-rw-r--r--Documentation/nvme-zns-open-zone.txt57
-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.190
-rw-r--r--Documentation/nvme-zns-reset-zone.html854
-rw-r--r--Documentation/nvme-zns-reset-zone.txt55
-rw-r--r--Documentation/nvme-zns-set-zone-desc.194
-rw-r--r--Documentation/nvme-zns-set-zone-desc.html866
-rw-r--r--Documentation/nvme-zns-set-zone-desc.txt59
-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.1119
-rw-r--r--Documentation/nvme-zns-zone-mgmt-recv.html887
-rw-r--r--Documentation/nvme-zns-zone-mgmt-recv.txt76
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.1136
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.html921
-rw-r--r--Documentation/nvme-zns-zone-mgmt-send.txt84
-rw-r--r--Documentation/nvme-zns-zrwa-flush-zone.184
-rw-r--r--Documentation/nvme-zns-zrwa-flush-zone.html842
-rw-r--r--Documentation/nvme-zns-zrwa-flush-zone.txt50
-rw-r--r--Documentation/nvme.1886
-rw-r--r--Documentation/nvme.html2121
-rw-r--r--Documentation/nvme.txt70
-rw-r--r--LICENSE340
-rw-r--r--Makefile64
-rw-r--r--README.md335
l---------ccan/ccan/build_assert/LICENSE1
-rw-r--r--ccan/ccan/build_assert/build_assert.h40
l---------ccan/ccan/check_type/LICENSE1
-rw-r--r--ccan/ccan/check_type/check_type.h64
l---------ccan/ccan/compiler/LICENSE1
-rw-r--r--ccan/ccan/compiler/compiler.h317
l---------ccan/ccan/container_of/LICENSE1
-rw-r--r--ccan/ccan/container_of/container_of.h145
l---------ccan/ccan/endian/LICENSE1
-rw-r--r--ccan/ccan/endian/endian.h363
l---------ccan/ccan/hash/LICENSE1
-rw-r--r--ccan/ccan/hash/hash.c926
-rw-r--r--ccan/ccan/hash/hash.h313
l---------ccan/ccan/htable/LICENSE1
-rw-r--r--ccan/ccan/htable/htable.c491
-rw-r--r--ccan/ccan/htable/htable.h290
-rw-r--r--ccan/ccan/htable/htable_type.h188
l---------ccan/ccan/ilog/LICENSE1
-rw-r--r--ccan/ccan/ilog/ilog.c141
-rw-r--r--ccan/ccan/ilog/ilog.h154
l---------ccan/ccan/likely/LICENSE1
-rw-r--r--ccan/ccan/likely/likely.c136
-rw-r--r--ccan/ccan/likely/likely.h111
l---------ccan/ccan/list/LICENSE1
-rw-r--r--ccan/ccan/list/list.c43
-rw-r--r--ccan/ccan/list/list.h842
l---------ccan/ccan/short_types/LICENSE1
-rw-r--r--ccan/ccan/short_types/short_types.h35
l---------ccan/ccan/str/LICENSE1
-rw-r--r--ccan/ccan/str/debug.c108
-rw-r--r--ccan/ccan/str/str.c13
-rw-r--r--ccan/ccan/str/str.h228
-rw-r--r--ccan/ccan/str/str_debug.h30
-rw-r--r--ccan/ccan/strset/strset.c309
-rw-r--r--ccan/ccan/strset/strset.h167
l---------ccan/ccan/typesafe_cb/LICENSE1
-rw-r--r--ccan/ccan/typesafe_cb/typesafe_cb.h134
-rw-r--r--ccan/licenses/BSD-MIT17
-rw-r--r--ccan/licenses/CC028
-rw-r--r--ccan/licenses/LGPL-2.1510
-rw-r--r--ccan/meson.build17
-rw-r--r--cmd.h11
-rw-r--r--cmd_handler.h109
-rw-r--r--codecov.yml6
-rw-r--r--common.h38
-rw-r--r--completions/README120
-rw-r--r--completions/_nvme2316
-rw-r--r--completions/bash-nvme-completion.sh1604
-rw-r--r--define_cmd.h20
-rw-r--r--etc/discovery.conf.in4
-rw-r--r--fabrics.c1448
-rw-r--r--fabrics.h22
-rw-r--r--libnvme-wrap.c73
-rw-r--r--meson.build358
-rw-r--r--meson_options.txt72
-rw-r--r--nbft.c210
-rw-r--r--nbft.h19
-rw-r--r--nvme-builtin.h119
-rw-r--r--nvme-models.c357
-rw-r--r--nvme-models.h7
-rw-r--r--nvme-print-binary.c386
-rw-r--r--nvme-print-json.c4514
-rw-r--r--nvme-print-stdout.c5174
-rw-r--r--nvme-print.c1076
-rw-r--r--nvme-print.h313
-rw-r--r--nvme-rpmb.c1057
-rw-r--r--nvme-wrap.c436
-rw-r--r--nvme-wrap.h151
-rw-r--r--nvme.c9105
-rw-r--r--nvme.control.in9
-rw-r--r--nvme.h131
-rw-r--r--nvme.spec.in66
-rw-r--r--nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in1
-rw-r--r--nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in13
-rw-r--r--nvmf-autoconnect/systemd/nvmf-autoconnect.service.in15
-rw-r--r--nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in14
-rw-r--r--nvmf-autoconnect/systemd/nvmf-connect.target.in2
-rw-r--r--nvmf-autoconnect/systemd/nvmf-connect@.service.in16
-rw-r--r--nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in2
-rw-r--r--nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in32
-rw-r--r--nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in6
-rw-r--r--plugin.c218
-rw-r--r--plugin.h37
-rw-r--r--plugins/amzn/amzn-nvme.c54
-rw-r--r--plugins/amzn/amzn-nvme.h18
-rw-r--r--plugins/dell/dell-nvme.c54
-rw-r--r--plugins/dell/dell-nvme.h18
-rw-r--r--plugins/dera/dera-nvme.c205
-rw-r--r--plugins/dera/dera-nvme.h18
-rw-r--r--plugins/fdp/fdp.c541
-rw-r--r--plugins/fdp/fdp.h24
-rw-r--r--plugins/huawei/huawei-nvme.c383
-rw-r--r--plugins/huawei/huawei-nvme.h19
-rw-r--r--plugins/innogrit/innogrit-nvme.c466
-rw-r--r--plugins/innogrit/innogrit-nvme.h20
-rw-r--r--plugins/innogrit/typedef.h79
-rw-r--r--plugins/inspur/inspur-nvme.c233
-rw-r--r--plugins/inspur/inspur-nvme.h18
-rw-r--r--plugins/inspur/inspur-utils.h175
-rw-r--r--plugins/intel/intel-nvme.c1738
-rw-r--r--plugins/intel/intel-nvme.h25
-rw-r--r--plugins/memblaze/memblaze-nvme.c1842
-rw-r--r--plugins/memblaze/memblaze-nvme.h29
-rw-r--r--plugins/memblaze/memblaze-utils.h217
-rw-r--r--plugins/meson.build35
-rw-r--r--plugins/micron/micron-nvme.c3390
-rw-r--r--plugins/micron/micron-nvme.h36
-rw-r--r--plugins/nbft/nbft-plugin.c563
-rw-r--r--plugins/nbft/nbft-plugin.h18
-rw-r--r--plugins/netapp/netapp-nvme.c654
-rw-r--r--plugins/netapp/netapp-nvme.h19
-rw-r--r--plugins/nvidia/nvidia-nvme.c53
-rw-r--r--plugins/nvidia/nvidia-nvme.h18
-rw-r--r--plugins/ocp/meson.build8
-rw-r--r--plugins/ocp/ocp-clear-features.c93
-rw-r--r--plugins/ocp/ocp-clear-features.h12
-rw-r--r--plugins/ocp/ocp-fw-activation-history.c225
-rw-r--r--plugins/ocp/ocp-fw-activation-history.h17
-rw-r--r--plugins/ocp/ocp-nvme.c2971
-rw-r--r--plugins/ocp/ocp-nvme.h38
-rw-r--r--plugins/ocp/ocp-smart-extended-log.c352
-rw-r--r--plugins/ocp/ocp-smart-extended-log.h18
-rw-r--r--plugins/ocp/ocp-utils.c32
-rw-r--r--plugins/ocp/ocp-utils.h18
-rw-r--r--plugins/scaleflux/sfx-nvme.c1687
-rw-r--r--plugins/scaleflux/sfx-nvme.h26
-rw-r--r--plugins/seagate/seagate-diag.h388
-rw-r--r--plugins/seagate/seagate-nvme.c1968
-rw-r--r--plugins/seagate/seagate-nvme.h51
-rw-r--r--plugins/sed/meson.build4
-rw-r--r--plugins/sed/sed.c178
-rw-r--r--plugins/sed/sed.h19
-rw-r--r--plugins/sed/sedopal_cmd.c512
-rw-r--r--plugins/sed/sedopal_cmd.h55
-rw-r--r--plugins/sed/sedopal_spec.h71
-rw-r--r--plugins/shannon/shannon-nvme.c381
-rw-r--r--plugins/shannon/shannon-nvme.h21
-rw-r--r--plugins/solidigm/meson.build16
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.c138
-rw-r--r--plugins/solidigm/solidigm-garbage-collection.h8
-rw-r--r--plugins/solidigm/solidigm-get-drive-info.c79
-rw-r--r--plugins/solidigm/solidigm-get-drive-info.h8
-rw-r--r--plugins/solidigm/solidigm-id-ctrl.c73
-rw-r--r--plugins/solidigm/solidigm-id-ctrl.h10
-rw-r--r--plugins/solidigm/solidigm-internal-logs.c657
-rw-r--r--plugins/solidigm/solidigm-internal-logs.h8
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.c474
-rw-r--r--plugins/solidigm/solidigm-latency-tracking.h9
-rw-r--r--plugins/solidigm/solidigm-log-page-dir.c286
-rw-r--r--plugins/solidigm/solidigm-log-page-dir.h17
-rw-r--r--plugins/solidigm/solidigm-market-log.c63
-rw-r--r--plugins/solidigm/solidigm-market-log.h8
-rw-r--r--plugins/solidigm/solidigm-nvme.c109
-rw-r--r--plugins/solidigm/solidigm-nvme.h40
-rw-r--r--plugins/solidigm/solidigm-ocp-version.c25
-rw-r--r--plugins/solidigm/solidigm-ocp-version.h8
-rw-r--r--plugins/solidigm/solidigm-smart.c271
-rw-r--r--plugins/solidigm/solidigm-smart.h8
-rw-r--r--plugins/solidigm/solidigm-telemetry.c189
-rw-r--r--plugins/solidigm/solidigm-telemetry.h8
-rw-r--r--plugins/solidigm/solidigm-telemetry/cod.c190
-rw-r--r--plugins/solidigm/solidigm-telemetry/cod.h9
-rw-r--r--plugins/solidigm/solidigm-telemetry/config.c76
-rw-r--r--plugins/solidigm/solidigm-telemetry/config.h19
-rw-r--r--plugins/solidigm/solidigm-telemetry/data-area.c472
-rw-r--r--plugins/solidigm/solidigm-telemetry/data-area.h10
-rw-r--r--plugins/solidigm/solidigm-telemetry/header.c223
-rw-r--r--plugins/solidigm/solidigm-telemetry/header.h9
-rw-r--r--plugins/solidigm/solidigm-telemetry/meson.build7
-rw-r--r--plugins/solidigm/solidigm-telemetry/nlog.c131
-rw-r--r--plugins/solidigm/solidigm-telemetry/nlog.h11
-rw-r--r--plugins/solidigm/solidigm-telemetry/telemetry-log.h31
-rw-r--r--plugins/solidigm/solidigm-temp-stats.c108
-rw-r--r--plugins/solidigm/solidigm-temp-stats.h8
-rw-r--r--plugins/solidigm/solidigm-util.c20
-rw-r--r--plugins/solidigm/solidigm-util.h12
-rw-r--r--plugins/toshiba/toshiba-nvme.c573
-rw-r--r--plugins/toshiba/toshiba-nvme.h21
-rw-r--r--plugins/transcend/transcend-nvme.c86
-rw-r--r--plugins/transcend/transcend-nvme.h21
-rw-r--r--plugins/virtium/virtium-nvme.c1051
-rw-r--r--plugins/virtium/virtium-nvme.h22
-rw-r--r--plugins/wdc/wdc-nvme.c12486
-rw-r--r--plugins/wdc/wdc-nvme.h91
-rw-r--r--plugins/wdc/wdc-utils.c196
-rw-r--r--plugins/wdc/wdc-utils.h81
-rw-r--r--plugins/ymtc/ymtc-nvme.c161
-rw-r--r--plugins/ymtc/ymtc-nvme.h25
-rw-r--r--plugins/ymtc/ymtc-utils.h81
-rw-r--r--plugins/zns/zns.c1274
-rw-r--r--plugins/zns/zns.h32
-rwxr-xr-xscripts/build.sh230
-rw-r--r--scripts/gen-hostnqn.sh4
-rwxr-xr-xscripts/latency115
-rwxr-xr-xscripts/meson-vcs-tag.sh17
-rwxr-xr-xscripts/regress113
-rwxr-xr-xscripts/release.sh132
-rwxr-xr-xscripts/update-docs.sh17
-rw-r--r--subprojects/json-c.wrap13
-rw-r--r--subprojects/libnvme.wrap7
-rw-r--r--tests/README98
-rw-r--r--tests/TODO14
-rw-r--r--tests/config.json5
-rw-r--r--tests/meson.build99
-rw-r--r--tests/nvme_attach_detach_ns_test.py92
-rw-r--r--tests/nvme_compare_test.py80
-rw-r--r--tests/nvme_copy_test.py113
-rw-r--r--tests/nvme_create_max_ns_test.py100
-rw-r--r--tests/nvme_ctrl_reset_test.py48
-rw-r--r--tests/nvme_dsm_test.py56
-rw-r--r--tests/nvme_error_log_test.py64
-rw-r--r--tests/nvme_flush_test.py62
-rw-r--r--tests/nvme_format_test.py150
-rw-r--r--tests/nvme_fw_log_test.py73
-rw-r--r--tests/nvme_get_features_test.py108
-rw-r--r--tests/nvme_get_lba_status_test.py70
-rw-r--r--tests/nvme_id_ctrl_test.py56
-rw-r--r--tests/nvme_id_ns_test.py90
-rw-r--r--tests/nvme_lba_status_log_test.py59
-rw-r--r--tests/nvme_read_write_test.py75
-rw-r--r--tests/nvme_simple_template_test.py57
-rw-r--r--tests/nvme_smart_log_test.py89
-rw-r--r--tests/nvme_test.py504
-rw-r--r--tests/nvme_test_io.py98
-rw-r--r--tests/nvme_test_logger.py55
-rw-r--r--tests/nvme_verify_test.py55
-rw-r--r--tests/nvme_writeuncor_test.py77
-rw-r--r--tests/nvme_writezeros_test.py105
-rw-r--r--tests/run_py_linters.py123
-rw-r--r--unit/meson.build46
-rw-r--r--unit/test-argconfig-parse.c164
-rw-r--r--unit/test-suffix-binary-parse.c68
-rw-r--r--unit/test-suffix-si-parse.c83
-rw-r--r--unit/test-uint128-si.c66
-rw-r--r--unit/test-uint128.c74
-rw-r--r--util/argconfig.c589
-rw-r--r--util/argconfig.h189
-rw-r--r--util/base64.c107
-rw-r--r--util/base64.h8
-rw-r--r--util/cleanup.h37
-rw-r--r--util/crc32.c100
-rw-r--r--util/crc32.h11
-rw-r--r--util/json.c74
-rw-r--r--util/json.h61
-rw-r--r--util/mem.c109
-rw-r--r--util/mem.h20
-rw-r--r--util/meson.build16
-rw-r--r--util/suffix.c266
-rw-r--r--util/suffix.h45
-rw-r--r--util/types.c204
-rw-r--r--util/types.h60
891 files changed, 296678 insertions, 0 deletions
diff --git a/.github/AppImageBuilder.yml b/.github/AppImageBuilder.yml
new file mode 100644
index 0000000..cce4689
--- /dev/null
+++ b/.github/AppImageBuilder.yml
@@ -0,0 +1,57 @@
+# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
+version: 1
+script:
+ # Ensure that the mksquashfs tool is installed (workaround for the AppImageCrafters/build-appimage GHA)
+ - which mksquashfs || apt install squashfs-tools
+ # fake icons
+ - mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps
+ - touch AppDir/usr/share/icons/hicolor/64x64/apps/nvme-cli.png
+
+AppDir:
+ path: AppDir
+ app_info:
+ id: linux-nvme.nvme-cli
+ name: nvme-cli
+ version: latest
+ icon: nvme-cli
+ exec: usr/sbin/nvme
+ exec_args: $@
+ apt:
+ arch: amd64
+ allow_unauthenticated: true
+ sources:
+ - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse
+ key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C'
+ - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-updates main restricted universe multiverse
+ - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-backports main restricted universe multiverse
+ - sourceline: deb http://archive.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse
+ include:
+ - libjson-c5
+ - libssl3
+ files:
+ include:
+ - libcrypt.so.3
+ - libdbus-1.so.3
+ - libjson-c.so.5
+ exclude:
+ - usr/share/man
+ - usr/share/doc
+ test:
+ fedora-30:
+ image: appimagecrafters/tests-env:fedora-30
+ command: ./AppRun
+ debian-stable:
+ image: appimagecrafters/tests-env:debian-stable
+ command: ./AppRun
+ archlinux-latest:
+ image: appimagecrafters/tests-env:archlinux-latest
+ command: ./AppRun
+ centos-7:
+ image: appimagecrafters/tests-env:centos-7
+ command: ./AppRun
+ ubuntu-xenial:
+ image: appimagecrafters/tests-env:ubuntu-xenial
+ command: ./AppRun
+AppImage:
+ update-information: 'gh-releases-zsync|linux-nvme|nvme-cli|latest|*x86_64.AppImage.zsync'
+ arch: x86_64
diff --git a/.github/azure-pipelines.yml b/.github/azure-pipelines.yml
new file mode 100644
index 0000000..f9eb5ed
--- /dev/null
+++ b/.github/azure-pipelines.yml
@@ -0,0 +1,38 @@
+---
+# Do not run following tests
+# - exclude data varification tests, too slow
+# - nvme/010
+# - nvme/011
+# - nvme/012
+# - nvme/013
+
+trigger:
+ - master
+pr:
+ - master
+
+jobs:
+ - job: blktests
+ timeoutInMinutes: 5
+ pool:
+ name: linux-nvme
+ steps:
+ - script: |
+ meson $(Agent.TempDirectory)/build
+ ninja -C $(Agent.TempDirectory)/build
+ displayName: Build nvme-cli
+ - script: |
+ git clone --depth 1 https://github.com/osandov/blktests.git $(Agent.TempDirectory)/blktests
+ displayName: Clone blktests
+ - script: |
+ cd $(Agent.TempDirectory)/blktests
+ sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=tcp ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme'
+ displayName: Run blktests for NVMe transport TCP
+ - script: |
+ cd $(Agent.TempDirectory)/blktests
+ sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=rdma ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme'
+ displayName: Run blktests for NVMe transport RDMA
+ - script: |
+ cd $(Agent.TempDirectory)/blktests
+ sudo sh -c 'PATH=$(Agent.TempDirectory)/build:$PATH nvme_trtype=fc ./check -x nvme/010 -x nvme/011 -x nvme/012 -x nvme/013 nvme'
+ displayName: Run blktests for NVMe transport FC
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
new file mode 100644
index 0000000..d9079fd
--- /dev/null
+++ b/.github/codeql/codeql-config.yml
@@ -0,0 +1,3 @@
+name: "CodeQL Config"
+paths-ignore:
+ - subprojects/**
diff --git a/.github/cross/ubuntu-cross-armhf.txt b/.github/cross/ubuntu-cross-armhf.txt
new file mode 100644
index 0000000..41c8328
--- /dev/null
+++ b/.github/cross/ubuntu-cross-armhf.txt
@@ -0,0 +1,18 @@
+[binaries]
+c = '/usr/bin/arm-linux-gnueabihf-gcc'
+ar = '/usr/arm-linux-gnueabihf/bin/ar'
+strip = '/usr/arm-linux-gnueabihf/bin/strip'
+pkgconfig = '/usr/bin/arm-linux-gnueabihf-pkg-config'
+ld = '/usr/bin/arm-linux/gnueabihf-ld'
+exe_wrapper = '/usr/bin/qemu-arm-static'
+
+[properties]
+root = '/usr/arm-linux-gnueabihf'
+has_function_printf = true
+skip_sanity_check = true
+
+[host_machine]
+system = 'linux'
+cpu_family = 'arm'
+cpu = 'armv7'
+endian = 'little'
diff --git a/.github/cross/ubuntu-cross-ppc64le.txt b/.github/cross/ubuntu-cross-ppc64le.txt
new file mode 100644
index 0000000..6baaefb
--- /dev/null
+++ b/.github/cross/ubuntu-cross-ppc64le.txt
@@ -0,0 +1,18 @@
+[binaries]
+c = '/usr/bin/powerpc64le-linux-gnu-gcc'
+ar = '/usr/powerpc64le-linux-gnu/bin/ar'
+strip = '/usr/powerpc64le-linux-gnu/bin/strip'
+pkgconfig = '/usr/bin/powerpc64le-linux-gnu-pkg-config'
+ld = '/usr/bin/powerpc64le-linux-gnu-ld'
+exe_wrapper = '/usr/bin/qemu-ppc64le-static'
+
+[properties]
+root = '/usr/powerpc64le-linux-gnu'
+has_function_printf = true
+skip_sanity_check = true
+
+[host_machine]
+system = 'linux'
+cpu_family = 'ppc64'
+cpu = ''
+endian = 'little'
diff --git a/.github/cross/ubuntu-cross-s390x.txt b/.github/cross/ubuntu-cross-s390x.txt
new file mode 100644
index 0000000..51a3511
--- /dev/null
+++ b/.github/cross/ubuntu-cross-s390x.txt
@@ -0,0 +1,18 @@
+[binaries]
+c = '/usr/bin/s390x-linux-gnu-gcc'
+ar = '/usr/s390x-linux-gnu/bin/ar'
+strip = '/usr/s390x-linux-gnu/bin/strip'
+pkgconfig = '/usr/bin/s390x-linux-gnu-pkg-config'
+ld = '/usr/bin/s390x-linux-gnu-ld'
+exe_wrapper = '/usr/bin/qemu-s390x-static'
+
+[properties]
+root = '/usr/s390x-linux-gnu'
+has_function_printf = true
+skip_sanity_check = true
+
+[host_machine]
+system = 'linux'
+cpu_family = 's390x'
+cpu = ''
+endian = 'big'
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..23c4cb3
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,7 @@
+---
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml
new file mode 100644
index 0000000..6c0d3e5
--- /dev/null
+++ b/.github/workflows/appimage.yml
@@ -0,0 +1,56 @@
+---
+name: appimage
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+env:
+ DESTDIR: ../AppDir
+
+jobs:
+ build-appimage:
+ name: build AppImage
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh appimage
+ - name: build AppImage
+ uses: AppImageCrafters/build-appimage@v1.3
+ with:
+ recipe: .github/AppImageBuilder.yml
+ - uses: actions/upload-artifact@v4
+ name: upload artifacts to github
+ with:
+ name: AppImage
+ path: '*.AppImage*'
+
+ deploy-appimage:
+ name: deploy AppImage
+ runs-on: ubuntu-latest
+ needs: build-appimage
+ if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'linux-nvme/nvme-cli' }}
+ steps:
+ - name: Download artifact
+ uses: dawidd6/action-download-artifact@v3
+ with:
+ workflow: ${{ github.event.workflow_run.workflow_id }}
+ workflow_conclusion: success
+ - name: FTP Deployer
+ uses: sand4rt/ftp-deployer@v1.7
+ with:
+ sftp: true
+ host: ${{ secrets.SFTP_SERVER }}
+ port: 22
+ username: ${{ secrets.SFTP_USERNAME }}
+ password: ${{ secrets.SFTP_PASSWORD }}
+ remote_folder: '/upload'
+ local_folder: '.'
+ cleanup: false
+ include: '[ "*", "**/*" ]'
+ exclude: '[".github/**", ".git/**", "*.env"]'
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..0b12517
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,101 @@
+---
+name: build
+
+on:
+ push:
+ branches: [master]
+ pull_request:
+ branches: [master]
+
+ workflow_dispatch:
+
+jobs:
+ default:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ compiler: [gcc, clang]
+ buildtype: [debug, release]
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian.python:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh -b ${{ matrix.buildtype }} -c ${{ matrix.compiler }}
+ - uses: actions/upload-artifact@v4
+ name: upload logs
+ if: failure()
+ with:
+ name: logs files
+ path: |
+ .build-ci/meson-logs/*.txt
+
+ cross:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ include:
+ - arch: armhf
+ - arch: s390x
+ - arch: ppc64le
+ steps:
+ - uses: actions/checkout@v4
+ - name: enable foreign arch
+ uses: dbhi/qus/action@main
+ - name: compile and run unit tests
+ uses: mosteo-actions/docker-run@v1
+ with:
+ image: ghcr.io/igaw/linux-nvme/ubuntu-cross-${{ matrix.arch }}:latest
+ guest-dir: /build
+ host-dir: ${{ github.workspace }}
+ command: |
+ scripts/build.sh -b release -c gcc -t ${{ matrix.arch }} cross
+ params: "--platform linux/amd64"
+ pull-params: "--platform linux/amd64"
+ - uses: actions/upload-artifact@v4
+ name: upload logs
+ if: failure()
+ with:
+ name: log files
+ path: |
+ .build-ci/meson-logs/*.txt
+
+ fallback-shared-libraries:
+ name: fallback shared libraries
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian:latest
+ if: github.ref == 'refs/heads/master'
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh -b release -c gcc fallback
+ - uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: log files
+ path: |
+ .build-ci/meson-logs/*.txt
+
+ build-muon:
+ name: muon minimal static
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh -m muon
+ build-make-static:
+ name: make static
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ make static
diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml
new file mode 100644
index 0000000..c0a09b7
--- /dev/null
+++ b/.github/workflows/checkpatch.yml
@@ -0,0 +1,15 @@
+name: checkpatch review
+on: [pull_request]
+jobs:
+ checkpatch:
+ name: checkpatch review
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Calculate PR commits + 1'
+ run: echo "PR_FETCH_DEPTH=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> $GITHUB_ENV
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+ - name: Run checkpatch review
+ uses: webispy/checkpatch-action@v9
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..d57e17a
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,71 @@
+# CodeQL build configuration for nvme-cli
+# Mostly based on auto-configuration with additions and tweaks for:
+# * meson install
+# * language detection
+name: "CodeQL"
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [ "master" ]
+ schedule:
+ - cron: '24 2 * * 5'
+
+jobs:
+ analyze:
+ name: Analyze
+ # Runner size impacts CodeQL analysis time. To learn more, please see:
+ # - https://gh.io/recommended-hardware-resources-for-running-codeql
+ # - https://gh.io/supported-runners-and-hardware-resources
+ # - https://gh.io/using-larger-runners
+ # Consider using larger runners for possible analysis time improvements.
+ runs-on: 'ubuntu-latest'
+ timeout-minutes: 360
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: [ 'c-cpp', 'python' ]
+ # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
+ # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
+ # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
+ # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Install build tools
+ run: |
+ sudo apt-get update
+ sudo apt-get install meson
+
+ # Initializes the CodeQL tools for scanning.
+ - if: matrix.language == 'c-cpp'
+ name: Initialize CodeQL C
+ uses: github/codeql-action/init@v3
+ with:
+ languages: 'c-cpp'
+
+ - if: matrix.language == 'python'
+ name: Initialize CodeQL Python
+ uses: github/codeql-action/init@v3
+ with:
+ languages: 'python'
+ config-file: ./.github/codeql/codeql-config.yml
+
+ - name: meson build
+ run: |
+ meson setup --force-fallback-for=libnvme,json-c .build
+ ninja -C .build
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
new file mode 100644
index 0000000..875ed6d
--- /dev/null
+++ b/.github/workflows/coverage.yml
@@ -0,0 +1,22 @@
+---
+name: coverage
+
+on:
+ push:
+ branches: [master]
+
+jobs:
+ code-coverage:
+ if: github.repository == 'linux-nvme/nvme-cli'
+ name: code coverage
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/igaw/linux-nvme/debian.python:latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: build
+ run: |
+ scripts/build.sh coverage
+ - uses: codecov/codecov-action@v4
+ with:
+ fail_ci_if_error: false
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..8a5651c
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,20 @@
+---
+name: release
+
+on:
+ push:
+ branches: [ master ]
+ tags:
+ - '**'
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ if: startsWith(github.ref, 'refs/tags/v') && github.repository == 'linux-nvme/nvme-cli'
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v4
+ - uses: ncipollo/release-action@v1
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..da4804c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+nvme
+*.xml
+a.out
+*.o
+*~
+*.swp
+nvme-*.tar.gz
+
+subprojects/*
+!subprojects/*.wrap
+
+cscope.*
+compile_commands.json
+
+tests/__pycache__
+tests/nvmetests
+tests/*.pyc
+
+.build
+.cache
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitmodules
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..b506f85
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1 @@
+Vigneshwaran Saravanan <s.vignesh@samsung.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..cde8527
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,24 @@
+# Contributing to the NVM-e CLI
+
+Here you will find instructions on how to contribute to the NVM-Express command
+line interface.
+
+Contributions and new ideas are most welcome!
+
+**NOTE: If you do decide to implement code changes and contribute them,
+please make sure you agree your contribution can be made available
+under the [GPLv2-style License used for the NVMe CLI](https://github.com/linux-nvme/nvme-cli/blob/master/LICENSE).
+(SPDX-License-Identifier: GPL-2.0-or-later)**
+
+Because there are a few files licensed under GPL-2.0-only, the whole
+project is tagged as GPL-2.0-only and not as GPL-2.0-or-later.
+
+### Code Contributions
+
+Please feel free to use the github forums to ask for comments & questions on
+your code before submitting a pull request. The NVMe CLI project uses the
+common *fork and merge* workflow used by most GitHub-hosted projects.
+
+### Bug Reports
+
+Bugs for the NVM Library project are tracked in our [GitHub Issues Database](https://github.com/linux-nvme/nvme-cli/issues).
diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf
new file mode 100644
index 0000000..f8a6e93
--- /dev/null
+++ b/Documentation/asciidoc.conf
@@ -0,0 +1,91 @@
+## linknvme: macro
+#
+# Usage: linknvme:command[manpage-section]
+#
+# Note, {0} is the manpage section, while {target} is the command.
+#
+# Show Git link as: <command>(<section>); if section is defined, else just show
+# the command.
+
+[macros]
+(?su)[\\]?(?P<name>linknvme):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+[attributes]
+asterisk=&#42;
+plus=&#43;
+caret=&#94;
+startsb=&#91;
+endsb=&#93;
+backslash=&#92;
+tilde=&#126;
+apostrophe=&#39;
+backtick=&#96;
+litdd=&#45;&#45;
+
+ifdef::backend-docbook[]
+[linknvme-inlinemacro]
+{0%{target}}
+{0#<citerefentry>}
+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+{0#</citerefentry>}
+endif::backend-docbook[]
+
+ifdef::backend-docbook[]
+ifndef::git-asciidoc-no-roff[]
+# "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
+# v1.72 breaks with this because it replaces dots not in roff requests.
+[listingblock]
+<example><title>{title}</title>
+<literallayout class="monospaced">
+|
+</literallayout>
+{title#}</example>
+endif::git-asciidoc-no-roff[]
+
+ifdef::git-asciidoc-no-roff[]
+ifdef::doctype-manpage[]
+# The following two small workarounds insert a simple paragraph after screen
+[listingblock]
+<example><title>{title}</title>
+<literallayout class="monospaced">
+|
+</literallayout><simpara></simpara>
+{title#}</example>
+
+[verseblock]
+<formalpara{id? id="{id}"}><title>{title}</title><para>
+{title%}<literallayout{id? id="{id}"}>
+{title#}<literallayout>
+|
+</literallayout>
+{title#}</para></formalpara>
+{title%}<simpara></simpara>
+endif::doctype-manpage[]
+endif::git-asciidoc-no-roff[]
+endif::backend-docbook[]
+
+ifdef::doctype-manpage[]
+ifdef::backend-docbook[]
+[header]
+template::[header-declarations]
+<refentry>
+<refmeta>
+<refentrytitle>{mantitle}</refentrytitle>
+<manvolnum>{manvolnum}</manvolnum>
+<refmiscinfo class="source">NVMe</refmiscinfo>
+<refmiscinfo class="version">{nvme_version}</refmiscinfo>
+<refmiscinfo class="manual">NVMe Manual</refmiscinfo>
+</refmeta>
+<refnamediv>
+ <refname>{manname}</refname>
+ <refpurpose>{manpurpose}</refpurpose>
+</refnamediv>
+endif::backend-docbook[]
+endif::doctype-manpage[]
+
+ifdef::backend-xhtml11[]
+[attributes]
+git-relative-html-prefix=
+[linknvme-inlinemacro]
+<a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
+endif::backend-xhtml11[]
diff --git a/Documentation/asciidoctor-extensions.rb b/Documentation/asciidoctor-extensions.rb
new file mode 100644
index 0000000..8948e11
--- /dev/null
+++ b/Documentation/asciidoctor-extensions.rb
@@ -0,0 +1,29 @@
+require 'asciidoctor'
+require 'asciidoctor/extensions'
+
+module Nvme
+ module Documentation
+ class LinkNvmeProcessor < Asciidoctor::Extensions::InlineMacroProcessor
+ use_dsl
+
+ named :chrome
+
+ def process(parent, target, attrs)
+ if parent.document.basebackend? 'html'
+ %(<a href="#{target}.html">#{target}(#{attrs[1]})</a>\n)
+ elsif parent.document.basebackend? 'manpage'
+ "#{target}(#{attrs[1]})"
+ elsif parent.document.basebackend? 'docbook'
+ "<citerefentry>\n" \
+ "<refentrytitle>#{target}</refentrytitle>" \
+ "<manvolnum>#{attrs[1]}</manvolnum>\n" \
+ "</citerefentry>\n"
+ end
+ end
+ end
+ end
+end
+
+Asciidoctor::Extensions.register do
+ inline_macro Nvme::Documentation::LinkNvmeProcessor, :linknvme
+end
diff --git a/Documentation/cmd-plugins.txt b/Documentation/cmd-plugins.txt
new file mode 100644
index 0000000..f767603
--- /dev/null
+++ b/Documentation/cmd-plugins.txt
@@ -0,0 +1,203 @@
+linknvme:nvme-intel-id-ctrl[1]::
+ Intel - NVMe Identify Controller
+
+linknvme:nvme-intel-internal-log[1]::
+ Retrieve Intel device's internal log and save to file
+
+linknvme:nvme-intel-lat-stats[1]::
+ Retrieve NVMe Identify Controller, return result and structure
+
+linknvme:nvme-intel-market-name[1]::
+ Intel vendor specific marketing name log page
+
+linknvme:nvme-intel-smart-log-add[1]::
+ NVMe Intel Additional SMART log page
+
+linknvme:nvme-intel-temp-stats[1]::
+ NVMe Intel Additional SMART log page for temp stats
+
+linknvme:nvme-huawei-id-ctrl[1]::
+ NVMe huawei Identify Controller
+
+linknvme:nvme-huawei-list[1]::
+ List all recognized Huawei NVMe devices
+
+linknvme:nvme-dera-stat[1]::
+ NVMe Dera Device status and Additional SMART log page request
+
+linknvme:nvme-micron-clear-pcie-errors[1]::
+ Clears correctable PCIe correctable errors of given Micron device
+
+linknvme:nvme-micron-internal-log[1]::
+ Retrieve Micron device's internal logs and save to given zip file
+
+linknvme:nvme-micron-nand-stats[1]::
+ Retrieves NAND statistics of given micron device
+
+linknvme:nvme-micron-pcie-stats[1]::
+ Retrieves pcie error statistics for given micron device
+
+linknvme:nvme-micron-selective-download[1]::
+ Performs selective firmware download
+
+linknvme:nvme-micron-smart-add-log[1]::
+ Retrieves NAND statistics
+
+linknvme:nvme-micron-temperature-stats[1]::
+ Retrieves temperature information of given micron device
+
+linknvme:nvme-netapp-ontapdevices[1]::
+ Display information about ONTAP devices
+
+linknvme:nvme-netapp-smdevices[1]::
+ Display information for each NVMe path to an E-Series volume
+
+linknvme:nvme-toshiba-clear-pcie-correctable-errors[1]::
+ Reset the PCIe correctable errors count to zero
+
+linknvme:nvme-toshiba-vs-internal-log[1]::
+ Retrieve a Toshiba device's vendor specific internal log
+
+linknvme:nvme-toshiba-vs-smart-add-log[1]::
+ Retrieve a Toshiba device's vendor specific extended SMART log page
+
+linknvme:nvme-transcend-badblock[1]::
+ Retrieve Transcend NVMe device's bad blocks
+
+linknvme:nvme-transcend-healthvalue[1]::
+ Use NVMe SMART table to analyze the health value of Transcend device
+
+linknvme:nvme-virtium-show-identify[1]::
+ Show a complete detail of identify device information in json format
+
+linknvme:nvme-virtium-save-smart-to-vtview-log[1]::
+ Periodically save smart attributes into a log file
+
+linknvme:nvme-wdc-cap-diag[1]::
+ Retrieve WDC device's diagnostic log and save to file
+
+linknvme:nvme-wdc-capabilities[1]::
+ Display WDC plugin command capabilities
+
+linknvme:nvme-wdc-clear-assert-dump[1]::
+ Clears the assert dump (if present)
+
+linknvme:nvme-wdc-clear-fw-activate-history[1]::
+ Clears the firmware activate history table
+
+linknvme:nvme-wdc-clear-pcie-corr[1]::
+ Clears the pcie correctable errors field
+
+linknvme:nvme-wdc-clear-pcie-correctable-errors[1]::
+ Clears the pcie correctable errors returned in the smart-log-add command
+
+linknvme:nvme-wdc-cloud-SSD-plugin-version[1]::
+ Display WDC plugin Cloud SSD Plugin Version
+
+linknvme:nvme-wdc-drive-essentials[1]::
+ Retrieve WDC device's drive essentials bin files
+
+linknvme:nvme-wdc-drive-log[1]::
+ Retrieve WDC device's drive log and save to file
+
+linknvme:nvme-wdc-drive-resize[1]::
+ Send NVMe WDC Resize Vendor Unique Command
+
+linknvme:nvme-wdc-enc-get-log[1]::
+ Send NVMe WDC enc-get-log Vendor Unique Command
+
+linknvme:nvme-wdc-get-crash-dump[1]::
+ Retrieve WDC device's crash dump
+
+linknvme:nvme-wdc-get-drive-status[1]::
+ Send the NVMe WDC get-drive-status command
+
+linknvme:nvme-wdc-get-latency-monitor-log[1]::
+ Display latency monitor log page data in human readable format
+
+linknvme:nvme-wdc-get-pfail-dump[1]::
+ Retrieve WDC device's pfail crash dump
+
+linknvme:nvme-wdc-id-ctrl[1]::
+ Send NVMe Identify Controller, return result and structure
+
+linknvme:nvme-wdc-log-page-directory[1]::
+ Retrieves the list of Log IDs supported by the drive
+
+linknvme:nvme-wdc-namespace-resize[1]::
+ Resizes the device's namespace
+
+linknvme:nvme-wdc-purge-monitor[1]::
+ Send NVMe WDC Purge-Monitor Vendor Unique Command
+
+linknvme:nvme-wdc-purge[1]::
+ Send NVMe WDC Purge Vendor Unique Command
+
+linknvme:nvme-wdc-smart-add-log[1]::
+ Send NVMe WDC smart add log Vendor Unique Command
+
+linknvme:nvme-wdc-vs-drive-info[1]::
+ Send the NVMe WDC vs-drive-info command
+
+linknvme:nvme-wdc-vs-error-reason-identifier[1]::
+ Retrieve WDC device's telemetry log error reason identifier field
+
+linknvme:nvme-wdc-vs-fw-activate-history[1]::
+ Execute NVMe WDC vs-fw-activate-history Vendor Unique Command
+
+linknvme:nvme-wdc-vs-internal-log[1]::
+ Retrieve WDC device's internal firmware log and save to file
+
+linknvme:nvme-wdc-vs-nand-stats[1]::
+ Send NVMe WDC vs-nand-stats Vendor Unique Command
+
+linknvme:nvme-wdc-vs-telemetry-controller-option[1]::
+ Disable/Enable the controller initiated option of the telemetry log page
+
+linknvme:nvme-wdc-vs-temperature-stats[1]::
+ Display temperature-related statistics
+
+linknvme:nvme-zns-changed-zone-list[1]::
+ Retrieve Changed Zone log for the given device
+
+linknvme:nvme-zns-close-zone[1]::
+ Closes one or all zones
+
+linknvme:nvme-zns-finish-zone[1]::
+ Finishes one or all zones
+
+linknvme:nvme-zns-id-ctrl[1]::
+ Send NVMe Zoned Command Set Identify Controller
+
+linknvme:nvme-zns-id-ns[1]::
+ Send NVMe Zoned Command Set Identify Namespace
+
+linknvme:nvme-zns-offline-zone[1]::
+ Offlines one or all zones
+
+linknvme:nvme-zns-open-zone[1]::
+ Opens one or all zones
+
+linknvme:nvme-zns-report-zones[1]::
+ Retrieve and display the Report Zones data structure
+
+linknvme:nvme-zns-reset-zone[1]::
+ Resets one or all zones
+
+linknvme:nvme-zns-set-zone-desc[1]::
+ Set extended descriptor data for a zone
+
+linknvme:nvme-zns-zone-append[1]::
+ Send an NVMe write command, provide results
+
+linknvme:nvme-zns-zone-mgmt-recv[1]::
+ Zone Management Receive command
+
+linknvme:nvme-zns-zone-mgmt-send[1]::
+ Zone Management Send command
+
+linknvme:nvme-zns-zrwa-flush-zone[1]::
+ Flush LBAs associated with a ZRWA to a zone
+
+linknvme:nvme-inspur-nvme-vendor-log[1]::
+ NVMe Inspur Device Vendor log page request
diff --git a/Documentation/cmds-main.txt b/Documentation/cmds-main.txt
new file mode 100644
index 0000000..14a6ff6
--- /dev/null
+++ b/Documentation/cmds-main.txt
@@ -0,0 +1,275 @@
+linknvme:nvme-admin-passthru[1]::
+ Admin Passthrough Command
+
+linknvme:nvme-compare[1]::
+ IO Compare
+
+linknvme:nvme-error-log[1]::
+ Retrieve error logs
+
+linknvme:nvme-flush[1]::
+ Submit flush
+
+linknvme:nvme-dsm[1]::
+ Submit Data Set Management
+
+linknvme:nvme-format[1]::
+ Format namespace(s)
+
+linknvme:nvme-fw-activate[1]::
+ 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
+
+linknvme:nvme-fw-log[1]::
+ Retrieve f/w log
+
+linknvme:nvme-get-feature[1]::
+ Get Features
+
+linknvme:nvme-get-log[1]::
+ Generic Get Log
+
+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]::
+ Retrieve 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
+
+linknvme:nvme-help[1]::
+ NVMe CLI Help
+
+linknvme:nvme-id-ctrl[1]::
+ Identify Controller
+
+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
+
+linknvme:nvme-delete-ns[1]::
+ Delete existing namespace
+
+linknvme:nvme-attach-ns[1]::
+ Attach namespace
+
+linknvme:nvme-detach-ns[1]::
+ Detach namespace
+
+linknvme:nvme-io-passthru[1]::
+ IO Passthrough Command
+
+linknvme:nvme-list-ns[1]::
+ List all nvme namespaces
+
+linknvme:nvme-ns-descs[1]::
+ Identify Namespace Identification Descriptor
+
+linknvme:nvme-list[1]::
+ List all nvme controllers
+
+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
+
+linknvme:nvme-write[1]::
+ Issue IO Write Command
+
+linknvme:nvme-write-zeroes[1]::
+ Issue IO Write Zeroes Command
+
+linknvme:nvme-write-uncor[1]::
+ Issue IO Write Uncorrectable Command
+
+linknvme:nvme-resv-acquire[1]::
+ Acquire Namespace Reservation
+
+linknvme:nvme-resv-register[1]::
+ Register Namespace Reservation
+
+linknvme:nvme-resv-release[1]::
+ Release Namespace Reservation
+
+linknvme:nvme-resv-report[1]::
+ Report Reservation Capabilities
+
+linknvme:nvme-security-recv[1]::
+ Security Receive
+
+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
+
+linknvme:nvme-show-regs[1]::
+ Show NVMe Controller Registers
+
+linknvme:nvme-discover[1]::
+ Send Get Log Page request to Discovery Controller
+
+linknvme:nvme-connect-all[1]::
+ Discover and connect to all NVMe-over-Fabrics subsystems
+
+linknvme:nvme-connect[1]::
+ Connect to an NVMe-over-Fabrics subsystem
+
+linknvme:nvme-dim[1]::
+ Send Discovery Information Management command to a Discovery Controller
+
+linknvme:nvme-disconnect[1]::
+ Disconnect from an NVMe-over-Fabrics subsystem
+
+linknvme:nvme-disconnect-all[1]::
+ Disconnect from all NVMe-over-Fabrics subsystems
+
+linknvme:nvme-get-property[1]::
+ Reads and shows NVMe-over-Fabrics controller property
+
+linknvme:nvme-media-unit-stat-log[1]::
+ Retrieve and show the configuration and wear of media units
+
+linknvme:nvme-supported-cap-config-log[1]::
+ Retrieve and show the list of Supported Capacity Configuration Descriptors
+
+linknvme:nvme-boot-part-log[1]::
+ Retrieve Boot Partition Log
+
+linknvme:nvme-capacity-mgmt[1]::
+ Capacity Management Command
+
+linknvme:nvme-check-dhchap-key[1]::
+ Generate NVMeoF DH-HMAC-CHAP host key
+
+linknvme:nvme-check-tls-key[1]::
+ Validate NVMeoF TLS PSK
+
+linknvme:nvme-cmdset-ind-id-ns[1]::
+ I/O Command Set Independent Identify Namespace
+
+linknvme:nvme-endurance-event-agg-log[1]::
+ Retrieve Endurance Group Event Aggregate Log
+
+linknvme:nvme-fid-support-effects-log[1]::
+ Retrieve FID Support and Effects log
+
+linknvme:nvme-gen-dhchap-key[1]::
+ Generate NVMeoF DH-HMAC-CHAP host key
+
+linknvme:nvme-gen-hostnqn[1]::
+ Generate NVMeoF host NQN
+
+linknvme:nvme-gen-tls-key[1]::
+ Generate NVMeoF TLS PSK
+
+linknvme:nvme-get-lba-status[1]::
+ Get LBA Status command
+
+linknvme:nvme-id-domain[1]::
+ NVMe Identify Domain List
+
+linknvme:nvme-id-ns-lba-format[1]::
+ NVMe Identify Namespace for the specified LBA Format index
+
+linknvme:nvme-lba-status-log[1]::
+ Retrieve LBA Status Information Log
+
+linknvme:nvme-list-endgrp[1]::
+ NVMe Identify Endurance Group List
+
+linknvme:nvme-ns-rescan[1]::
+ Rescans the NVME namespaces
+
+linknvme:nvme-nvm-id-ctrl[1]::
+ NVMe Identify Controller NVM Command Set
+
+linknvme:nvme-nvm-id-ns[1]::
+ NVMe Identify Namespace NVM Command Set
+
+linknvme:nvme-nvm-id-ns-lba-format[1]::
+ NVMe Identify Namespace NVM Command Set for the specified LBA Format index
+
+linknvme:nvme-persistent-event-log[1]::
+ Retrieve Persistent Event Log
+
+linknvme:nvme-predictable-lat-log[1]::
+ Retrieve Predictable Latency per Nvmset Log
+
+linknvme:nvme-pred-lat-event-agg-log[1]::
+ Retrieve Predictable Latency Event Aggregate Log
+
+linknvme:nvme-primary-ctrl-caps[1]::
+ NVMe Identify Primary Controller Capabilities
+
+linknvme:nvme-reset[1]::
+ Resets the controller
+
+linknvme:nvme-rpmb[1]::
+ Replay Protection Memory Block commands
+
+linknvme:nvme-sanitize-log[1]::
+ Retrieve sanitize log
+
+linknvme:nvme-set-property[1]::
+ Set a property and show the resulting value
+
+linknvme:nvme-show-hostnqn[1]::
+ Show NVMeoF host NQN
+
+linknvme:nvme-subsystem-reset[1]::
+ Resets the subsystem
+
+linknvme:nvme-supported-log-pages[1]::
+ Retrieve the Supported Log pages details
+
+linknvme:nvme-verify[1]::
+ verify command
+
+linknvme:nvme-show-topology[1]::
+ Show NVMe topology
diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh
new file mode 100755
index 0000000..ed8b4ff
--- /dev/null
+++ b/Documentation/install-webdoc.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+T="$1"
+
+for h in \
+ *.txt *.html \
+ howto/*.txt howto/*.html \
+ technical/*.txt technical/*.html \
+ RelNotes/*.txt *.css
+do
+ if test ! -f "$h"
+ then
+ : did not match
+ elif test -f "$T/$h" &&
+ $DIFF -u -I'^Last updated ' "$T/$h" "$h"
+ then
+ :; # up to date
+ else
+ echo >&2 "# install $h $T/$h"
+ rm -f "$T/$h"
+ mkdir -p $(dirname "$T/$h")
+ cp "$h" "$T/$h"
+ fi
+done
+strip_leading=$(echo "$T/" | sed -e 's|.|.|g')
+for th in \
+ "$T"/*.html "$T"/*.txt \
+ "$T"/howto/*.txt "$T"/howto/*.html \
+ "$T"/technical/*.txt "$T"/technical/*.html
+do
+ h=$(expr "$th" : "$strip_leading"'\(.*\)')
+ case "$h" in
+ RelNotes-*.txt | index.html) continue ;;
+ esac
+ test -f "$h" && continue
+ echo >&2 "# rm -f $th"
+ rm -f "$th"
+done
+ln -sf git.html "$T/index.html"
diff --git a/Documentation/manpage-base.xsl b/Documentation/manpage-base.xsl
new file mode 100644
index 0000000..023c417
--- /dev/null
+++ b/Documentation/manpage-base.xsl
@@ -0,0 +1,35 @@
+<!-- manpage-base.xsl:
+ special formatting for manpages rendered from asciidoc+docbook -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<!-- these params silence some output from xmlto -->
+<xsl:param name="man.output.quietly" select="1"/>
+<xsl:param name="refentry.meta.get.quietly" select="1"/>
+
+<!-- convert asciidoc callouts to man page format;
+ nvme.docbook.backslash and nvme.docbook.dot params
+ must be supplied by another XSL file or other means -->
+<xsl:template match="co">
+ <xsl:value-of select="concat(
+ $nvme.docbook.backslash,'fB(',
+ substring-after(@id,'-'),')',
+ $nvme.docbook.backslash,'fR')"/>
+</xsl:template>
+<xsl:template match="calloutlist">
+ <xsl:value-of select="$nvme.docbook.dot"/>
+ <xsl:text>sp&#10;</xsl:text>
+ <xsl:apply-templates/>
+ <xsl:text>&#10;</xsl:text>
+</xsl:template>
+<xsl:template match="callout">
+ <xsl:value-of select="concat(
+ $nvme.docbook.backslash,'fB',
+ substring-after(@arearefs,'-'),
+ '. ',$nvme.docbook.backslash,'fR')"/>
+ <xsl:apply-templates/>
+ <xsl:value-of select="$nvme.docbook.dot"/>
+ <xsl:text>br&#10;</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
new file mode 100644
index 0000000..b730031
--- /dev/null
+++ b/Documentation/manpage-normal.xsl
@@ -0,0 +1,13 @@
+<!-- manpage-normal.xsl:
+ special settings for manpages rendered from asciidoc+docbook
+ handles anything we want to keep away from docbook-xsl 1.72.0 -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+
+<xsl:import href="manpage-base.xsl"/>
+
+<!-- these are the normal values for the roff control characters -->
+<xsl:param name="nvme.docbook.backslash">\</xsl:param>
+<xsl:param name="nvme.docbook.dot" >.</xsl:param>
+
+</xsl:stylesheet>
diff --git a/Documentation/meson.build b/Documentation/meson.build
new file mode 100644
index 0000000..0dc0300
--- /dev/null
+++ b/Documentation/meson.build
@@ -0,0 +1,293 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+adoc_sources = [
+ 'nvme',
+ 'nvme-admin-passthru',
+ 'nvme-ana-log',
+ 'nvme-attach-ns',
+ 'nvme-boot-part-log',
+ 'nvme-capacity-mgmt',
+ 'nvme-changed-ns-list-log',
+ 'nvme-cmdset-ind-id-ns',
+ 'nvme-compare',
+ 'nvme-connect',
+ 'nvme-connect-all',
+ 'nvme-copy',
+ 'nvme-create-ns',
+ 'nvme-delete-ns',
+ 'nvme-dera-stat',
+ 'nvme-detach-ns',
+ 'nvme-device-self-test',
+ 'nvme-dim',
+ 'nvme-dir-receive',
+ 'nvme-dir-send',
+ 'nvme-disconnect',
+ 'nvme-disconnect-all',
+ 'nvme-discover',
+ 'nvme-dsm',
+ 'nvme-effects-log',
+ 'nvme-endurance-event-agg-log',
+ 'nvme-endurance-log',
+ 'nvme-error-log',
+ 'nvme-fid-support-effects-log',
+ 'nvme-mi-cmd-support-effects-log',
+ 'nvme-fdp-configs',
+ 'nvme-fdp-usage',
+ 'nvme-fdp-stats',
+ 'nvme-fdp-events',
+ 'nvme-fdp-status',
+ 'nvme-fdp-update',
+ 'nvme-fdp-set-events',
+ 'nvme-flush',
+ 'nvme-format',
+ 'nvme-fw-commit',
+ 'nvme-fw-download',
+ 'nvme-fw-log',
+ 'nvme-gen-hostnqn',
+ 'nvme-get-feature',
+ 'nvme-get-lba-status',
+ 'nvme-get-log',
+ 'nvme-get-ns-id',
+ 'nvme-get-property',
+ 'nvme-help',
+ 'nvme-huawei-id-ctrl',
+ 'nvme-huawei-list',
+ 'nvme-id-ctrl',
+ 'nvme-id-domain',
+ 'nvme-id-iocs',
+ 'nvme-id-ns',
+ 'nvme-id-nvmset',
+ 'nvme-intel-id-ctrl',
+ 'nvme-intel-internal-log',
+ 'nvme-intel-lat-stats',
+ 'nvme-intel-market-name',
+ 'nvme-intel-smart-log-add',
+ 'nvme-intel-temp-stats',
+ 'nvme-io-mgmt-recv',
+ 'nvme-io-mgmt-send',
+ 'nvme-io-passthru',
+ 'nvme-lba-status-log',
+ 'nvme-list',
+ 'nvme-list-ctrl',
+ 'nvme-list-endgrp',
+ 'nvme-list-ns',
+ 'nvme-list-subsys',
+ 'nvme-lockdown',
+ 'nvme-micron-clear-pcie-errors',
+ 'nvme-micron-internal-log',
+ 'nvme-micron-nand-stats',
+ 'nvme-micron-pcie-stats',
+ 'nvme-micron-selective-download',
+ 'nvme-micron-smart-add-log',
+ 'nvme-micron-temperature-stats',
+ 'nvme-netapp-ontapdevices',
+ 'nvme-netapp-smdevices',
+ 'nvme-ns-descs',
+ 'nvme-ns-rescan',
+ 'nvme-nvme-mi-recv',
+ 'nvme-nvme-mi-send',
+ 'nvme-nvm-id-ctrl',
+ 'nvme-ocp-latency-monitor-log',
+ 'nvme-ocp-smart-add-log',
+ 'nvme-ocp-clear-fw-activate-history',
+ 'nvme-ocp-clear-pcie-correctable-error-counters',
+ 'nvme-ocp-eol-plp-failure-mode',
+ 'nvme-persistent-event-log',
+ 'nvme-pred-lat-event-agg-log',
+ 'nvme-predictable-lat-log',
+ 'nvme-primary-ctrl-caps',
+ 'nvme-read',
+ 'nvme-reset',
+ 'nvme-resv-acquire',
+ 'nvme-resv-notif-log',
+ 'nvme-resv-register',
+ 'nvme-resv-release',
+ 'nvme-resv-report',
+ 'nvme-rpmb',
+ 'nvme-sanitize',
+ 'nvme-sanitize-log',
+ 'nvme-seagate-clear-pcie-correctable-errors',
+ 'nvme-seagate-get-ctrl-tele',
+ 'nvme-seagate-get-host-tele',
+ 'nvme-seagate-help',
+ 'nvme-seagate-plugin-version',
+ 'nvme-seagate-version',
+ 'nvme-seagate-vs-internal-log',
+ 'nvme-seagate-vs-log-page-sup',
+ 'nvme-seagate-vs-pcie-stats',
+ 'nvme-seagate-vs-smart-add-log',
+ 'nvme-seagate-vs-temperature-stats',
+ 'nvme-seagate-cloud-SSD-plugin-version',
+ 'nvme-seagate-vs-fw-activate-history',
+ 'nvme-seagate-clear-fw-activate-history',
+ 'nvme-security-recv',
+ 'nvme-security-send',
+ 'nvme-self-test-log',
+ 'nvme-set-feature',
+ 'nvme-set-property',
+ 'nvme-show-hostnqn',
+ 'nvme-show-regs',
+ 'nvme-show-topology',
+ 'nvme-smart-log',
+ 'nvme-subsystem-reset',
+ 'nvme-supported-log-pages',
+ 'nvme-telemetry-log',
+ 'nvme-toshiba-clear-pcie-correctable-errors',
+ 'nvme-toshiba-vs-internal-log',
+ 'nvme-toshiba-vs-smart-add-log',
+ 'nvme-transcend-badblock',
+ 'nvme-transcend-healthvalue',
+ 'nvme-verify',
+ 'nvme-virtium-save-smart-to-vtview-log',
+ 'nvme-virtium-show-identify',
+ 'nvme-wdc-cap-diag',
+ 'nvme-wdc-capabilities',
+ 'nvme-wdc-clear-assert-dump',
+ 'nvme-wdc-clear-fw-activate-history',
+ 'nvme-wdc-clear-pcie-correctable-errors',
+ 'nvme-wdc-cloud-boot-SSD-version',
+ 'nvme-wdc-cloud-SSD-plugin-version',
+ 'nvme-wdc-drive-essentials',
+ 'nvme-wdc-drive-log',
+ 'nvme-wdc-drive-resize',
+ 'nvme-wdc-enc-get-log',
+ 'nvme-wdc-get-crash-dump',
+ 'nvme-wdc-get-dev-capabilities-log',
+ 'nvme-wdc-get-drive-status',
+ 'nvme-wdc-get-error-recovery-log',
+ 'nvme-wdc-get-latency-monitor-log',
+ 'nvme-wdc-get-pfail-dump',
+ 'nvme-wdc-get-unsupported-reqs-log',
+ 'nvme-wdc-id-ctrl',
+ 'nvme-wdc-log-page-directory',
+ 'nvme-wdc-namespace-resize',
+ 'nvme-wdc-purge',
+ 'nvme-wdc-purge-monitor',
+ 'nvme-wdc-vs-cloud-log',
+ 'nvme-wdc-vs-device-waf',
+ 'nvme-wdc-vs-drive-info',
+ 'nvme-wdc-vs-error-reason-identifier',
+ 'nvme-wdc-vs-fw-activate-history',
+ 'nvme-wdc-vs-hw-rev-log',
+ 'nvme-wdc-vs-internal-log',
+ 'nvme-wdc-vs-nand-stats',
+ 'nvme-wdc-vs-smart-add-log',
+ 'nvme-wdc-vs-telemetry-controller-option',
+ 'nvme-wdc-vs-temperature-stats',
+ 'nvme-write',
+ 'nvme-write-uncor',
+ 'nvme-write-zeroes',
+ 'nvme-zns-changed-zone-list',
+ 'nvme-zns-close-zone',
+ 'nvme-zns-finish-zone',
+ 'nvme-zns-id-ctrl',
+ 'nvme-zns-id-ns',
+ 'nvme-zns-offline-zone',
+ 'nvme-zns-open-zone',
+ 'nvme-zns-report-zones',
+ 'nvme-zns-reset-zone',
+ 'nvme-zns-set-zone-desc',
+ 'nvme-zns-zone-append',
+ 'nvme-zns-zone-mgmt-recv',
+ 'nvme-zns-zone-mgmt-send',
+ 'nvme-inspur-nvme-vendor-log',
+]
+
+adoc_includes = [
+ 'cmd-plugins.txt',
+ 'cmds-main.txt',
+]
+
+want_docs = get_option('docs')
+want_docs_build = get_option('docs-build')
+if want_docs != 'false'
+ mandir = join_paths(get_option('mandir'), 'man1')
+ htmldir = join_paths(get_option('htmldir'), 'nvme')
+
+ asciidoctor = find_program('asciidoc', required: get_option('docs-build'))
+ if want_docs_build and asciidoctor.found()
+ # Build documentation before installing
+
+ foreach file : adoc_includes
+ configure_file(
+ input: file,
+ output: file,
+ copy: true)
+ endforeach
+
+ # man pages
+ if want_docs == 'all' or want_docs == 'man'
+ xmlto = find_program('xmlto', required: false)
+ if xmlto.found()
+ foreach adoc : adoc_sources
+ input = adoc + '.txt'
+ subst = configure_file(
+ input: adoc + '.txt',
+ output: adoc + '.msubst',
+ configuration: substs)
+ xml = custom_target(
+ adoc.underscorify() + '_xml',
+ input: subst,
+ output: '@BASENAME@.xml',
+ command: [asciidoctor,
+ '-f', files('asciidoc.conf'),
+ '-b', 'docbook',
+ '-d', 'manpage',
+ '-o', '@OUTPUT@',
+ '@INPUT@'],
+ )
+ custom_target(
+ adoc.underscorify() + '_man',
+ input: xml,
+ output: '@BASENAME@.1',
+ command: [xmlto,
+ '-m', files('manpage-normal.xsl'),
+ '-o', '@OUTDIR@',
+ '--skip-validation',
+ 'man',
+ '@INPUT@'],
+ install: true,
+ install_dir: mandir)
+ endforeach
+ endif
+ endif
+
+ # html
+ if want_docs == 'all' or want_docs == 'html'
+ foreach adoc : adoc_sources
+ input = adoc + '.txt'
+ subst = configure_file(
+ input: adoc + '.txt',
+ output: adoc + '.hsubst',
+ configuration: substs)
+ custom_target(
+ adoc.underscorify() + '_html',
+ input: subst,
+ output: '@BASENAME@.html',
+ command: [asciidoctor,
+ '-f', files('asciidoc.conf'),
+ '-b', 'xhtml11',
+ '-d', 'manpage',
+ '-o', '@OUTPUT@',
+ '@INPUT@'],
+ install: true,
+ install_dir: htmldir)
+ endforeach
+ endif
+
+ else
+ # asciidoctor not found, install pre compiled documetationx
+
+ foreach adoc : adoc_sources
+ if want_docs == 'all' or want_docs == 'man'
+ man = files(adoc + '.1')
+ install_data(man, install_dir: mandir)
+ endif
+ if want_docs == 'all' or want_docs == 'html'
+ html = files(adoc + '.html')
+ install_data(html, install_dir: htmldir)
+ endif
+ endforeach
+
+ endif
+endif
diff --git a/Documentation/nvme-admin-passthru.1 b/Documentation/nvme-admin-passthru.1
new file mode 100644
index 0000000..b057dec
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.1
@@ -0,0 +1,194 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ADMIN\-PASSTHR" "1" "02/14/2024" "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-admin-passthru \- Submit an arbitrary admin command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-admin\-passthru\fR <device> [\-\-opcode=<opcode> | \-O <opcode>]
+ [\-\-flags=<flags> | \-f <flags>] [\-rsvd=<rsvd> | \-R <rsvd>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>] [\-\-cdw2=<cdw2> | \-2 <cdw2>]
+ [\-\-cdw3=<cdw3> | \-3 <cdw3>] [\-\-cdw10=<cdw10> | \-4 <cdw4>]
+ [\-\-cdw11=<cdw11> | \-5 <cdw5>] [\-\-cdw12=<cdw12> | \-6 <cdw6>]
+ [\-\-cdw13=<cdw13> | \-7 <cdw7>] [\-\-cdw14=<cdw14> | \-8 <cdw8>]
+ [\-\-cdw15=<cdw15> | \-9 <cdw9>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-metadata\-len=<len> | \-m <len>]
+ [\-\-input\-file=<file> | \-i <file>]
+ [\-\-read | \-r] [\-\-write | \-w]
+ [\-\-timeout=<to> | \-t <to>]
+ [\-\-show\-command | \-s]
+ [\-\-dry\-run | \-d]
+ [\-\-raw\-binary | \-b]
+ [\-\-prefill=<prefill> | \-p <prefill>]
+ [\-\-latency | \-T]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an arbitrary NVMe admin command and returns the applicable results\&. This may be the simply the commands result and status, or may also include a buffer if the command returns one\&. This command does no interpretation of the opcodes or options\&.
+.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 structure (if applicable) may be returned in one of several ways depending on the option flags; the structure may printed by the program as a hex dump, or may be returned as a raw buffer printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-O <opcode>, \-\-opcode=<opcode>
+.RS 4
+The NVMe opcode to send to the device in the command
+.RE
+.PP
+\-f <flags>, \-\-flags=<flags>
+.RS 4
+The NVMe command flags to send to the device in the command
+.RE
+.PP
+\-R <rsvd>, \-\-rsvd=<rsvd>
+.RS 4
+The value for the reserved field in the command\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The value for the ns\-id in the command\&.
+.RE
+.PP
+\-[2\-9] <cdw>, \-\-cdw[2\-3,10\-15]=<cdw>
+.RS 4
+Specifies the command dword value for that specified entry in the command
+.RE
+.PP
+\-r, \-\-read, \-w, \-\-write
+.RS 4
+Used for the data\-direction for the command and required for commands sending/receiving data\&. Don\(cqt use both read and write at the same time\&.
+.RE
+.PP
+\-i <file>, \-\-input\-file=<file>
+.RS 4
+If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&.
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer used for this command\&.
+.RE
+.PP
+\-m <data\-len>, \-\-metadata\-len=<data\-len>
+.RS 4
+The metadata length for the buffer used for this command\&.
+.RE
+.PP
+\-s, \-\-show\-cmd
+.RS 4
+Print out the command to be sent\&.
+.RE
+.PP
+\-d, \-\-dry\-run
+.RS 4
+Do not actually send the command\&. If want to use \-\-dry\-run option, \-\-show\-cmd option
+\fImust\fR
+be set\&. Otherwise \-\-dry\-run option will be
+\fIignored\fR\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw returned buffer to stdout if the command returns a structure\&.
+.RE
+.PP
+\-p, \-\-prefill
+.RS 4
+Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may be useful if the data you are writing is shorter than the required buffer, and you need to pad it with a known value\&. It may also be useful if you need to confirm if a device is overwriting a buffer for a data\-in command\&.
+.RE
+.PP
+\-T, \-\-latency
+.RS 4
+Print out the latency the IOCTL took (in us)\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The following will run the admin command with opcode=6 and cdw10=1, which corresponds to an identify controller command\&. This example requires the data\-len param be 4096, which is the size of the returned structure\&. The \-r option is used because it is a data\-in command
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme admin\-passthru /dev/nvme0 \-\-opcode=06 \-\-data\-len=4096 \-\-cdw10=1 \-r
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Or if you want to save that structure to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme admin\-passthru /dev/nvme0 \-\-opcode=06 \-\-data\-len=4096 \-\-cdw10=1 \-r \-b > id_ns\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-admin-passthru.html b/Documentation/nvme-admin-passthru.html
new file mode 100644
index 0000000..7a4f6ac
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.html
@@ -0,0 +1,1034 @@
+<?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 10.2.0" />
+<title>nvme-admin-passthru(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-admin-passthru(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-admin-passthru -
+ Submit an arbitrary admin command, return 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-admin-passthru</em> &lt;device&gt; [--opcode=&lt;opcode&gt; | -O &lt;opcode&gt;]
+ [--flags=&lt;flags&gt; | -f &lt;flags&gt;] [-rsvd=&lt;rsvd&gt; | -R &lt;rsvd&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;] [--cdw2=&lt;cdw2&gt; | -2 &lt;cdw2&gt;]
+ [--cdw3=&lt;cdw3&gt; | -3 &lt;cdw3&gt;] [--cdw10=&lt;cdw10&gt; | -4 &lt;cdw4&gt;]
+ [--cdw11=&lt;cdw11&gt; | -5 &lt;cdw5&gt;] [--cdw12=&lt;cdw12&gt; | -6 &lt;cdw6&gt;]
+ [--cdw13=&lt;cdw13&gt; | -7 &lt;cdw7&gt;] [--cdw14=&lt;cdw14&gt; | -8 &lt;cdw8&gt;]
+ [--cdw15=&lt;cdw15&gt; | -9 &lt;cdw9&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--metadata-len=&lt;len&gt; | -m &lt;len&gt;]
+ [--input-file=&lt;file&gt; | -i &lt;file&gt;]
+ [--read | -r] [--write | -w]
+ [--timeout=&lt;to&gt; | -t &lt;to&gt;]
+ [--show-command | -s]
+ [--dry-run | -d]
+ [--raw-binary | -b]
+ [--prefill=&lt;prefill&gt; | -p &lt;prefill&gt;]
+ [--latency | -T]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an arbitrary NVMe admin command and returns the applicable
+results. This may be the simply the commands result and status, or may
+also include a buffer if the command returns one. This command does no
+interpretation of the opcodes or options.</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 structure (if applicable) may be returned in
+one of several ways depending on the option flags; the structure may
+printed by the program as a hex dump, or may be returned as a raw buffer
+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;opcode&gt;
+</dt>
+<dt class="hdlist1">
+--opcode=&lt;opcode&gt;
+</dt>
+<dd>
+<p>
+ The NVMe opcode to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;flags&gt;
+</dt>
+<dt class="hdlist1">
+--flags=&lt;flags&gt;
+</dt>
+<dd>
+<p>
+ The NVMe command flags to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-R &lt;rsvd&gt;
+</dt>
+<dt class="hdlist1">
+--rsvd=&lt;rsvd&gt;
+</dt>
+<dd>
+<p>
+ The value for the reserved field in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The value for the ns-id in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-[2-9] &lt;cdw&gt;
+</dt>
+<dt class="hdlist1">
+--cdw[2-3,10-15]=&lt;cdw&gt;
+</dt>
+<dd>
+<p>
+ Specifies the command dword value for that specified entry in
+ the command
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--read
+</dt>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--write
+</dt>
+<dd>
+<p>
+ Used for the data-direction for the command and required for
+ commands sending/receiving data. Don&#8217;t use both read and write
+ at the same time.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--input-file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The metadata length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-s
+</dt>
+<dt class="hdlist1">
+--show-cmd
+</dt>
+<dd>
+<p>
+ Print out the command to be sent.
+</p>
+</dd>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--dry-run
+</dt>
+<dd>
+<p>
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option <em>must</em> be set. Otherwise --dry-run option will be
+ <em>ignored</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw returned buffer to stdout if the command returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--prefill
+</dt>
+<dd>
+<p>
+ Prefill the buffer with a predetermined byte value. Defaults to 0.
+ This may be useful if the data you are writing is shorter
+ than the required buffer, and you need to pad it with a known
+ value. It may also be useful if you need to confirm if a device
+ is overwriting a buffer for a data-in command.
+</p>
+</dd>
+<dt class="hdlist1">
+-T
+</dt>
+<dt class="hdlist1">
+--latency
+</dt>
+<dd>
+<p>
+ Print out the latency the IOCTL took (in us).
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+The following will run the admin command with opcode=6 and cdw10=1, which
+ corresponds to an identify controller command. This example requires the
+ data-len param be 4096, which is the size of the returned structure. The -r
+ option is used because it is a data-in command
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme admin-passthru /dev/nvme0 --opcode=06 --data-len=4096 --cdw10=1 -r</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Or if you want to save that structure to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme admin-passthru /dev/nvme0 --opcode=06 --data-len=4096 --cdw10=1 -r -b &gt; id_ns.raw</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-admin-passthru.txt b/Documentation/nvme-admin-passthru.txt
new file mode 100644
index 0000000..22559db
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.txt
@@ -0,0 +1,146 @@
+nvme-admin-passthru(1)
+======================
+
+NAME
+----
+nvme-admin-passthru - Submit an arbitrary admin command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-admin-passthru' <device> [--opcode=<opcode> | -O <opcode>]
+ [--flags=<flags> | -f <flags>] [-rsvd=<rsvd> | -R <rsvd>]
+ [--namespace-id=<nsid> | -n <nsid>] [--cdw2=<cdw2> | -2 <cdw2>]
+ [--cdw3=<cdw3> | -3 <cdw3>] [--cdw10=<cdw10> | -4 <cdw4>]
+ [--cdw11=<cdw11> | -5 <cdw5>] [--cdw12=<cdw12> | -6 <cdw6>]
+ [--cdw13=<cdw13> | -7 <cdw7>] [--cdw14=<cdw14> | -8 <cdw8>]
+ [--cdw15=<cdw15> | -9 <cdw9>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--metadata-len=<len> | -m <len>]
+ [--input-file=<file> | -i <file>]
+ [--read | -r] [--write | -w]
+ [--timeout=<to> | -t <to>]
+ [--show-command | -s]
+ [--dry-run | -d]
+ [--raw-binary | -b]
+ [--prefill=<prefill> | -p <prefill>]
+ [--latency | -T]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an arbitrary NVMe admin command and returns the applicable
+results. This may be the simply the commands result and status, or may
+also include a buffer if the command returns one. This command does no
+interpretation of the opcodes or options.
+
+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 structure (if applicable) may be returned in
+one of several ways depending on the option flags; the structure may
+printed by the program as a hex dump, or may be returned as a raw buffer
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-O <opcode>::
+--opcode=<opcode>::
+ The NVMe opcode to send to the device in the command
+
+-f <flags>::
+--flags=<flags>::
+ The NVMe command flags to send to the device in the command
+
+-R <rsvd>::
+--rsvd=<rsvd>::
+ The value for the reserved field in the command.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ The value for the ns-id in the command.
+
+-[2-9] <cdw>::
+--cdw[2-3,10-15]=<cdw>::
+ Specifies the command dword value for that specified entry in
+ the command
+
+-r::
+--read::
+-w::
+--write::
+ Used for the data-direction for the command and required for
+ commands sending/receiving data. Don't use both read and write
+ at the same time.
+
+-i <file>::
+--input-file=<file>::
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer used for this command.
+
+-m <data-len>::
+--metadata-len=<data-len>::
+ The metadata length for the buffer used for this command.
+
+-s::
+--show-cmd::
+ Print out the command to be sent.
+
+-d::
+--dry-run::
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option _must_ be set. Otherwise --dry-run option will be
+ _ignored_.
+
+-b::
+--raw-binary::
+ Print the raw returned buffer to stdout if the command returns
+ a structure.
+
+-p::
+--prefill::
+ Prefill the buffer with a predetermined byte value. Defaults to 0.
+ This may be useful if the data you are writing is shorter
+ than the required buffer, and you need to pad it with a known
+ value. It may also be useful if you need to confirm if a device
+ is overwriting a buffer for a data-in command.
+
+-T::
+--latency::
+ Print out the latency the IOCTL took (in us).
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* The following will run the admin command with opcode=6 and cdw10=1, which
+ corresponds to an identify controller command. This example requires the
+ data-len param be 4096, which is the size of the returned structure. The -r
+ option is used because it is a data-in command
++
+------------
+# nvme admin-passthru /dev/nvme0 --opcode=06 --data-len=4096 --cdw10=1 -r
+------------
++
+
+* Or if you want to save that structure to a file:
++
+------------
+# nvme admin-passthru /dev/nvme0 --opcode=06 --data-len=4096 --cdw10=1 -r -b > id_ns.raw
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-ana-log.1 b/Documentation/nvme-ana-log.1
new file mode 100644
index 0000000..eb3042a
--- /dev/null
+++ b/Documentation/nvme-ana-log.1
@@ -0,0 +1,89 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ANA\-LOG" "1" "02/14/2024" "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-ana-log \- Send NVMe ANA log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ana\-log\fR <device> [\-\-groups | \-g]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned ANA 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
+\-g, \-\-groups
+.RS 4
+Return the list of ANA groups without the namespace listing\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the ANA log page in a human readable format:
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ana\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-ana-log.html b/Documentation/nvme-ana-log.html
new file mode 100644
index 0000000..2adec9f
--- /dev/null
+++ b/Documentation/nvme-ana-log.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 10.2.0" />
+<title>nvme-ana-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 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-ana-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ana-log -
+ Send NVMe ANA 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 ana-log</em> &lt;device&gt; [--groups | -g]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Asymmetric Namespace Access log page from an NVMe device
+and provides the returned structure.</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, the returned ANA 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">
+-g
+</dt>
+<dt class="hdlist1">
+--groups
+</dt>
+<dd>
+<p>
+ Return the list of ANA groups without the namespace listing.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 ANA log page in a human readable format:
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ana-log /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt
new file mode 100644
index 0000000..92dc12a
--- /dev/null
+++ b/Documentation/nvme-ana-log.txt
@@ -0,0 +1,50 @@
+nvme-ana-log(1)
+===============
+
+NAME
+----
+nvme-ana-log - Send NVMe ANA log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme ana-log' <device> [--groups | -g]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Asymmetric Namespace Access log page from an NVMe device
+and provides the returned structure.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+On success, the returned ANA 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
+-------
+-g::
+--groups::
+ Return the list of ANA groups without the namespace listing.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the ANA log page in a human readable format:
+------------
+# nvme ana-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-attach-ns.1 b/Documentation/nvme-attach-ns.1
new file mode 100644
index 0000000..0eb5c2c
--- /dev/null
+++ b/Documentation/nvme-attach-ns.1
@@ -0,0 +1,90 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ATTACH\-NS" "1" "02/14/2024" "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-attach-ns \- Send NVMe attach namespace, return result\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme attach\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-controllers=<ctrl\-list,> | \-c <ctrl\-list,>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the nvme namespace attach command for the provided namespace identifier, attaching to the provided list of controller identifiers\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The namespace identifier to attach\&.
+.RE
+.PP
+\-c <ctrl\-list,>, \-controllers=<ctrl\-list,>
+.RS 4
+The comma separated list of controller identifiers to attach the namespace too\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Attach namespace to the controller:
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme attach\-ns /dev/nvme1 \-n 0x2 \-c 0x21
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-attach-ns.html b/Documentation/nvme-attach-ns.html
new file mode 100644
index 0000000..eae3957
--- /dev/null
+++ b/Documentation/nvme-attach-ns.html
@@ -0,0 +1,848 @@
+<?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 10.2.0" />
+<title>nvme-attach-ns(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-attach-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-attach-ns -
+ Send NVMe attach namespace, 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 attach-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--controllers=&lt;ctrl-list,&gt; | -c &lt;ctrl-list,&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 nvme namespace attach command for
+the provided namespace identifier, attaching to the provided list of
+controller identifiers.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The namespace identifier to attach.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;ctrl-list,&gt;
+</dt>
+<dt class="hdlist1">
+-controllers=&lt;ctrl-list,&gt;
+</dt>
+<dd>
+<p>
+ The comma separated list of controller identifiers to attach
+ the namespace too.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="literalblock">
+<div class="content">
+<pre><code>Attach namespace to the controller:</code></pre>
+</div></div>
+<div class="literalblock">
+<div class="content">
+<pre><code># nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-attach-ns.txt b/Documentation/nvme-attach-ns.txt
new file mode 100644
index 0000000..601c20d
--- /dev/null
+++ b/Documentation/nvme-attach-ns.txt
@@ -0,0 +1,49 @@
+nvme-attach-ns(1)
+=================
+
+NAME
+----
+nvme-attach-ns - Send NVMe attach namespace, return result.
+
+SYNOPSIS
+--------
+[verse]
+'nvme attach-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--controllers=<ctrl-list,> | -c <ctrl-list,>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the nvme namespace attach command for
+the provided namespace identifier, attaching to the provided list of
+controller identifiers.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ The namespace identifier to attach.
+
+-c <ctrl-list,>::
+-controllers=<ctrl-list,>::
+ The comma separated list of controller identifiers to attach
+ the namespace too.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+ Attach namespace to the controller:
+
+ # nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-boot-part-log.1 b/Documentation/nvme-boot-part-log.1
new file mode 100644
index 0000000..6bbd3a3
--- /dev/null
+++ b/Documentation/nvme-boot-part-log.1
@@ -0,0 +1,95 @@
+'\" t
+.\" Title: nvme-boot-part-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-BOOT\-PART\-LO" "1" "02/14/2024" "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-boot-part-log \- Retrieves a Boot Partition log page from an NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme boot\-part\-log\fR <device> [\-\-lsp=<field> | \-s <field>]
+ [\-\-output\-file=<file> | \-f <file>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves an Boot Partition 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 log structure will be in raw binary format \fIonly\fR with \-\-output\-file option which is mandatory\&.
+.SH "OPTIONS"
+.PP
+\-s <field>, \-\-lsp=<field>
+.RS 4
+The log specified field of LID\&.
+.RE
+.PP
+\-f <file>, \-\-output\-file=<file>
+.RS 4
+File name to which raw binary data will be saved to\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve Boot Partition data to boot_part_log\&.bin
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme boot\-part\-log /dev/nvme0 \-\-output\-file=boot_part_log\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-boot-part-log.html b/Documentation/nvme-boot-part-log.html
new file mode 100644
index 0000000..64a79e5
--- /dev/null
+++ b/Documentation/nvme-boot-part-log.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<title>nvme-boot-part-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 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-boot-part-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-boot-part-log -
+ Retrieves a Boot Partition log page from 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 boot-part-log</em> &lt;device&gt; [--lsp=&lt;field&gt; | -s &lt;field&gt;]
+ [--output-file=&lt;file&gt; | -f &lt;file&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves an Boot Partition 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 log structure will be in raw binary format <em>only</em> with
+--output-file option which is mandatory.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;field&gt;
+</dt>
+<dt class="hdlist1">
+--lsp=&lt;field&gt;
+</dt>
+<dd>
+<p>
+ The log specified field of LID.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ File name to which raw binary data will be saved to.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve Boot Partition data to boot_part_log.bin
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme boot-part-log /dev/nvme0 --output-file=boot_part_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-boot-part-log.txt b/Documentation/nvme-boot-part-log.txt
new file mode 100644
index 0000000..0999071
--- /dev/null
+++ b/Documentation/nvme-boot-part-log.txt
@@ -0,0 +1,55 @@
+nvme-boot-part-log(1)
+=====================
+
+NAME
+----
+nvme-boot-part-log - Retrieves a Boot Partition log page from an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme boot-part-log' <device> [--lsp=<field> | -s <field>]
+ [--output-file=<file> | -f <file>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves an Boot Partition 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 log structure will be in raw binary format _only_ with
+--output-file option which is mandatory.
+
+OPTIONS
+-------
+-s <field>::
+--lsp=<field>::
+ The log specified field of LID.
+
+-f <file>::
+--output-file=<file>::
+ File name to which raw binary data will be saved to.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Retrieve Boot Partition data to boot_part_log.bin
++
+------------
+# nvme boot-part-log /dev/nvme0 --output-file=boot_part_log.bin
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-capacity-mgmt.1 b/Documentation/nvme-capacity-mgmt.1
new file mode 100644
index 0000000..19593c4
--- /dev/null
+++ b/Documentation/nvme-capacity-mgmt.1
@@ -0,0 +1,86 @@
+'\" t
+.\" Title: nvme-capacity-mgmt
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CAPACITY\-MGMT" "1" "02/14/2024" "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-capacity-mgmt \- Send capacity management command to configure/create/delete Endurance Groups or NVM Sets, returns results\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme capacity\-mgmt\fR <device> [\-\-operation=<operation> | \-O <operation>]
+ [\-\-element\-id=<element\-id> | \-i <element\-id>]
+ [\-\-cap\-lower=<cap\-lower> | \-l <cap\-lower>]
+ [\-\-cap\-upper=<cap\-upper> | \-u <cap\-upper>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a capacity management command to configure/create/delete the Endurance Groups or NVM Sets with the requested operation and element_id\&. On success, if the Operation is Create Endurance group or NVM Set, CQE CDW0 contains Created element identifier else CQE CDW0 is reserved\&.
+.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
+\-O <operation>, \-\-operation=<operation>
+.RS 4
+Operation to be performed by the controller
+.RE
+.PP
+\-i <element\-id>, \-\-element\-id=<element\-id>
+.RS 4
+Value specific to the value of the Operation field\&.
+.RE
+.PP
+\-l <cap\-lower>, \-\-cap\-lower=<cap\-lower>
+.RS 4
+Least significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created
+.RE
+.PP
+\-u <cap\-upper>, \-\-cap\-upper=<cap\-upper>
+.RS 4
+Most significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples provided yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-capacity-mgmt.html b/Documentation/nvme-capacity-mgmt.html
new file mode 100644
index 0000000..29cc903
--- /dev/null
+++ b/Documentation/nvme-capacity-mgmt.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 10.2.0" />
+<title>nvme-capacity-mgmt(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-capacity-mgmt(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-capacity-mgmt -
+ Send capacity management command to configure/create/delete Endurance Groups or NVM Sets, returns 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 capacity-mgmt</em> &lt;device&gt; [--operation=&lt;operation&gt; | -O &lt;operation&gt;]
+ [--element-id=&lt;element-id&gt; | -i &lt;element-id&gt;]
+ [--cap-lower=&lt;cap-lower&gt; | -l &lt;cap-lower&gt;]
+ [--cap-upper=&lt;cap-upper&gt; | -u &lt;cap-upper&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 a capacity management command to
+configure/create/delete the Endurance Groups or NVM Sets with the requested
+operation and element_id. On success, if the Operation is Create Endurance
+group or NVM Set, CQE CDW0 contains Created element identifier else CQE CDW0 is
+reserved.</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">
+-O &lt;operation&gt;
+</dt>
+<dt class="hdlist1">
+--operation=&lt;operation&gt;
+</dt>
+<dd>
+<p>
+ Operation to be performed by the controller
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;element-id&gt;
+</dt>
+<dt class="hdlist1">
+--element-id=&lt;element-id&gt;
+</dt>
+<dd>
+<p>
+ Value specific to the value of the Operation field.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;cap-lower&gt;
+</dt>
+<dt class="hdlist1">
+--cap-lower=&lt;cap-lower&gt;
+</dt>
+<dd>
+<p>
+ Least significant 32 bits of the capacity in bytes of the Endurance Group or
+ NVM Set to be created
+</p>
+</dd>
+<dt class="hdlist1">
+-u &lt;cap-upper&gt;
+</dt>
+<dt class="hdlist1">
+--cap-upper=&lt;cap-upper&gt;
+</dt>
+<dd>
+<p>
+ Most significant 32 bits of the capacity in bytes of the Endurance Group or
+ NVM Set to be created
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No examples provided 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-capacity-mgmt.txt b/Documentation/nvme-capacity-mgmt.txt
new file mode 100644
index 0000000..a20561f
--- /dev/null
+++ b/Documentation/nvme-capacity-mgmt.txt
@@ -0,0 +1,64 @@
+nvme-capacity-mgmt(1)
+=====================
+
+NAME
+----
+nvme-capacity-mgmt - Send capacity management command to configure/create/delete
+Endurance Groups or NVM Sets, returns results.
+
+SYNOPSIS
+--------
+[verse]
+'nvme capacity-mgmt' <device> [--operation=<operation> | -O <operation>]
+ [--element-id=<element-id> | -i <element-id>]
+ [--cap-lower=<cap-lower> | -l <cap-lower>]
+ [--cap-upper=<cap-upper> | -u <cap-upper>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a capacity management command to
+configure/create/delete the Endurance Groups or NVM Sets with the requested
+operation and element_id. On success, if the Operation is Create Endurance
+group or NVM Set, CQE CDW0 contains Created element identifier else CQE CDW0 is
+reserved.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-O <operation>::
+--operation=<operation>::
+ Operation to be performed by the controller
+
+-i <element-id>::
+--element-id=<element-id>::
+ Value specific to the value of the Operation field.
+
+-l <cap-lower>::
+--cap-lower=<cap-lower>::
+ Least significant 32 bits of the capacity in bytes of the Endurance Group or
+ NVM Set to be created
+
+-u <cap-upper>::
+--cap-upper=<cap-upper>::
+ Most significant 32 bits of the capacity in bytes of the Endurance Group or
+ NVM Set to be created
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples provided yet.
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-changed-ns-list-log.1 b/Documentation/nvme-changed-ns-list-log.1
new file mode 100644
index 0000000..2ab0d3b
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CHANGED\-NS\-L" "1" "02/14/2024" "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-changed-ns-list-log \- Send NVMe Changed Namespace List log page request, returns result and log\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme changed\-ns\-list\-log\fR <device> [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Changed Namespace List log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and must be a NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned Changed Namespace List 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
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw Changed Namespace List log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Changed Namespace List Log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme changed\-ns\-list\-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 Changed Namespace List log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme changed\-ns\-list\-log /dev/nvme0 \-\-raw\-binary > 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-changed-ns-list-log.html b/Documentation/nvme-changed-ns-list-log.html
new file mode 100644
index 0000000..2b7aa28
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-log.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<title>nvme-changed-ns-list-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 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-changed-ns-list-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-changed-ns-list-log -
+ Send NVMe Changed Namespace List 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 changed-ns-list-log</em> &lt;device&gt; [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Changed Namespace List 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 must be a NVMe character device
+(ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success, the returned Changed Namespace List 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">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw Changed Namespace List log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 Changed Namespace List Log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme changed-ns-list-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw Changed Namespace List log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme changed-ns-list-log /dev/nvme0 --raw-binary &gt; 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-changed-ns-list-log.txt b/Documentation/nvme-changed-ns-list-log.txt
new file mode 100644
index 0000000..22e552f
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-log.txt
@@ -0,0 +1,62 @@
+nvme-changed-ns-list-log(1)
+===========================
+
+NAME
+----
+nvme-changed-ns-list-log - Send NVMe Changed Namespace List log page
+request, returns result and log.
+
+SYNOPSIS
+--------
+[verse]
+'nvme changed-ns-list-log' <device> [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Changed Namespace List log page from an NVMe device and
+provides the returned structure.
+
+The <device> parameter is mandatory and must be a NVMe character device
+(ex: /dev/nvme0).
+
+On success, the returned Changed Namespace List 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
+-------
+-b::
+--raw-binary::
+ Print the raw Changed Namespace List log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the Changed Namespace List Log page in a human readable format:
++
+------------
+# nvme changed-ns-list-log /dev/nvme0
+------------
++
+
+* Print the raw Changed Namespace List log to a file:
++
+------------
+# nvme changed-ns-list-log /dev/nvme0 --raw-binary > 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-check-dhchap-key.1 b/Documentation/nvme-check-dhchap-key.1
new file mode 100644
index 0000000..df8df21
--- /dev/null
+++ b/Documentation/nvme-check-dhchap-key.1
@@ -0,0 +1,51 @@
+'\" t
+.\" Title: nvme-check-dhchap-key
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 11/25/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CHECK\-DHCHAP\" "1" "11/25/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-check-dhchap-key \- Check a generated host DH\-HMAC\-CHAP key
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme check\-dhchap\-key\fR [\-\-key=<key> ]
+.fi
+.SH "DESCRIPTION"
+.sp
+Checks if the key is a valid DH\-HMAC\-CHAP host key of the form: DHHC\-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n: and prints it to stdout\&.
+.SH "OPTIONS"
+.PP
+\-k <key>, \-\-key=<key>
+.RS 4
+Key to be checked\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No Examples
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-check-dhchap-key.html b/Documentation/nvme-check-dhchap-key.html
new file mode 100644
index 0000000..927ed7e
--- /dev/null
+++ b/Documentation/nvme-check-dhchap-key.html
@@ -0,0 +1,800 @@
+<!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-check-dhchap-key(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-check-dhchap-key(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-check-dhchap-key -
+ Check a generated host DH-HMAC-CHAP key
+</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 check-dhchap-key</em> [--key=&lt;key&gt; ]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Checks if the key is a valid DH-HMAC-CHAP host key of the form:
+DHHC-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n:
+and prints it to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-k &lt;key&gt;
+</dt>
+<dt class="hdlist1">
+--key=&lt;key&gt;
+</dt>
+<dd>
+<p>
+ Key to be checked.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Examples</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 2021-11-25 14:13:07 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-check-dhchap-key.txt b/Documentation/nvme-check-dhchap-key.txt
new file mode 100644
index 0000000..b131afe
--- /dev/null
+++ b/Documentation/nvme-check-dhchap-key.txt
@@ -0,0 +1,41 @@
+nvme-check-dhchap-key(1)
+========================
+
+NAME
+----
+nvme-check-dhchap-key - Check a generated host DH-HMAC-CHAP key
+
+SYNOPSIS
+--------
+[verse]
+'nvme check-dhchap-key' [--key=<key>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Checks if the key is a valid DH-HMAC-CHAP host key of the form:
+DHHC-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n:
+and prints it to stdout.
+
+OPTIONS
+-------
+-k <key>::
+--key=<key>::
+ Key to be checked.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-check-tls-key.txt b/Documentation/nvme-check-tls-key.txt
new file mode 100644
index 0000000..2df4fca
--- /dev/null
+++ b/Documentation/nvme-check-tls-key.txt
@@ -0,0 +1,79 @@
+nvme-check-tls-key(1)
+========================
+
+NAME
+----
+nvme-check-tls-key - Check a generated NVMe TLS PSK
+
+SYNOPSIS
+--------
+[verse]
+'nvme check-tls-key' [--keyring=<name> | -k <name>]
+ [--keytype=<type> | -t <type>]
+ [--hostnqn=<nqn> | -n <nqn>]
+ [--subsysnqn=<nqn> | -c <nqn>]
+ [--keydata=<key> | -d <key>]
+ [--output-format=<fmt> | -o <fmt>]
+ [--identity=<id-vers> | -I <id-vers>]
+ [--insert | -i ]
+ [--verbose | -v]
+
+DESCRIPTION
+-----------
+Checks if the key is a valid NVMe TLS PSK in the PSK interchange format
+'NVMeTLSkey-1:01:<base64-encoded data>:'. If '--insert' is specified the
+the derived 'retained' TLS key is stored in the keyring, otherwise the
+TLS identity of the key is printed out.
+
+OPTIONS
+-------
+-k <name>::
+--keyring=<name>::
+ Name of the keyring into which the 'retained' TLS key should be
+ stored. Default is '.nvme'.
+
+-t <type>::
+--keytype=<type>::
+ Type of the key for resulting TLS key.
+ Default is 'psk'.
+
+-n <nqn>::
+--hostnqn=<nqn>::
+ Host NVMe Qualified Name (NQN) to be used to derive the
+ 'retained' TLS key
+
+-c <nqn>::
+--subsysnqn=<nqn>::
+ Subsystem NVMe Qualified Name (NQN) to be used to derive the
+ 'retained' TLS key
+
+-d <key>::
+--keydata=<key>::
+ Key to be checked.
+
+-I <id-vers>::
+--identity=<id-vers>::
+ NVMe TLS key identity version to be used; '0' for the default
+ identity, and '1' for the TLS identity suffixed by the PSK hash
+ as specified in TP8018.
+
+-i:
+--insert:
+ Insert the derived 'retained' key in the keyring.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-cmdset-ind-id-ns.1 b/Documentation/nvme-cmdset-ind-id-ns.1
new file mode 100644
index 0000000..7d6053d
--- /dev/null
+++ b/Documentation/nvme-cmdset-ind-id-ns.1
@@ -0,0 +1,147 @@
+'\" t
+.\" Title: nvme-cmdset-ind-id-ns
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CMDSET\-IND\-I" "1" "02/14/2024" "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-cmdset-ind-id-ns \- Send NVMe I/O Command Set Independent Identify Namespace, return result and structure\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme cmdset\-ind\-id\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-raw\-binary | \-b] [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an I/O Command Set Independent identify namespace 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)\&. If the character device is given, the \*(Aq\-\-namespace\-id\*(Aq option is mandatory, otherwise it will use the ns\-id of the namespace for the block device you opened\&. For block devices, the ns\-id used can be overridden with the same option\&.
+.sp
+On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the identify namespace structure for the given nsid\&. This is required for the character devices, or overrides the block nsid if given\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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 cmdset\-ind\-id\-ns /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If using the character device or overriding namespace id:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme cmdset\-ind\-id\-ns /dev/nvme0 \-n 1
+# nvme cmdset\-ind\-id\-ns /dev/nvme0n1 \-n 1
+# nvme cmdset\-ind\-id\-ns /dev/nvme0 \-\-namespace\-id=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme cmdset\-ind\-id\-ns /dev/nvme0n1 \-\-raw\-binary > id_ns\&.raw
+# nvme cmdset\-ind\-id\-ns /dev/nvme0n1 \-b > id_ns\&.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-cmdset-ind-id-ns.html b/Documentation/nvme-cmdset-ind-id-ns.html
new file mode 100644
index 0000000..59a36f0
--- /dev/null
+++ b/Documentation/nvme-cmdset-ind-id-ns.html
@@ -0,0 +1,896 @@
+<?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 10.2.0" />
+<title>nvme-cmdset-ind-id-ns(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-cmdset-ind-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-cmdset-ind-id-ns -
+ Send NVMe I/O Command Set Independent Identify Namespace, 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 cmdset-ind-id-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--raw-binary | -b] [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an I/O Command Set Independent
+identify namespace 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).
+If the character device is given, the <code>'--namespace-id'</code> option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.</p></div>
+<div class="paragraph"><p>On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify namespace structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 cmdset-ind-id-ns /dev/nvme0n1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+If using the character device or overriding namespace id:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme cmdset-ind-id-ns /dev/nvme0 -n 1
+# nvme cmdset-ind-id-ns /dev/nvme0n1 -n 1
+# nvme cmdset-ind-id-ns /dev/nvme0 --namespace-id=1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme cmdset-ind-id-ns /dev/nvme0n1 --raw-binary &gt; id_ns.raw
+# nvme cmdset-ind-id-ns /dev/nvme0n1 -b &gt; id_ns.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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-cmdset-ind-id-ns.txt b/Documentation/nvme-cmdset-ind-id-ns.txt
new file mode 100644
index 0000000..5bf3862
--- /dev/null
+++ b/Documentation/nvme-cmdset-ind-id-ns.txt
@@ -0,0 +1,88 @@
+nvme-cmdset-ind-id-ns(1)
+========================
+
+NAME
+----
+nvme-cmdset-ind-id-ns - Send NVMe I/O Command Set Independent Identify Namespace, return result and structure.
+
+SYNOPSIS
+--------
+[verse]
+'nvme cmdset-ind-id-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--raw-binary | -b] [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an I/O Command Set Independent
+identify namespace 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).
+If the character device is given, the `'--namespace-id'` option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the identify namespace structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme cmdset-ind-id-ns /dev/nvme0n1
+------------
++
+
+* If using the character device or overriding namespace id:
++
+------------
+# nvme cmdset-ind-id-ns /dev/nvme0 -n 1
+# nvme cmdset-ind-id-ns /dev/nvme0n1 -n 1
+# nvme cmdset-ind-id-ns /dev/nvme0 --namespace-id=1
+------------
++
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme cmdset-ind-id-ns /dev/nvme0n1 --raw-binary > id_ns.raw
+# nvme cmdset-ind-id-ns /dev/nvme0n1 -b > id_ns.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-compare.1 b/Documentation/nvme-compare.1
new file mode 100644
index 0000000..68b0f75
--- /dev/null
+++ b/Documentation/nvme-compare.1
@@ -0,0 +1,229 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-COMPARE" "1" "02/14/2024" "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-compare \- Send an NVMe Compare command, provide results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-compare\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-data\-size=<size> | \-z <size>]
+ [\-\-metadata\-size=<metasize> | \-y <metasize>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-data=<data\-file> | \-d <data\-file>]
+ [\-\-metadata=<meta> | \-M <meta>]
+ [\-\-prinfo=<prinfo> | \-p <prinfo>]
+ [\-\-app\-tag\-mask=<appmask> | \-m <appmask>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>]
+ [\-\-limited\-retry | \-l]
+ [\-\-force\-unit\-access | \-f]
+ [\-\-dir\-type=<type> | \-T <type>]
+ [\-\-dir\-spec=<spec> | \-S <spec>]
+ [\-\-dsm=<dsm> | \-D <dsm>]
+ [\-\-show\-command | \-V]
+ [\-\-dry\-run | \-w]
+ [\-\-latency | \-t]
+ [\-\-storage\-tag<storage\-tag> | \-g <storage\-tag>]
+ [\-\-storage\-tag\-check | \-C]
+ [\-\-force]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Compare command reads the logical blocks specified by the command from the medium and compares the data read to a comparison data buffer transferred as part of the command\&. If the data read from the controller and the comparison data buffer are equivalent with no miscompares, then the command completes successfully\&. If there is any miscompare, the command completes with an error of Compare Failure\&. If metadata is provided, then a comparison is also performed for the metadata\&.
+.SH "OPTIONS"
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+64\-bit address of the first block to access\&.
+.RE
+.PP
+\-c <nlb>, \-\-block\-count=<nlb>
+.RS 4
+Number of blocks to be accessed (zero\-based)\&.
+.RE
+.PP
+\-z <size>, \-\-data\-size=<size>
+.RS 4
+Size of data to be compared in bytes\&.
+.RE
+.PP
+\-y <metasize>, \-\-metadata\-size=<metasize>
+.RS 4
+Size of metadata to be transferred in bytes\&.
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+Reference Tag for Protection Information
+.RE
+.PP
+\-d <data\-file>, \-\-data=<data\-file>
+.RS 4
+Data file\&.
+.RE
+.PP
+\-M <meta>, \-\-metadata=<meta>
+.RS 4
+Metadata file\&.
+.RE
+.PP
+\-p <prinfo>, \-\-prinfo=<prinfo>
+.RS 4
+Protection Information and check field\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Bit
+T}:T{
+Description
+T}
+T{
+3
+T}:T{
+PRACT: Protection Information Action\&. When set to 1, PI is stripped/inserted on read/write when the block format\(cqs metadata size is 8\&. When set to 0, metadata is passes\&.
+T}
+T{
+2:0
+T}:T{
+PRCHK: Protection Information Check:
+T}
+T{
+2
+T}:T{
+Set to 1 enables checking the guard tag
+T}
+T{
+1
+T}:T{
+Set to 1 enables checking the application tag
+T}
+T{
+0
+T}:T{
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-m <appmask>, \-\-app\-tag\-mask=<appmask>
+.RS 4
+App Tag Mask for Protection Information
+.RE
+.PP
+\-a <apptag>, \-\-app\-tag=<apptag>
+.RS 4
+App Tag for Protection Information
+.RE
+.PP
+\-l, \-\-limited\-retry
+.RS 4
+Number of limited attempts to media\&.
+.RE
+.PP
+\-f, \-\-force\-unit\-access
+.RS 4
+FUA option to guarantee that data is stored to media\&.
+.RE
+.PP
+\-T <type>, \-\-dir\-type=<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 specification (1\&.3a) defines only one directive, 01h, for write stream identifiers\&.
+.RE
+.PP
+\-S <spec>, \-\-dir\-spec=<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
+\-D <dsm>, \-\-dsm=<dsm>
+.RS 4
+The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&.
+.RE
+.PP
+\-V, \-\-show\-cmd
+.RS 4
+Print out the command to be sent\&.
+.RE
+.PP
+\-w, \-\-dry\-run
+.RS 4
+Do not actually send the command\&. If want to use \-\-dry\-run option, \-\-show\-cmd option
+\fImust\fR
+be set\&. Otherwise \-\-dry\-run option will be
+\fIignored\fR\&.
+.RE
+.PP
+\-t, \-\-latency
+.RS 4
+Print out the latency the IOCTL took (in us)\&.
+.RE
+.PP
+\-g <storage\-tag>, \-\-storage\-tag=<storage\-tag>
+.RS 4
+Variable Sized Expected Logical Block Storage Tag(ELBST)\&.
+.RE
+.PP
+\-C, \-\-storage\-tag\-check
+.RS 4
+This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Ignore namespace is currently busy and performed the operation even though\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-compare.html b/Documentation/nvme-compare.html
new file mode 100644
index 0000000..e05cb8a
--- /dev/null
+++ b/Documentation/nvme-compare.html
@@ -0,0 +1,1123 @@
+<?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 10.2.0" />
+<title>nvme-compare(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-compare(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-compare -
+ Send an NVMe Compare 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-compare</em> &lt;device&gt; [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;]
+ [--data-size=&lt;size&gt; | -z &lt;size&gt;]
+ [--metadata-size=&lt;metasize&gt; | -y &lt;metasize&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--data=&lt;data-file&gt; | -d &lt;data-file&gt;]
+ [--metadata=&lt;meta&gt; | -M &lt;meta&gt;]
+ [--prinfo=&lt;prinfo&gt; | -p &lt;prinfo&gt;]
+ [--app-tag-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--dir-type=&lt;type&gt; | -T &lt;type&gt;]
+ [--dir-spec=&lt;spec&gt; | -S &lt;spec&gt;]
+ [--dsm=&lt;dsm&gt; | -D &lt;dsm&gt;]
+ [--show-command | -V]
+ [--dry-run | -w]
+ [--latency | -t]
+ [--storage-tag&lt;storage-tag&gt; | -g &lt;storage-tag&gt;]
+ [--storage-tag-check | -C]
+ [--force]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Compare command reads the logical blocks specified by the command
+from the medium and compares the data read to a comparison data buffer
+transferred as part of the command. If the data read from the controller
+and the comparison data buffer are equivalent with no miscompares,
+then the command completes successfully. If there is any miscompare,
+the command completes with an error of Compare Failure. If metadata is
+provided, then a comparison is also performed for the metadata.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ 64-bit address of the first block to access.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;nlb&gt;
+</dt>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dd>
+<p>
+ Number of blocks to be accessed (zero-based).
+</p>
+</dd>
+<dt class="hdlist1">
+-z &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--data-size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of data to be compared in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-y &lt;metasize&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-size=&lt;metasize&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata to be transferred in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Reference Tag for Protection Information
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Data file.
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;meta&gt;
+</dt>
+<dt class="hdlist1">
+--metadata=&lt;meta&gt;
+</dt>
+<dd>
+<p>
+ Metadata file.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dd>
+<p>
+ Protection Information and check field.
+</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">Bit</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format&#8217;s metadata size is 8. When set to 0,
+metadata is passes.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2:0</p></td>
+<td align="left" valign="top"><p class="table">PRCHK: Protection Information Check:</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the guard tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the application tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the reference tag</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ App Tag Mask for Protection Information
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ App Tag for Protection Information
+</p>
+</dd>
+<dt class="hdlist1">
+-l
+</dt>
+<dt class="hdlist1">
+--limited-retry
+</dt>
+<dd>
+<p>
+ Number of limited attempts to media.
+</p>
+</dd>
+<dt class="hdlist1">
+-f
+</dt>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dd>
+<p>
+ FUA option to guarantee that data is stored to media.
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;type&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&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
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;spec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&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">
+-D &lt;dsm&gt;
+</dt>
+<dt class="hdlist1">
+--dsm=&lt;dsm&gt;
+</dt>
+<dd>
+<p>
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dt class="hdlist1">
+--show-cmd
+</dt>
+<dd>
+<p>
+ Print out the command to be sent.
+</p>
+</dd>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--dry-run
+</dt>
+<dd>
+<p>
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option <em>must</em> be set. Otherwise --dry-run option will be
+ <em>ignored</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-t
+</dt>
+<dt class="hdlist1">
+--latency
+</dt>
+<dd>
+<p>
+ Print out the latency the IOCTL took (in us).
+</p>
+</dd>
+<dt class="hdlist1">
+-g &lt;storage-tag&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag=&lt;storage-tag&gt;
+</dt>
+<dd>
+<p>
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+</p>
+</dd>
+<dt class="hdlist1">
+-C
+</dt>
+<dt class="hdlist1">
+--storage-tag-check
+</dt>
+<dd>
+<p>
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Ignore namespace is currently busy and performed the operation
+ even though.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-compare.txt b/Documentation/nvme-compare.txt
new file mode 100644
index 0000000..59d1ea9
--- /dev/null
+++ b/Documentation/nvme-compare.txt
@@ -0,0 +1,172 @@
+nvme-compare(1)
+===============
+
+NAME
+----
+nvme-compare - Send an NVMe Compare command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-compare' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--data-size=<size> | -z <size>]
+ [--metadata-size=<metasize> | -y <metasize>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--data=<data-file> | -d <data-file>]
+ [--metadata=<meta> | -M <meta>]
+ [--prinfo=<prinfo> | -p <prinfo>]
+ [--app-tag-mask=<appmask> | -m <appmask>]
+ [--app-tag=<apptag> | -a <apptag>]
+ [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--dir-type=<type> | -T <type>]
+ [--dir-spec=<spec> | -S <spec>]
+ [--dsm=<dsm> | -D <dsm>]
+ [--show-command | -V]
+ [--dry-run | -w]
+ [--latency | -t]
+ [--storage-tag<storage-tag> | -g <storage-tag>]
+ [--storage-tag-check | -C]
+ [--force]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Compare command reads the logical blocks specified by the command
+from the medium and compares the data read to a comparison data buffer
+transferred as part of the command. If the data read from the controller
+and the comparison data buffer are equivalent with no miscompares,
+then the command completes successfully. If there is any miscompare,
+the command completes with an error of Compare Failure. If metadata is
+provided, then a comparison is also performed for the metadata.
+
+OPTIONS
+-------
+-s <slba>::
+--start-block=<slba>::
+ 64-bit address of the first block to access.
+
+-c <nlb>::
+--block-count=<nlb>::
+ Number of blocks to be accessed (zero-based).
+
+-z <size>::
+--data-size=<size>::
+ Size of data to be compared in bytes.
+
+-y <metasize>::
+--metadata-size=<metasize>::
+ Size of metadata to be transferred in bytes.
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ Reference Tag for Protection Information
+
+-d <data-file>::
+--data=<data-file>::
+ Data file.
+
+-M <meta>::
+--metadata=<meta>::
+ Metadata file.
+
+-p <prinfo>::
+--prinfo=<prinfo>::
+ Protection Information and check field.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+-m <appmask>::
+--app-tag-mask=<appmask>::
+ App Tag Mask for Protection Information
+
+-a <apptag>::
+--app-tag=<apptag>::
+ App Tag for Protection Information
+
+-l::
+--limited-retry::
+ Number of limited attempts to media.
+
+-f::
+--force-unit-access::
+ FUA option to guarantee that data is stored to media.
+
+-T <type>::
+--dir-type=<type>::
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+
+-S <spec>::
+--dir-spec=<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.
+
+-D <dsm>::
+--dsm=<dsm>::
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+-V::
+--show-cmd::
+ Print out the command to be sent.
+
+-w::
+--dry-run::
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option _must_ be set. Otherwise --dry-run option will be
+ _ignored_.
+
+-t::
+--latency::
+ Print out the latency the IOCTL took (in us).
+
+-g <storage-tag>::
+--storage-tag=<storage-tag>::
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+
+-C::
+--storage-tag-check::
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+
+--force::
+ Ignore namespace is currently busy and performed the operation
+ even though.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-config.txt b/Documentation/nvme-config.txt
new file mode 100644
index 0000000..8a66644
--- /dev/null
+++ b/Documentation/nvme-config.txt
@@ -0,0 +1,213 @@
+nvme-config(1)
+===============
+
+NAME
+----
+nvme-config - NVMe-over-Fabrics configuration.
+
+SYNOPSIS
+--------
+[verse]
+'nvme config' [--scan | -R] [--modify | -M] [--update | -U] [--dump | -O]
+ [--config=<cfg> | -J <cfg>]
+ [--transport=<trtype> | -t <trtype>]
+ [--nqn=<subnqn> | -n <subnqn>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--host-iface=<iface> | -f <iface>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--dhchap-secret=<secret> | -S <secret>]
+ [--dhchap-ctrl-secret=<secret> | -C <secret>]
+ [--nr-io-queues=<#> | -i <#>]
+ [--nr-write-queues=<#> | -W <#>]
+ [--nr-poll-queues=<#> | -P <#>]
+ [--queue-size=<#> | -Q <#>]
+ [--keep-alive-tmo=<#> | -k <#>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>]
+ [--duplicate-connect | -D] [--disable-sqflow | -d]
+ [--hdr-digest | -g] [--data-digest | -G]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Read in the NVMe over Fabrics configuration from the specified JSON
+configuration file and allow to update or modify the contents.
+The JSON configuration file format is documented in
+https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json
+
+OPTIONS
+-------
+-R::
+--scan::
+ Additionally read the current configuration from sysfs.
+
+-M::
+--modify::
+ Add or modify entries in the configuration based on the values from
+ the commandline.
+
+-U::
+--update::
+ Write updated configuration into the JSON configuration file.
+
+-O::
+--dump::
+ Print out resulting JSON configuration file to stdout.
+
+-J <cfg>::
+--config=<cfg>::
+ Use the specified JSON configuration file instead of the
+ default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in
+ an existing configuration file.
+
+-t <trtype>::
+--transport=<trtype>::
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string values include:
++
+[]
+|=================
+|Value|Definition
+|rdma|The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
+|fc |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
+|=================
+
+-n <subnqn>::
+--nqn <subnqn>::
+ This field specifies the name for the NVMe subsystem to connect to.
+
+-a <traddr>::
+--traddr=<traddr>::
+ This field specifies the network address of the Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+
+-s <trsvcid>::
+--trsvcid=<trsvcid>::
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+
+-w <traddr>::
+--host-traddr=<traddr>::
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+
+-f <iface>::
+--host-iface=<iface>::
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+
+-q <hostnqn>::
+--hostnqn=<hostnqn>::
+ Overrides the default Host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ @SYSCONFDIR@/nvme/hostnqn first. If that does not exist, the autogenerated
+ NQN value from the NVMe Host kernel module is used next.
+ The Host NQN uniquely identifies the NVMe Host.
+
+-I <hostid>::
+--hostid=<hostid>::
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+
+-S <secret>::
+--dhchap-secret=<secret>::
+ NVMe In-band authentication secret; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 'Secret representation'.
+ If this option is not specified, the default is read from
+ @SYSCONFDIR@/nvme/hostkey. If that does not exist no in-band authentication
+ is attempted.
+
+-C <secret>::
+--dhchap-ctrl-secret=<secret>::
+ NVMe In-band authentication controller secret for bi-directional
+ authentication; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 'Secret representation'.
+ If not present bi-directional authentication is not attempted.
+
+-i <#>::
+--nr-io-queues=<#>::
+ Overrides the default number of I/O queues create by the driver.
+
+-W <#>::
+--nr-write-queues=<#>::
+ Adds additional queues that will be used for write I/O.
+
+-P <#>::
+--nr-poll-queues=<#>::
+ Adds additional queues that will be used for polling latency sensitive I/O.
+
+-Q <#>::
+--queue-size=<#>::
+ Overrides the default number of elements in the I/O queues created
+ by the driver.
+
+-k <#>::
+--keep-alive-tmo=<#>::
+ Overrides the default keep alive timeout (in seconds).
+
+-c <#>::
+--reconnect-delay=<#>::
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+
+-l <#>::
+--ctrl-loss-tmo=<#>::
+ Overrides the default controller loss timeout period (in seconds).
+
+-D::
+--duplicate-connect::
+ Allows duplicated connections between same transport host and subsystem
+ port.
+
+-d::
+--disable-sqflow::
+ Disables SQ flow control to omit head doorbell update for submission
+ queues when sending nvme completions.
+
+-g::
+--hdr-digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data-digest::
+ Generates/verifies data digest (TCP).
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Read the current system configuration and write the contents to /tmp/config.json:
++
+------------
+# nvme config --config /tmp/config.json --scan --update
+------------
+
+SEE ALSO
+--------
+nvme-discover(1)
+nvme-connect(1)
+https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json
+
+AUTHORS
+-------
+This was written by mailto:hare@suse.com[Hannes Reinecke]
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-connect-all.1 b/Documentation/nvme-connect-all.1
new file mode 100644
index 0000000..3ee4f6d
--- /dev/null
+++ b/Documentation/nvme-connect-all.1
@@ -0,0 +1,385 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CONNECT\-ALL" "1" "02/14/2024" "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-connect-all \- Discover and Connect to Fabrics controllers\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme connect\-all\fR [\-\-transport=<trtype> | \-t <trtype>]
+ [\-\-nqn=<subnqn> | \-n <subnqn>]
+ [\-\-traddr=<traddr> | \-a <traddr>]
+ [\-\-trsvcid=<trsvcid> | \-s <trsvcid>]
+ [\-\-host\-traddr=<traddr> | \-w <traddr>]
+ [\-\-host\-iface=<iface> | \-f <iface>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-raw=<filename> | \-r <filename>]
+ [\-\-device=<device> | \-d <device>]
+ [\-\-config=<filename> | \-J <cfg>]
+ [\-\-keep\-alive\-tmo=<sec> | \-k <sec>]
+ [\-\-reconnect\-delay=<#> | \-c <#>]
+ [\-\-ctrl\-loss\-tmo=<#> | \-l <#>]
+ [\-\-nr\-io\-queues=<#> | \-i <#>]
+ [\-\-nr\-write\-queues=<#> | \-W <#>]
+ [\-\-nr\-poll\-queues=<#> | \-P <#>]
+ [\-\-queue\-size=<#> | \-Q <#>] [\-\-keyring=<#>]
+ [\-\-tls_key=<#>] [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G]
+ [\-\-persistent | \-p] [\-\-tls] [\-\-concat] [\-\-quiet | \-S]
+ [\-\-dump\-config | \-O] [\-\-nbft] [\-\-no\-nbft]
+ [\-\-nbft\-path=<STR>] [\-\-context=<STR>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send one or more Discovery requests to a NVMe over Fabrics Discovery Controller, and create controllers for the returned discovery records\&.
+.sp
+If no parameters are given, then \fInvme connect\-all\fR will attempt to find a /usr/local/etc/nvme/discovery\&.conf file to use to supply a list of connect\-all commands to run\&. If no /usr/local/etc/nvme/discovery\&.conf file exists, the command will quit with an error\&.
+.sp
+Otherwise a specific Discovery Controller should be specified using the \-\-transport, \-\-traddr and if necessary the \-\-trsvcid and a Discovery request will be sent to the specified Discovery Controller\&.
+.sp
+See the documentation for the nvme\-discover(1) command for further background\&.
+.SH "OPTIONS"
+.PP
+\-t <trtype>, \-\-transport=<trtype>
+.RS 4
+This field specifies the network fabric being used for a NVMe\-over\-Fabrics network\&. Current string values include:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+rdma
+T}:T{
+The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
+T}
+T{
+fc
+T}:T{
+\fBWIP\fR
+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
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-n <subnqn>, \-\-nqn <subnqn>
+.RS 4
+This field specifies the name for the NVMe subsystem to connect to\&.
+.RE
+.PP
+\-a <traddr>, \-\-traddr=<traddr>
+.RS 4
+This field specifies the network address of the Discovery Controller\&. For transports using IP addressing (e\&.g\&. rdma) this should be an IP\-based address (ex\&. IPv4)\&.
+.RE
+.PP
+\-s <trsvcid>, \-\-trsvcid=<trsvcid>
+.RS 4
+This field specifies the transport service id\&. For transports using IP addressing (e\&.g\&. rdma) this field is the port number\&. By default, the IP port number for the RDMA transport is 4420\&.
+.RE
+.PP
+\-w <traddr>, \-\-host\-traddr=<traddr>
+.RS 4
+This field specifies the network address used on the host to connect to the Controller\&. For TCP, this sets the source address on the socket\&.
+.RE
+.PP
+\-f <iface>, \-\-host\-iface=<iface>
+.RS 4
+This field specifies the network interface used on the host to connect to the Controller (e\&.g\&. IP eth1, enp2s0, enx78e7d1ea46da)\&. This forces the connection to be made on a specific interface instead of letting the system decide\&.
+.RE
+.PP
+\-q <hostnqn>, \-\-hostnqn=<hostnqn>
+.RS 4
+Overrides the default Host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&. The Host NQN uniquely identifies the NVMe Host, and may be used by the the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection\&.
+.RE
+.PP
+\-I <hostid>, \-\-hostid=<hostid>
+.RS 4
+UUID(Universally Unique Identifier) to be discovered which should be formatted\&.
+.RE
+.PP
+\-r <filename>, \-\-raw=<filename>
+.RS 4
+This field will take the output of the
+\fInvme connect\-all\fR
+command and dump it to a raw binary file\&. By default
+\fInvme connect\-all\fR
+will dump the output to stdout\&.
+.RE
+.PP
+\-d <device>, \-\-device=<device>
+.RS 4
+This field takes a device as input\&. It must be a persistent device associated with a Discovery Controller previously created by the command "connect\-all" or "discover"\&. <device> follows the format nvme*, eg\&. nvme0, nvme1\&.
+.RE
+.PP
+\-J <filename>, \-\-config=<filename>
+.RS 4
+Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or
+\fInone\fR
+to not read in an existing configuration file\&. The JSON configuration file format is documented in
+\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[]
+.RE
+.PP
+\-k <#>, \-\-keep\-alive\-tmo=<#>
+.RS 4
+Overrides the default keep alive timeout (in seconds)\&. This option will be ignored for discovery, but will be passed on to the subsequent connect call\&.
+.RE
+.PP
+\-c <#>, \-\-reconnect\-delay=<#>
+.RS 4
+Overrides the default delay (in seconds) before reconnect is attempted after a connect loss\&.
+.RE
+.PP
+\-l <#>, \-\-ctrl\-loss\-tmo=<#>
+.RS 4
+Overrides the default controller loss timeout period (in seconds)\&.
+.RE
+.PP
+\-i <#>, \-\-nr\-io\-queues=<#>
+.RS 4
+Overrides the default number of I/O queues create by the driver\&. This option will be ignored for discovery, but will be passed on to the subsequent connect call\&.
+.RE
+.PP
+\-W <#>, \-\-nr\-write\-queues=<#>
+.RS 4
+Adds additional queues that will be used for write I/O\&.
+.RE
+.PP
+\-P <#>, \-\-nr\-poll\-queues=<#>
+.RS 4
+Adds additional queues that will be used for polling latency sensitive I/O\&.
+.RE
+.PP
+\-Q <#>, \-\-queue\-size=<#>
+.RS 4
+Overrides the default number of elements in the I/O queues created by the driver\&. This option will be ignored for discovery, but will be passed on to the subsequent connect call\&.
+.RE
+.PP
+\-\-keyring=<#>
+.RS 4
+Keyring for TLS key lookup\&.
+.RE
+.PP
+\-\-tls_key=<#>
+.RS 4
+TLS key for the connection (TCP)\&.
+.RE
+.PP
+\-g, \-\-hdr\-digest
+.RS 4
+Generates/verifies header digest (TCP)\&.
+.RE
+.PP
+\-G, \-\-data\-digest
+.RS 4
+Generates/verifies data digest (TCP)\&.
+.RE
+.PP
+\-p, \-\-persistent
+.RS 4
+Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
+.RE
+.PP
+\-\-tls
+.RS 4
+Enable TLS encryption (TCP)\&.
+.RE
+.PP
+\-\-concat
+.RS 4
+Enable secure concatenation (TCP)\&.
+.RE
+.PP
+\-S, \-\-quiet
+.RS 4
+Suppress error messages\&.
+.RE
+.PP
+\-O, \-\-dump\-config
+.RS 4
+Print out resulting JSON configuration file to stdout\&.
+.RE
+.PP
+\-\-nbft
+.RS 4
+Only look at NBFT tables
+.RE
+.PP
+\-\-no\-nbft
+.RS 4
+Do not look at NBFT tables
+.RE
+.PP
+\-\-nbft\-path=<STR>
+.RS 4
+Use a user\-defined path to the NBFT tables
+.RE
+.PP
+\-\-context <STR>
+.RS 4
+Set the execution context to <STR>\&. This allows to coordinate the management of the global resources\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Connect to all records returned by the Discover Controller with IP4 address 192\&.168\&.1\&.3 for all resources allocated for NVMe Host name host1\-rogue\-nqn on the RDMA network\&. Port 4420 is used by default:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme connect\-all \-\-transport=rdma \-\-traddr=192\&.168\&.1\&.3 \e
+\-\-hostnqn=host1\-rogue\-nqn
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme connect\-all\fR
+command using the default system defined NBFT tables:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme connect\-all \-\-nbft
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme connect\-all\fR
+command with a user\-defined path for the NBFT table:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme connet\-all \-\-nbft\-path=/sys/firmware/acpi/tables/NBFT1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme connect\-all\fR
+command using a /usr/local/etc/nvme/discovery\&.conf file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Machine default \*(Aqnvme discover\*(Aq commands\&. Query the
+# Discovery Controller\*(Aqs two ports (some resources may only
+# be accessible on a single port)\&. Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example\&.
+\-t rdma \-a 192\&.168\&.69\&.33 \-s 4420 \-q nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+\-t rdma \-a 192\&.168\&.1\&.4 \-s 4420 \-q nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+
+At the prompt type "nvme connect\-all"\&.
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-discover(1) nvme\-connect(1)
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-connect-all.html b/Documentation/nvme-connect-all.html
new file mode 100644
index 0000000..5a3ef23
--- /dev/null
+++ b/Documentation/nvme-connect-all.html
@@ -0,0 +1,1283 @@
+<?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 10.2.0" />
+<title>nvme-connect-all(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-connect-all(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-connect-all -
+ Discover and Connect to Fabrics controllers.
+</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 connect-all</em> [--transport=&lt;trtype&gt; | -t &lt;trtype&gt;]
+ [--nqn=&lt;subnqn&gt; | -n &lt;subnqn&gt;]
+ [--traddr=&lt;traddr&gt; | -a &lt;traddr&gt;]
+ [--trsvcid=&lt;trsvcid&gt; | -s &lt;trsvcid&gt;]
+ [--host-traddr=&lt;traddr&gt; | -w &lt;traddr&gt;]
+ [--host-iface=&lt;iface&gt; | -f &lt;iface&gt;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&gt;]
+ [--raw=&lt;filename&gt; | -r &lt;filename&gt;]
+ [--device=&lt;device&gt; | -d &lt;device&gt;]
+ [--config=&lt;filename&gt; | -J &lt;cfg&gt;]
+ [--keep-alive-tmo=&lt;sec&gt; | -k &lt;sec&gt;]
+ [--reconnect-delay=&lt;#&gt; | -c &lt;#&gt;]
+ [--ctrl-loss-tmo=&lt;#&gt; | -l &lt;#&gt;]
+ [--nr-io-queues=&lt;#&gt; | -i &lt;#&gt;]
+ [--nr-write-queues=&lt;#&gt; | -W &lt;#&gt;]
+ [--nr-poll-queues=&lt;#&gt; | -P &lt;#&gt;]
+ [--queue-size=&lt;#&gt; | -Q &lt;#&gt;] [--keyring=&lt;#&gt;]
+ [--tls_key=&lt;#&gt;] [--hdr-digest | -g] [--data-digest | -G]
+ [--persistent | -p] [--tls] [--concat] [--quiet | -S]
+ [--dump-config | -O] [--nbft] [--no-nbft]
+ [--nbft-path=&lt;STR&gt;] [--context=&lt;STR&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send one or more Discovery requests to a NVMe over Fabrics Discovery
+Controller, and create controllers for the returned discovery records.</p></div>
+<div class="paragraph"><p>If no parameters are given, then <em>nvme connect-all</em> will attempt to
+find a /usr/local/etc/nvme/discovery.conf file to use to supply a list of
+connect-all commands to run. If no /usr/local/etc/nvme/discovery.conf file
+exists, the command will quit with an error.</p></div>
+<div class="paragraph"><p>Otherwise a specific Discovery Controller should be specified using the
+--transport, --traddr and if necessary the --trsvcid and a Discovery
+request will be sent to the specified Discovery Controller.</p></div>
+<div class="paragraph"><p>See the documentation for the nvme-discover(1) command for further
+background.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-t &lt;trtype&gt;
+</dt>
+<dt class="hdlist1">
+--transport=&lt;trtype&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string 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">rdma</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">fc</p></td>
+<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>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-n &lt;subnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn &lt;subnqn&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the name for the NVMe subsystem to connect to.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address of the Discovery Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;trsvcid&gt;
+</dt>
+<dt class="hdlist1">
+--trsvcid=&lt;trsvcid&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+</p>
+</dd>
+<dt class="hdlist1">
+-w &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--host-traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;iface&gt;
+</dt>
+<dt class="hdlist1">
+--host-iface=&lt;iface&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+</p>
+</dd>
+<dt class="hdlist1">
+-q &lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+--hostnqn=&lt;hostnqn&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default Host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ /usr/local/etc/nvme/hostnqn first. If that does not exist, the
+ autogenerated NQN value from the NVMe Host kernel module is used next.
+ The Host NQN uniquely identifies the NVMe Host, and may be used by the
+ the Discovery Controller to control what NVMe Target resources are
+ allocated to the NVMe Host for a connection.
+</p>
+</dd>
+<dt class="hdlist1">
+-I &lt;hostid&gt;
+</dt>
+<dt class="hdlist1">
+--hostid=&lt;hostid&gt;
+</dt>
+<dd>
+<p>
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;filename&gt;
+</dt>
+<dt class="hdlist1">
+--raw=&lt;filename&gt;
+</dt>
+<dd>
+<p>
+ This field will take the output of the <em>nvme connect-all</em> command
+ and dump it to a raw binary file. By default <em>nvme connect-all</em> will
+ dump the output to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;device&gt;
+</dt>
+<dt class="hdlist1">
+--device=&lt;device&gt;
+</dt>
+<dd>
+<p>
+ This field takes a device as input. It must be a persistent device
+ associated with a Discovery Controller previously created by the
+ command "connect-all" or "discover". &lt;device&gt; follows the format
+ nvme*, eg. nvme0, nvme1.
+</p>
+</dd>
+<dt class="hdlist1">
+-J &lt;filename&gt;
+</dt>
+<dt class="hdlist1">
+--config=&lt;filename&gt;
+</dt>
+<dd>
+<p>
+ Use the specified JSON configuration file instead of the
+ default /usr/local/etc/nvme/config.json file or <em>none</em> to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ <a href="https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json">https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json</a>
+</p>
+</dd>
+<dt class="hdlist1">
+-k &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--keep-alive-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default keep alive timeout (in seconds). This
+ option will be ignored for discovery, but will be passed on to
+ the subsequent connect call.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--reconnect-delay=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--ctrl-loss-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default controller loss timeout period (in seconds).
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-io-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of I/O queues create by the driver.
+ This option will be ignored for discovery, but will be passed on
+ to the subsequent connect call.
+</p>
+</dd>
+<dt class="hdlist1">
+-W &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-write-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for write I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-P &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-poll-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for polling latency sensitive I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-Q &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--queue-size=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of elements in the I/O queues created
+ by the driver. This option will be ignored for discovery, but will be
+ passed on to the subsequent connect call.
+</p>
+</dd>
+<dt class="hdlist1">
+--keyring=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Keyring for TLS key lookup.
+</p>
+</dd>
+<dt class="hdlist1">
+--tls_key=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ TLS key for the connection (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-g
+</dt>
+<dt class="hdlist1">
+--hdr-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies header digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-G
+</dt>
+<dt class="hdlist1">
+--data-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies data digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--persistent
+</dt>
+<dd>
+<p>
+ Don&#8217;t remove the discovery controller after retrieving the discovery
+ log page.
+</p>
+</dd>
+<dt class="hdlist1">
+--tls
+</dt>
+<dd>
+<p>
+ Enable TLS encryption (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+--concat
+</dt>
+<dd>
+<p>
+ Enable secure concatenation (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-S
+</dt>
+<dt class="hdlist1">
+--quiet
+</dt>
+<dd>
+<p>
+ Suppress error messages.
+</p>
+</dd>
+<dt class="hdlist1">
+-O
+</dt>
+<dt class="hdlist1">
+--dump-config
+</dt>
+<dd>
+<p>
+ Print out resulting JSON configuration file to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+--nbft
+</dt>
+<dd>
+<p>
+ Only look at NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--no-nbft
+</dt>
+<dd>
+<p>
+ Do not look at NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--nbft-path=&lt;STR&gt;
+</dt>
+<dd>
+<p>
+ Use a user-defined path to the NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--context &lt;STR&gt;
+</dt>
+<dd>
+<p>
+ Set the execution context to &lt;STR&gt;. This allows to coordinate
+ the management of the global resources.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Connect to all records returned by the Discover Controller with IP4 address
+192.168.1.3 for all resources allocated for NVMe Host name host1-rogue-nqn on
+the RDMA network. Port 4420 is used by default:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme connect-all --transport=rdma --traddr=192.168.1.3 \
+--hostnqn=host1-rogue-nqn</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme connect-all</em> command using the default system defined NBFT tables:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme connect-all --nbft</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme connect-all</em> command with a user-defined path for the NBFT table:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme connet-all --nbft-path=/sys/firmware/acpi/tables/NBFT1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme connect-all</em> command using a /usr/local/etc/nvme/discovery.conf file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># Machine default 'nvme discover' commands. Query the
+# Discovery Controller's two ports (some resources may only
+# be accessible on a single port). Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example.
+-t rdma -a 192.168.69.33 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+-t rdma -a 192.168.1.4 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+
+At the prompt type "nvme connect-all".</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-discover(1)
+nvme-connect(1)</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt
new file mode 100644
index 0000000..4cd1873
--- /dev/null
+++ b/Documentation/nvme-connect-all.txt
@@ -0,0 +1,267 @@
+nvme-connect-all(1)
+===================
+
+NAME
+----
+nvme-connect-all - Discover and Connect to Fabrics controllers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme connect-all' [--transport=<trtype> | -t <trtype>]
+ [--nqn=<subnqn> | -n <subnqn>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--host-iface=<iface> | -f <iface>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--raw=<filename> | -r <filename>]
+ [--device=<device> | -d <device>]
+ [--config=<filename> | -J <cfg>]
+ [--keep-alive-tmo=<sec> | -k <sec>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>]
+ [--nr-io-queues=<#> | -i <#>]
+ [--nr-write-queues=<#> | -W <#>]
+ [--nr-poll-queues=<#> | -P <#>]
+ [--queue-size=<#> | -Q <#>] [--keyring=<#>]
+ [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G]
+ [--persistent | -p] [--tls] [--concat] [--quiet | -S]
+ [--dump-config | -O] [--nbft] [--no-nbft]
+ [--nbft-path=<STR>] [--context=<STR>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send one or more Discovery requests to a NVMe over Fabrics Discovery
+Controller, and create controllers for the returned discovery records.
+
+If no parameters are given, then 'nvme connect-all' will attempt to
+find a @SYSCONFDIR@/nvme/discovery.conf file to use to supply a list of
+connect-all commands to run. If no @SYSCONFDIR@/nvme/discovery.conf file
+exists, the command will quit with an error.
+
+Otherwise a specific Discovery Controller should be specified using the
+--transport, --traddr and if necessary the --trsvcid and a Discovery
+request will be sent to the specified Discovery Controller.
+
+See the documentation for the nvme-discover(1) command for further
+background.
+
+OPTIONS
+-------
+-t <trtype>::
+--transport=<trtype>::
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string values include:
++
+[]
+|=================
+|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
+|=================
+
+-n <subnqn>::
+--nqn <subnqn>::
+ This field specifies the name for the NVMe subsystem to connect to.
+
+-a <traddr>::
+--traddr=<traddr>::
+ This field specifies the network address of the Discovery Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+
+-s <trsvcid>::
+--trsvcid=<trsvcid>::
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+
+-w <traddr>::
+--host-traddr=<traddr>::
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+
+-f <iface>::
+--host-iface=<iface>::
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+
+-q <hostnqn>::
+--hostnqn=<hostnqn>::
+ Overrides the default Host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ @SYSCONFDIR@/nvme/hostnqn first. If that does not exist, the
+ autogenerated NQN value from the NVMe Host kernel module is used next.
+ The Host NQN uniquely identifies the NVMe Host, and may be used by the
+ the Discovery Controller to control what NVMe Target resources are
+ allocated to the NVMe Host for a connection.
+
+-I <hostid>::
+--hostid=<hostid>::
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+
+-r <filename>::
+--raw=<filename>::
+ This field will take the output of the 'nvme connect-all' command
+ and dump it to a raw binary file. By default 'nvme connect-all' will
+ dump the output to stdout.
+
+-d <device>::
+--device=<device>::
+ This field takes a device as input. It must be a persistent device
+ associated with a Discovery Controller previously created by the
+ command "connect-all" or "discover". <device> follows the format
+ nvme*, eg. nvme0, nvme1.
+
+-J <filename>::
+--config=<filename>::
+ Use the specified JSON configuration file instead of the
+ default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json
+
+-k <#>::
+--keep-alive-tmo=<#>::
+ Overrides the default keep alive timeout (in seconds). This
+ option will be ignored for discovery, but will be passed on to
+ the subsequent connect call.
+
+-c <#>::
+--reconnect-delay=<#>::
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+
+-l <#>::
+--ctrl-loss-tmo=<#>::
+ Overrides the default controller loss timeout period (in seconds).
+
+-i <#>::
+--nr-io-queues=<#>::
+ Overrides the default number of I/O queues create by the driver.
+ This option will be ignored for discovery, but will be passed on
+ to the subsequent connect call.
+
+-W <#>::
+--nr-write-queues=<#>::
+ Adds additional queues that will be used for write I/O.
+
+-P <#>::
+--nr-poll-queues=<#>::
+ Adds additional queues that will be used for polling latency sensitive I/O.
+
+-Q <#>::
+--queue-size=<#>::
+ Overrides the default number of elements in the I/O queues created
+ by the driver. This option will be ignored for discovery, but will be
+ passed on to the subsequent connect call.
+
+--keyring=<#>::
+ Keyring for TLS key lookup.
+
+--tls_key=<#>::
+ TLS key for the connection (TCP).
+
+-g::
+--hdr-digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data-digest::
+ Generates/verifies data digest (TCP).
+
+-p::
+--persistent::
+ Don't remove the discovery controller after retrieving the discovery
+ log page.
+
+--tls::
+ Enable TLS encryption (TCP).
+
+--concat::
+ Enable secure concatenation (TCP).
+
+-S::
+--quiet::
+ Suppress error messages.
+
+-O::
+--dump-config::
+ Print out resulting JSON configuration file to stdout.
+
+--nbft::
+ Only look at NBFT tables
+
+--no-nbft::
+ Do not look at NBFT tables
+
+--nbft-path=<STR>::
+ Use a user-defined path to the NBFT tables
+
+--context <STR>::
+ Set the execution context to <STR>. This allows to coordinate
+ the management of the global resources.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Connect to all records returned by the Discover Controller with IP4 address
+192.168.1.3 for all resources allocated for NVMe Host name host1-rogue-nqn on
+the RDMA network. Port 4420 is used by default:
++
+------------
+# nvme connect-all --transport=rdma --traddr=192.168.1.3 \
+--hostnqn=host1-rogue-nqn
+------------
++
+* Issue a 'nvme connect-all' command using the default system defined NBFT tables:
++
+-----------
+# nvme connect-all --nbft
+------------
++
+* Issue a 'nvme connect-all' command with a user-defined path for the NBFT table:
++
+-----------
+# nvme connet-all --nbft-path=/sys/firmware/acpi/tables/NBFT1
+------------
++
+* Issue a 'nvme connect-all' command using a @SYSCONFDIR@/nvme/discovery.conf file:
++
+-----------
+# Machine default 'nvme discover' commands. Query the
+# Discovery Controller's two ports (some resources may only
+# be accessible on a single port). Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example.
+-t rdma -a 192.168.69.33 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+-t rdma -a 192.168.1.4 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+
+At the prompt type "nvme connect-all".
+
+------------
+
+SEE ALSO
+--------
+nvme-discover(1)
+nvme-connect(1)
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-connect.1 b/Documentation/nvme-connect.1
new file mode 100644
index 0000000..0210d8a
--- /dev/null
+++ b/Documentation/nvme-connect.1
@@ -0,0 +1,304 @@
+'\" t
+.\" Title: nvme-connect
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CONNECT" "1" "02/14/2024" "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-connect \- Connect to a Fabrics controller\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme connect\fR [\-\-transport=<trtype> | \-t <trtype>]
+ [\-\-nqn=<subnqn> | \-n <subnqn>]
+ [\-\-traddr=<traddr> | \-a <traddr>]
+ [\-\-trsvcid=<trsvcid> | \-s <trsvcid>]
+ [\-\-host\-traddr=<traddr> | \-w <traddr>]
+ [\-\-host\-iface=<iface> | \-f <iface>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-config=<filename> | \-J <filename>]
+ [\-\-dhchap\-secret=<secret> | \-S <secret>]
+ [\-\-dhchap\-ctrl\-secret=<secret> | \-C <secret>]
+ [\-\-nr\-io\-queues=<#> | \-i <#>]
+ [\-\-nr\-write\-queues=<#> | \-W <#>]
+ [\-\-nr\-poll\-queues=<#> | \-P <#>]
+ [\-\-queue\-size=<#> | \-Q <#>]
+ [\-\-keep\-alive\-tmo=<#> | \-k <#>]
+ [\-\-reconnect\-delay=<#> | \-c <#>]
+ [\-\-ctrl\-loss\-tmo=<#> | \-l <#>] [\-\-tos=<#> | \-T <#>]
+ [\-\-keyring=<#>] [\-\-tls_key=<#>]
+ [\-\-duplicate\-connect | \-D] [\-\-disable\-sqflow | \-d]
+ [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G] [\-\-tls]
+ [\-\-concat] [\-\-dump\-config | \-O] [\-\-application=<id>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Create a transport connection to a remote system (specified by \-\-traddr and \-\-trsvcid) and create a NVMe over Fabrics controller for the NVMe subsystem specified by the \-\-nqn option\&.
+.SH "OPTIONS"
+.PP
+\-t <trtype>, \-\-transport=<trtype>
+.RS 4
+This field specifies the network fabric being used for a NVMe\-over\-Fabrics network\&. Current string values include:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+rdma
+T}:T{
+The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
+T}
+T{
+fc
+T}:T{
+\fBWIP\fR
+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
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-n <subnqn>, \-\-nqn <subnqn>
+.RS 4
+This field specifies the name for the NVMe subsystem to connect to\&.
+.RE
+.PP
+\-a <traddr>, \-\-traddr=<traddr>
+.RS 4
+This field specifies the network address of the Controller\&. For transports using IP addressing (e\&.g\&. rdma) this should be an IP\-based address (ex\&. IPv4)\&.
+.RE
+.PP
+\-s <trsvcid>, \-\-trsvcid=<trsvcid>
+.RS 4
+This field specifies the transport service id\&. For transports using IP addressing (e\&.g\&. rdma) this field is the port number\&. By default, the IP port number for the RDMA transport is 4420\&.
+.RE
+.PP
+\-w <traddr>, \-\-host\-traddr=<traddr>
+.RS 4
+This field specifies the network address used on the host to connect to the Controller\&. For TCP, this sets the source address on the socket\&.
+.RE
+.PP
+\-f <iface>, \-\-host\-iface=<iface>
+.RS 4
+This field specifies the network interface used on the host to connect to the Controller (e\&.g\&. IP eth1, enp2s0, enx78e7d1ea46da)\&. This forces the connection to be made on a specific interface instead of letting the system decide\&.
+.RE
+.PP
+\-q <hostnqn>, \-\-hostnqn=<hostnqn>
+.RS 4
+Overrides the default Host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&. The Host NQN uniquely identifies the NVMe Host\&.
+.RE
+.PP
+\-I <hostid>, \-\-hostid=<hostid>
+.RS 4
+UUID(Universally Unique Identifier) to be discovered which should be formatted\&.
+.RE
+.PP
+\-J <filename>, \-\-config=<filename>
+.RS 4
+Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or
+\fInone\fR
+to not read in an existing configuration file\&. The JSON configuration file format is documented in
+\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[]
+.RE
+.PP
+\-S <secret>, \-\-dhchap\-secret=<secret>
+.RS 4
+NVMe In\-band authentication secret; needs to be in ASCII format as specified in NVMe 2\&.0 section 8\&.13\&.5\&.8
+\fISecret representation\fR\&.
+.RE
+.PP
+\-C <secret>, \-\-dhchap\-ctrl\-secret=<secret>
+.RS 4
+NVMe In\-band authentication controller secret for bi\-directional authentication; needs to be in ASCII format as specified in NVMe 2\&.0 section 8\&.13\&.5\&.8
+\fISecret representation\fR\&. If not present bi\-directional authentication is not attempted\&.
+.RE
+.PP
+\-i <#>, \-\-nr\-io\-queues=<#>
+.RS 4
+Overrides the default number of I/O queues create by the driver\&.
+.RE
+.PP
+\-W <#>, \-\-nr\-write\-queues=<#>
+.RS 4
+Adds additional queues that will be used for write I/O\&.
+.RE
+.PP
+\-P <#>, \-\-nr\-poll\-queues=<#>
+.RS 4
+Adds additional queues that will be used for polling latency sensitive I/O\&.
+.RE
+.PP
+\-Q <#>, \-\-queue\-size=<#>
+.RS 4
+Overrides the default number of elements in the I/O queues created by the driver\&.
+.RE
+.PP
+\-k <#>, \-\-keep\-alive\-tmo=<#>
+.RS 4
+Overrides the default keep alive timeout (in seconds)\&.
+.RE
+.PP
+\-c <#>, \-\-reconnect\-delay=<#>
+.RS 4
+Overrides the default delay (in seconds) before reconnect is attempted after a connect loss\&.
+.RE
+.PP
+\-l <#>, \-\-ctrl\-loss\-tmo=<#>
+.RS 4
+Overrides the default controller loss timeout period (in seconds)\&.
+.RE
+.PP
+\-T <#>, \-\-tos=<#>
+.RS 4
+Type of service for the connection (TCP)
+.RE
+.PP
+\-\-keyring=<#>
+.RS 4
+Keyring for TLS key lookup\&.
+.RE
+.PP
+\-\-tls_key=<#>
+.RS 4
+TLS key for the connection (TCP)\&.
+.RE
+.PP
+\-D, \-\-duplicate\-connect
+.RS 4
+Allows duplicated connections between same transport host and subsystem port\&.
+.RE
+.PP
+\-d, \-\-disable\-sqflow
+.RS 4
+Disables SQ flow control to omit head doorbell update for submission queues when sending nvme completions\&.
+.RE
+.PP
+\-g, \-\-hdr\-digest
+.RS 4
+Generates/verifies header digest (TCP)\&.
+.RE
+.PP
+\-G, \-\-data\-digest
+.RS 4
+Generates/verifies data digest (TCP)\&.
+.RE
+.PP
+\-\-tls
+.RS 4
+Enable TLS encryption (TCP)\&.
+.RE
+.PP
+\-\-concat
+.RS 4
+Enable secure concatenation (TCP)\&.
+.RE
+.PP
+\-O, \-\-dump\-config
+.RS 4
+Print out resulting JSON configuration file to stdout\&.
+.RE
+.PP
+\-\-context <STR>
+.RS 4
+Set the execution context to <STR>\&. This allows to coordinate the management of the global resources\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Connect to a subsystem named nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432 on the IP4 address 192\&.168\&.1\&.3\&. Port 4420 is used by default:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme connect \-\-transport=rdma \-\-traddr=192\&.168\&.1\&.3 \e
+\-\-nqn=nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-discover(1) nvme\-connect\-all(1)
+.SH "AUTHORS"
+.sp
+This was co\-written by \m[blue]\fBJay Freyensee\fR\m[]\&\s-2\u[1]\d\s+2 and \m[blue]\fBChristoph Hellwig\fR\m[]\&\s-2\u[2]\d\s+2
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
+.SH "NOTES"
+.IP " 1." 4
+Jay Freyensee
+.RS 4
+\%mailto:james.p.freyensee@intel.com
+.RE
+.IP " 2." 4
+Christoph Hellwig
+.RS 4
+\%mailto:hch@lst.de
+.RE
diff --git a/Documentation/nvme-connect.html b/Documentation/nvme-connect.html
new file mode 100644
index 0000000..a3e1ff5
--- /dev/null
+++ b/Documentation/nvme-connect.html
@@ -0,0 +1,1226 @@
+<?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 10.2.0" />
+<title>nvme-connect(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-connect(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-connect -
+ Connect to a Fabrics controller.
+</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 connect</em> [--transport=&lt;trtype&gt; | -t &lt;trtype&gt;]
+ [--nqn=&lt;subnqn&gt; | -n &lt;subnqn&gt;]
+ [--traddr=&lt;traddr&gt; | -a &lt;traddr&gt;]
+ [--trsvcid=&lt;trsvcid&gt; | -s &lt;trsvcid&gt;]
+ [--host-traddr=&lt;traddr&gt; | -w &lt;traddr&gt;]
+ [--host-iface=&lt;iface&gt; | -f &lt;iface&gt;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&gt;]
+ [--config=&lt;filename&gt; | -J &lt;filename&gt;]
+ [--dhchap-secret=&lt;secret&gt; | -S &lt;secret&gt;]
+ [--dhchap-ctrl-secret=&lt;secret&gt; | -C &lt;secret&gt;]
+ [--nr-io-queues=&lt;#&gt; | -i &lt;#&gt;]
+ [--nr-write-queues=&lt;#&gt; | -W &lt;#&gt;]
+ [--nr-poll-queues=&lt;#&gt; | -P &lt;#&gt;]
+ [--queue-size=&lt;#&gt; | -Q &lt;#&gt;]
+ [--keep-alive-tmo=&lt;#&gt; | -k &lt;#&gt;]
+ [--reconnect-delay=&lt;#&gt; | -c &lt;#&gt;]
+ [--ctrl-loss-tmo=&lt;#&gt; | -l &lt;#&gt;] [--tos=&lt;#&gt; | -T &lt;#&gt;]
+ [--keyring=&lt;#&gt;] [--tls_key=&lt;#&gt;]
+ [--duplicate-connect | -D] [--disable-sqflow | -d]
+ [--hdr-digest | -g] [--data-digest | -G] [--tls]
+ [--concat] [--dump-config | -O] [--application=&lt;id&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Create a transport connection to a remote system (specified by --traddr and
+--trsvcid) and create a NVMe over Fabrics controller for the NVMe subsystem
+specified by the --nqn option.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-t &lt;trtype&gt;
+</dt>
+<dt class="hdlist1">
+--transport=&lt;trtype&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string 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">rdma</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">fc</p></td>
+<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>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-n &lt;subnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn &lt;subnqn&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the name for the NVMe subsystem to connect to.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address of the Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;trsvcid&gt;
+</dt>
+<dt class="hdlist1">
+--trsvcid=&lt;trsvcid&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+</p>
+</dd>
+<dt class="hdlist1">
+-w &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--host-traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;iface&gt;
+</dt>
+<dt class="hdlist1">
+--host-iface=&lt;iface&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+</p>
+</dd>
+<dt class="hdlist1">
+-q &lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+--hostnqn=&lt;hostnqn&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default Host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ /usr/local/etc/nvme/hostnqn first. If that does not exist, the autogenerated
+ NQN value from the NVMe Host kernel module is used next.
+ The Host NQN uniquely identifies the NVMe Host.
+</p>
+</dd>
+<dt class="hdlist1">
+-I &lt;hostid&gt;
+</dt>
+<dt class="hdlist1">
+--hostid=&lt;hostid&gt;
+</dt>
+<dd>
+<p>
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+</p>
+</dd>
+<dt class="hdlist1">
+-J &lt;filename&gt;
+</dt>
+<dt class="hdlist1">
+--config=&lt;filename&gt;
+</dt>
+<dd>
+<p>
+ Use the specified JSON configuration file instead of the
+ default /usr/local/etc/nvme/config.json file or <em>none</em> to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ <a href="https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json">https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json</a>
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;secret&gt;
+</dt>
+<dt class="hdlist1">
+--dhchap-secret=&lt;secret&gt;
+</dt>
+<dd>
+<p>
+ NVMe In-band authentication secret; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 <em>Secret representation</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-C &lt;secret&gt;
+</dt>
+<dt class="hdlist1">
+--dhchap-ctrl-secret=&lt;secret&gt;
+</dt>
+<dd>
+<p>
+ NVMe In-band authentication controller secret for bi-directional
+ authentication; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 <em>Secret representation</em>.
+ If not present bi-directional authentication is not attempted.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-io-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of I/O queues create by the driver.
+</p>
+</dd>
+<dt class="hdlist1">
+-W &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-write-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for write I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-P &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-poll-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for polling latency sensitive I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-Q &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--queue-size=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of elements in the I/O queues created
+ by the driver.
+</p>
+</dd>
+<dt class="hdlist1">
+-k &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--keep-alive-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default keep alive timeout (in seconds).
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--reconnect-delay=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--ctrl-loss-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default controller loss timeout period (in seconds).
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--tos=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Type of service for the connection (TCP)
+</p>
+</dd>
+<dt class="hdlist1">
+--keyring=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Keyring for TLS key lookup.
+</p>
+</dd>
+<dt class="hdlist1">
+--tls_key=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ TLS key for the connection (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-D
+</dt>
+<dt class="hdlist1">
+--duplicate-connect
+</dt>
+<dd>
+<p>
+ Allows duplicated connections between same transport host and subsystem
+ port.
+</p>
+</dd>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--disable-sqflow
+</dt>
+<dd>
+<p>
+ Disables SQ flow control to omit head doorbell update for submission
+ queues when sending nvme completions.
+</p>
+</dd>
+<dt class="hdlist1">
+-g
+</dt>
+<dt class="hdlist1">
+--hdr-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies header digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-G
+</dt>
+<dt class="hdlist1">
+--data-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies data digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+--tls
+</dt>
+<dd>
+<p>
+ Enable TLS encryption (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+--concat
+</dt>
+<dd>
+<p>
+ Enable secure concatenation (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-O
+</dt>
+<dt class="hdlist1">
+--dump-config
+</dt>
+<dd>
+<p>
+ Print out resulting JSON configuration file to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+--context &lt;STR&gt;
+</dt>
+<dd>
+<p>
+ Set the execution context to &lt;STR&gt;. This allows to coordinate
+ the management of the global resources.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Connect to a subsystem named nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+on the IP4 address 192.168.1.3. Port 4420 is used by default:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme connect --transport=rdma --traddr=192.168.1.3 \
+--nqn=nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-discover(1)
+nvme-connect-all(1)</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_authors">AUTHORS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This was co-written by <a href="mailto:james.p.freyensee@intel.com">Jay Freyensee</a>
+and <a href="mailto:hch@lst.de">Christoph Hellwig</a></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-connect.txt b/Documentation/nvme-connect.txt
new file mode 100644
index 0000000..583aaf9
--- /dev/null
+++ b/Documentation/nvme-connect.txt
@@ -0,0 +1,221 @@
+nvme-connect(1)
+===============
+
+NAME
+----
+nvme-connect - Connect to a Fabrics controller.
+
+SYNOPSIS
+--------
+[verse]
+'nvme connect' [--transport=<trtype> | -t <trtype>]
+ [--nqn=<subnqn> | -n <subnqn>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--host-iface=<iface> | -f <iface>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--config=<filename> | -J <filename>]
+ [--dhchap-secret=<secret> | -S <secret>]
+ [--dhchap-ctrl-secret=<secret> | -C <secret>]
+ [--nr-io-queues=<#> | -i <#>]
+ [--nr-write-queues=<#> | -W <#>]
+ [--nr-poll-queues=<#> | -P <#>]
+ [--queue-size=<#> | -Q <#>]
+ [--keep-alive-tmo=<#> | -k <#>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>] [--tos=<#> | -T <#>]
+ [--keyring=<#>] [--tls_key=<#>]
+ [--duplicate-connect | -D] [--disable-sqflow | -d]
+ [--hdr-digest | -g] [--data-digest | -G] [--tls]
+ [--concat] [--dump-config | -O] [--application=<id>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Create a transport connection to a remote system (specified by --traddr and
+--trsvcid) and create a NVMe over Fabrics controller for the NVMe subsystem
+specified by the --nqn option.
+
+OPTIONS
+-------
+-t <trtype>::
+--transport=<trtype>::
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string values include:
++
+[]
+|=================
+|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
+|=================
+
+-n <subnqn>::
+--nqn <subnqn>::
+ This field specifies the name for the NVMe subsystem to connect to.
+
+-a <traddr>::
+--traddr=<traddr>::
+ This field specifies the network address of the Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+
+-s <trsvcid>::
+--trsvcid=<trsvcid>::
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+
+-w <traddr>::
+--host-traddr=<traddr>::
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+
+-f <iface>::
+--host-iface=<iface>::
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+
+-q <hostnqn>::
+--hostnqn=<hostnqn>::
+ Overrides the default Host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ @SYSCONFDIR@/nvme/hostnqn first. If that does not exist, the autogenerated
+ NQN value from the NVMe Host kernel module is used next.
+ The Host NQN uniquely identifies the NVMe Host.
+
+-I <hostid>::
+--hostid=<hostid>::
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+
+-J <filename>::
+--config=<filename>::
+ Use the specified JSON configuration file instead of the
+ default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json
+
+-S <secret>::
+--dhchap-secret=<secret>::
+ NVMe In-band authentication secret; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 'Secret representation'.
+
+-C <secret>::
+--dhchap-ctrl-secret=<secret>::
+ NVMe In-band authentication controller secret for bi-directional
+ authentication; needs to be in ASCII format as
+ specified in NVMe 2.0 section 8.13.5.8 'Secret representation'.
+ If not present bi-directional authentication is not attempted.
+
+-i <#>::
+--nr-io-queues=<#>::
+ Overrides the default number of I/O queues create by the driver.
+
+-W <#>::
+--nr-write-queues=<#>::
+ Adds additional queues that will be used for write I/O.
+
+-P <#>::
+--nr-poll-queues=<#>::
+ Adds additional queues that will be used for polling latency sensitive I/O.
+
+-Q <#>::
+--queue-size=<#>::
+ Overrides the default number of elements in the I/O queues created
+ by the driver.
+
+-k <#>::
+--keep-alive-tmo=<#>::
+ Overrides the default keep alive timeout (in seconds).
+
+-c <#>::
+--reconnect-delay=<#>::
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+
+-l <#>::
+--ctrl-loss-tmo=<#>::
+ Overrides the default controller loss timeout period (in seconds).
+
+-T <#>::
+--tos=<#>::
+ Type of service for the connection (TCP)
+
+--keyring=<#>::
+ Keyring for TLS key lookup.
+
+--tls_key=<#>::
+ TLS key for the connection (TCP).
+
+-D::
+--duplicate-connect::
+ Allows duplicated connections between same transport host and subsystem
+ port.
+
+-d::
+--disable-sqflow::
+ Disables SQ flow control to omit head doorbell update for submission
+ queues when sending nvme completions.
+
+-g::
+--hdr-digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data-digest::
+ Generates/verifies data digest (TCP).
+
+--tls::
+ Enable TLS encryption (TCP).
+
+--concat::
+ Enable secure concatenation (TCP).
+
+-O::
+--dump-config::
+ Print out resulting JSON configuration file to stdout.
+
+--context <STR>::
+ Set the execution context to <STR>. This allows to coordinate
+ the management of the global resources.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Connect to a subsystem named nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+on the IP4 address 192.168.1.3. Port 4420 is used by default:
++
+------------
+# nvme connect --transport=rdma --traddr=192.168.1.3 \
+--nqn=nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+------------
+
+SEE ALSO
+--------
+nvme-discover(1)
+nvme-connect-all(1)
+
+AUTHORS
+-------
+This was co-written by mailto:james.p.freyensee@intel.com[Jay Freyensee]
+and mailto:hch@lst.de[Christoph Hellwig]
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-copy.1 b/Documentation/nvme-copy.1
new file mode 100644
index 0000000..6e0c67d
--- /dev/null
+++ b/Documentation/nvme-copy.1
@@ -0,0 +1,168 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-COPY" "1" "02/14/2024" "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,>]
+ [\-\-snsids=<snsids,> | \-N <snsids,>]
+ [\-\-sopts=<sopts,> | \-O <sopts,>]
+ [\-\-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>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.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
+\-d <sdlba>, \-\-sdlba=<sdlba>
+.RS 4
+64\-bit addr of first destination logical block
+.RE
+.PP
+\-b <nlb\-list,>, \-\-blocks=<nlb\-list,>
+.RS 4
+Comma separated list of the number of blocks in each range
+.RE
+.PP
+\-s <slbas,>, \-\-slbs=<slbas,>
+.RS 4
+Comma separated list of the starting blocks in each range
+.RE
+.PP
+\-\-snsids=<snsids,>, \-N <snsids,>
+.RS 4
+Comma separated list of the source namespace identifiers in each range
+.RE
+.PP
+\-\-sopts=<sopts,>, \-O <sopts,>
+.RS 4
+Comma separated list of the source options in each range
+.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
+\-p <prinfow>, \-\-prinfow=<prinfow>
+.RS 4
+Protection Information field write definition\&.
+.RE
+.PP
+\-P <prinfor>, \-\-prinfor=<prinfor>
+.RS 4
+Protection Information field read definition\&.
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+initial lba reference tag\&.
+.RE
+.PP
+\-R <reftag,>, \-\-expected\-ref\-tags=<reftag,>
+.RS 4
+expected lba reference tags (comma\-separated list)\&.
+.RE
+.PP
+\-a <apptag>, \-\-app\-tag=<apptag>
+.RS 4
+lba app tag
+.RE
+.PP
+\-A <apptag,>, \-\-expected\-app\-tags=<apptag,>
+.RS 4
+expected lba app tags (comma\-separated list)
+.RE
+.PP
+\-m <appmask>, \-\-app\-mask=<appmask>
+.RS 4
+lba tag mask
+.RE
+.PP
+\-M <appmask,>, \-\-expected\-app\-masks=<appmask,>
+.RS 4
+expected lba tag masks (comma\-separated list)
+.RE
+.PP
+\-T <type>, \-\-dir\-type=<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 specification (1\&.3a) defines only one directive, 01h, for write stream identifiers\&.
+.RE
+.PP
+\-S <spec>, \-\-dir\-spec=<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
+\-F <entry\-format>, \-\-format=<entry\-format>
+.RS 4
+source range entry format
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..54921be
--- /dev/null
+++ b/Documentation/nvme-copy.html
@@ -0,0 +1,1037 @@
+<?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 10.2.0" />
+<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 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-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;]
+ [--snsids=&lt;snsids,&gt; | -N &lt;snsids,&gt;]
+ [--sopts=&lt;sopts,&gt; | -O &lt;sopts,&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;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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">
+-d &lt;sdlba&gt;
+</dt>
+<dt class="hdlist1">
+--sdlba=&lt;sdlba&gt;
+</dt>
+<dd>
+<p>
+ 64-bit addr of first destination logical block
+</p>
+</dd>
+<dt class="hdlist1">
+-b &lt;nlb-list,&gt;
+</dt>
+<dt class="hdlist1">
+--blocks=&lt;nlb-list,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the number of blocks in each range
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;slbas,&gt;
+</dt>
+<dt class="hdlist1">
+--slbs=&lt;slbas,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the starting blocks in each range
+</p>
+</dd>
+<dt class="hdlist1">
+--snsids=&lt;snsids,&gt;
+</dt>
+<dt class="hdlist1">
+-N &lt;snsids,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the source namespace identifiers in each range
+</p>
+</dd>
+<dt class="hdlist1">
+--sopts=&lt;sopts,&gt;
+</dt>
+<dt class="hdlist1">
+-O &lt;sopts,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the source options in each range
+</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">
+-p &lt;prinfow&gt;
+</dt>
+<dt class="hdlist1">
+--prinfow=&lt;prinfow&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field write definition.
+</p>
+</dd>
+<dt class="hdlist1">
+-P &lt;prinfor&gt;
+</dt>
+<dt class="hdlist1">
+--prinfor=&lt;prinfor&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field read definition.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ initial lba reference tag.
+</p>
+</dd>
+<dt class="hdlist1">
+-R &lt;reftag,&gt;
+</dt>
+<dt class="hdlist1">
+--expected-ref-tags=&lt;reftag,&gt;
+</dt>
+<dd>
+<p>
+ expected lba reference tags (comma-separated list).
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ lba app tag
+</p>
+</dd>
+<dt class="hdlist1">
+-A &lt;apptag,&gt;
+</dt>
+<dt class="hdlist1">
+--expected-app-tags=&lt;apptag,&gt;
+</dt>
+<dd>
+<p>
+ expected lba app tags (comma-separated list)
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ lba tag mask
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;appmask,&gt;
+</dt>
+<dt class="hdlist1">
+--expected-app-masks=&lt;appmask,&gt;
+</dt>
+<dd>
+<p>
+ expected lba tag masks (comma-separated list)
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;type&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&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
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;spec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&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">
+-F &lt;entry-format&gt;
+</dt>
+<dt class="hdlist1">
+--format=&lt;entry-format&gt;
+</dt>
+<dd>
+<p>
+ source range entry format
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-copy.txt b/Documentation/nvme-copy.txt
new file mode 100644
index 0000000..7c5fb0e
--- /dev/null
+++ b/Documentation/nvme-copy.txt
@@ -0,0 +1,131 @@
+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,>]
+ [--snsids=<snsids,> | -N <snsids,>]
+ [--sopts=<sopts,> | -O <sopts,>]
+ [--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>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+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
+-------
+-d <sdlba>::
+--sdlba=<sdlba>::
+ 64-bit addr of first destination logical block
+
+-b <nlb-list,>::
+--blocks=<nlb-list,>::
+ Comma separated list of the number of blocks in each range
+
+-s <slbas,>::
+--slbs=<slbas,>::
+ Comma separated list of the starting blocks in each range
+
+--snsids=<snsids,>::
+-N <snsids,>::
+ Comma separated list of the source namespace identifiers in each range
+
+--sopts=<sopts,>::
+-O <sopts,>::
+ Comma separated list of the source options in each range
+
+-l::
+--limited-retry::
+ Sets the limited retry flag.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-p <prinfow>::
+--prinfow=<prinfow>::
+ Protection Information field write definition.
+
+-P <prinfor>::
+--prinfor=<prinfor>::
+ Protection Information field read definition.
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ initial lba reference tag.
+
+-R <reftag,>::
+--expected-ref-tags=<reftag,>::
+ expected lba reference tags (comma-separated list).
+
+-a <apptag>::
+--app-tag=<apptag>::
+ lba app tag
+
+-A <apptag,>::
+--expected-app-tags=<apptag,>::
+ expected lba app tags (comma-separated list)
+
+-m <appmask>::
+--app-mask=<appmask>::
+ lba tag mask
+
+-M <appmask,>::
+--expected-app-masks=<appmask,>::
+ expected lba tag masks (comma-separated list)
+
+-T <type>::
+--dir-type=<type>::
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+
+-S <spec>::
+--dir-spec=<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.
+
+-F <entry-format>::
+--format=<entry-format>::
+ source range entry format
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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
new file mode 100644
index 0000000..b4818bd
--- /dev/null
+++ b/Documentation/nvme-create-ns.1
@@ -0,0 +1,197 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CREATE\-NS" "1" "02/14/2024" "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-create-ns \- Send NVMe Namespace management command to create namespace, returns results\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme create\-ns\fR <device> [\-\-nsze=<nsze> | \-s <nsze>]
+ [\-\-ncap=<ncap> | \-c <ncap>]
+ [\-\-flbas=<flbas> | \-f <flbas>]
+ [\-\-dps=<dps> | \-d <dps>]
+ [\-\-nmic=<nmic> | \-m <nmic>]
+ [\-\-anagrp\-id=<anagrpid> | \-a <anagrpid>]
+ [\-\-nvmset\-id=<nvmsetid> | \-i <nvmsetid>]
+ [\-\-endg\-id=<endgid> | \-e <endgid>]
+ [\-\-csi=<command_set_identifier> | \-y <command_set_identifier>]
+ [\-\-lbstm=<lbstm> | \-l <lbstm>]
+ [\-\-nphndls=<nphndls> | \-n <nphndls>]
+ [\-\-block\-size=<block\-size> | \-b <block\-size>]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+ [\-\-nsze\-si=<nsze\-si> | \-S <nsze\-si>]
+ [\-\-ncap\-si=<ncap\-si> | \-C <ncap\-si>]
+ [\-\-azr | \-z]
+ [\-\-rar=<rar> | \-r <rar>]
+ [\-\-ror=<ror> | \-O <ror>]
+ [\-\-rnumzrwa=<rnumzrwa> | \-u <rnumzrwa>]
+ [\-\-phndls=<placement\-handle\-list,> | \-p <placement\-handle\-list,>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a namespace management command to create the namespace with the requested settings\&. On success, the namespace identifier assigned by the controller is returned\&.
+.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
+\-s, \-\-nsze
+.RS 4
+The namespace size\&.
+.RE
+.PP
+\-c, \-\-ncap
+.RS 4
+The namespace capacity\&.
+.RE
+.PP
+\-f, \-\-flbas
+.RS 4
+The namespace formatted logical block size setting\&. Conflicts with \-\-block\-size argument\&.
+.RE
+.PP
+\-d, \-\-dps
+.RS 4
+The data protection settings\&.
+.RE
+.PP
+\-m, \-\-nmic
+.RS 4
+Namespace multipath and sharing capabilities\&.
+.RE
+.PP
+\-a, \-\-anagrp\-id
+.RS 4
+ANA Group Identifier\&. If this value is 0h specifies that the controller determines the value to use
+.RE
+.PP
+\-i <nvmsetid>, \-\-nvmset\-id=<nvmsetid>
+.RS 4
+This field specifies the identifier of the NVM Set\&.
+.RE
+.PP
+\-e <endgid>, \-\-endg\-id=<endgid>
+.RS 4
+This field specifies the identifier of the endurance group\&.
+.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
+\-l <lbstm>, \-\-lbstm=<lbstm>
+.RS 4
+Logical Block Storage Tag Mask for end\-to\-end protection\&.
+.RE
+.PP
+\-n <nphndls>, \-\-nphndls=<nphndls>
+.RS 4
+Number of Placement Handle included in the Placement Handle List\&. If the Flexible Data Placement capability is not supported or not enabled in specified Endurance Group, then the controller shall ignore this field\&.
+.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\&.
+.RE
+.PP
+\-S, \-\-nsze\-si
+.RS 4
+The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries, unless the controller recommends a smaller value)\&. The value SI suffixed is divided by the namespace LBA size to set as NSZE\&. If the value not suffixed it is set as same with the nsze option\&.
+.RE
+.PP
+\-C, \-\-ncap\-si
+.RS 4
+The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries, unless the controller recommends a smaller value)\&. The value SI suffixed is divided by the namespace LBA size to set as NCAP\&. If the value not suffixed it is set as same with the ncap option\&.
+.RE
+.PP
+\-z, \-\-azr
+.RS 4
+Allocate ZRWA Resources\&. If set to 1, then the namespace is to be created with the number of ZRWA resource specified in the RNUMZRWA field of this data structure\&. If cleared to 0, then no ZRWA resources are allocated to the namespace to be created\&.
+.RE
+.PP
+\-r <rar>, \-\-rar=<rar>
+.RS 4
+Requested Active Resources\&. This field specifies the number of active resources to be allocated to the created namespace\&.
+.RE
+.PP
+\-O <ror>, \-\-ror=<ror>
+.RS 4
+Requested Open Resources\&. This field specifies the number of open resources to be allocated to the created namespace\&.
+.RE
+.PP
+\-u <rnumzrwa>, \-\-rnumzrwa=<rnumzrwa>
+.RS 4
+Requested Number of ZRWA Resources\&. This field specifies the number of ZRWA resources to be allocated to the created namespace\&.
+.RE
+.PP
+\-p <placement\-handle\-list,>, \-\-phndls=<placement\-handle\-list,>
+.RS 4
+The comma separated list of Reclaim Unit Handle Identifier to be associated with each Placement Handle\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Create a namespace:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme create\-ns /dev/nvme0 \-\-nsze 11995709440 \-\-ncap 1199570940 \-\-flbas 0 \-\-dps 0 \-\-nmic 0
+# nvme create\-ns /dev/nvme0 \-\-nsze\-si 6\&.14T \-\-ncap 1199570940 \-\-flbas 0 \-\-dps 0 \-\-nmic 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-create-ns.html b/Documentation/nvme-create-ns.html
new file mode 100644
index 0000000..c3a9ece
--- /dev/null
+++ b/Documentation/nvme-create-ns.html
@@ -0,0 +1,1078 @@
+<?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 10.2.0" />
+<title>nvme-create-ns(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-create-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-create-ns -
+ Send NVMe Namespace management command to create namespace, returns 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 create-ns</em> &lt;device&gt; [--nsze=&lt;nsze&gt; | -s &lt;nsze&gt;]
+ [--ncap=&lt;ncap&gt; | -c &lt;ncap&gt;]
+ [--flbas=&lt;flbas&gt; | -f &lt;flbas&gt;]
+ [--dps=&lt;dps&gt; | -d &lt;dps&gt;]
+ [--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;]
+ [--endg-id=&lt;endgid&gt; | -e &lt;endgid&gt;]
+ [--csi=&lt;command_set_identifier&gt; | -y &lt;command_set_identifier&gt;]
+ [--lbstm=&lt;lbstm&gt; | -l &lt;lbstm&gt;]
+ [--nphndls=&lt;nphndls&gt; | -n &lt;nphndls&gt;]
+ [--block-size=&lt;block-size&gt; | -b &lt;block-size&gt;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&gt;]
+ [--nsze-si=&lt;nsze-si&gt; | -S &lt;nsze-si&gt;]
+ [--ncap-si=&lt;ncap-si&gt; | -C &lt;ncap-si&gt;]
+ [--azr | -z]
+ [--rar=&lt;rar&gt; | -r &lt;rar&gt;]
+ [--ror=&lt;ror&gt; | -O &lt;ror&gt;]
+ [--rnumzrwa=&lt;rnumzrwa&gt; | -u &lt;rnumzrwa&gt;]
+ [--phndls=&lt;placement-handle-list,&gt; | -p &lt;placement-handle-list,&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 a namespace management command to create
+the namespace with the requested settings. On success, the namespace
+identifier assigned by the controller is returned.</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">
+-s
+</dt>
+<dt class="hdlist1">
+--nsze
+</dt>
+<dd>
+<p>
+ The namespace size.
+</p>
+</dd>
+<dt class="hdlist1">
+-c
+</dt>
+<dt class="hdlist1">
+--ncap
+</dt>
+<dd>
+<p>
+ The namespace capacity.
+</p>
+</dd>
+<dt class="hdlist1">
+-f
+</dt>
+<dt class="hdlist1">
+--flbas
+</dt>
+<dd>
+<p>
+ The namespace formatted logical block size setting.
+ Conflicts with --block-size argument.
+</p>
+</dd>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--dps
+</dt>
+<dd>
+<p>
+ The data protection settings.
+</p>
+</dd>
+<dt class="hdlist1">
+-m
+</dt>
+<dt class="hdlist1">
+--nmic
+</dt>
+<dd>
+<p>
+ Namespace multipath and sharing capabilities.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--anagrp-id
+</dt>
+<dd>
+<p>
+ ANA Group Identifier. If this value is 0h specifies
+ that the controller determines the value to use
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;nvmsetid&gt;
+</dt>
+<dt class="hdlist1">
+--nvmset-id=&lt;nvmsetid&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the identifier of the NVM Set.
+</p>
+</dd>
+<dt class="hdlist1">
+-e &lt;endgid&gt;
+</dt>
+<dt class="hdlist1">
+--endg-id=&lt;endgid&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the identifier of the endurance group.
+</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">
+-l &lt;lbstm&gt;
+</dt>
+<dt class="hdlist1">
+--lbstm=&lt;lbstm&gt;
+</dt>
+<dd>
+<p>
+ Logical Block Storage Tag Mask for end-to-end protection.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nphndls&gt;
+</dt>
+<dt class="hdlist1">
+--nphndls=&lt;nphndls&gt;
+</dt>
+<dd>
+<p>
+ Number of Placement Handle included in the Placement Handle List.
+ If the Flexible Data Placement capability is not supported or not enabled
+ in specified Endurance Group, then the controller shall ignore this field.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--block-size
+</dt>
+<dd>
+<p>
+ 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.
+</p>
+</dd>
+<dt class="hdlist1">
+-S
+</dt>
+<dt class="hdlist1">
+--nsze-si
+</dt>
+<dd>
+<p>
+ The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries,
+ unless the controller recommends a smaller value).
+ The value SI suffixed is divided by the namespace LBA size to set as NSZE.
+ If the value not suffixed it is set as same with the nsze option.
+</p>
+</dd>
+<dt class="hdlist1">
+-C
+</dt>
+<dt class="hdlist1">
+--ncap-si
+</dt>
+<dd>
+<p>
+ The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries,
+ unless the controller recommends a smaller value).
+ The value SI suffixed is divided by the namespace LBA size to set as NCAP.
+ If the value not suffixed it is set as same with the ncap option.
+</p>
+</dd>
+<dt class="hdlist1">
+-z
+</dt>
+<dt class="hdlist1">
+--azr
+</dt>
+<dd>
+<p>
+ Allocate ZRWA Resources.
+ If set to 1, then the namespace is to be created with the number of ZRWA
+ resource specified in the RNUMZRWA field of this data structure. If cleared
+ to 0, then no ZRWA resources are allocated to the namespace to be created.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;rar&gt;
+</dt>
+<dt class="hdlist1">
+--rar=&lt;rar&gt;
+</dt>
+<dd>
+<p>
+ Requested Active Resources. This field specifies the number of active
+ resources to be allocated to the created namespace.
+</p>
+</dd>
+<dt class="hdlist1">
+-O &lt;ror&gt;
+</dt>
+<dt class="hdlist1">
+--ror=&lt;ror&gt;
+</dt>
+<dd>
+<p>
+ Requested Open Resources. This field specifies the number of open resources
+ to be allocated to the created namespace.
+</p>
+</dd>
+<dt class="hdlist1">
+-u &lt;rnumzrwa&gt;
+</dt>
+<dt class="hdlist1">
+--rnumzrwa=&lt;rnumzrwa&gt;
+</dt>
+<dd>
+<p>
+ Requested Number of ZRWA Resources. This field specifies the number of ZRWA
+ resources to be allocated to the created namespace.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;placement-handle-list,&gt;
+</dt>
+<dt class="hdlist1">
+--phndls=&lt;placement-handle-list,&gt;
+</dt>
+<dd>
+<p>
+ The comma separated list of Reclaim Unit Handle Identifier to be associated
+ with each Placement Handle.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Create a namespace:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme create-ns /dev/nvme0 --nsze 11995709440 --ncap 1199570940 --flbas 0 --dps 0 --nmic 0
+# nvme create-ns /dev/nvme0 --nsze-si 6.14T --ncap 1199570940 --flbas 0 --dps 0 --nmic 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 the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt
new file mode 100644
index 0000000..352a945
--- /dev/null
+++ b/Documentation/nvme-create-ns.txt
@@ -0,0 +1,160 @@
+nvme-create-ns(1)
+=================
+
+NAME
+----
+nvme-create-ns - Send NVMe Namespace management command to create namespace, returns results.
+
+SYNOPSIS
+--------
+[verse]
+'nvme create-ns' <device> [--nsze=<nsze> | -s <nsze>]
+ [--ncap=<ncap> | -c <ncap>]
+ [--flbas=<flbas> | -f <flbas>]
+ [--dps=<dps> | -d <dps>]
+ [--nmic=<nmic> | -m <nmic>]
+ [--anagrp-id=<anagrpid> | -a <anagrpid>]
+ [--nvmset-id=<nvmsetid> | -i <nvmsetid>]
+ [--endg-id=<endgid> | -e <endgid>]
+ [--csi=<command_set_identifier> | -y <command_set_identifier>]
+ [--lbstm=<lbstm> | -l <lbstm>]
+ [--nphndls=<nphndls> | -n <nphndls>]
+ [--block-size=<block-size> | -b <block-size>]
+ [--timeout=<timeout> | -t <timeout>]
+ [--nsze-si=<nsze-si> | -S <nsze-si>]
+ [--ncap-si=<ncap-si> | -C <ncap-si>]
+ [--azr | -z]
+ [--rar=<rar> | -r <rar>]
+ [--ror=<ror> | -O <ror>]
+ [--rnumzrwa=<rnumzrwa> | -u <rnumzrwa>]
+ [--phndls=<placement-handle-list,> | -p <placement-handle-list,>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a namespace management command to create
+the namespace with the requested settings. On success, the namespace
+identifier assigned by the controller is returned.
+
+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
+-------
+-s::
+--nsze::
+ The namespace size.
+
+-c::
+--ncap::
+ The namespace capacity.
+
+-f::
+--flbas::
+ The namespace formatted logical block size setting.
+ Conflicts with --block-size argument.
+
+-d::
+--dps::
+ The data protection settings.
+
+-m::
+--nmic::
+ Namespace multipath and sharing capabilities.
+
+-a::
+--anagrp-id::
+ ANA Group Identifier. If this value is 0h specifies
+ that the controller determines the value to use
+
+-i <nvmsetid>::
+--nvmset-id=<nvmsetid>::
+ This field specifies the identifier of the NVM Set.
+
+-e <endgid>::
+--endg-id=<endgid>::
+ This field specifies the identifier of the endurance group.
+
+-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.
+
+-l <lbstm>::
+--lbstm=<lbstm>::
+ Logical Block Storage Tag Mask for end-to-end protection.
+
+-n <nphndls>::
+--nphndls=<nphndls>::
+ Number of Placement Handle included in the Placement Handle List.
+ If the Flexible Data Placement capability is not supported or not enabled
+ in specified Endurance Group, then the controller shall ignore this field.
+
+-b::
+--block-size::
+ 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.
+
+-S::
+--nsze-si::
+ The namespace size (NSZE) in standard SI units (aligned on 1Mib boundaries,
+ unless the controller recommends a smaller value).
+ The value SI suffixed is divided by the namespace LBA size to set as NSZE.
+ If the value not suffixed it is set as same with the nsze option.
+
+-C::
+--ncap-si::
+ The namespace capacity (NCAP) in standard SI units (aligned on 1Mib boundaries,
+ unless the controller recommends a smaller value).
+ The value SI suffixed is divided by the namespace LBA size to set as NCAP.
+ If the value not suffixed it is set as same with the ncap option.
+
+-z::
+--azr::
+ Allocate ZRWA Resources.
+ If set to 1, then the namespace is to be created with the number of ZRWA
+ resource specified in the RNUMZRWA field of this data structure. If cleared
+ to 0, then no ZRWA resources are allocated to the namespace to be created.
+
+-r <rar>::
+--rar=<rar>::
+ Requested Active Resources. This field specifies the number of active
+ resources to be allocated to the created namespace.
+
+-O <ror>::
+--ror=<ror>::
+ Requested Open Resources. This field specifies the number of open resources
+ to be allocated to the created namespace.
+
+-u <rnumzrwa>::
+--rnumzrwa=<rnumzrwa>::
+ Requested Number of ZRWA Resources. This field specifies the number of ZRWA
+ resources to be allocated to the created namespace.
+
+-p <placement-handle-list,>::
+--phndls=<placement-handle-list,>::
+ The comma separated list of Reclaim Unit Handle Identifier to be associated
+ with each Placement Handle.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Create a namespace:
++
+------------
+# nvme create-ns /dev/nvme0 --nsze 11995709440 --ncap 1199570940 --flbas 0 --dps 0 --nmic 0
+# nvme create-ns /dev/nvme0 --nsze-si 6.14T --ncap 1199570940 --flbas 0 --dps 0 --nmic 0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-delete-ns.1 b/Documentation/nvme-delete-ns.1
new file mode 100644
index 0000000..80454d1
--- /dev/null
+++ b/Documentation/nvme-delete-ns.1
@@ -0,0 +1,68 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "02/14/2024" "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-delete-ns \- Send NVMe Namespace Management delete namespace command, return result\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme delete\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an nvme namespace management command to delete the requested namespace and provides the result\&.
+.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)\&. The \*(Aq\-\-namespace\-id\*(Aq option is mandatory\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The namespace identifier to delete\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-delete-ns.html b/Documentation/nvme-delete-ns.html
new file mode 100644
index 0000000..eb379d3
--- /dev/null
+++ b/Documentation/nvme-delete-ns.html
@@ -0,0 +1,830 @@
+<?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 10.2.0" />
+<title>nvme-id-ns(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-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-delete-ns -
+ Send NVMe Namespace Management delete namespace 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 delete-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an nvme namespace management command
+to delete the requested namespace and provides the result.</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).
+The <code>'--namespace-id'</code> option is mandatory.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The namespace identifier to delete.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-delete-ns.txt b/Documentation/nvme-delete-ns.txt
new file mode 100644
index 0000000..1b306b2
--- /dev/null
+++ b/Documentation/nvme-delete-ns.txt
@@ -0,0 +1,44 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-delete-ns - Send NVMe Namespace Management delete namespace command, return result.
+
+SYNOPSIS
+--------
+[verse]
+'nvme delete-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an nvme namespace management command
+to delete the requested namespace and provides the result.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+The `'--namespace-id'` option is mandatory.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ The namespace identifier to delete.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-dera-stat.1 b/Documentation/nvme-dera-stat.1
new file mode 100644
index 0000000..5469c14
--- /dev/null
+++ b/Documentation/nvme-dera-stat.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DERA\-STAT" "1" "02/14/2024" "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-dera-stat \- Send NVMe Dera Device status and Additional SMART log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme dera stat\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Dera Device status and Additional SMART log page from the 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 status and smart log structure are printed in a readable format\&.
+.SH "OPTIONS"
+.sp
+none
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Dera Device status and Additional SMART log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dera stat /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-dera-stat.html b/Documentation/nvme-dera-stat.html
new file mode 100644
index 0000000..c265ee7
--- /dev/null
+++ b/Documentation/nvme-dera-stat.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 10.2.0" />
+<title>nvme-dera-stat(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-dera-stat(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-dera-stat -
+ Send NVMe Dera Device status and Additional SMART 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 dera stat</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>Retrieves the NVMe Dera Device status and Additional SMART log page from the 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 status and smart log structure are printed in a readable format.</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>
+Print the Dera Device status and Additional SMART log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dera stat /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dera-stat.txt b/Documentation/nvme-dera-stat.txt
new file mode 100644
index 0000000..f3a87ae
--- /dev/null
+++ b/Documentation/nvme-dera-stat.txt
@@ -0,0 +1,37 @@
+nvme-dera-stat(1)
+=================
+
+NAME
+----
+nvme-dera-stat - Send NVMe Dera Device status and Additional SMART log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme dera stat' <device>
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Dera Device status and Additional SMART log page from the 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 status and smart log structure are printed in a readable format.
+
+OPTIONS
+-------
+none
+
+EXAMPLES
+--------
+* Print the Dera Device status and Additional SMART log page in a human readable format:
++
+------------
+# nvme dera stat /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-detach-ns.1 b/Documentation/nvme-detach-ns.1
new file mode 100644
index 0000000..70c29a4
--- /dev/null
+++ b/Documentation/nvme-detach-ns.1
@@ -0,0 +1,72 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DETACH\-NS" "1" "02/14/2024" "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-detach-ns \- Send NVMe detach namespace, return result\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme detach\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-controllers=<ctrl\-list,> | \-c <ctrl\-list,>
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the nvme namespace detach command for the provided namespace identifier, attaching to the provided list of controller identifiers\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The namespace identifier to detach\&.
+.RE
+.PP
+\-c <ctrl\-list,>, \-\-controllers=<ctrl\-list,>
+.RS 4
+The comma separated list of controller identifiers to detach the namespace from\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-detach-ns.html b/Documentation/nvme-detach-ns.html
new file mode 100644
index 0000000..28d2c7c
--- /dev/null
+++ b/Documentation/nvme-detach-ns.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 10.2.0" />
+<title>nvme-detach-ns(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-detach-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-detach-ns -
+ Send NVMe detach namespace, 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 detach-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--controllers=&lt;ctrl-list,&gt; | -c &lt;ctrl-list,&gt;
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 nvme namespace detach command for
+the provided namespace identifier, attaching to the provided list of
+controller identifiers.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The namespace identifier to detach.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;ctrl-list,&gt;
+</dt>
+<dt class="hdlist1">
+--controllers=&lt;ctrl-list,&gt;
+</dt>
+<dd>
+<p>
+ The comma separated list of controller identifiers to detach
+ the namespace from.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-detach-ns.txt b/Documentation/nvme-detach-ns.txt
new file mode 100644
index 0000000..842889c
--- /dev/null
+++ b/Documentation/nvme-detach-ns.txt
@@ -0,0 +1,47 @@
+nvme-detach-ns(1)
+=================
+
+NAME
+----
+nvme-detach-ns - Send NVMe detach namespace, return result.
+
+SYNOPSIS
+--------
+[verse]
+'nvme detach-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--controllers=<ctrl-list,> | -c <ctrl-list,>
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the nvme namespace detach command for
+the provided namespace identifier, attaching to the provided list of
+controller identifiers.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ The namespace identifier to detach.
+
+-c <ctrl-list,>::
+--controllers=<ctrl-list,>::
+ The comma separated list of controller identifiers to detach
+ the namespace from.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-device-self-test.1 b/Documentation/nvme-device-self-test.1
new file mode 100644
index 0000000..605baf8
--- /dev/null
+++ b/Documentation/nvme-device-self-test.1
@@ -0,0 +1,121 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DEVICE\-SELF\-" "1" "02/14/2024" "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-device-self-test \- Perform the necessary tests to observe the performance and the parameters
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme device\-self\-test\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-self\-test\-code=<NUM> | \-s <NUM>] [\-\-wait | \-w]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Initiates the required test based on the user input\&.
+.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 corresponding test is initiated\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Indicate the namespace in which the device self\-test has to be carried out
+.RE
+.PP
+\-s <NUM>, \-\-self\-test\-code=<NUM>
+.RS 4
+This field specifies the action taken by the device self\-test command : 0h: Show current state of device self\-test operation 1h: Start a short device self\-test operation 2h: Start a extended device self\-test operation eh: Start a vendor specific device self\-test operation fh: Abort the device self\-test operation Default is 0h\&.
+.RE
+.PP
+\-w, \-\-wait
+.RS 4
+Wait for the device self test to complete before exiting The device self\-test is aborted by SIGINT signal interrupt for the wait The option is ignored if the abort self\-test code option specified\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Start a short device self\-test in the namespace\-id 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme device\-self\-test /dev/nvme0 \-n 1 \-s 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Abort the device self\-test operation in the namespace\-id 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme device\-self\-test /dev/nvme0 \-n 1 \-s 0xf
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-device-self-test.html b/Documentation/nvme-device-self-test.html
new file mode 100644
index 0000000..ea0cb13
--- /dev/null
+++ b/Documentation/nvme-device-self-test.html
@@ -0,0 +1,879 @@
+<?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 10.2.0" />
+<title>nvme-device-self-test(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-device-self-test(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-device-self-test -
+ Perform the necessary tests to observe the performance and the parameters
+</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 device-self-test</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--self-test-code=&lt;NUM&gt; | -s &lt;NUM&gt;] [--wait | -w]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Initiates the required test based on the user input.</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 corresponding test is initiated.</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>
+ Indicate the namespace in which the device self-test has to be carried out
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--self-test-code=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the action taken by the device self-test command :
+ 0h: Show current state of device self-test operation
+ 1h: Start a short device self-test operation
+ 2h: Start a extended device self-test operation
+ eh: Start a vendor specific device self-test operation
+ fh: Abort the device self-test operation
+ Default is 0h.
+</p>
+</dd>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--wait
+</dt>
+<dd>
+<p>
+ Wait for the device self test to complete before exiting
+ The device self-test is aborted by SIGINT signal interrupt for the wait
+ The option is ignored if the abort self-test code option specified.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Start a short device self-test in the namespace-id 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme device-self-test /dev/nvme0 -n 1 -s 1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Abort the device self-test operation in the namespace-id 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme device-self-test /dev/nvme0 -n 1 -s 0xf</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-device-self-test.txt b/Documentation/nvme-device-self-test.txt
new file mode 100644
index 0000000..17fe875
--- /dev/null
+++ b/Documentation/nvme-device-self-test.txt
@@ -0,0 +1,72 @@
+nvme-device-self-test(1)
+========================
+
+NAME
+----
+nvme-device-self-test - Perform the necessary tests to observe the performance and the parameters
+
+SYNOPSIS
+--------
+[verse]
+'nvme device-self-test' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--self-test-code=<NUM> | -s <NUM>] [--wait | -w]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Initiates the required test based on the user input.
+
+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 corresponding test is initiated.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Indicate the namespace in which the device self-test has to be carried out
+
+-s <NUM>::
+--self-test-code=<NUM>::
+ This field specifies the action taken by the device self-test command :
+ 0h: Show current state of device self-test operation
+ 1h: Start a short device self-test operation
+ 2h: Start a extended device self-test operation
+ eh: Start a vendor specific device self-test operation
+ fh: Abort the device self-test operation
+ Default is 0h.
+
+-w::
+--wait::
+ Wait for the device self test to complete before exiting
+ The device self-test is aborted by SIGINT signal interrupt for the wait
+ The option is ignored if the abort self-test code option specified.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Start a short device self-test in the namespace-id 1:
++
+------------
+# nvme device-self-test /dev/nvme0 -n 1 -s 1
+------------
++
+
+* Abort the device self-test operation in the namespace-id 1:
++
+------------
+# nvme device-self-test /dev/nvme0 -n 1 -s 0xf
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-dim.1 b/Documentation/nvme-dim.1
new file mode 100644
index 0000000..f9245ea
--- /dev/null
+++ b/Documentation/nvme-dim.1
@@ -0,0 +1,126 @@
+'\" t
+.\" Title: nvme-dim
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DIM" "1" "02/14/2024" "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-dim \- Send Discovery Information Management command to one or more Discovery Controllers\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme dim\fR [\-\-task=<task> | \-t <task>] [\-\-nqn=<nqn> | \-n <nqn>]
+ [\-\-device=<device> | \-d <device>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send Discovery Information Management (DIM) command to one or more Discovery Controllers\&. The DIM command allows performing two types of tasks: register or deregister\&.
+.sp
+The DIM command is used to explicitly register with Discovery Controllers (DC), especially with Central Discovery Controllers (CDC)\&. CDCs maintain a database (DB) of all the Hosts and Storage Subsystems in a network\&. The register task is used to add a host to the CDC\(cqs DB\&. The deregister task is used to remove a host from the CDC\(cqs DB\&.
+.sp
+During a register operation the host will send mandatory information such as the Host\(cqs NQN and ID, as well as the Host\(cqs hostname and the Operating System\(cqs version that it is running on\&. There is also an optional Host Symbolic Name that can be registered with the CDC\&.
+.sp
+This command can only be applied to existing DC connections previously created with the nvme\-discover(1) command using the \-\-persistent option\&.
+.SH "OPTIONS"
+.PP
+\-t <task>, \-\-task <task>
+.RS 4
+The task to perform: "register" or "deregister"\&.
+.RE
+.PP
+\-n <subnqn>, \-\-nqn <nqn>
+.RS 4
+The DIM command will be sent to the Discovery Controller (DC) matching this NQN\&. A list of comma\-separated NQNs can be supplied to apply the command to more than one DC\&.
+.RE
+.PP
+\-d <device>, \-\-device <device>
+.RS 4
+The DIM command will be sent to the Discovery Controllers (DC) associated with this NVMe device handle\&. A list of comma\-separated device handles can be supplied to apply the command to more than one DC\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Register with the Central Discovery Controller (CDC) named nqn\&.1988\-11\&.com\&.dell:SFSS:1:20220118125153e8:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dim \-\-task=register \-\-nqn=nqn\&.1988\-11\&.com\&.dell:SFSS:1:20220118125153e8
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Deregister from Central Discovery Controller (CDC) associated with nvme4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dim \-\-task=deregister \-\-device=nvme4
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-discover(1)
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-dim.html b/Documentation/nvme-dim.html
new file mode 100644
index 0000000..2678197
--- /dev/null
+++ b/Documentation/nvme-dim.html
@@ -0,0 +1,892 @@
+<?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 10.2.0" />
+<title>nvme-dim(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-dim(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-dim -
+ Send Discovery Information Management command to one or more Discovery Controllers.
+</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 dim</em> [--task=&lt;task&gt; | -t &lt;task&gt;] [--nqn=&lt;nqn&gt; | -n &lt;nqn&gt;]
+ [--device=&lt;device&gt; | -d &lt;device&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send Discovery Information Management (DIM) command to one or more Discovery
+Controllers. The DIM command allows performing two types of tasks: register or
+deregister.</p></div>
+<div class="paragraph"><p>The DIM command is used to explicitly register with Discovery Controllers (DC),
+especially with Central Discovery Controllers (CDC). CDCs maintain a database (DB)
+of all the Hosts and Storage Subsystems in a network. The register task is used
+to add a host to the CDC&#8217;s DB. The deregister task is used to remove a host from
+the CDC&#8217;s DB.</p></div>
+<div class="paragraph"><p>During a register operation the host will send mandatory information such as the
+Host&#8217;s NQN and ID, as well as the Host&#8217;s hostname and the Operating System&#8217;s
+version that it is running on. There is also an optional Host Symbolic Name
+that can be registered with the CDC.</p></div>
+<div class="paragraph"><p>This command can only be applied to existing DC connections previously created
+with the nvme-discover(1) command using the --persistent option.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-t &lt;task&gt;
+</dt>
+<dt class="hdlist1">
+--task &lt;task&gt;
+</dt>
+<dd>
+<p>
+ The task to perform: "register" or "deregister".
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;subnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn &lt;nqn&gt;
+</dt>
+<dd>
+<p>
+ The DIM command will be sent to the Discovery Controller (DC) matching this
+ NQN. A list of comma-separated NQNs can be supplied to apply the command to
+ more than one DC.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;device&gt;
+</dt>
+<dt class="hdlist1">
+--device &lt;device&gt;
+</dt>
+<dd>
+<p>
+ The DIM command will be sent to the Discovery Controllers (DC) associated
+ with this NVMe device handle. A list of comma-separated device handles can
+ be supplied to apply the command to more than one DC.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Register with the Central Discovery Controller (CDC) named
+nqn.1988-11.com.dell:SFSS:1:20220118125153e8:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dim --task=register --nqn=nqn.1988-11.com.dell:SFSS:1:20220118125153e8</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Deregister from Central Discovery Controller (CDC) associated with nvme4
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dim --task=deregister --device=nvme4</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-discover(1)</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dim.txt b/Documentation/nvme-dim.txt
new file mode 100644
index 0000000..fcfc9b8
--- /dev/null
+++ b/Documentation/nvme-dim.txt
@@ -0,0 +1,84 @@
+nvme-dim(1)
+===========
+
+NAME
+----
+nvme-dim - Send Discovery Information Management command to one or more
+Discovery Controllers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme dim' [--task=<task> | -t <task>] [--nqn=<nqn> | -n <nqn>]
+ [--device=<device> | -d <device>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send Discovery Information Management (DIM) command to one or more Discovery
+Controllers. The DIM command allows performing two types of tasks: register or
+deregister.
+
+The DIM command is used to explicitly register with Discovery Controllers (DC),
+especially with Central Discovery Controllers (CDC). CDCs maintain a database (DB)
+of all the Hosts and Storage Subsystems in a network. The register task is used
+to add a host to the CDC's DB. The deregister task is used to remove a host from
+the CDC's DB.
+
+During a register operation the host will send mandatory information such as the
+Host's NQN and ID, as well as the Host's hostname and the Operating System's
+version that it is running on. There is also an optional Host Symbolic Name
+that can be registered with the CDC.
+
+This command can only be applied to existing DC connections previously created
+with the nvme-discover(1) command using the --persistent option.
+
+OPTIONS
+-------
+-t <task>::
+--task <task>::
+ The task to perform: "register" or "deregister".
+
+-n <subnqn>::
+--nqn <nqn>::
+ The DIM command will be sent to the Discovery Controller (DC) matching this
+ NQN. A list of comma-separated NQNs can be supplied to apply the command to
+ more than one DC.
+
+-d <device>::
+--device <device>::
+ The DIM command will be sent to the Discovery Controllers (DC) associated
+ with this NVMe device handle. A list of comma-separated device handles can
+ be supplied to apply the command to more than one DC.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Register with the Central Discovery Controller (CDC) named
+nqn.1988-11.com.dell:SFSS:1:20220118125153e8:
++
+------------
+# nvme dim --task=register --nqn=nqn.1988-11.com.dell:SFSS:1:20220118125153e8
+------------
+
+* Deregister from Central Discovery Controller (CDC) associated with nvme4
++
+------------
+# nvme dim --task=deregister --device=nvme4
+------------
+
+SEE ALSO
+--------
+nvme-discover(1)
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-dir-receive.1 b/Documentation/nvme-dir-receive.1
new file mode 100644
index 0000000..2d62d2d
--- /dev/null
+++ b/Documentation/nvme-dir-receive.1
@@ -0,0 +1,235 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DIR\-RECEIVE" "1" "02/14/2024" "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-dir-receive \- Send a directive receive command, returns applicable results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme dir\-receive\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-dir\-type=<dtype> | \-D <dtype>]
+ [\-\-dir\-spec=<dspec> | \-S <dspec>]
+ [\-\-dir\-oper=<doper> | \-O <doper>]
+ [\-\-req\-resource=<nsr> | \-r <nsr>]
+ [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an NVMe Directive Receive admin command and returns the applicable results\&. This may be the combination of directive type, and operation, as well as number of requested resource if specific operation needs it\&.
+.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 directive\(cqs parameter structure (if applicable) is returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format if it is a known structure, displayed in hex, or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the feature for the given nsid\&. This is optional and most features do not use this value\&.
+.RE
+.PP
+\-D <dtype>, \-\-dir\-type=<dtype>
+.RS 4
+Directive type
+.RE
+.PP
+\-S <dspec>, \-\-dir\-spec=<dspec>
+.RS 4
+Directive specific
+.RE
+.PP
+\-O <doper>, \-\-dir\-oper=<doper>
+.RS 4
+Directive operation
+.RE
+.PP
+\-r <nsr>, \-\-req\-resource=<nsr>
+.RS 4
+Directive requested resource count
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Select
+T}:T{
+Description
+T}
+T{
+0
+T}:T{
+Current
+T}
+T{
+1
+T}:T{
+Default
+T}
+T{
+2
+T}:T{
+Saved
+T}
+T{
+3
+T}:T{
+Supported capabilities
+T}
+T{
+4\(en7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer returned for this feature\&. Most known features do not use this value\&. The exception is LBA Range Type
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw receive buffer to stdout if the command returns a structure\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+Print the decoded receive buffer to stdout if the command returns a structure\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Identify directive type supported :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-receive /dev/nvme0 \-\-dir\-type 0 \-\-dir\-oper 1 \-\-human\-readable
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get stream directive parameters :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-receive /dev/nvme0 \-\-dir\-type 1 \-\-dir\-oper 1 \-\-human\-readable
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Allocate 3 streams for namespace 1
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-receive /dev/nvme0n1 \-\-dir\-type 1 \-\-dir\-oper 3 \-\-req\-resource 3 \-\-human\-readable
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get streams directive status :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-receive /dev/nvme0 \-\-dir\-type 1 \-\-dir\-oper 2 \-\-human\-readable
+.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-dir-receive.html b/Documentation/nvme-dir-receive.html
new file mode 100644
index 0000000..49d29f9
--- /dev/null
+++ b/Documentation/nvme-dir-receive.html
@@ -0,0 +1,996 @@
+<?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 10.2.0" />
+<title>nvme-dir-receive(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-dir-receive(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-dir-receive -
+ Send a directive receive command, returns applicable 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 dir-receive</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--dir-type=&lt;dtype&gt; | -D &lt;dtype&gt;]
+ [--dir-spec=&lt;dspec&gt; | -S &lt;dspec&gt;]
+ [--dir-oper=&lt;doper&gt; | -O &lt;doper&gt;]
+ [--req-resource=&lt;nsr&gt; | -r &lt;nsr&gt;]
+ [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an NVMe Directive Receive admin command and returns the applicable
+results. This may be the combination of directive type, and operation, as
+well as number of requested resource if specific operation needs it.</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 directive&#8217;s parameter structure (if applicable) is
+returned in one of several ways depending on the option flags; the
+structure may parsed by the program and printed in a readable format
+if it is a known structure, displayed in hex, 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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+</p>
+</dd>
+<dt class="hdlist1">
+-D &lt;dtype&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&lt;dtype&gt;
+</dt>
+<dd>
+<p>
+ Directive type
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;dspec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&lt;dspec&gt;
+</dt>
+<dd>
+<p>
+ Directive specific
+</p>
+</dd>
+<dt class="hdlist1">
+-O &lt;doper&gt;
+</dt>
+<dt class="hdlist1">
+--dir-oper=&lt;doper&gt;
+</dt>
+<dd>
+<p>
+ Directive operation
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;nsr&gt;
+</dt>
+<dt class="hdlist1">
+--req-resource=&lt;nsr&gt;
+</dt>
+<dd>
+<p>
+ Directive requested resource count
+</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">Select</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Current</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Default</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Saved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Supported capabilities</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4–7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw receive buffer to stdout if the command returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ Print the decoded receive buffer to stdout if the command returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Identify directive type supported :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-receive /dev/nvme0 --dir-type 0 --dir-oper 1 --human-readable</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get stream directive parameters :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-receive /dev/nvme0 --dir-type 1 --dir-oper 1 --human-readable</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Allocate 3 streams for namespace 1
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-receive /dev/nvme0n1 --dir-type 1 --dir-oper 3 --req-resource 3 --human-readable</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get streams directive status :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-receive /dev/nvme0 --dir-type 1 --dir-oper 2 --human-readable</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dir-receive.txt b/Documentation/nvme-dir-receive.txt
new file mode 100644
index 0000000..f3f31ba
--- /dev/null
+++ b/Documentation/nvme-dir-receive.txt
@@ -0,0 +1,126 @@
+nvme-dir-receive(1)
+===================
+
+NAME
+----
+nvme-dir-receive - Send a directive receive command, returns applicable results
+
+SYNOPSIS
+--------
+[verse]
+'nvme dir-receive' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--dir-type=<dtype> | -D <dtype>]
+ [--dir-spec=<dspec> | -S <dspec>]
+ [--dir-oper=<doper> | -O <doper>]
+ [--req-resource=<nsr> | -r <nsr>]
+ [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an NVMe Directive Receive admin command and returns the applicable
+results. This may be the combination of directive type, and operation, as
+well as number of requested resource if specific operation needs it.
+
+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 directive's parameter structure (if applicable) is
+returned in one of several ways depending on the option flags; the
+structure may parsed by the program and printed in a readable format
+if it is a known structure, displayed in hex, or the raw buffer may be
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+
+-D <dtype>::
+--dir-type=<dtype>::
+ Directive type
+
+-S <dspec>::
+--dir-spec=<dspec>::
+ Directive specific
+
+-O <doper>::
+--dir-oper=<doper>::
+ Directive operation
+
+-r <nsr>::
+--req-resource=<nsr>::
+ Directive requested resource count
++
+[]
+|==================
+|Select|Description
+|0|Current
+|1|Default
+|2|Saved
+|3|Supported capabilities
+|4–7|Reserved
+|==================
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+
+-b::
+--raw-binary::
+ Print the raw receive buffer to stdout if the command returns
+ a structure.
+
+-H::
+--human-readable::
+ Print the decoded receive buffer to stdout if the command returns
+ a structure.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Identify directive type supported :
++
+------------
+# nvme dir-receive /dev/nvme0 --dir-type 0 --dir-oper 1 --human-readable
+------------
++
+
+* Get stream directive parameters :
++
+------------
+# nvme dir-receive /dev/nvme0 --dir-type 1 --dir-oper 1 --human-readable
+------------
++
+
+* Allocate 3 streams for namespace 1
++
+------------
+# nvme dir-receive /dev/nvme0n1 --dir-type 1 --dir-oper 3 --req-resource 3 --human-readable
+------------
++
+
+* Get streams directive status :
++
+------------
+# nvme dir-receive /dev/nvme0 --dir-type 1 --dir-oper 2 --human-readable
+------------
++
+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-dir-send.1 b/Documentation/nvme-dir-send.1
new file mode 100644
index 0000000..482c777
--- /dev/null
+++ b/Documentation/nvme-dir-send.1
@@ -0,0 +1,241 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DIR\-SEND" "1" "02/14/2024" "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-dir-send \- Issue a directive send command, returns applicable results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme dir\-send\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-dir\-type=<dtype> | \-D <dtype>]
+ [\-\-dir\-spec=<dspec> | \-S <dspec>]
+ [\-\-dir\-oper=<doper> | \-O <doper>]
+ [\-\-endir=<endir> | \-e <endir>]
+ [\-\-target\-dir=<tdir> | \-T <tdir>]
+ [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an NVMe Directive Send admin command and returns the applicable results\&. This may be the combination of directive type, and operation, as well as target directive and its enable/disable status of the operation, if specific operation needs it\&.
+.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 directive\(cqs parameter structure (if applicable) is returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format if it is a known structure, displayed in hex, or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the feature for the given nsid\&. This is optional and most features do not use this value\&.
+.RE
+.PP
+\-D <dtype>, \-\-dir\-type=<dtype>
+.RS 4
+Directive type
+.RE
+.PP
+\-S <dspec>, \-\-dir\-spec=<dspec>
+.RS 4
+Directive specific
+.RE
+.PP
+\-O <doper>, \-\-dir\-oper=<doper>
+.RS 4
+Directive operation
+.RE
+.PP
+\-T <tdir>, \-\-target\-dir=<nsr>
+.RS 4
+Target directive of the operation
+.RE
+.PP
+\-e <endir>, \-\-endir=<endir>
+.RS 4
+Target directive enable(1) or disable (0) operation
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Select
+T}:T{
+Description
+T}
+T{
+0
+T}:T{
+Current
+T}
+T{
+1
+T}:T{
+Default
+T}
+T{
+2
+T}:T{
+Saved
+T}
+T{
+3
+T}:T{
+Supported capabilities
+T}
+T{
+4\(en7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer returned for this feature\&. Most known features do not use this value\&. The exception is LBA Range Type
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw receive buffer to stdout if the command returns a structure\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+Print the decoded receive buffer to stdout if the command returns a structure\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Enable streams directive :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-send /dev/nvme0n1 \-\-dir\-type 0 \-\-dir\-oper 1 \-\-target\-dir 1 \-\-endir 1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Disable streams directive :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-send /dev/nvme0n1 \-\-dir\-type 0 \-\-dir\-oper 1 \-\-target\-dir 1 \-\-endir 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Release all allocated streams resource :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-send /dev/nvme0n1 \-\-dir\-type 1 \-\-dir\-oper 2
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Release stream ID 3 :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme dir\-send /dev/nvme0 \-\-dir\-type 1 \-\-dir\-oper 1 \-\-dir\-spec 3
+.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-dir-send.html b/Documentation/nvme-dir-send.html
new file mode 100644
index 0000000..a8182fa
--- /dev/null
+++ b/Documentation/nvme-dir-send.html
@@ -0,0 +1,1009 @@
+<?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 10.2.0" />
+<title>nvme-dir-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 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-dir-send(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-dir-send -
+ Issue a directive send command, returns applicable 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 dir-send</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--dir-type=&lt;dtype&gt; | -D &lt;dtype&gt;]
+ [--dir-spec=&lt;dspec&gt; | -S &lt;dspec&gt;]
+ [--dir-oper=&lt;doper&gt; | -O &lt;doper&gt;]
+ [--endir=&lt;endir&gt; | -e &lt;endir&gt;]
+ [--target-dir=&lt;tdir&gt; | -T &lt;tdir&gt;]
+ [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an NVMe Directive Send admin command and returns the applicable
+results. This may be the combination of directive type, and operation, as
+well as target directive and its enable/disable status of the operation,
+if specific operation needs it.</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 directive&#8217;s parameter structure (if applicable) is
+returned in one of several ways depending on the option flags; the
+structure may parsed by the program and printed in a readable format
+if it is a known structure, displayed in hex, 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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+</p>
+</dd>
+<dt class="hdlist1">
+-D &lt;dtype&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&lt;dtype&gt;
+</dt>
+<dd>
+<p>
+ Directive type
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;dspec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&lt;dspec&gt;
+</dt>
+<dd>
+<p>
+ Directive specific
+</p>
+</dd>
+<dt class="hdlist1">
+-O &lt;doper&gt;
+</dt>
+<dt class="hdlist1">
+--dir-oper=&lt;doper&gt;
+</dt>
+<dd>
+<p>
+ Directive operation
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;tdir&gt;
+</dt>
+<dt class="hdlist1">
+--target-dir=&lt;nsr&gt;
+</dt>
+<dd>
+<p>
+ Target directive of the operation
+</p>
+</dd>
+<dt class="hdlist1">
+-e &lt;endir&gt;
+</dt>
+<dt class="hdlist1">
+--endir=&lt;endir&gt;
+</dt>
+<dd>
+<p>
+ Target directive enable(1) or disable (0) operation
+</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">Select</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Current</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Default</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Saved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Supported capabilities</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4–7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw receive buffer to stdout if the command returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ Print the decoded receive buffer to stdout if the command returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Enable streams directive :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-send /dev/nvme0n1 --dir-type 0 --dir-oper 1 --target-dir 1 --endir 1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Disable streams directive :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-send /dev/nvme0n1 --dir-type 0 --dir-oper 1 --target-dir 1 --endir 0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Release all allocated streams resource :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-send /dev/nvme0n1 --dir-type 1 --dir-oper 2</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Release stream ID 3 :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme dir-send /dev/nvme0 --dir-type 1 --dir-oper 1 --dir-spec 3</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dir-send.txt b/Documentation/nvme-dir-send.txt
new file mode 100644
index 0000000..1e3743d
--- /dev/null
+++ b/Documentation/nvme-dir-send.txt
@@ -0,0 +1,132 @@
+nvme-dir-send(1)
+================
+
+NAME
+----
+nvme-dir-send - Issue a directive send command, returns applicable results
+
+SYNOPSIS
+--------
+[verse]
+'nvme dir-send' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--dir-type=<dtype> | -D <dtype>]
+ [--dir-spec=<dspec> | -S <dspec>]
+ [--dir-oper=<doper> | -O <doper>]
+ [--endir=<endir> | -e <endir>]
+ [--target-dir=<tdir> | -T <tdir>]
+ [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an NVMe Directive Send admin command and returns the applicable
+results. This may be the combination of directive type, and operation, as
+well as target directive and its enable/disable status of the operation,
+if specific operation needs it.
+
+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 directive's parameter structure (if applicable) is
+returned in one of several ways depending on the option flags; the
+structure may parsed by the program and printed in a readable format
+if it is a known structure, displayed in hex, or the raw buffer may be
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+
+-D <dtype>::
+--dir-type=<dtype>::
+ Directive type
+
+-S <dspec>::
+--dir-spec=<dspec>::
+ Directive specific
+
+-O <doper>::
+--dir-oper=<doper>::
+ Directive operation
+
+-T <tdir>::
+--target-dir=<nsr>::
+ Target directive of the operation
+
+-e <endir>::
+--endir=<endir>::
+ Target directive enable(1) or disable (0) operation
++
+[]
+|==================
+|Select|Description
+|0|Current
+|1|Default
+|2|Saved
+|3|Supported capabilities
+|4–7|Reserved
+|==================
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+
+-b::
+--raw-binary::
+ Print the raw receive buffer to stdout if the command returns
+ a structure.
+
+-H::
+--human-readable::
+ Print the decoded receive buffer to stdout if the command returns
+ a structure.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Enable streams directive :
++
+------------
+# nvme dir-send /dev/nvme0n1 --dir-type 0 --dir-oper 1 --target-dir 1 --endir 1
+------------
++
+
+* Disable streams directive :
++
+------------
+# nvme dir-send /dev/nvme0n1 --dir-type 0 --dir-oper 1 --target-dir 1 --endir 0
+------------
++
+
+* Release all allocated streams resource :
++
+------------
+# nvme dir-send /dev/nvme0n1 --dir-type 1 --dir-oper 2
+------------
++
+
+* Release stream ID 3 :
++
+------------
+# nvme dir-send /dev/nvme0 --dir-type 1 --dir-oper 1 --dir-spec 3
+------------
++
+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-disconnect-all.1 b/Documentation/nvme-disconnect-all.1
new file mode 100644
index 0000000..9652365
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.1
@@ -0,0 +1,84 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCONNECT\-AL" "1" "02/14/2024" "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-disconnect-all \- Disconnect from all connected Fabrics controllers\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme disconnect\-all\fR [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Disconnects and removes all existing NVMe over Fabrics controllers\&.
+.sp
+See the documentation for the nvme\-disconnect(1) command for further background\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Disconnect all existing nvme controllers:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme disconnect\-all
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-disconnect(1)
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-disconnect-all.html b/Documentation/nvme-disconnect-all.html
new file mode 100644
index 0000000..59b545e
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.html
@@ -0,0 +1,832 @@
+<?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 10.2.0" />
+<title>nvme-disconnect-all(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-disconnect-all(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-disconnect-all -
+ Disconnect from all connected Fabrics controllers.
+</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 disconnect-all</em> [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Disconnects and removes all existing NVMe over Fabrics controllers.</p></div>
+<div class="paragraph"><p>See the documentation for the nvme-disconnect(1) command for further
+background.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Disconnect all existing nvme controllers:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme disconnect-all</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-disconnect(1)</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-disconnect-all.txt b/Documentation/nvme-disconnect-all.txt
new file mode 100644
index 0000000..9f023ea
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.txt
@@ -0,0 +1,45 @@
+nvme-disconnect-all(1)
+======================
+
+NAME
+----
+nvme-disconnect-all - Disconnect from all connected Fabrics controllers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme disconnect-all' [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Disconnects and removes all existing NVMe over Fabrics controllers.
+
+See the documentation for the nvme-disconnect(1) command for further
+background.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Disconnect all existing nvme controllers:
++
+------------
+# nvme disconnect-all
+------------
+
+SEE ALSO
+--------
+nvme-disconnect(1)
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-disconnect.1 b/Documentation/nvme-disconnect.1
new file mode 100644
index 0000000..2fcf331
--- /dev/null
+++ b/Documentation/nvme-disconnect.1
@@ -0,0 +1,115 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCONNECT" "1" "02/14/2024" "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-disconnect \- Disconnect one or more Fabrics controller(s)\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme disconnect\fR [\-\-nqn=<subnqn> | \-n <subnqn>]
+ [\-\-device=<device> | \-d <device>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Disconnects and removes one or more existing NVMe over Fabrics controllers\&. If the \-\-nqn option is specified all controllers connecting to the Subsystem identified by subnqn will be removed\&. If the \-\-device option is specified the controller specified by the \-\-device option will be removed\&.
+.SH "OPTIONS"
+.PP
+\-n <subnqn>, \-\-nqn <subnqn>
+.RS 4
+Indicates that all controllers for the NVMe subsystems specified should be removed\&.
+.RE
+.PP
+\-d <device>, \-\-device <device>
+.RS 4
+Indicates that the controller with the specified name should be removed\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Disconnect all controllers for a subsystem named nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme disconnect \-\-nqn=nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Disconnect the controller nvme4
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme disconnect \-\-device=nvme4
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-connect(1)
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-disconnect.html b/Documentation/nvme-disconnect.html
new file mode 100644
index 0000000..486efb4
--- /dev/null
+++ b/Documentation/nvme-disconnect.html
@@ -0,0 +1,869 @@
+<?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 10.2.0" />
+<title>nvme-disconnect(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-disconnect(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-disconnect -
+ Disconnect one or more Fabrics controller(s).
+</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 disconnect</em> [--nqn=&lt;subnqn&gt; | -n &lt;subnqn&gt;]
+ [--device=&lt;device&gt; | -d &lt;device&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Disconnects and removes one or more existing NVMe over Fabrics controllers.
+If the --nqn option is specified all controllers connecting to the Subsystem
+identified by subnqn will be removed. If the --device option is specified
+the controller specified by the --device option will be removed.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;subnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn &lt;subnqn&gt;
+</dt>
+<dd>
+<p>
+ Indicates that all controllers for the NVMe subsystems specified
+ should be removed.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;device&gt;
+</dt>
+<dt class="hdlist1">
+--device &lt;device&gt;
+</dt>
+<dd>
+<p>
+ Indicates that the controller with the specified name should be
+ removed.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Disconnect all controllers for a subsystem named
+nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme disconnect --nqn=nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Disconnect the controller nvme4
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme disconnect --device=nvme4</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-connect(1)</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-disconnect.txt b/Documentation/nvme-disconnect.txt
new file mode 100644
index 0000000..d3b8c52
--- /dev/null
+++ b/Documentation/nvme-disconnect.txt
@@ -0,0 +1,64 @@
+nvme-disconnect(1)
+==================
+
+NAME
+----
+nvme-disconnect - Disconnect one or more Fabrics controller(s).
+
+SYNOPSIS
+--------
+[verse]
+'nvme disconnect' [--nqn=<subnqn> | -n <subnqn>]
+ [--device=<device> | -d <device>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Disconnects and removes one or more existing NVMe over Fabrics controllers.
+If the --nqn option is specified all controllers connecting to the Subsystem
+identified by subnqn will be removed. If the --device option is specified
+the controller specified by the --device option will be removed.
+
+OPTIONS
+-------
+-n <subnqn>::
+--nqn <subnqn>::
+ Indicates that all controllers for the NVMe subsystems specified
+ should be removed.
+
+-d <device>::
+--device <device>::
+ Indicates that the controller with the specified name should be
+ removed.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Disconnect all controllers for a subsystem named
+nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432:
++
+------------
+# nvme disconnect --nqn=nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+------------
+
+* Disconnect the controller nvme4
++
+------------
+# nvme disconnect --device=nvme4
+------------
+
+SEE ALSO
+--------
+nvme-connect(1)
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-discover.1 b/Documentation/nvme-discover.1
new file mode 100644
index 0000000..c099d1a
--- /dev/null
+++ b/Documentation/nvme-discover.1
@@ -0,0 +1,414 @@
+'\" t
+.\" Title: nvme-discover
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCOVER" "1" "02/14/2024" "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-discover \- Send Get Log Page request to Discovery Controller\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme discover\fR [\-\-transport=<trtype> | \-t <trtype>]
+ [\-\-nqn=<subnqn> | \-n <subnqn>]
+ [\-\-traddr=<traddr> | \-a <traddr>]
+ [\-\-trsvcid=<trsvcid> | \-s <trsvcid>]
+ [\-\-host\-traddr=<traddr> | \-w <traddr>]
+ [\-\-host\-iface=<iface> | \-f <iface>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-raw=<filename> | \-r <filename>]
+ [\-\-device=<device> | \-d <device>]
+ [\-\-config=<filename> | \-J <filename>]
+ [\-\-keep\-alive\-tmo=<sec> | \-k <sec>]
+ [\-\-reconnect\-delay=<#> | \-c <#>]
+ [\-\-ctrl\-loss\-tmo=<#> | \-l <#>]
+ [\-\-nr\-io\-queues=<#> | \-i <#>]
+ [\-\-nr\-write\-queues=<#> | \-W <#>]
+ [\-\-nr\-poll\-queues=<#> | \-P <#>]
+ [\-\-queue\-size=<#> | \-Q <#>] [\-\-keyring=<#>]
+ [\-\-tls_key=<#>] [\-\-hdr\-digest | \-g] [\-\-data\-digest | \-G]
+ [\-\-persistent | \-p] [\-\-quiet | \-S] [\-\-tls] [\-\-concat]
+ [\-\-dump\-config | \-O] [\-\-output\-format=<fmt> | \-o <fmt>]
+ [\-\-force] [\-\-nbft] [\-\-no\-nbft] [\-\-nbft\-path=<STR>]
+ [\-\-context=<STR>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send one or more Get Log Page requests to a NVMe\-over\-Fabrics Discovery Controller\&.
+.sp
+If no parameters are given, then \fInvme discover\fR will attempt to find a /usr/local/etc/nvme/discovery\&.conf file to use to supply a list of Discovery commands to run\&. If no /usr/local/etc/nvme/discovery\&.conf file exists, the command will quit with an error\&.
+.sp
+Otherwise, a specific Discovery Controller should be specified using the \-\-transport, \-\-traddr, and if necessary the \-\-trsvcid flags\&. A Discovery request will then be sent to the specified Discovery Controller\&.
+.SH "BACKGROUND"
+.sp
+The NVMe\-over\-Fabrics specification defines the concept of a Discovery Controller that an NVMe Host can query on a fabric network to discover NVMe subsystems contained in NVMe Targets which it can connect to on the network\&. The Discovery Controller will return Discovery Log Pages that provide the NVMe Host with specific information (such as network address and unique subsystem NQN) the NVMe Host can use to issue an NVMe connect command to connect itself to a storage resource contained in that NVMe subsystem on the NVMe Target\&.
+.sp
+Note that the base NVMe specification defines the NQN (NVMe Qualified Name) format which an NVMe endpoint (device, subsystem, etc) must follow to guarantee a unique name under the NVMe standard\&. In particular, the Host NQN uniquely identifies the NVMe Host, and may be used by the Discovery Controller to control what NVMe Target resources are allocated to the NVMe Host for a connection\&.
+.sp
+A Discovery Controller has it\(cqs own NQN defined in the NVMe\-over\-Fabrics specification, \fBnqn\&.2014\-08\&.org\&.nvmexpress\&.discovery\fR\&. All Discovery Controllers must use this NQN name\&. This NQN is used by default by nvme\-cli for the \fIdiscover\fR command\&.
+.SH "OPTIONS"
+.PP
+\-t <trtype>, \-\-transport=<trtype>
+.RS 4
+This field specifies the network fabric being used for a NVMe\-over\-Fabrics network\&. Current string values include:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+rdma
+T}:T{
+The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)
+T}
+T{
+fc
+T}:T{
+\fBWIP\fR
+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
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-n <subnqn>, \-\-nqn <subnqn>
+.RS 4
+This field specifies the name for the NVMe subsystem to connect to\&.
+.RE
+.PP
+\-a <traddr>, \-\-traddr=<traddr>
+.RS 4
+This field specifies the network address of the Discovery Controller\&. For transports using IP addressing (e\&.g\&. rdma) this should be an IP\-based address (ex\&. IPv4)\&.
+.RE
+.PP
+\-s <trsvcid>, \-\-trsvcid=<trsvcid>
+.RS 4
+This field specifies the transport service id\&. For transports using IP addressing (e\&.g\&. rdma) this field is the port number\&. By default, the IP port number for the RDMA transport is 4420\&.
+.RE
+.PP
+\-w <traddr>, \-\-host\-traddr=<traddr>
+.RS 4
+This field specifies the network address used on the host to connect to the Controller\&. For TCP, this sets the source address on the socket\&.
+.RE
+.PP
+\-f <iface>, \-\-host\-iface=<iface>
+.RS 4
+This field specifies the network interface used on the host to connect to the Controller (e\&.g\&. IP eth1, enp2s0, enx78e7d1ea46da)\&. This forces the connection to be made on a specific interface instead of letting the system decide\&.
+.RE
+.PP
+\-q <hostnqn>, \-\-hostnqn=<hostnqn>
+.RS 4
+Overrides the default host NQN that identifies the NVMe Host\&. If this option is not specified, the default is read from /usr/local/etc/nvme/hostnqn first\&. If that does not exist, the autogenerated NQN value from the NVMe Host kernel module is used next\&.
+.RE
+.PP
+\-I <hostid>, \-\-hostid=<hostid>
+.RS 4
+UUID(Universally Unique Identifier) to be discovered which should be formatted\&.
+.RE
+.PP
+\-r <filename>, \-\-raw=<filename>
+.RS 4
+This field will take the output of the
+\fInvme discover\fR
+command and dump it to a raw binary file\&. By default
+\fInvme discover\fR
+will dump the output to stdout\&.
+.RE
+.PP
+\-d <device>, \-\-device=<device>
+.RS 4
+This field takes a device as input\&. It must be a persistent device associated with a Discovery Controller previously created by the command "connect\-all" or "discover"\&. <device> follows the format nvme*, eg\&. nvme0, nvme1\&.
+.RE
+.PP
+\-J <filename>, \-\-config=<filename>
+.RS 4
+Use the specified JSON configuration file instead of the default /usr/local/etc/nvme/config\&.json file or
+\fInone\fR
+to not read in an existing configuration file\&. The JSON configuration file format is documented in
+\m[blue]\fBhttps://github\&.com/linux\-nvme/libnvme/blob/master/doc/config\-schema\&.json\fR\m[]
+.RE
+.PP
+\-k <#>, \-\-keep\-alive\-tmo=<#>
+.RS 4
+Overrides the default keep alive timeout (in seconds)\&. This option will be ignored for discovery, and it is only implemented for completeness\&.
+.RE
+.PP
+\-c <#>, \-\-reconnect\-delay=<#>
+.RS 4
+Overrides the default delay (in seconds) before reconnect is attempted after a connect loss\&.
+.RE
+.PP
+\-l <#>, \-\-ctrl\-loss\-tmo=<#>
+.RS 4
+Overrides the default controller loss timeout period (in seconds)\&.
+.RE
+.PP
+\-i <#>, \-\-nr\-io\-queues=<#>
+.RS 4
+Overrides the default number of I/O queues create by the driver\&. This option will be ignored for the discovery, and it is only implemented for completeness\&.
+.RE
+.PP
+\-W <#>, \-\-nr\-write\-queues=<#>
+.RS 4
+Adds additional queues that will be used for write I/O\&.
+.RE
+.PP
+\-P <#>, \-\-nr\-poll\-queues=<#>
+.RS 4
+Adds additional queues that will be used for polling latency sensitive I/O\&.
+.RE
+.PP
+\-Q <#>, \-\-queue\-size=<#>
+.RS 4
+Overrides the default number of elements in the I/O queues created by the driver which can be found at drivers/nvme/host/fabrics\&.h\&. This option will be ignored for the discovery, and it is only implemented for completeness\&.
+.RE
+.PP
+\-\-keyring=<#>
+.RS 4
+Keyring for TLS key lookup\&.
+.RE
+.PP
+\-\-tls_key=<#>
+.RS 4
+TLS key for the connection (TCP)\&.
+.RE
+.PP
+\-g, \-\-hdr\-digest
+.RS 4
+Generates/verifies header digest (TCP)\&.
+.RE
+.PP
+\-G, \-\-data\-digest
+.RS 4
+Generates/verifies data digest (TCP)\&.
+.RE
+.PP
+\-p, \-\-persistent
+.RS 4
+Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
+.RE
+.PP
+\-\-tls
+.RS 4
+Enable TLS encryption (TCP)\&.
+.RE
+.PP
+\-\-concat
+.RS 4
+Enable secure concatenation (TCP)\&.
+.RE
+.PP
+\-S, \-\-quiet
+.RS 4
+Suppress already connected errors\&.
+.RE
+.PP
+\-O, \-\-dump\-config
+.RS 4
+Print out resulting JSON configuration file to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-\-force
+.RS 4
+Disable the built\-in persistent discover connection rules\&. Combined with \-\-persistent flag, always create new persistent discovery connection\&.
+.RE
+.PP
+\-\-nbft
+.RS 4
+Only look at NBFT tables
+.RE
+.PP
+\-\-no\-nbft
+.RS 4
+Do not look at NBFT tables
+.RE
+.PP
+\-\-nbft\-path=<STR>
+.RS 4
+Use a user\-defined path to the NBFT tables
+.RE
+.PP
+\-\-context <STR>
+.RS 4
+Set the execution context to <STR>\&. This allows to coordinate the management of the global resources\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Query the Discover Controller with IP4 address 192\&.168\&.1\&.3 for all resources allocated for NVMe Host name host1\-rogue\-nqn on the RDMA network\&. Port 4420 is used by default:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme discover \-\-transport=rdma \-\-traddr=192\&.168\&.1\&.3 \e
+\-\-hostnqn=host1\-rogue\-nqn
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme discover\fR
+command using the default system defined NBFT tables:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme discover \-\-nbft
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme discover\fR
+command with a user\-defined path for the NBFT table:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme discover \-\-nbft\-path=/sys/firmware/acpi/tables/NBFT1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Issue a
+\fInvme discover\fR
+command using a /usr/local/etc/nvme/discovery\&.conf file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# Machine default \*(Aqnvme discover\*(Aq commands\&. Query the
+# Discovery Controller\*(Aqs two ports (some resources may only
+# be accessible on a single port)\&. Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example\&.
+\-t rdma \-a 192\&.168\&.69\&.33 \-s 4420 \-q nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+\-t rdma \-a 192\&.168\&.1\&.4 \-s 4420 \-q nqn\&.2014\-08\&.com\&.example:nvme:nvm\-subsystem\-sn\-d78432
+
+At the prompt type "nvme discover"\&.
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "SEE ALSO"
+.sp
+nvme\-connect(1) nvme\-connect\-all(1)
+.SH "AUTHORS"
+.sp
+This was written by \m[blue]\fBJay Freyensee\fR\m[]\&\s-2\u[1]\d\s+2
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
+.SH "NOTES"
+.IP " 1." 4
+Jay Freyensee
+.RS 4
+\%mailto:james.p.freyensee@intel.com
+.RE
diff --git a/Documentation/nvme-discover.html b/Documentation/nvme-discover.html
new file mode 100644
index 0000000..0d5f6a9
--- /dev/null
+++ b/Documentation/nvme-discover.html
@@ -0,0 +1,1332 @@
+<?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 10.2.0" />
+<title>nvme-discover(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-discover(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-discover -
+ Send Get Log Page request to Discovery Controller.
+</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 discover</em> [--transport=&lt;trtype&gt; | -t &lt;trtype&gt;]
+ [--nqn=&lt;subnqn&gt; | -n &lt;subnqn&gt;]
+ [--traddr=&lt;traddr&gt; | -a &lt;traddr&gt;]
+ [--trsvcid=&lt;trsvcid&gt; | -s &lt;trsvcid&gt;]
+ [--host-traddr=&lt;traddr&gt; | -w &lt;traddr&gt;]
+ [--host-iface=&lt;iface&gt; | -f &lt;iface&gt;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&gt;]
+ [--raw=&lt;filename&gt; | -r &lt;filename&gt;]
+ [--device=&lt;device&gt; | -d &lt;device&gt;]
+ [--config=&lt;filename&gt; | -J &lt;filename&gt;]
+ [--keep-alive-tmo=&lt;sec&gt; | -k &lt;sec&gt;]
+ [--reconnect-delay=&lt;#&gt; | -c &lt;#&gt;]
+ [--ctrl-loss-tmo=&lt;#&gt; | -l &lt;#&gt;]
+ [--nr-io-queues=&lt;#&gt; | -i &lt;#&gt;]
+ [--nr-write-queues=&lt;#&gt; | -W &lt;#&gt;]
+ [--nr-poll-queues=&lt;#&gt; | -P &lt;#&gt;]
+ [--queue-size=&lt;#&gt; | -Q &lt;#&gt;] [--keyring=&lt;#&gt;]
+ [--tls_key=&lt;#&gt;] [--hdr-digest | -g] [--data-digest | -G]
+ [--persistent | -p] [--quiet | -S] [--tls] [--concat]
+ [--dump-config | -O] [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
+ [--force] [--nbft] [--no-nbft] [--nbft-path=&lt;STR&gt;]
+ [--context=&lt;STR&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send one or more Get Log Page requests to a NVMe-over-Fabrics Discovery
+Controller.</p></div>
+<div class="paragraph"><p>If no parameters are given, then <em>nvme discover</em> will attempt to
+find a /usr/local/etc/nvme/discovery.conf file to use to supply a list of
+Discovery commands to run. If no /usr/local/etc/nvme/discovery.conf file
+exists, the command will quit with an error.</p></div>
+<div class="paragraph"><p>Otherwise, a specific Discovery Controller should be specified using the
+--transport, --traddr, and if necessary the --trsvcid flags. A Discovery
+request will then be sent to the specified Discovery Controller.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_background">BACKGROUND</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The NVMe-over-Fabrics specification defines the concept of a
+Discovery Controller that an NVMe Host can query on a fabric
+network to discover NVMe subsystems contained in NVMe Targets
+which it can connect to on the network. The Discovery Controller
+will return Discovery Log Pages that provide the NVMe Host
+with specific information (such as network address and unique
+subsystem NQN) the NVMe Host can use to issue an
+NVMe connect command to connect itself to a storage resource
+contained in that NVMe subsystem on the NVMe Target.</p></div>
+<div class="paragraph"><p>Note that the base NVMe specification defines the NQN (NVMe Qualified
+Name) format which an NVMe endpoint (device, subsystem, etc) must
+follow to guarantee a unique name under the NVMe standard.
+In particular, the Host NQN uniquely identifies the NVMe Host, and
+may be used by the Discovery Controller to control what NVMe Target
+resources are allocated to the NVMe Host for a connection.</p></div>
+<div class="paragraph"><p>A Discovery Controller has it&#8217;s own NQN defined in the NVMe-over-Fabrics
+specification, <strong>nqn.2014-08.org.nvmexpress.discovery</strong>. All Discovery
+Controllers must use this NQN name. This NQN is used by default by
+nvme-cli for the <em>discover</em> command.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-t &lt;trtype&gt;
+</dt>
+<dt class="hdlist1">
+--transport=&lt;trtype&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string 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">rdma</p></td>
+<td align="left" valign="top"><p class="table">The network fabric is an rdma network (RoCE, iWARP, Infiniband, basic rdma, etc)</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">fc</p></td>
+<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>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-n &lt;subnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn &lt;subnqn&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the name for the NVMe subsystem to connect to.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address of the Discovery Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;trsvcid&gt;
+</dt>
+<dt class="hdlist1">
+--trsvcid=&lt;trsvcid&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+</p>
+</dd>
+<dt class="hdlist1">
+-w &lt;traddr&gt;
+</dt>
+<dt class="hdlist1">
+--host-traddr=&lt;traddr&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;iface&gt;
+</dt>
+<dt class="hdlist1">
+--host-iface=&lt;iface&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+</p>
+</dd>
+<dt class="hdlist1">
+-q &lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+--hostnqn=&lt;hostnqn&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ /usr/local/etc/nvme/hostnqn first. If that does not exist, the
+ autogenerated NQN value from the NVMe Host kernel module is used next.
+</p>
+</dd>
+<dt class="hdlist1">
+-I &lt;hostid&gt;
+</dt>
+<dt class="hdlist1">
+--hostid=&lt;hostid&gt;
+</dt>
+<dd>
+<p>
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;filename&gt;
+</dt>
+<dt class="hdlist1">
+--raw=&lt;filename&gt;
+</dt>
+<dd>
+<p>
+ This field will take the output of the <em>nvme discover</em> command
+ and dump it to a raw binary file. By default <em>nvme discover</em> will
+ dump the output to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;device&gt;
+</dt>
+<dt class="hdlist1">
+--device=&lt;device&gt;
+</dt>
+<dd>
+<p>
+ This field takes a device as input. It must be a persistent device
+ associated with a Discovery Controller previously created by the
+ command "connect-all" or "discover". &lt;device&gt; follows the format
+ nvme*, eg. nvme0, nvme1.
+</p>
+</dd>
+<dt class="hdlist1">
+-J &lt;filename&gt;
+</dt>
+<dt class="hdlist1">
+--config=&lt;filename&gt;
+</dt>
+<dd>
+<p>
+ Use the specified JSON configuration file instead of the
+ default /usr/local/etc/nvme/config.json file or <em>none</em> to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ <a href="https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json">https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json</a>
+</p>
+</dd>
+<dt class="hdlist1">
+-k &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--keep-alive-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default keep alive timeout (in seconds). This
+ option will be ignored for discovery, and it is only
+ implemented for completeness.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--reconnect-delay=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--ctrl-loss-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default controller loss timeout period (in seconds).
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-io-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of I/O queues create by the driver.
+ This option will be ignored for the discovery, and it is only
+ implemented for completeness.
+</p>
+</dd>
+<dt class="hdlist1">
+-W &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-write-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for write I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-P &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--nr-poll-queues=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Adds additional queues that will be used for polling latency sensitive I/O.
+</p>
+</dd>
+<dt class="hdlist1">
+-Q &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--queue-size=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default number of elements in the I/O queues created
+ by the driver which can be found at drivers/nvme/host/fabrics.h.
+ This option will be ignored for the discovery, and it is only
+ implemented for completeness.
+</p>
+</dd>
+<dt class="hdlist1">
+--keyring=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Keyring for TLS key lookup.
+</p>
+</dd>
+<dt class="hdlist1">
+--tls_key=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ TLS key for the connection (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-g
+</dt>
+<dt class="hdlist1">
+--hdr-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies header digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-G
+</dt>
+<dt class="hdlist1">
+--data-digest
+</dt>
+<dd>
+<p>
+ Generates/verifies data digest (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--persistent
+</dt>
+<dd>
+<p>
+ Don&#8217;t remove the discovery controller after retrieving the discovery
+ log page.
+</p>
+</dd>
+<dt class="hdlist1">
+--tls
+</dt>
+<dd>
+<p>
+ Enable TLS encryption (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+--concat
+</dt>
+<dd>
+<p>
+ Enable secure concatenation (TCP).
+</p>
+</dd>
+<dt class="hdlist1">
+-S
+</dt>
+<dt class="hdlist1">
+--quiet
+</dt>
+<dd>
+<p>
+ Suppress already connected errors.
+</p>
+</dd>
+<dt class="hdlist1">
+-O
+</dt>
+<dt class="hdlist1">
+--dump-config
+</dt>
+<dd>
+<p>
+ Print out resulting JSON configuration file to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+--force
+</dt>
+<dd>
+<p>
+ Disable the built-in persistent discover connection rules.
+ Combined with --persistent flag, always create new
+ persistent discovery connection.
+</p>
+</dd>
+<dt class="hdlist1">
+--nbft
+</dt>
+<dd>
+<p>
+ Only look at NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--no-nbft
+</dt>
+<dd>
+<p>
+ Do not look at NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--nbft-path=&lt;STR&gt;
+</dt>
+<dd>
+<p>
+ Use a user-defined path to the NBFT tables
+</p>
+</dd>
+<dt class="hdlist1">
+--context &lt;STR&gt;
+</dt>
+<dd>
+<p>
+ Set the execution context to &lt;STR&gt;. This allows to coordinate
+ the management of the global resources.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Query the Discover Controller with IP4 address 192.168.1.3 for all
+resources allocated for NVMe Host name host1-rogue-nqn on the RDMA network.
+Port 4420 is used by default:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme discover --transport=rdma --traddr=192.168.1.3 \
+--hostnqn=host1-rogue-nqn</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme discover</em> command using the default system defined NBFT tables:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme discover --nbft</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme discover</em> command with a user-defined path for the NBFT table:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme discover --nbft-path=/sys/firmware/acpi/tables/NBFT1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Issue a <em>nvme discover</em> command using a /usr/local/etc/nvme/discovery.conf file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># Machine default 'nvme discover' commands. Query the
+# Discovery Controller's two ports (some resources may only
+# be accessible on a single port). Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example.
+-t rdma -a 192.168.69.33 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+-t rdma -a 192.168.1.4 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+
+At the prompt type "nvme discover".</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_see_also">SEE ALSO</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-connect(1)
+nvme-connect-all(1)</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_authors">AUTHORS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This was written by <a href="mailto:james.p.freyensee@intel.com">Jay Freyensee</a></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt
new file mode 100644
index 0000000..1069d3c
--- /dev/null
+++ b/Documentation/nvme-discover.txt
@@ -0,0 +1,301 @@
+nvme-discover(1)
+================
+
+NAME
+----
+nvme-discover - Send Get Log Page request to Discovery Controller.
+
+SYNOPSIS
+--------
+[verse]
+'nvme discover' [--transport=<trtype> | -t <trtype>]
+ [--nqn=<subnqn> | -n <subnqn>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--host-iface=<iface> | -f <iface>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--raw=<filename> | -r <filename>]
+ [--device=<device> | -d <device>]
+ [--config=<filename> | -J <filename>]
+ [--keep-alive-tmo=<sec> | -k <sec>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>]
+ [--nr-io-queues=<#> | -i <#>]
+ [--nr-write-queues=<#> | -W <#>]
+ [--nr-poll-queues=<#> | -P <#>]
+ [--queue-size=<#> | -Q <#>] [--keyring=<#>]
+ [--tls_key=<#>] [--hdr-digest | -g] [--data-digest | -G]
+ [--persistent | -p] [--quiet | -S] [--tls] [--concat]
+ [--dump-config | -O] [--output-format=<fmt> | -o <fmt>]
+ [--force] [--nbft] [--no-nbft] [--nbft-path=<STR>]
+ [--context=<STR>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send one or more Get Log Page requests to a NVMe-over-Fabrics Discovery
+Controller.
+
+If no parameters are given, then 'nvme discover' will attempt to
+find a @SYSCONFDIR@/nvme/discovery.conf file to use to supply a list of
+Discovery commands to run. If no @SYSCONFDIR@/nvme/discovery.conf file
+exists, the command will quit with an error.
+
+Otherwise, a specific Discovery Controller should be specified using the
+--transport, --traddr, and if necessary the --trsvcid flags. A Discovery
+request will then be sent to the specified Discovery Controller.
+
+BACKGROUND
+----------
+The NVMe-over-Fabrics specification defines the concept of a
+Discovery Controller that an NVMe Host can query on a fabric
+network to discover NVMe subsystems contained in NVMe Targets
+which it can connect to on the network. The Discovery Controller
+will return Discovery Log Pages that provide the NVMe Host
+with specific information (such as network address and unique
+subsystem NQN) the NVMe Host can use to issue an
+NVMe connect command to connect itself to a storage resource
+contained in that NVMe subsystem on the NVMe Target.
+
+Note that the base NVMe specification defines the NQN (NVMe Qualified
+Name) format which an NVMe endpoint (device, subsystem, etc) must
+follow to guarantee a unique name under the NVMe standard.
+In particular, the Host NQN uniquely identifies the NVMe Host, and
+may be used by the Discovery Controller to control what NVMe Target
+resources are allocated to the NVMe Host for a connection.
+
+A Discovery Controller has it's own NQN defined in the NVMe-over-Fabrics
+specification, *nqn.2014-08.org.nvmexpress.discovery*. All Discovery
+Controllers must use this NQN name. This NQN is used by default by
+nvme-cli for the 'discover' command.
+
+OPTIONS
+-------
+-t <trtype>::
+--transport=<trtype>::
+ This field specifies the network fabric being used for
+ a NVMe-over-Fabrics network. Current string values include:
++
+[]
+|=================
+|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
+|=================
+
+-n <subnqn>::
+--nqn <subnqn>::
+ This field specifies the name for the NVMe subsystem to connect to.
+
+-a <traddr>::
+--traddr=<traddr>::
+ This field specifies the network address of the Discovery Controller.
+ For transports using IP addressing (e.g. rdma) this should be an
+ IP-based address (ex. IPv4).
+
+-s <trsvcid>::
+--trsvcid=<trsvcid>::
+ This field specifies the transport service id. For transports using IP
+ addressing (e.g. rdma) this field is the port number. By default, the IP
+ port number for the RDMA transport is 4420.
+
+-w <traddr>::
+--host-traddr=<traddr>::
+ This field specifies the network address used on the host to connect
+ to the Controller. For TCP, this sets the source address on the socket.
+
+-f <iface>::
+--host-iface=<iface>::
+ This field specifies the network interface used on the host to connect
+ to the Controller (e.g. IP eth1, enp2s0, enx78e7d1ea46da). This forces
+ the connection to be made on a specific interface instead of letting
+ the system decide.
+
+-q <hostnqn>::
+--hostnqn=<hostnqn>::
+ Overrides the default host NQN that identifies the NVMe Host.
+ If this option is not specified, the default is read from
+ @SYSCONFDIR@/nvme/hostnqn first. If that does not exist, the
+ autogenerated NQN value from the NVMe Host kernel module is used next.
+
+-I <hostid>::
+--hostid=<hostid>::
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+
+-r <filename>::
+--raw=<filename>::
+ This field will take the output of the 'nvme discover' command
+ 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. It must be a persistent device
+ associated with a Discovery Controller previously created by the
+ command "connect-all" or "discover". <device> follows the format
+ nvme*, eg. nvme0, nvme1.
+
+-J <filename>::
+--config=<filename>::
+ Use the specified JSON configuration file instead of the
+ default @SYSCONFDIR@/nvme/config.json file or 'none' to not read in
+ an existing configuration file. The JSON configuration file
+ format is documented in
+ https://github.com/linux-nvme/libnvme/blob/master/doc/config-schema.json
+
+-k <#>::
+--keep-alive-tmo=<#>::
+ Overrides the default keep alive timeout (in seconds). This
+ option will be ignored for discovery, and it is only
+ implemented for completeness.
+
+-c <#>::
+--reconnect-delay=<#>::
+ Overrides the default delay (in seconds) before reconnect is attempted
+ after a connect loss.
+
+-l <#>::
+--ctrl-loss-tmo=<#>::
+ Overrides the default controller loss timeout period (in seconds).
+
+-i <#>::
+--nr-io-queues=<#>::
+ Overrides the default number of I/O queues create by the driver.
+ This option will be ignored for the discovery, and it is only
+ implemented for completeness.
+
+-W <#>::
+--nr-write-queues=<#>::
+ Adds additional queues that will be used for write I/O.
+
+-P <#>::
+--nr-poll-queues=<#>::
+ Adds additional queues that will be used for polling latency sensitive I/O.
+
+-Q <#>::
+--queue-size=<#>::
+ Overrides the default number of elements in the I/O queues created
+ by the driver which can be found at drivers/nvme/host/fabrics.h.
+ This option will be ignored for the discovery, and it is only
+ implemented for completeness.
+
+--keyring=<#>::
+ Keyring for TLS key lookup.
+
+--tls_key=<#>::
+ TLS key for the connection (TCP).
+
+-g::
+--hdr-digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data-digest::
+ Generates/verifies data digest (TCP).
+
+-p::
+--persistent::
+ Don't remove the discovery controller after retrieving the discovery
+ log page.
+
+--tls::
+ Enable TLS encryption (TCP).
+
+--concat::
+ Enable secure concatenation (TCP).
+
+-S::
+--quiet::
+ Suppress already connected errors.
+
+-O::
+--dump-config::
+ Print out resulting JSON configuration file to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+--force::
+ Disable the built-in persistent discover connection rules.
+ Combined with --persistent flag, always create new
+ persistent discovery connection.
+
+--nbft::
+ Only look at NBFT tables
+
+--no-nbft::
+ Do not look at NBFT tables
+
+--nbft-path=<STR>::
+ Use a user-defined path to the NBFT tables
+
+--context <STR>::
+ Set the execution context to <STR>. This allows to coordinate
+ the management of the global resources.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Query the Discover Controller with IP4 address 192.168.1.3 for all
+resources allocated for NVMe Host name host1-rogue-nqn on the RDMA network.
+Port 4420 is used by default:
++
+------------
+# nvme discover --transport=rdma --traddr=192.168.1.3 \
+--hostnqn=host1-rogue-nqn
+------------
++
+* Issue a 'nvme discover' command using the default system defined NBFT tables:
++
+-----------
+# nvme discover --nbft
+------------
++
+* Issue a 'nvme discover' command with a user-defined path for the NBFT table:
++
+-----------
+# nvme discover --nbft-path=/sys/firmware/acpi/tables/NBFT1
+------------
++
+* Issue a 'nvme discover' command using a @SYSCONFDIR@/nvme/discovery.conf file:
++
+-----------
+# Machine default 'nvme discover' commands. Query the
+# Discovery Controller's two ports (some resources may only
+# be accessible on a single port). Note an official
+# nqn (Host) name defined in the NVMe specification is being used
+# in this example.
+-t rdma -a 192.168.69.33 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+-t rdma -a 192.168.1.4 -s 4420 -q nqn.2014-08.com.example:nvme:nvm-subsystem-sn-d78432
+
+At the prompt type "nvme discover".
+
+------------
+
+SEE ALSO
+--------
+nvme-connect(1)
+nvme-connect-all(1)
+
+AUTHORS
+-------
+This was written by mailto:james.p.freyensee@intel.com[Jay Freyensee]
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-dsm.1 b/Documentation/nvme-dsm.1
new file mode 100644
index 0000000..ba3b709
--- /dev/null
+++ b/Documentation/nvme-dsm.1
@@ -0,0 +1,113 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DSM" "1" "02/14/2024" "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-dsm \- Send NVMe Data Set Management, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme dsm\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-ctx\-attrs=<attribute\-list,> | \-a <attribute\-list,>]
+ [\-\-blocks=<nlb\-list,> | \-b <nlb\-list,>]
+ [\-\-slbs=<slba\-list,> | \-s <slba\-list,>]
+ [\-\-ad=<deallocate> | \-d <deallocate>]
+ [\-\-idw=<write> | \-w <write>] [\-\-idr=<read> | \-r <read>]
+ [\-\-cdw11=<cdw11> | \-c <cdw11>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a Data Set Management 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)\&. If the character device is given, the \*(Aq\-\-namespace\-id\*(Aq option is mandatory, otherwise it will use the ns\-id of the namespace for the block device you opened\&. For block devices, the ns\-id used can be overridden with the same option\&.
+.sp
+You must specify at least one of the values for range list\&. If the range lists provided do not list the same number of elements, the default values for the remaining in the range will be set to 0\&.
+.sp
+The command dword 11 may be provided at the command line\&. For convenience, the current defined attributes (discard, integral read/write) for a data\-set management have flags\&. If cdw11 is specified, this will override any settings from the flags may have provided\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sends the command with the requested nsid\&. This is required for the character devices, or overrides the block nsid if given\&.
+.RE
+.PP
+\-a <attribute\-list,>, \-\-ctx\-attrs=<attribute\-list>
+.RS 4
+Comma separated list of the context attributes in each range
+.RE
+.PP
+\-b <nlb\-list,>, \-\-blocks=<nlb\-list,>
+.RS 4
+Comma separated list of the number of blocks in each range
+.RE
+.PP
+\-s <slba\-list,>, \-\-slbs=<slba\-list,>
+.RS 4
+Comma separated list of the starting block in each range
+.RE
+.PP
+\-d <deallocate>, \-\-ad=<deallocate>
+.RS 4
+Attribute Deallocate\&.
+.RE
+.PP
+\-w <write>, \-\-idw=<write>
+.RS 4
+Attribute Integral Dataset for Write\&.
+.RE
+.PP
+\-r <read>, \-\-idr=<read>
+.RS 4
+Attribute Integral Dataset for Read\&.
+.RE
+.PP
+\-c <cdw11>, \-\-cdw11=<cdw11>
+.RS 4
+All the command command dword 11 attributes\&. Use exclusive from specifying individual attributes
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-dsm.html b/Documentation/nvme-dsm.html
new file mode 100644
index 0000000..f5b4de2
--- /dev/null
+++ b/Documentation/nvme-dsm.html
@@ -0,0 +1,925 @@
+<?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 10.2.0" />
+<title>nvme-dsm(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-dsm(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-dsm -
+ Send NVMe Data Set Management, return 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 dsm</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--ctx-attrs=&lt;attribute-list,&gt; | -a &lt;attribute-list,&gt;]
+ [--blocks=&lt;nlb-list,&gt; | -b &lt;nlb-list,&gt;]
+ [--slbs=&lt;slba-list,&gt; | -s &lt;slba-list,&gt;]
+ [--ad=&lt;deallocate&gt; | -d &lt;deallocate&gt;]
+ [--idw=&lt;write&gt; | -w &lt;write&gt;] [--idr=&lt;read&gt; | -r &lt;read&gt;]
+ [--cdw11=&lt;cdw11&gt; | -c &lt;cdw11&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 a Data Set Management 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).
+If the character device is given, the <code>'--namespace-id'</code> option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.</p></div>
+<div class="paragraph"><p>You must specify at least one of the values for range list. If the range
+lists provided do not list the same number of elements, the default
+values for the remaining in the range will be set to 0.</p></div>
+<div class="paragraph"><p>The command dword 11 may be provided at the command line. For convenience,
+the current defined attributes (discard, integral read/write) for a
+data-set management have flags. If cdw11 is specified, this will override
+any settings from the flags may have provided.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sends the command with the requested nsid. This is required for the
+ character devices, or overrides the block nsid if given.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;attribute-list,&gt;
+</dt>
+<dt class="hdlist1">
+--ctx-attrs=&lt;attribute-list&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the context attributes in each range
+</p>
+</dd>
+<dt class="hdlist1">
+-b &lt;nlb-list,&gt;
+</dt>
+<dt class="hdlist1">
+--blocks=&lt;nlb-list,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the number of blocks in each range
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;slba-list,&gt;
+</dt>
+<dt class="hdlist1">
+--slbs=&lt;slba-list,&gt;
+</dt>
+<dd>
+<p>
+ Comma separated list of the starting block in each range
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;deallocate&gt;
+</dt>
+<dt class="hdlist1">
+--ad=&lt;deallocate&gt;
+</dt>
+<dd>
+<p>
+ Attribute Deallocate.
+</p>
+</dd>
+<dt class="hdlist1">
+-w &lt;write&gt;
+</dt>
+<dt class="hdlist1">
+--idw=&lt;write&gt;
+</dt>
+<dd>
+<p>
+ Attribute Integral Dataset for Write.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;read&gt;
+</dt>
+<dt class="hdlist1">
+--idr=&lt;read&gt;
+</dt>
+<dd>
+<p>
+ Attribute Integral Dataset for Read.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;cdw11&gt;
+</dt>
+<dt class="hdlist1">
+--cdw11=&lt;cdw11&gt;
+</dt>
+<dd>
+<p>
+ All the command command dword 11 attributes. Use exclusive from
+ specifying individual attributes
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dsm.txt b/Documentation/nvme-dsm.txt
new file mode 100644
index 0000000..6a2e61a
--- /dev/null
+++ b/Documentation/nvme-dsm.txt
@@ -0,0 +1,92 @@
+nvme-dsm(1)
+===========
+
+NAME
+----
+nvme-dsm - Send NVMe Data Set Management, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme dsm' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--ctx-attrs=<attribute-list,> | -a <attribute-list,>]
+ [--blocks=<nlb-list,> | -b <nlb-list,>]
+ [--slbs=<slba-list,> | -s <slba-list,>]
+ [--ad=<deallocate> | -d <deallocate>]
+ [--idw=<write> | -w <write>] [--idr=<read> | -r <read>]
+ [--cdw11=<cdw11> | -c <cdw11>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a Data Set Management 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).
+If the character device is given, the `'--namespace-id'` option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.
+
+You must specify at least one of the values for range list. If the range
+lists provided do not list the same number of elements, the default
+values for the remaining in the range will be set to 0.
+
+The command dword 11 may be provided at the command line. For convenience,
+the current defined attributes (discard, integral read/write) for a
+data-set management have flags. If cdw11 is specified, this will override
+any settings from the flags may have provided.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sends the command with the requested nsid. This is required for the
+ character devices, or overrides the block nsid if given.
+
+-a <attribute-list,>::
+--ctx-attrs=<attribute-list>::
+ Comma separated list of the context attributes in each range
+
+-b <nlb-list,>::
+--blocks=<nlb-list,>::
+ Comma separated list of the number of blocks in each range
+
+-s <slba-list,>::
+--slbs=<slba-list,>::
+ Comma separated list of the starting block in each range
+
+-d <deallocate>::
+--ad=<deallocate>::
+ Attribute Deallocate.
+
+-w <write>::
+--idw=<write>::
+ Attribute Integral Dataset for Write.
+
+-r <read>::
+--idr=<read>::
+ Attribute Integral Dataset for Read.
+
+-c <cdw11>::
+--cdw11=<cdw11>::
+ All the command command dword 11 attributes. Use exclusive from
+ specifying individual attributes
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-effects-log.1 b/Documentation/nvme-effects-log.1
new file mode 100644
index 0000000..112c264
--- /dev/null
+++ b/Documentation/nvme-effects-log.1
@@ -0,0 +1,116 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-EFFECTS\-LOG" "1" "02/14/2024" "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-effects-log \- Send NVMe Command Effects log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme effects\-log\fR <device> [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Command Effects log page from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and should be the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned command effects log structure will be printed for each command that is supported\&.
+.SH "OPTIONS"
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into a human\-readable format\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+This option will print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the human\-readable option\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the effects log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme effects\-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
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme effects\-log /dev/nvme0 \-\-raw\-binary > effects_log\&.raw
+# nvme effects\-log /dev/nvme0 \-b > effects_log\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-effects-log.html b/Documentation/nvme-effects-log.html
new file mode 100644
index 0000000..b7570a9
--- /dev/null
+++ b/Documentation/nvme-effects-log.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 10.2.0" />
+<title>nvme-effects-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 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-effects-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-effects-log -
+ Send NVMe Command Effects 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 effects-log</em> &lt;device&gt; [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Command Effects 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 should be the NVMe character
+device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success, the returned command effects log structure will be printed
+for each command that is supported.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields into a
+ human-readable format.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ This option will print the raw buffer to stdout. Structure is not
+ parsed by program. This overrides the human-readable option.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 effects log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme effects-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme effects-log /dev/nvme0 --raw-binary &gt; effects_log.raw
+# nvme effects-log /dev/nvme0 -b &gt; effects_log.raw</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-effects-log.txt b/Documentation/nvme-effects-log.txt
new file mode 100644
index 0000000..57a1369
--- /dev/null
+++ b/Documentation/nvme-effects-log.txt
@@ -0,0 +1,66 @@
+nvme-effects-log(1)
+===================
+
+NAME
+----
+nvme-effects-log - Send NVMe Command Effects log page request, returns result
+and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme effects-log' <device> [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Command Effects log page from an NVMe device and provides
+the returned structure.
+
+The <device> parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).
+
+On success, the returned command effects log structure will be printed
+for each command that is supported.
+
+OPTIONS
+-------
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields into a
+ human-readable format.
+
+-b::
+--raw-binary::
+ This option will print the raw buffer to stdout. Structure is not
+ parsed by program. This overrides the human-readable option.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the effects log page in a human readable format:
++
+------------
+# nvme effects-log /dev/nvme0
+------------
++
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme effects-log /dev/nvme0 --raw-binary > effects_log.raw
+# nvme effects-log /dev/nvme0 -b > effects_log.raw
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-endurance-event-agg-log.1 b/Documentation/nvme-endurance-event-agg-log.1
new file mode 100644
index 0000000..08c22e9
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" Title: nvme-endurance-event-agg-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ENDURANCE\-EVE" "1" "02/14/2024" "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>] [\-\-verbose | \-v]
+.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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..0bfc9e1
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.html
@@ -0,0 +1,869 @@
+<?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 10.2.0" />
+<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 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-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;] [--verbose | -v]</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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</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..7cbceb1
--- /dev/null
+++ b/Documentation/nvme-endurance-event-agg-log.txt
@@ -0,0 +1,70 @@
+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>] [--verbose | -v]
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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
new file mode 100644
index 0000000..91cbdc1
--- /dev/null
+++ b/Documentation/nvme-endurance-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ENDURANCE\-LOG" "1" "02/14/2024" "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-log \- Send NVMe Endurance log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme endurance\-log\fR <device> [\-\-group\-id=<group> | \-g <group>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Endurance 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 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
+\-g <group>, \-\-group\-id=<group>
+.RS 4
+The endurance group identifier\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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\-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\-log /dev/nvme0 \-\-output=binary > endurance_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-log.html b/Documentation/nvme-endurance-log.html
new file mode 100644
index 0000000..49ee586
--- /dev/null
+++ b/Documentation/nvme-endurance-log.html
@@ -0,0 +1,852 @@
+<?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 10.2.0" />
+<title>nvme-endurance-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 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-endurance-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-endurance-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-log</em> &lt;device&gt; [--group-id=&lt;group&gt; | -g &lt;group&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 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 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">
+-g &lt;group&gt;
+</dt>
+<dt class="hdlist1">
+--group-id=&lt;group&gt;
+</dt>
+<dd>
+<p>
+ The endurance group identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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-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-log /dev/nvme0 --output=binary &gt; endurance_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-endurance-log.txt b/Documentation/nvme-endurance-log.txt
new file mode 100644
index 0000000..c263834
--- /dev/null
+++ b/Documentation/nvme-endurance-log.txt
@@ -0,0 +1,60 @@
+nvme-endurance-log(1)
+=====================
+
+NAME
+----
+nvme-endurance-log - Send NVMe Endurance log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme endurance-log' <device> [--group-id=<group> | -g <group>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Endurance 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 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
+-------
+-g <group>::
+--group-id=<group>::
+ The endurance group identifier.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the Endurance log page in a human readable format:
++
+------------
+# nvme endurance-log /dev/nvme0
+------------
++
+
+* Print the raw Endurance log to a file:
++
+------------
+# nvme endurance-log /dev/nvme0 --output=binary > endurance_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-error-log.1 b/Documentation/nvme-error-log.1
new file mode 100644
index 0000000..b710a06
--- /dev/null
+++ b/Documentation/nvme-error-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ERROR\-LOG" "1" "02/14/2024" "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-error-log \- Send NVME Error log page request, return result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme error\-log\fR <device> [\-\-log\-entries=<entries> | \-e <entries>]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves NVMe Error 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 error 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
+\-e <entries>, \-\-log\-entries=<entries>
+.RS 4
+Specifies how many log entries the program should request from the device\&. This must be at least one, and shouldn\(cqt exceed the device\(cqs capabilities\&. Defaults to 64 log entries\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw error log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the error log and print it in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme error\-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 output to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme error\-log /dev/nvme0 \-\-raw\-binary > error_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-error-log.html b/Documentation/nvme-error-log.html
new file mode 100644
index 0000000..acf35fc
--- /dev/null
+++ b/Documentation/nvme-error-log.html
@@ -0,0 +1,867 @@
+<?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 10.2.0" />
+<title>nvme-error-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 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-error-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-error-log -
+ Send NVME Error 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 error-log</em> &lt;device&gt; [--log-entries=&lt;entries&gt; | -e &lt;entries&gt;]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Error 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 error 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">
+-e &lt;entries&gt;
+</dt>
+<dt class="hdlist1">
+--log-entries=&lt;entries&gt;
+</dt>
+<dd>
+<p>
+ Specifies how many log entries the program should request from
+ the device. This must be at least one, and shouldn&#8217;t exceed the
+ device&#8217;s capabilities. Defaults to 64 log entries.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw error log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 error log and print it in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme error-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw output to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme error-log /dev/nvme0 --raw-binary &gt; error_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-error-log.txt b/Documentation/nvme-error-log.txt
new file mode 100644
index 0000000..94442ee
--- /dev/null
+++ b/Documentation/nvme-error-log.txt
@@ -0,0 +1,68 @@
+nvme-error-log(1)
+=================
+
+NAME
+----
+nvme-error-log - Send NVME Error log page request, return result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme error-log' <device> [--log-entries=<entries> | -e <entries>]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves NVMe Error 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 error 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
+-------
+-e <entries>::
+--log-entries=<entries>::
+ Specifies how many log entries the program should request from
+ the device. This must be at least one, and shouldn't exceed the
+ device's capabilities. Defaults to 64 log entries.
+
+-b::
+--raw-binary::
+ Print the raw error log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Get the error log and print it in a human readable format:
++
+------------
+# nvme error-log /dev/nvme0
+------------
++
+
+* Print the raw output to a file:
++
+------------
+# nvme error-log /dev/nvme0 --raw-binary > error_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-fdp-configs.1 b/Documentation/nvme-fdp-configs.1
new file mode 100644
index 0000000..1fdb44b
--- /dev/null
+++ b/Documentation/nvme-fdp-configs.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-fdp-configs
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-CONFIGS" "1" "02/14/2024" "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-fdp-configs \- Get Flexible Data Placement Configurations
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp configs\fR <device> [\-\-endgrp\-id=<NUM> | \-e <NUM>]
+ [\-\-human\-readable | \-H] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, and the endurance group identifier specified, list the possible configurations for Flexible Data Placement\&.
+.SH "OPTIONS"
+.PP
+\-e <NUM>, \-\-endgrp\-id=<NUM>
+.RS 4
+The endurance group identifier to use when requesting the log page\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+Parse, print and describe individual parts of bitfields\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-configs.html b/Documentation/nvme-fdp-configs.html
new file mode 100644
index 0000000..dfcc5aa
--- /dev/null
+++ b/Documentation/nvme-fdp-configs.html
@@ -0,0 +1,833 @@
+<?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 10.2.0" />
+<title>nvme-fdp-configs(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-fdp-configs(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-configs -
+ Get Flexible Data Placement Configurations
+</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 fdp configs</em> &lt;device&gt; [--endgrp-id=&lt;NUM&gt; | -e &lt;NUM&gt;]
+ [--human-readable | -H] [--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>For the NVMe device given, and the endurance group identifier specified, list
+the possible configurations for Flexible Data Placement.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--endgrp-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The endurance group identifier to use when requesting the log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ Parse, print and describe individual parts of bitfields.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-configs.txt b/Documentation/nvme-fdp-configs.txt
new file mode 100644
index 0000000..d5cc487
--- /dev/null
+++ b/Documentation/nvme-fdp-configs.txt
@@ -0,0 +1,41 @@
+nvme-fdp-configs(1)
+===================
+
+NAME
+----
+nvme-fdp-configs - Get Flexible Data Placement Configurations
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp configs' <device> [--endgrp-id=<NUM> | -e <NUM>]
+ [--human-readable | -H] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, and the endurance group identifier specified, list
+the possible configurations for Flexible Data Placement.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+ The endurance group identifier to use when requesting the log page.
+
+-H::
+--human-readable::
+ Parse, print and describe individual parts of bitfields.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-events.1 b/Documentation/nvme-fdp-events.1
new file mode 100644
index 0000000..03c6ef2
--- /dev/null
+++ b/Documentation/nvme-fdp-events.1
@@ -0,0 +1,67 @@
+'\" t
+.\" Title: nvme-fdp-events
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-EVENTS" "1" "02/14/2024" "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-fdp-events \- Get Flexible Data Placement Events
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp events\fR <device> [\-\-endgrp\-id=<NUM> | \-e <NUM>] [\-\-host\-events | \-E]
+ [\-\-raw\-binary | \-b] [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, provide information about events affecting Reclaim Units and media usage in an Endurance Group\&.
+.SH "OPTIONS"
+.PP
+\-e <NUM>, \-\-endgrp\-id=<NUM>
+.RS 4
+The endurance group identifier to use when requesting the log page\&.
+.RE
+.PP
+\-E, \-\-host\-events
+.RS 4
+Request the controller to report host events\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-events.html b/Documentation/nvme-fdp-events.html
new file mode 100644
index 0000000..79fffaf
--- /dev/null
+++ b/Documentation/nvme-fdp-events.html
@@ -0,0 +1,832 @@
+<?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 10.2.0" />
+<title>nvme-fdp-events(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-fdp-events(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-events -
+ Get Flexible Data Placement Events
+</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 fdp events</em> &lt;device&gt; [--endgrp-id=&lt;NUM&gt; | -e &lt;NUM&gt;] [--host-events | -E]
+ [--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>For the NVMe device given, provide information about events affecting Reclaim
+Units and media usage in an Endurance Group.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--endgrp-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The endurance group identifier to use when requesting the log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-E
+</dt>
+<dt class="hdlist1">
+--host-events
+</dt>
+<dd>
+<p>
+ Request the controller to report host events.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-events.txt b/Documentation/nvme-fdp-events.txt
new file mode 100644
index 0000000..5602f44
--- /dev/null
+++ b/Documentation/nvme-fdp-events.txt
@@ -0,0 +1,40 @@
+nvme-fdp-events(1)
+==================
+
+NAME
+----
+nvme-fdp-events - Get Flexible Data Placement Events
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp events' <device> [--endgrp-id=<NUM> | -e <NUM>] [--host-events | -E]
+ [--raw-binary | -b] [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about events affecting Reclaim
+Units and media usage in an Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+ The endurance group identifier to use when requesting the log page.
+
+-E::
+--host-events::
+ Request the controller to report host events.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-set-events.1 b/Documentation/nvme-fdp-set-events.1
new file mode 100644
index 0000000..66aaa7e
--- /dev/null
+++ b/Documentation/nvme-fdp-set-events.1
@@ -0,0 +1,63 @@
+'\" t
+.\" Title: nvme-fdp-set-events
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-SET\-EVEN" "1" "02/14/2024" "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-fdp-set-events \- Enable or disable FDP events
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp set\-events\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-placement\-handle=<NUM> | \-p <NUM>] [\-\-enable | \-e]
+ [\-\-event\-types=<NUM,> | \-t <NUM,>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, enable or disable a list of event types from being generated for the Reclaim Unit Handle reference by the specified Placement Handle\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Namespace identifier\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-set-events.html b/Documentation/nvme-fdp-set-events.html
new file mode 100644
index 0000000..4615772
--- /dev/null
+++ b/Documentation/nvme-fdp-set-events.html
@@ -0,0 +1,823 @@
+<?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 10.2.0" />
+<title>nvme-fdp-set-events(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-fdp-set-events(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-set-events -
+ Enable or disable FDP events
+</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 fdp set-events</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--placement-handle=&lt;NUM&gt; | -p &lt;NUM&gt;] [--enable | -e]
+ [--event-types=&lt;NUM,&gt; | -t &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>For the NVMe device given, enable or disable a list of event types from being
+generated for the Reclaim Unit Handle reference by the specified Placement
+Handle.</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>
+ Namespace identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-set-events.txt b/Documentation/nvme-fdp-set-events.txt
new file mode 100644
index 0000000..b93cdc3
--- /dev/null
+++ b/Documentation/nvme-fdp-set-events.txt
@@ -0,0 +1,38 @@
+nvme-fdp-set-events(1)
+======================
+
+NAME
+----
+nvme-fdp-set-events - Enable or disable FDP events
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp set-events' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--placement-handle=<NUM> | -p <NUM>] [--enable | -e]
+ [--event-types=<NUM,> | -t <NUM,>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, enable or disable a list of event types from being
+generated for the Reclaim Unit Handle reference by the specified Placement
+Handle.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Namespace identifier.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-stats.1 b/Documentation/nvme-fdp-stats.1
new file mode 100644
index 0000000..fb11832
--- /dev/null
+++ b/Documentation/nvme-fdp-stats.1
@@ -0,0 +1,62 @@
+'\" t
+.\" Title: nvme-fdp-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-STATS" "1" "02/14/2024" "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-fdp-stats \- Get Flexible Data Placement Statistics
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp stats\fR <device> [\-\-endgrp\-id=<NUM> | \-e <NUM>] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, provide information about the FDP configuration over the life of the FDP configuration in an Endurance Group\&.
+.SH "OPTIONS"
+.PP
+\-e <NUM>, \-\-endgrp\-id=<NUM>
+.RS 4
+The endurance group identifier to use when requesting the log page\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-stats.html b/Documentation/nvme-fdp-stats.html
new file mode 100644
index 0000000..009bb38
--- /dev/null
+++ b/Documentation/nvme-fdp-stats.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<title>nvme-fdp-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-fdp-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-stats -
+ Get Flexible Data Placement 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 fdp stats</em> &lt;device&gt; [--endgrp-id=&lt;NUM&gt; | -e &lt;NUM&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>For the NVMe device given, provide information about the FDP configuration over
+the life of the FDP configuration in an Endurance Group.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--endgrp-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The endurance group identifier to use when requesting the log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-stats.txt b/Documentation/nvme-fdp-stats.txt
new file mode 100644
index 0000000..0b184a9
--- /dev/null
+++ b/Documentation/nvme-fdp-stats.txt
@@ -0,0 +1,36 @@
+nvme-fdp-stats(1)
+=================
+
+NAME
+----
+nvme-fdp-stats - Get Flexible Data Placement Statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp stats' <device> [--endgrp-id=<NUM> | -e <NUM>] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about the FDP configuration over
+the life of the FDP configuration in an Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+ The endurance group identifier to use when requesting the log page.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-status.1 b/Documentation/nvme-fdp-status.1
new file mode 100644
index 0000000..362f4b1
--- /dev/null
+++ b/Documentation/nvme-fdp-status.1
@@ -0,0 +1,62 @@
+'\" t
+.\" Title: nvme-fdp-status
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-STATUS" "1" "02/14/2024" "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-fdp-status \- Get Reclaim Unit Handle Status
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp status\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, provide information about Reclaim Unit Handles that are accessible by the specified namespace\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Namespace identifier\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-status.html b/Documentation/nvme-fdp-status.html
new file mode 100644
index 0000000..a073a94
--- /dev/null
+++ b/Documentation/nvme-fdp-status.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<title>nvme-fdp-status(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-fdp-status(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-status -
+ Get Reclaim Unit Handle Status
+</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 fdp status</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&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>For the NVMe device given, provide information about Reclaim Unit Handles that
+are accessible by the specified namespace.</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>
+ Namespace identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-status.txt b/Documentation/nvme-fdp-status.txt
new file mode 100644
index 0000000..78dddae
--- /dev/null
+++ b/Documentation/nvme-fdp-status.txt
@@ -0,0 +1,36 @@
+nvme-fdp-status(1)
+==================
+
+NAME
+----
+nvme-fdp-status - Get Reclaim Unit Handle Status
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp status' <device> [--namespace-id=<NUM> | -n <NUM>] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about Reclaim Unit Handles that
+are accessible by the specified namespace.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Namespace identifier.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-update.1 b/Documentation/nvme-fdp-update.1
new file mode 100644
index 0000000..ca7e39a
--- /dev/null
+++ b/Documentation/nvme-fdp-update.1
@@ -0,0 +1,54 @@
+'\" t
+.\" Title: nvme-fdp-update
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-UPDATE" "1" "02/14/2024" "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-fdp-update \- Reclaim Unit Handle Update
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp update\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-pids=<NUM,> | \-p <NUM,>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, update the given Placement Identifiers to reference a different Reclaim Unit accessible by the specified namespace\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Namespace identifier\&.
+.RE
+.PP
+\-p <NUM,>, \-\-pids=<NUM,>
+.RS 4
+Comma\-separated list of placement identifiers to update\&.
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-update.html b/Documentation/nvme-fdp-update.html
new file mode 100644
index 0000000..2ad566f
--- /dev/null
+++ b/Documentation/nvme-fdp-update.html
@@ -0,0 +1,809 @@
+<?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 10.2.0" />
+<title>nvme-fdp-update(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-fdp-update(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-update -
+ Reclaim Unit Handle Update
+</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 fdp update</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--pids=&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>For the NVMe device given, update the given Placement Identifiers to reference
+a different Reclaim Unit accessible by the specified namespace.</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>
+ Namespace identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;NUM,&gt;
+</dt>
+<dt class="hdlist1">
+--pids=&lt;NUM,&gt;
+</dt>
+<dd>
+<p>
+ Comma-separated list of placement identifiers to update.
+</p>
+</dd>
+</dl></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-update.txt b/Documentation/nvme-fdp-update.txt
new file mode 100644
index 0000000..5af83e5
--- /dev/null
+++ b/Documentation/nvme-fdp-update.txt
@@ -0,0 +1,31 @@
+nvme-fdp-update(1)
+==================
+
+NAME
+----
+nvme-fdp-update - Reclaim Unit Handle Update
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp update' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--pids=<NUM,> | -p <NUM,>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, update the given Placement Identifiers to reference
+a different Reclaim Unit accessible by the specified namespace.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Namespace identifier.
+
+-p <NUM,>::
+--pids=<NUM,>::
+ Comma-separated list of placement identifiers to update.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fdp-usage.1 b/Documentation/nvme-fdp-usage.1
new file mode 100644
index 0000000..912d0fd
--- /dev/null
+++ b/Documentation/nvme-fdp-usage.1
@@ -0,0 +1,62 @@
+'\" t
+.\" Title: nvme-fdp-usage
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FDP\-USAGE" "1" "02/14/2024" "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-fdp-usage \- Get Reclaim Unit Handle Usage
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fdp usage\fR <device> [\-\-endgrp\-id=<NUM> | \-e <NUM>] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, provide information about the Reclaim Unit Handles associated with the Placement Handles of the namespaces in the specified Endurance Group\&.
+.SH "OPTIONS"
+.PP
+\-e <NUM>, \-\-endgrp\-id=<NUM>
+.RS 4
+The endurance group identifier to use when requesting the log page\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to the standard output stream\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-fdp-usage.html b/Documentation/nvme-fdp-usage.html
new file mode 100644
index 0000000..aaa349b
--- /dev/null
+++ b/Documentation/nvme-fdp-usage.html
@@ -0,0 +1,822 @@
+<?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 10.2.0" />
+<title>nvme-fdp-usage(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-fdp-usage(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fdp-usage -
+ Get Reclaim Unit Handle Usage
+</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 fdp usage</em> &lt;device&gt; [--endgrp-id=&lt;NUM&gt; | -e &lt;NUM&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>For the NVMe device given, provide information about the Reclaim Unit Handles
+associated with the Placement Handles of the namespaces in the specified
+Endurance Group.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-e &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--endgrp-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ The endurance group identifier to use when requesting the log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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="_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fdp-usage.txt b/Documentation/nvme-fdp-usage.txt
new file mode 100644
index 0000000..3e0fb98
--- /dev/null
+++ b/Documentation/nvme-fdp-usage.txt
@@ -0,0 +1,37 @@
+nvme-fdp-usage(1)
+=================
+
+NAME
+----
+nvme-fdp-usage - Get Reclaim Unit Handle Usage
+
+SYNOPSIS
+--------
+[verse]
+'nvme fdp usage' <device> [--endgrp-id=<NUM> | -e <NUM>] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, provide information about the Reclaim Unit Handles
+associated with the Placement Handles of the namespaces in the specified
+Endurance Group.
+
+OPTIONS
+-------
+-e <NUM>::
+--endgrp-id=<NUM>::
+ The endurance group identifier to use when requesting the log page.
+
+-b::
+--raw-binary::
+ Print the raw buffer to the standard output stream.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one
+ output format can be used at a time.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-fid-support-effects-log.1 b/Documentation/nvme-fid-support-effects-log.1
new file mode 100644
index 0000000..82417b4
--- /dev/null
+++ b/Documentation/nvme-fid-support-effects-log.1
@@ -0,0 +1,69 @@
+'\" t
+.\" Title: nvme-fid-support-effects-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FID\-SUPPORT\-" "1" "02/14/2024" "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-fid-support-effects-log \- Send NVMe FID Support and Effects log, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fid\-support\-effects\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an FID Support and Effects log and provides the result and returned log 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-fid-support-effects-log.html b/Documentation/nvme-fid-support-effects-log.html
new file mode 100644
index 0000000..d23d711
--- /dev/null
+++ b/Documentation/nvme-fid-support-effects-log.html
@@ -0,0 +1,832 @@
+<?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 10.2.0" />
+<title>nvme-fid-support-effects-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 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-fid-support-effects-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fid-support-effects-log -
+ Send NVMe FID Support and Effects log, 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 fid-support-effects-log</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an FID Support and Effects log and
+provides the result and returned log 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fid-support-effects-log.txt b/Documentation/nvme-fid-support-effects-log.txt
new file mode 100644
index 0000000..9670b88
--- /dev/null
+++ b/Documentation/nvme-fid-support-effects-log.txt
@@ -0,0 +1,47 @@
+nvme-fid-support-effects-log(1)
+===============================
+
+NAME
+----
+nvme-fid-support-effects-log - Send NVMe FID Support and Effects log, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme fid-support-effects-log' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an FID Support and Effects log and
+provides the result and returned log structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-flush.1 b/Documentation/nvme-flush.1
new file mode 100644
index 0000000..a5ca384
--- /dev/null
+++ b/Documentation/nvme-flush.1
@@ -0,0 +1,66 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FLUSH" "1" "02/14/2024" "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-flush \- Flush command\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme flush\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Flush command shall commit data and metadata associated with the specified namespace(s) to nonvolatile media\&. The flush applies to all commands completed prior to the submission of the Flush command\&. The controller may also flush additional data and/or metadata from any namespace\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Specify the optional namespace id for this command\&. Defaults to 0xffffffff, indicating flush for all namespaces\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-flush.html b/Documentation/nvme-flush.html
new file mode 100644
index 0000000..b008b96
--- /dev/null
+++ b/Documentation/nvme-flush.html
@@ -0,0 +1,831 @@
+<?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 10.2.0" />
+<title>nvme-flush(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-flush(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-flush -
+ Flush 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 flush</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Flush command shall commit data and metadata associated with the
+specified namespace(s) to nonvolatile media. The flush applies to
+all commands completed prior to the submission of the Flush command.
+The controller may also flush additional data and/or metadata from
+any namespace.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Specify the optional namespace id for this command. Defaults to
+ 0xffffffff, indicating flush for all namespaces.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-flush.txt b/Documentation/nvme-flush.txt
new file mode 100644
index 0000000..102cd71
--- /dev/null
+++ b/Documentation/nvme-flush.txt
@@ -0,0 +1,44 @@
+nvme-flush(1)
+=============
+
+NAME
+----
+nvme-flush - Flush command.
+
+SYNOPSIS
+--------
+[verse]
+'nvme flush' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Flush command shall commit data and metadata associated with the
+specified namespace(s) to nonvolatile media. The flush applies to
+all commands completed prior to the submission of the Flush command.
+The controller may also flush additional data and/or metadata from
+any namespace.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Specify the optional namespace id for this command. Defaults to
+ 0xffffffff, indicating flush for all namespaces.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-format.1 b/Documentation/nvme-format.1
new file mode 100644
index 0000000..6837f23
--- /dev/null
+++ b/Documentation/nvme-format.1
@@ -0,0 +1,237 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FORMAT" "1" "02/14/2024" "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-format \- Format an NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme format\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-lbaf=<lbaf> | \-l <lbaf>]
+ [\-\-block\-size=<block size | \-b <block size>]
+ [\-\-ses=<ses> | \-s <ses>] [\-\-pil=<pil> | \-p <pil>]
+ [\-\-pi=<pi> | \-i <pi>] [\-\-ms=<ms> | \-m <ms>]
+ [\-\-reset | \-r] [\-\-force]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an nvme Format Namespace admin command and provides the results\&.
+.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)\&. If the character device is given, and the controller does not support formatting of particular namespaces (ID_CTRL\&.FNA bit 0 enabled), then all namespaces will be formatted\&. If FNA is disabled, then the namespace identifier must be specified with the \fInamespace\-id\fR option; specify a value of 0xffffffff to send the format to all namespaces\&. If the block device is given, the namespace identifier will default to the namespace ID of the block device given, but can be overridden with the same option\&.
+.sp
+Note, the numeric suffix on the character device, for example the \fI0\fR in /dev/nvme0, does NOT indicate this device handle is the parent controller of any namespaces with the same suffix\&. The namespace handle\(cqs numeral may be coming from the subsystem identifier, which is independent of the controller\(cqs identifier\&. Do not assume any particular device relationship based on their names\&. If you do, you may irrevocably erase data on an unintended device\&.
+.sp
+On success, the program will automatically issue BLKRRPART ioctl to force rescanning the namespaces\&. If the driver is recent enough, this will automatically update the physical block size\&. If it is not recent enough, you will need to remove and rescan your device some other way for the new block size to be visible, if the size was changed with this command\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Send the format command for the specified nsid\&. This can be used to override the default value for either character device (unspecified) or the block device (result from NVME_IOCTL_ID)\&.
+.RE
+.PP
+\-l <lbaf>, \-\-lbaf=<lbaf>
+.RS 4
+LBA Format: This field specifies the LBA format to apply to the NVM media\&. This corresponds to the LBA formats indicated in the Identify Namespace command\&. Conflicts with \-\-block\-size argument\&. Defaults to 0\&.
+.RE
+.PP
+\-b <block size>, \-\-block\-size=<block size>
+.RS 4
+Block Size: This field is used to specify the target block size to format to\&. Potential lbaf values will be scanned and the lowest numbered will be selected for the format operation\&. Conflicts with \-\-lbaf argument\&.
+.RE
+.PP
+\-s <ses>, \-\-ses=<ses>
+.RS 4
+Secure Erase Settings: This field specifies whether a secure erase should be performed as part of the format and the type of the secure erase operation\&. The erase applies to all user data, regardless of location (e\&.g\&., within an exposed LBA, within a cache, within deallocated LBAs, etc)\&. Defaults to 0\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+No secure erase operation requested
+T}
+T{
+1
+T}:T{
+User Data Erase: All user data shall be erased, contents of the user data after the erase is indeterminate (e\&.g\&., the user data may be zero filled, one filled, etc)\&. The controller may perform a cryptographic erase when a User Data Erase is requested if all user data is encrypted\&.
+T}
+T{
+2
+T}:T{
+Cryptographic Erase: All user data shall be erased cryptographically\&. This is accomplished by deleting the encryption key\&.
+T}
+T{
+3\(en7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-p <pil>, \-\-pil=<pil>
+.RS 4
+Protection Information Location: If set to \(oq1\(cq and protection information is enabled, then protection information is transferred as the first eight bytes of metadata\&. If cleared to \(oq0\(cq and protection information is enabled, then protection information is transferred as the last eight bytes of metadata\&. Defaults to 0\&.
+.RE
+.PP
+\-i <pi>, \-\-pi=<pi>
+.RS 4
+Protection Information: This field specifies whether end\-to\-end data protection is enabled and the type of protection information\&. Defaults to 0\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+Protection information is not enabled
+T}
+T{
+1
+T}:T{
+Protection information is enabled, Type 1
+T}
+T{
+2
+T}:T{
+Protection information is enabled, Type 2
+T}
+T{
+3
+T}:T{
+Protection information is enabled, Type 3
+T}
+T{
+4\(en7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-m <ms>, \-\-ms=<ms>
+.RS 4
+Metadata Settings: This field is set to \(oq1\(cq if the metadata is transferred as part of an extended data LBA\&. This field is cleared to \(oq0\(cq if the metadata is transferred as part of a separate buffer\&. The metadata may include protection information, based on the Protection Information (PI) field\&. Defaults to 0\&.
+.RE
+.PP
+\-r, \-\-reset
+.RS 4
+Issue a reset after successful format\&. Must use the character device for this\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Just send the command immediately without warning of the implications\&.
+.RE
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Format the device using all defaults:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme format /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Format namespace 1 with user data secure erase settings and protection information:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme format /dev/nvme0 \-\-namespace\-id=1 \-\-ses=1 \-\-pi=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-format.html b/Documentation/nvme-format.html
new file mode 100644
index 0000000..f462649
--- /dev/null
+++ b/Documentation/nvme-format.html
@@ -0,0 +1,1063 @@
+<?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 10.2.0" />
+<title>nvme-format(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-format(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-format -
+ Format 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 format</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--lbaf=&lt;lbaf&gt; | -l &lt;lbaf&gt;]
+ [--block-size=&lt;block size | -b &lt;block size&gt;]
+ [--ses=&lt;ses&gt; | -s &lt;ses&gt;] [--pil=&lt;pil&gt; | -p &lt;pil&gt;]
+ [--pi=&lt;pi&gt; | -i &lt;pi&gt;] [--ms=&lt;ms&gt; | -m &lt;ms&gt;]
+ [--reset | -r] [--force]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Format Namespace admin command
+and provides the results.</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).
+If the character device is given, and the controller does not support
+formatting of particular namespaces (ID_CTRL.FNA bit 0 enabled), then all
+namespaces will be formatted. If FNA is disabled, then the namespace
+identifier must be specified with the <em>namespace-id</em> option; specify a
+value of 0xffffffff to send the format to all namespaces. If the block
+device is given, the namespace identifier will default to the namespace
+ID of the block device given, but can be overridden with the same option.</p></div>
+<div class="paragraph"><p>Note, the numeric suffix on the character device, for example the <em>0</em> in
+/dev/nvme0, does NOT indicate this device handle is the parent controller
+of any namespaces with the same suffix. The namespace handle&#8217;s numeral
+may be coming from the subsystem identifier, which is independent of the
+controller&#8217;s identifier. Do not assume any particular device relationship
+based on their names. If you do, you may irrevocably erase data on an
+unintended device.</p></div>
+<div class="paragraph"><p>On success, the program will automatically issue BLKRRPART ioctl to
+force rescanning the namespaces. If the driver is recent enough, this will
+automatically update the physical block size. If it is not recent enough,
+you will need to remove and rescan your device some other way for the
+new block size to be visible, if the size was changed with this command.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Send the format command for the specified nsid. This can be
+ used to override the default value for either character device
+ (unspecified) or the block device (result from NVME_IOCTL_ID).
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;lbaf&gt;
+</dt>
+<dt class="hdlist1">
+--lbaf=&lt;lbaf&gt;
+</dt>
+<dd>
+<p>
+ LBA Format: This field specifies the LBA format to apply to the NVM
+ media. This corresponds to the LBA formats indicated in the
+ Identify Namespace command. Conflicts with --block-size argument.
+ Defaults to 0.
+</p>
+</dd>
+<dt class="hdlist1">
+-b &lt;block size&gt;
+</dt>
+<dt class="hdlist1">
+--block-size=&lt;block size&gt;
+</dt>
+<dd>
+<p>
+ Block Size: This field is used to specify the target block size to
+ format to. Potential lbaf values will be scanned and the lowest
+ numbered will be selected for the format operation. Conflicts with
+ --lbaf argument.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;ses&gt;
+</dt>
+<dt class="hdlist1">
+--ses=&lt;ses&gt;
+</dt>
+<dd>
+<p>
+ Secure Erase Settings: This field specifies whether a secure
+ erase should be performed as part of the format and the type of
+ the secure erase operation. The erase applies to all user data,
+ regardless of location (e.g., within an exposed LBA, within a
+ cache, within deallocated LBAs, etc). Defaults to 0.
+</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">No secure erase operation requested</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">User Data Erase: All user data shall be erased, contents of the user
+data after the erase is indeterminate (e.g., the user data may be zero
+filled, one filled, etc). The controller may perform a cryptographic
+erase when a User Data Erase is requested if all user data is encrypted.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Cryptographic Erase: All user data shall be erased
+cryptographically. This is accomplished by deleting the encryption key.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3–7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-p &lt;pil&gt;
+</dt>
+<dt class="hdlist1">
+--pil=&lt;pil&gt;
+</dt>
+<dd>
+<p>
+ Protection Information Location: If set to ‘1’ and protection
+ information is enabled, then protection information is transferred
+ as the first eight bytes of metadata. If cleared to ‘0’ and
+ protection information is enabled, then protection information
+ is transferred as the last eight bytes of metadata. Defaults to 0.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;pi&gt;
+</dt>
+<dt class="hdlist1">
+--pi=&lt;pi&gt;
+</dt>
+<dd>
+<p>
+ Protection Information: This field specifies whether end-to-end
+ data protection is enabled and the type of protection
+ information. Defaults to 0.
+</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">Protection information is not enabled</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Protection information is enabled, Type 1</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Protection information is enabled, Type 2</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Protection information is enabled, Type 3</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4–7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-m &lt;ms&gt;
+</dt>
+<dt class="hdlist1">
+--ms=&lt;ms&gt;
+</dt>
+<dd>
+<p>
+ Metadata Settings: This field is set to ‘1’ if the metadata
+ is transferred as part of an extended data LBA. This field is
+ cleared to ‘0’ if the metadata is transferred as part of a
+ separate buffer. The metadata may include protection information,
+ based on the Protection Information (PI) field. Defaults to 0.
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--reset
+</dt>
+<dd>
+<p>
+ Issue a reset after successful format. Must use the character
+ device for this.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Just send the command immediately without warning of the implications.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Format the device using all defaults:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme format /dev/nvme0n1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Format namespace 1 with user data secure erase settings and protection
+information:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme format /dev/nvme0 --namespace-id=1 --ses=1 --pi=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 the nvme-user suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-format.txt b/Documentation/nvme-format.txt
new file mode 100644
index 0000000..e4623f1
--- /dev/null
+++ b/Documentation/nvme-format.txt
@@ -0,0 +1,163 @@
+nvme-format(1)
+==============
+
+NAME
+----
+nvme-format - Format an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme format' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--lbaf=<lbaf> | -l <lbaf>]
+ [--block-size=<block size | -b <block size>]
+ [--ses=<ses> | -s <ses>] [--pil=<pil> | -p <pil>]
+ [--pi=<pi> | -i <pi>] [--ms=<ms> | -m <ms>]
+ [--reset | -r] [--force]
+ [--timeout=<timeout> | -t <timeout>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an nvme Format Namespace admin command
+and provides the results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+If the character device is given, and the controller does not support
+formatting of particular namespaces (ID_CTRL.FNA bit 0 enabled), then all
+namespaces will be formatted. If FNA is disabled, then the namespace
+identifier must be specified with the 'namespace-id' option; specify a
+value of 0xffffffff to send the format to all namespaces. If the block
+device is given, the namespace identifier will default to the namespace
+ID of the block device given, but can be overridden with the same option.
+
+Note, the numeric suffix on the character device, for example the '0' in
+/dev/nvme0, does NOT indicate this device handle is the parent controller
+of any namespaces with the same suffix. The namespace handle's numeral
+may be coming from the subsystem identifier, which is independent of the
+controller's identifier. Do not assume any particular device relationship
+based on their names. If you do, you may irrevocably erase data on an
+unintended device.
+
+On success, the program will automatically issue BLKRRPART ioctl to
+force rescanning the namespaces. If the driver is recent enough, this will
+automatically update the physical block size. If it is not recent enough,
+you will need to remove and rescan your device some other way for the
+new block size to be visible, if the size was changed with this command.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Send the format command for the specified nsid. This can be
+ used to override the default value for either character device
+ (unspecified) or the block device (result from NVME_IOCTL_ID).
+
+-l <lbaf>::
+--lbaf=<lbaf>::
+ LBA Format: This field specifies the LBA format to apply to the NVM
+ media. This corresponds to the LBA formats indicated in the
+ Identify Namespace command. Conflicts with --block-size argument.
+ Defaults to 0.
+
+-b <block size>::
+--block-size=<block size>::
+ Block Size: This field is used to specify the target block size to
+ format to. Potential lbaf values will be scanned and the lowest
+ numbered will be selected for the format operation. Conflicts with
+ --lbaf argument.
+
+-s <ses>::
+--ses=<ses>::
+ Secure Erase Settings: This field specifies whether a secure
+ erase should be performed as part of the format and the type of
+ the secure erase operation. The erase applies to all user data,
+ regardless of location (e.g., within an exposed LBA, within a
+ cache, within deallocated LBAs, etc). Defaults to 0.
++
+[]
+|=================
+|Value|Definition
+|0|No secure erase operation requested
+|1|User Data Erase: All user data shall be erased, contents of the user
+data after the erase is indeterminate (e.g., the user data may be zero
+filled, one filled, etc). The controller may perform a cryptographic
+erase when a User Data Erase is requested if all user data is encrypted.
+|2|Cryptographic Erase: All user data shall be erased
+cryptographically. This is accomplished by deleting the encryption key.
+|3–7|Reserved
+|=================
+
+-p <pil>::
+--pil=<pil>::
+ Protection Information Location: If set to ‘1’ and protection
+ information is enabled, then protection information is transferred
+ as the first eight bytes of metadata. If cleared to ‘0’ and
+ protection information is enabled, then protection information
+ is transferred as the last eight bytes of metadata. Defaults to 0.
+
+-i <pi>::
+--pi=<pi>::
+ Protection Information: This field specifies whether end-to-end
+ data protection is enabled and the type of protection
+ information. Defaults to 0.
++
+[]
+|=================
+|Value|Definition
+|0|Protection information is not enabled
+|1|Protection information is enabled, Type 1
+|2|Protection information is enabled, Type 2
+|3|Protection information is enabled, Type 3
+|4–7|Reserved
+|=================
+
+-m <ms>::
+--ms=<ms>::
+ Metadata Settings: This field is set to ‘1’ if the metadata
+ is transferred as part of an extended data LBA. This field is
+ cleared to ‘0’ if the metadata is transferred as part of a
+ separate buffer. The metadata may include protection information,
+ based on the Protection Information (PI) field. Defaults to 0.
+
+-r::
+--reset::
+ Issue a reset after successful format. Must use the character
+ device for this.
+
+--force::
+ Just send the command immediately without warning of the implications.
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Format the device using all defaults:
++
+------------
+# nvme format /dev/nvme0n1
+------------
++
+
+* Format namespace 1 with user data secure erase settings and protection
+information:
++
+------------
+# nvme format /dev/nvme0 --namespace-id=1 --ses=1 --pi=1
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-fw-commit.1 b/Documentation/nvme-fw-commit.1
new file mode 100644
index 0000000..62e46ee
--- /dev/null
+++ b/Documentation/nvme-fw-commit.1
@@ -0,0 +1,162 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-COMMIT" "1" "02/14/2024" "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-fw-commit \- Used to verify and commit a firmware image\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fw\-commit\fR <device> [\-\-slot=<slot> | \-s <slot>]
+ [\-\-action=<action> | \-a <action>]
+ [\-\-bpid=<boot\-partid> | \-b <boot\-partid>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an nvme Firmware Commit admin command and provides the results\&.
+.sp
+The Firmware Commit command is used to verify that a valid firmware image has been downloaded and to commit that revision to a specific firmware slot\&. The host may select the firmware image to commit on the next controller reset (CC\&.EN transitions from \(oq1\(cq to \(oq0\(cq, a PCI function level reset, and/or other Controller or NVM Subsystem Reset) as part of this command\&. The currently executing firmware revision may be determined from the Firmware Revision field of the Identify Controller data structure as indicated in the Firmware Slot Information log page\&.
+.sp
+No further action is automatically taken to reset the device, which is usually required to complete the activation process\&. If your kernel and driver are recent enough, you can commit the firmware by issuing a reset through Linux sysfs, for example:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+ # echo 1 > /sys/class/nvme/nvme0/device/reset
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+If your kernel is not recent enough, you will need to remove and add the device some other way\&.
+.SH "OPTIONS"
+.PP
+\-a <action>, \-\-action=<action>
+.RS 4
+Commit Action: This field specifies the action that is taken on the image downloaded with the Firmware Image Download command or on a previously downloaded and placed image\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+Downloaded image replaces the image indicated by the Firmware Slot field\&. This image is not activated\&.
+T}
+T{
+1
+T}:T{
+Downloaded image replaces the image indicated by the Firmware Slot field\&. This image is activated at the next reset\&.
+T}
+T{
+2
+T}:T{
+The image indicated by the Firmware Slot field is activated at the next reset\&.
+T}
+T{
+3
+T}:T{
+The image specified by the Firmware Slot field is requested to be activated immediately without reset\&.
+T}
+T{
+6
+T}:T{
+Downloaded image replaces the Boot Partition specified by the Boot Partition ID field\&.
+T}
+T{
+7
+T}:T{
+Mark the Boot Partition specified in the BPID field as active and update BPINFO\&.ABPID\&.
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-s <slot>, \-\-slot=<slot>
+.RS 4
+Firmware Slot: Specifies the firmware slot that shall be used for the Commit Action, if applicable\&. If the value specified is 0h, then the controller shall choose the firmware slot (slot 1 \(en 7) to use for the operation\&.
+.RE
+.PP
+\-\-bpid=<boot\-partid>, \-b <boot\-partid>
+.RS 4
+Specifies the Boot partition that shall be used for the Commit Action, if applicable (default: 0)
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+commit the last downloaded fw to slot 1\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme fw\-commit /dev/nvme0 \-\-slot=1 \-\-action=2
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "ALIAS"
+.sp
+fw\-activate
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-fw-commit.html b/Documentation/nvme-fw-commit.html
new file mode 100644
index 0000000..5f02e38
--- /dev/null
+++ b/Documentation/nvme-fw-commit.html
@@ -0,0 +1,936 @@
+<?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 10.2.0" />
+<title>nvme-fw-commit(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-fw-commit(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fw-commit -
+ Used to verify and commit a firmware image.
+</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 fw-commit</em> &lt;device&gt; [--slot=&lt;slot&gt; | -s &lt;slot&gt;]
+ [--action=&lt;action&gt; | -a &lt;action&gt;]
+ [--bpid=&lt;boot-partid&gt; | -b &lt;boot-partid&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Firmware Commit admin command
+and provides the results.</p></div>
+<div class="paragraph"><p>The Firmware Commit command is used to verify that a valid firmware
+image has been downloaded and to commit that revision to a specific
+firmware slot. The host may select the firmware image to commit on the
+next controller reset (CC.EN transitions from ‘1’ to ‘0’, a PCI
+function level reset, and/or other Controller or NVM Subsystem Reset)
+as part of this command. The currently executing firmware revision may
+be determined from the Firmware Revision field of the Identify Controller
+data structure as indicated in the Firmware Slot Information log page.</p></div>
+<div class="paragraph"><p>No further action is automatically taken to reset the device, which is
+usually required to complete the activation process. If your kernel and
+driver are recent enough, you can commit the firmware by issuing a
+reset through Linux sysfs, for example:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code> # echo 1 &gt; /sys/class/nvme/nvme0/device/reset</code></pre>
+</div></div>
+<div class="paragraph"><p>If your kernel is not recent enough, you will need to remove and add
+the device some other way.</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>
+ Commit Action: This field specifies the action that is taken
+ on the image downloaded with the Firmware Image Download command
+ or on a previously downloaded and placed image.
+</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">Downloaded image replaces the image indicated by the Firmware Slot
+field. This image is not activated.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Downloaded image replaces the image indicated by the Firmware Slot
+field. This image is activated at the next reset.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">The image indicated by the Firmware Slot field is activated at the
+next reset.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">The image specified by the Firmware Slot field is requested to be
+activated immediately without reset.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">6</p></td>
+<td align="left" valign="top"><p class="table">Downloaded image replaces the Boot Partition specified by the Boot Partition
+ID field.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">7</p></td>
+<td align="left" valign="top"><p class="table">Mark the Boot Partition specified in the BPID field as active and update
+BPINFO.ABPID.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-s &lt;slot&gt;
+</dt>
+<dt class="hdlist1">
+--slot=&lt;slot&gt;
+</dt>
+<dd>
+<p>
+ Firmware Slot: Specifies the firmware slot that shall be used for
+ the Commit Action, if applicable. If the value specified is 0h,
+ then the controller shall choose the firmware slot (slot 1 – 7)
+ to use for the operation.
+</p>
+</dd>
+<dt class="hdlist1">
+--bpid=&lt;boot-partid&gt;
+</dt>
+<dt class="hdlist1">
+-b &lt;boot-partid&gt;
+</dt>
+<dd>
+<p>
+ Specifies the Boot partition that shall be used for the Commit Action,
+ if applicable (default: 0)
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+commit the last downloaded fw to slot 1.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme fw-commit /dev/nvme0 --slot=1 --action=2</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_alias">ALIAS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>fw-activate</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-commit.txt b/Documentation/nvme-fw-commit.txt
new file mode 100644
index 0000000..8e08bd4
--- /dev/null
+++ b/Documentation/nvme-fw-commit.txt
@@ -0,0 +1,103 @@
+nvme-fw-commit(1)
+=================
+
+NAME
+----
+nvme-fw-commit - Used to verify and commit a firmware image.
+
+SYNOPSIS
+--------
+[verse]
+'nvme fw-commit' <device> [--slot=<slot> | -s <slot>]
+ [--action=<action> | -a <action>]
+ [--bpid=<boot-partid> | -b <boot-partid>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an nvme Firmware Commit admin command
+and provides the results.
+
+The Firmware Commit command is used to verify that a valid firmware
+image has been downloaded and to commit that revision to a specific
+firmware slot. The host may select the firmware image to commit on the
+next controller reset (CC.EN transitions from ‘1’ to ‘0’, a PCI
+function level reset, and/or other Controller or NVM Subsystem Reset)
+as part of this command. The currently executing firmware revision may
+be determined from the Firmware Revision field of the Identify Controller
+data structure as indicated in the Firmware Slot Information log page.
+
+No further action is automatically taken to reset the device, which is
+usually required to complete the activation process. If your kernel and
+driver are recent enough, you can commit the firmware by issuing a
+reset through Linux sysfs, for example:
+
+------------
+ # echo 1 > /sys/class/nvme/nvme0/device/reset
+------------
+
+If your kernel is not recent enough, you will need to remove and add
+the device some other way.
+
+OPTIONS
+-------
+-a <action>::
+--action=<action>::
+ Commit Action: This field specifies the action that is taken
+ on the image downloaded with the Firmware Image Download command
+ or on a previously downloaded and placed image.
++
+[]
+|=================
+|Value|Definition
+|0|Downloaded image replaces the image indicated by the Firmware Slot
+field. This image is not activated.
+|1|Downloaded image replaces the image indicated by the Firmware Slot
+field. This image is activated at the next reset.
+|2|The image indicated by the Firmware Slot field is activated at the
+next reset.
+|3|The image specified by the Firmware Slot field is requested to be
+activated immediately without reset.
+|6|Downloaded image replaces the Boot Partition specified by the Boot Partition
+ID field.
+|7|Mark the Boot Partition specified in the BPID field as active and update
+BPINFO.ABPID.
+|=================
+
+-s <slot>::
+--slot=<slot>::
+ Firmware Slot: Specifies the firmware slot that shall be used for
+ the Commit Action, if applicable. If the value specified is 0h,
+ then the controller shall choose the firmware slot (slot 1 – 7)
+ to use for the operation.
+
+--bpid=<boot-partid>::
+-b <boot-partid>::
+ Specifies the Boot partition that shall be used for the Commit Action,
+ if applicable (default: 0)
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* commit the last downloaded fw to slot 1.
++
+------------
+# nvme fw-commit /dev/nvme0 --slot=1 --action=2
+------------
+
+ALIAS
+-----
+
+fw-activate
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-fw-download.1 b/Documentation/nvme-fw-download.1
new file mode 100644
index 0000000..18a87ca
--- /dev/null
+++ b/Documentation/nvme-fw-download.1
@@ -0,0 +1,103 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-DOWNLOAD" "1" "02/14/2024" "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-fw-download \- Download all or a portion of an nvme firmware image\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fw\-download\fR <device> [\-\-fw=<firmware\-file> | \-f <firmware\-file>]
+ [\-\-xfer=<transfer\-size> | \-x <transfer\-size>]
+ [\-\-offset=<offset> | \-O <offset>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Firmware Image Download command is used to download all or a portion of the firmware image for a future update to the controller\&. The Firmware Image Download command may be submitted while other commands on the Admin Submission Queue or I/O Submission Queues are outstanding\&. The Firmware Image Download command copies the new firmware image (in whole or in part) to the controller\&.
+.sp
+The firmware image may be constructed of multiple pieces that are individually downloaded with separate Firmware Image Download commands\&. Each Firmware Image Download command includes a Dword Offset and Number of Dwords that specify a Dword range\&. The host software shall ensure that firmware pieces do not have Dword ranges that overlap\&. Firmware portions may be submitted out of order to the controller\&.
+.sp
+The new firmware image is not applied as part of the Firmware Image Download command\&. It is applied following a reset, where the image to apply and the firmware slot it should be committed to is specified with the Firmware Commit command (nvme fw\-commit <args>)\&.
+.SH "OPTIONS"
+.PP
+\-f <firmware\-file>, \-\-fw=<firmware\-file>
+.RS 4
+Required argument\&. This specifies the path to the device\(cqs firmware file on your system that will be read by the program and sent to the device\&.
+.RE
+.PP
+\-x <transfer\-size>, \-\-xfer=<transfer\-size>
+.RS 4
+This specifies the size to split each transfer\&. This is useful if the device has a max transfer size requirement for firmware\&. It defaults to 4k\&.
+.RE
+.PP
+\-O <offset>, \-\-offset=<offset>
+.RS 4
+This specifies the starting offset in dwords\&. This is really only useful if your firmware is split in multiple files; otherwise the offset starts at zero and automatically adjusts based on the
+\fIxfer\fR
+size given\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Transfer a firmware size 128KiB at a time:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme fw\-download /dev/nvme0 \-\-fw=/path/to/nvme\&.fw \-\-xfer=0x20000
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-fw-download.html b/Documentation/nvme-fw-download.html
new file mode 100644
index 0000000..278bb7a
--- /dev/null
+++ b/Documentation/nvme-fw-download.html
@@ -0,0 +1,883 @@
+<?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 10.2.0" />
+<title>nvme-fw-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 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-fw-download(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fw-download -
+ Download all or a portion of an nvme firmware image.
+</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 fw-download</em> &lt;device&gt; [--fw=&lt;firmware-file&gt; | -f &lt;firmware-file&gt;]
+ [--xfer=&lt;transfer-size&gt; | -x &lt;transfer-size&gt;]
+ [--offset=&lt;offset&gt; | -O &lt;offset&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Firmware Image Download command is used to download all or a portion
+of the firmware image for a future update to the controller. The Firmware
+Image Download command may be submitted while other commands on the Admin
+Submission Queue or I/O Submission Queues are outstanding. The Firmware
+Image Download command copies the new firmware image (in whole or in part)
+to the controller.</p></div>
+<div class="paragraph"><p>The firmware image may be constructed of multiple pieces that
+are individually downloaded with separate Firmware Image Download
+commands. Each Firmware Image Download command includes a Dword
+Offset and Number of Dwords that specify a Dword range. The host
+software shall ensure that firmware pieces do not have Dword ranges
+that overlap. Firmware portions may be submitted out of order to the
+controller.</p></div>
+<div class="paragraph"><p>The new firmware image is not applied as part of the Firmware Image
+Download command. It is applied following a reset, where the image to
+apply and the firmware slot it should be committed to is specified with
+the Firmware Commit command (nvme fw-commit &lt;args&gt;).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-f &lt;firmware-file&gt;
+</dt>
+<dt class="hdlist1">
+--fw=&lt;firmware-file&gt;
+</dt>
+<dd>
+<p>
+ Required argument. This specifies the path to the device&#8217;s
+ firmware file on your system that will be read by the program
+ and sent to the device.
+</p>
+</dd>
+<dt class="hdlist1">
+-x &lt;transfer-size&gt;
+</dt>
+<dt class="hdlist1">
+--xfer=&lt;transfer-size&gt;
+</dt>
+<dd>
+<p>
+ This specifies the size to split each transfer. This is useful if
+ the device has a max transfer size requirement for firmware. It
+ defaults to 4k.
+</p>
+</dd>
+<dt class="hdlist1">
+-O &lt;offset&gt;
+</dt>
+<dt class="hdlist1">
+--offset=&lt;offset&gt;
+</dt>
+<dd>
+<p>
+ This specifies the starting offset in dwords. This is really only
+ useful if your firmware is split in multiple files; otherwise
+ the offset starts at zero and automatically adjusts based on the
+ <em>xfer</em> size given.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Transfer a firmware size 128KiB at a time:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme fw-download /dev/nvme0 --fw=/path/to/nvme.fw --xfer=0x20000</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-download.txt b/Documentation/nvme-fw-download.txt
new file mode 100644
index 0000000..1ec466f
--- /dev/null
+++ b/Documentation/nvme-fw-download.txt
@@ -0,0 +1,78 @@
+nvme-fw-download(1)
+===================
+
+NAME
+----
+nvme-fw-download - Download all or a portion of an nvme firmware image.
+
+SYNOPSIS
+--------
+[verse]
+'nvme fw-download' <device> [--fw=<firmware-file> | -f <firmware-file>]
+ [--xfer=<transfer-size> | -x <transfer-size>]
+ [--offset=<offset> | -O <offset>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Firmware Image Download command is used to download all or a portion
+of the firmware image for a future update to the controller. The Firmware
+Image Download command may be submitted while other commands on the Admin
+Submission Queue or I/O Submission Queues are outstanding. The Firmware
+Image Download command copies the new firmware image (in whole or in part)
+to the controller.
+
+The firmware image may be constructed of multiple pieces that
+are individually downloaded with separate Firmware Image Download
+commands. Each Firmware Image Download command includes a Dword
+Offset and Number of Dwords that specify a Dword range. The host
+software shall ensure that firmware pieces do not have Dword ranges
+that overlap. Firmware portions may be submitted out of order to the
+controller.
+
+The new firmware image is not applied as part of the Firmware Image
+Download command. It is applied following a reset, where the image to
+apply and the firmware slot it should be committed to is specified with
+the Firmware Commit command (nvme fw-commit <args>).
+
+OPTIONS
+-------
+-f <firmware-file>::
+--fw=<firmware-file>::
+ Required argument. This specifies the path to the device's
+ firmware file on your system that will be read by the program
+ and sent to the device.
+
+-x <transfer-size>::
+--xfer=<transfer-size>::
+ This specifies the size to split each transfer. This is useful if
+ the device has a max transfer size requirement for firmware. It
+ defaults to 4k.
+
+-O <offset>::
+--offset=<offset>::
+ This specifies the starting offset in dwords. This is really only
+ useful if your firmware is split in multiple files; otherwise
+ the offset starts at zero and automatically adjusts based on the
+ 'xfer' size given.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Transfer a firmware size 128KiB at a time:
++
+------------
+# nvme fw-download /dev/nvme0 --fw=/path/to/nvme.fw --xfer=0x20000
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-fw-log.1 b/Documentation/nvme-fw-log.1
new file mode 100644
index 0000000..03776a7
--- /dev/null
+++ b/Documentation/nvme-fw-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-LOG" "1" "02/14/2024" "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-fw-log \- Send NVMe Firmware log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme fw\-log\fR <device> [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Firmware 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 f/w 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
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw fw log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the firmware log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme fw\-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 log firmware to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme fw\-log /dev/nvme0 \-\-raw\-binary > fw_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-fw-log.html b/Documentation/nvme-fw-log.html
new file mode 100644
index 0000000..92fd8f0
--- /dev/null
+++ b/Documentation/nvme-fw-log.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<title>nvme-fw-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 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-fw-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-fw-log -
+ Send NVMe Firmware 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 fw-log</em> &lt;device&gt; [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Firmware 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 f/w 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">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw fw log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 firmware log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme fw-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the log firmware to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme fw-log /dev/nvme0 --raw-binary &gt; fw_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-log.txt b/Documentation/nvme-fw-log.txt
new file mode 100644
index 0000000..d957548
--- /dev/null
+++ b/Documentation/nvme-fw-log.txt
@@ -0,0 +1,61 @@
+nvme-fw-log(1)
+==============
+
+NAME
+----
+nvme-fw-log - Send NVMe Firmware log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme fw-log' <device> [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Firmware 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 f/w 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
+-------
+-b::
+--raw-binary::
+ Print the raw fw log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the firmware log page in a human readable format:
++
+------------
+# nvme fw-log /dev/nvme0
+------------
++
+
+* Print the log firmware to a file:
++
+------------
+# nvme fw-log /dev/nvme0 --raw-binary > fw_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-gen-dhchap-key.1 b/Documentation/nvme-gen-dhchap-key.1
new file mode 100644
index 0000000..ad54b1f
--- /dev/null
+++ b/Documentation/nvme-gen-dhchap-key.1
@@ -0,0 +1,69 @@
+'\" t
+.\" Title: nvme-gen-dhchap-key
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 11/25/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GEN\-DHCHAP\-K" "1" "11/25/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-gen-dhchap-key \- Generate a host DH\-HMAC\-CHAP key
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme gen\-dhchap\-key\fR [\-\-hmac=<hmac\-id> | \-h <hmac\-id>]
+ [\-\-secret=<secret> | \-s <secret> ]
+ [\-\-key\-length=<len> | \-l <len> ]
+ [\-\-nqn=<host\-nqn> | \-n <host\-nqn> ]
+.fi
+.SH "DESCRIPTION"
+.sp
+Generate a base64\-encoded DH\-HMAC\-CHAP host key in the form: DHHC\-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n: and prints it to stdout\&.
+.SH "OPTIONS"
+.PP
+\-h <hmac\-id>, \-\-hmac=<hmac\-id>
+.RS 4
+Select a HMAC algorithm to use\&. Possible values are: 0 \- No HMAC algorithm 1 \- SHA\-256 2 \- SHA\-384 3 \- SHA\-512
+.RE
+.PP
+\-s <secret>, \-\-secret=<secret>
+.RS 4
+Secret value (in hexadecimal) to be used for the key\&. If none are provided a random value is used\&.
+.RE
+.PP
+\-l <len>, \-\-key\-length=<len>
+.RS 4
+Length of the resulting key\&. Possible values are 32, 48, or 64\&.
+.RE
+.PP
+\-n <hostnqn>, \-\-nqn=<hostnqn>
+.RS 4
+Host\-NQN to be used for the transformation\&. This parameter is only valid if a non\-zero HMAC function has been specified\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No Examples
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-gen-dhchap-key.html b/Documentation/nvme-gen-dhchap-key.html
new file mode 100644
index 0000000..224e773
--- /dev/null
+++ b/Documentation/nvme-gen-dhchap-key.html
@@ -0,0 +1,842 @@
+<!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-gen-dhchap-key(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-gen-dhchap-key(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-gen-dhchap-key -
+ Generate a host DH-HMAC-CHAP key
+</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 gen-dhchap-key</em> [--hmac=&lt;hmac-id&gt; | -h &lt;hmac-id&gt;]
+ [--secret=&lt;secret&gt; | -s &lt;secret&gt; ]
+ [--key-length=&lt;len&gt; | -l &lt;len&gt; ]
+ [--nqn=&lt;host-nqn&gt; | -n &lt;host-nqn&gt; ]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Generate a base64-encoded DH-HMAC-CHAP host key in the form:
+DHHC-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n:
+and prints it to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-h &lt;hmac-id&gt;
+</dt>
+<dt class="hdlist1">
+--hmac=&lt;hmac-id&gt;
+</dt>
+<dd>
+<p>
+ Select a HMAC algorithm to use. Possible values are:
+ 0 - No HMAC algorithm
+ 1 - SHA-256
+ 2 - SHA-384
+ 3 - SHA-512
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;secret&gt;
+</dt>
+<dt class="hdlist1">
+--secret=&lt;secret&gt;
+</dt>
+<dd>
+<p>
+ Secret value (in hexadecimal) to be used for the key. If none are
+ provided a random value is used.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;len&gt;
+</dt>
+<dt class="hdlist1">
+--key-length=&lt;len&gt;
+</dt>
+<dd>
+<p>
+ Length of the resulting key. Possible values are 32, 48, or 64.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;hostnqn&gt;
+</dt>
+<dt class="hdlist1">
+--nqn=&lt;hostnqn&gt;
+</dt>
+<dd>
+<p>
+ Host-NQN to be used for the transformation. This parameter is only
+ valid if a non-zero HMAC function has been specified.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Examples</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 2021-11-25 14:12:38 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-gen-dhchap-key.txt b/Documentation/nvme-gen-dhchap-key.txt
new file mode 100644
index 0000000..1e5f969
--- /dev/null
+++ b/Documentation/nvme-gen-dhchap-key.txt
@@ -0,0 +1,62 @@
+nvme-gen-dhchap-key(1)
+======================
+
+NAME
+----
+nvme-gen-dhchap-key - Generate a host DH-HMAC-CHAP key
+
+SYNOPSIS
+--------
+[verse]
+'nvme gen-dhchap-key' [--hmac=<hmac-id> | -h <hmac-id>]
+ [--secret=<secret> | -s <secret>]
+ [--key-length=<len> | -l <len>]
+ [--nqn=<host-nqn> | -n <host-nqn>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Generate a base64-encoded DH-HMAC-CHAP host key in the form:
+DHHC-1:00:ia6zGodOr4SEG0Zzaw398rpY0wqipUWj4jWjUh4HWUz6aQ2n:
+and prints it to stdout.
+
+OPTIONS
+-------
+-h <hmac-id>::
+--hmac=<hmac-id>::
+ Select a HMAC algorithm to use. Possible values are:
+ 0 - No HMAC algorithm
+ 1 - SHA-256
+ 2 - SHA-384
+ 3 - SHA-512
+
+-s <secret>::
+--secret=<secret>::
+ Secret value (in hexadecimal) to be used for the key. If none are
+ provided a random value is used.
+
+-l <len>::
+--key-length=<len>::
+ Length of the resulting key. Possible values are 32, 48, or 64.
+
+-n <hostnqn>::
+--nqn=<hostnqn>::
+ Host-NQN to be used for the transformation. This parameter is only
+ valid if a non-zero HMAC function has been specified.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-gen-hostnqn.1 b/Documentation/nvme-gen-hostnqn.1
new file mode 100644
index 0000000..843a8a8
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.1
@@ -0,0 +1,60 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GEN\-HOSTNQN" "1" "02/14/2024" "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-gen-hostnqn \- Generate a host NVMe Qualified Name
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme gen\-hostnqn\fR [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Generate a random host NQN in the form: nqn\&.2014\-08\&.org\&.nvmexpress:uuid:1b4e28ba\-2fa1\-11d2\-883f\-0016d3cca427 and prints it to stdout\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+nvme gen\-hostnqn
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-gen-hostnqn.html b/Documentation/nvme-gen-hostnqn.html
new file mode 100644
index 0000000..a6d5fda
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.html
@@ -0,0 +1,816 @@
+<?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 10.2.0" />
+<title>nvme-gen-hostnqn(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-gen-hostnqn(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-gen-hostnqn -
+ Generate a host NVMe Qualified Name
+</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 gen-hostnqn</em> [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Generate a random host NQN in the form:
+nqn.2014-08.org.nvmexpress:uuid:1b4e28ba-2fa1-11d2-883f-0016d3cca427
+and prints it to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme gen-hostnqn</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-gen-hostnqn.txt b/Documentation/nvme-gen-hostnqn.txt
new file mode 100644
index 0000000..7b7d776
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.txt
@@ -0,0 +1,36 @@
+nvme-gen-hostnqn(1)
+===================
+
+NAME
+----
+nvme-gen-hostnqn - Generate a host NVMe Qualified Name
+
+SYNOPSIS
+--------
+[verse]
+'nvme gen-hostnqn' [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Generate a random host NQN in the form:
+nqn.2014-08.org.nvmexpress:uuid:1b4e28ba-2fa1-11d2-883f-0016d3cca427
+and prints it to stdout.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+nvme gen-hostnqn
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-gen-tls-key.txt b/Documentation/nvme-gen-tls-key.txt
new file mode 100644
index 0000000..772c7bc
--- /dev/null
+++ b/Documentation/nvme-gen-tls-key.txt
@@ -0,0 +1,99 @@
+nvme-gen-tls-key(1)
+======================
+
+NAME
+----
+nvme-gen-tls-key - Generate a NVMe TLS PSK
+
+SYNOPSIS
+--------
+[verse]
+'nvme gen-tls-key' [--keyring=<name> | -k <name>]
+ [--keytype=<type> | -t <type>]
+ [--hostnqn=<nqn> | -n <nqn>]
+ [--subsysnqn=<nqn> | -c <nqn>]
+ [--hmac=<hmac-id> | -h <hmac-id>]
+ [--identity=<id-vers> | -I <id-vers>]
+ [--secret=<secret> | -s <secret>]
+ [--insert | -i]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Generate a base64-encoded NVMe TLS pre-shared key (PSK).
+The resulting key is either printed in the PSK interchange format
+'NVMeTLSkey-1:01:<base64 encoded data>:' or inserted as a
+'retained' key into the specified keyring if the '--insert' option
+is given.
+When the PSK should be inserted into the keyring a 'retained' key
+is derived from the secret key material. The resulting 'retained'
+key is stored with the identity
+'NVMe0R0<hmac> <host NQN> <subsystem NQN>'
+(for identity version '0') or
+'NVMe1R0<hmac> <host NQN> <subsystem NQN> <PSK hash>'
+(for identity version '1') in the keyring.
+The 'retained' key is derived from the secret key material,
+the specified subsystem NQN, and the host NQN.
+Once the 'retained' key is stored in the keyring the original
+secret key material cannot be retrieved.
+
+OPTIONS
+-------
+-k <name>::
+--keyring=<name>::
+ Name of the keyring into which the 'retained' TLS key should be
+ stored. Default is '.nvme'.
+
+-t <type>::
+--keytype=<type>::
+ Type of the key for resulting TLS key.
+ Default is 'psk'.
+
+-n <nqn>::
+--hostnqn=<nqn>::
+ Host NVMe Qualified Name (NQN) to be used to derive the
+ 'retained' TLS key
+
+-c <nqn>::
+--subsysnqn=<nqn>::
+ Subsystem NVMe Qualified Name (NQN) to be used to derive the
+ 'retained' TLS key
+
+-h <hmac-id>::
+--hmac=<hmac-id>::
+ Select a HMAC algorithm to use. Possible values are:
+ 1 - SHA-256 (default)
+ 2 - SHA-384
+
+-I <vers>::
+--identity=<id-vers>::
+ Select the TLS identity to use. Possible values are:
+ 0 - Original NVMe TLS 1.0c identity
+ 1 - NVMe TLS 2.0 (TP8018) identity
+
+-s <secret>::
+--secret=<secret>::
+ Secret value (in hexadecimal) to be used for the key. If none are
+ provided a random value is used.
+
+-i::
+--insert::
+ Insert the resulting TLS key into the keyring without printing out
+ the key in PSK interchange format.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-get-feature.1 b/Documentation/nvme-get-feature.1
new file mode 100644
index 0000000..c183514
--- /dev/null
+++ b/Documentation/nvme-get-feature.1
@@ -0,0 +1,247 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-FEATURE" "1" "02/14/2024" "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-get-feature \- Gets an NVMe feature, returns applicable results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-feature\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-feature\-id=<fid> | \-f <fid>] [\-\-cdw11=<cdw11>]
+ [\-\-uuid\-index=<uuid\-index> | \-U <uuid_index>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-sel=<select> | \-s <select>]
+ [\-\-raw\-binary | \-b]
+ [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an NVMe Get Feature admin command and returns the applicable results\&. This may be the feature\(cqs value, or may also include a feature structure if the feature requires it (ex: LBA Range Type)\&.
+.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 feature\(cqs structure (if applicable) 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 if it is a known structure, displayed in hex, or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the feature for the given nsid\&. This is optional and most features do not use this value\&.
+.RE
+.PP
+\-f <fid>, \-\-feature\-id=<fid>
+.RS 4
+The feature id to send with the command\&. Value provided should be in hex\&.
+.RE
+.PP
+\-s <select>, \-\-sel=<select>
+.RS 4
+Select (SEL): This field specifies which value of the attributes to return in the provided data:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Select
+T}:T{
+Description
+T}
+T{
+0
+T}:T{
+Current
+T}
+T{
+1
+T}:T{
+Default
+T}
+T{
+2
+T}:T{
+Saved
+T}
+T{
+3
+T}:T{
+Supported capabilities
+T}
+T{
+4\-7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-U <uuid\-index>, \-\-uuid\-index=<uuid\-index>
+.RS 4
+UUID Index of the feature
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer returned for this feature\&. Most known features do not use this value\&. The exception is LBA Range Type
+.RE
+.PP
+\-\-cdw11=<cdw11>
+.RS 4
+The value for command dword 11, if applicable\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw feature buffer to stdout if the feature returns a structure\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieves the feature for Number of Queues, or feature id 7:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-feature /dev/nvme0 \-f 7
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The following retrieves the feature for the LBA Range Type, which implicitly requires a buffer and will be printed to the screen in human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-feature /dev/nvme0 \-f 3
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieves the feature for the some vendor specific feature and specifically requesting a buffer be allocate for this feature, which will be displayed to the user in as a hex dump:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-feature /dev/nvme0 \-f 0xc0 \-l 512
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Get feature with UUID index
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-feature /dev/nvme0 \-f 0xc0 \-l 512 \-U 0x1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The following retrieves the feature for the LBA Range Type, which implicitly requires a buffer and will be saved to a file in its raw format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-feature /dev/nvme0 \-f 3 \-\-raw\-binary > lba_range\&.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-get-feature.html b/Documentation/nvme-get-feature.html
new file mode 100644
index 0000000..920a5e3
--- /dev/null
+++ b/Documentation/nvme-get-feature.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 10.2.0" />
+<title>nvme-get-feature(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-get-feature(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-get-feature -
+ Gets an NVMe feature, returns applicable 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 get-feature</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--feature-id=&lt;fid&gt; | -f &lt;fid&gt;] [--cdw11=&lt;cdw11&gt;]
+ [--uuid-index=&lt;uuid-index&gt; | -U &lt;uuid_index&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--sel=&lt;select&gt; | -s &lt;select&gt;]
+ [--raw-binary | -b]
+ [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an NVMe Get Feature admin command and returns the applicable
+results. This may be the feature&#8217;s value, or may also include a feature
+structure if the feature requires it (ex: LBA Range Type).</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 feature&#8217;s structure (if applicable) 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
+if it is a known structure, displayed in hex, 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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;fid&gt;
+</dt>
+<dt class="hdlist1">
+--feature-id=&lt;fid&gt;
+</dt>
+<dd>
+<p>
+ The feature id to send with the command. Value provided should
+ be in hex.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;select&gt;
+</dt>
+<dt class="hdlist1">
+--sel=&lt;select&gt;
+</dt>
+<dd>
+<p>
+ Select (SEL): This field specifies which value of the attributes
+ to return in the provided data:
+</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">Select</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Current</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Default</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Saved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Supported capabilities</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4-7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-U &lt;uuid-index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid-index=&lt;uuid-index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index of the feature
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+</p>
+</dd>
+<dt class="hdlist1">
+--cdw11=&lt;cdw11&gt;
+</dt>
+<dd>
+<p>
+ The value for command dword 11, if applicable.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw feature buffer to stdout if the feature returns
+ a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieves the feature for Number of Queues, or feature id 7:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-feature /dev/nvme0 -f 7</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+The following retrieves the feature for the LBA Range Type, which
+implicitly requires a buffer and will be printed to the screen in human
+readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-feature /dev/nvme0 -f 3</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Retrieves the feature for the some vendor specific feature and
+specifically requesting a buffer be allocate for this feature, which
+will be displayed to the user in as a hex dump:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-feature /dev/nvme0 -f 0xc0 -l 512</code></pre>
+</div></div>
+<div class="paragraph"><p>Get feature with UUID index</p></div>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-feature /dev/nvme0 -f 0xc0 -l 512 -U 0x1</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+The following retrieves the feature for the LBA Range Type, which
+implicitly requires a buffer and will be saved to a file in its raw
+format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-feature /dev/nvme0 -f 3 --raw-binary &gt; lba_range.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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-feature.txt b/Documentation/nvme-get-feature.txt
new file mode 100644
index 0000000..6477bc6
--- /dev/null
+++ b/Documentation/nvme-get-feature.txt
@@ -0,0 +1,137 @@
+nvme-get-feature(1)
+===================
+
+NAME
+----
+nvme-get-feature - Gets an NVMe feature, returns applicable results
+
+SYNOPSIS
+--------
+[verse]
+'nvme get-feature' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--feature-id=<fid> | -f <fid>] [--cdw11=<cdw11>]
+ [--uuid-index=<uuid-index> | -U <uuid_index>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--sel=<select> | -s <select>]
+ [--raw-binary | -b]
+ [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an NVMe Get Feature admin command and returns the applicable
+results. This may be the feature's value, or may also include a feature
+structure if the feature requires it (ex: LBA Range Type).
+
+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 feature's structure (if applicable) 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
+if it is a known structure, displayed in hex, or the raw buffer may be
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the feature for the given nsid. This is optional and
+ most features do not use this value.
+
+-f <fid>::
+--feature-id=<fid>::
+ The feature id to send with the command. Value provided should
+ be in hex.
+
+-s <select>::
+--sel=<select>::
+ Select (SEL): This field specifies which value of the attributes
+ to return in the provided data:
++
+[]
+|==================
+|Select|Description
+|0|Current
+|1|Default
+|2|Saved
+|3|Supported capabilities
+|4-7|Reserved
+|==================
+
+-U <uuid-index>::
+--uuid-index=<uuid-index>::
+ UUID Index of the feature
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer returned for this feature. Most
+ known features do not use this value. The exception is LBA
+ Range Type
+
+--cdw11=<cdw11>::
+ The value for command dword 11, if applicable.
+
+-b::
+--raw-binary::
+ Print the raw feature buffer to stdout if the feature returns
+ a structure.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Retrieves the feature for Number of Queues, or feature id 7:
++
+------------
+# nvme get-feature /dev/nvme0 -f 7
+------------
++
+
+* The following retrieves the feature for the LBA Range Type, which
+implicitly requires a buffer and will be printed to the screen in human
+readable format:
++
+------------
+# nvme get-feature /dev/nvme0 -f 3
+------------
++
+
+* Retrieves the feature for the some vendor specific feature and
+specifically requesting a buffer be allocate for this feature, which
+will be displayed to the user in as a hex dump:
++
+------------
+# nvme get-feature /dev/nvme0 -f 0xc0 -l 512
+------------
++
+Get feature with UUID index
+------------
+# nvme get-feature /dev/nvme0 -f 0xc0 -l 512 -U 0x1
+------------
+
+* The following retrieves the feature for the LBA Range Type, which
+implicitly requires a buffer and will be saved to a file in its raw
+format:
++
+------------
+# nvme get-feature /dev/nvme0 -f 3 --raw-binary > lba_range.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-get-lba-status.1 b/Documentation/nvme-get-lba-status.1
new file mode 100644
index 0000000..473a5b9
--- /dev/null
+++ b/Documentation/nvme-get-lba-status.1
@@ -0,0 +1,140 @@
+'\" t
+.\" Title: nvme-get-lba-status
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-LBA\-STAT" "1" "02/14/2024" "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-get-lba-status \- Get LBA Status from NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-lba\-status\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-start\-lba=<slba> | \-s <slba>]
+ [\-\-max\-dw=<max\-dw> | \-m <max\-dw>]
+ [\-\-action=<action\-type> | \-a <action\-type>]
+ [\-\-range\-len=<range\-len> | \-l <range\-len>]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an nvme Get LBA Status admin command and provides the results\&.
+.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 get lba data structure may be returned in one of several ways depending on the option flags; the structure may parsed by the program and printed in a readable format or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Send the Get LBA Status command for the specified nsid\&. This can be used to override the default value for either character device (unspecified) or the block device (result from NVME_IOCTL_ID)\&.
+.RE
+.PP
+\-s <slba>, \-\-start\-lba=<slba>
+.RS 4
+Starting LBA(SLBA) in 64\-bit address of the first logical block addressed
+.RE
+.PP
+\-m <max\-dw>, \-\-max\-dw=<max\-dw>
+.RS 4
+Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return
+.RE
+.PP
+\-a <action\-type>, \-\-action=<action\-type>
+.RS 4
+Action Type(ATYPE) specifies the mechanism it uses in determining the LBA Status Descriptors\&.
+.RE
+.PP
+\-l <range\-len>, \-\-range\-len=<range\-len>
+.RS 4
+Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA
+.RE
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the LBA Status of the device using all defaults:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-lba\-status /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get LBA Status of the namespace 1 from SLBA 10 for the max Dwords of 0x1000
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-lba\-status /dev/nvme0 \-\-namespace\-id=1 \-\-start\-lba=10 \-\-max\-dw=0x1000
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-get-lba-status.html b/Documentation/nvme-get-lba-status.html
new file mode 100644
index 0000000..fe45726
--- /dev/null
+++ b/Documentation/nvme-get-lba-status.html
@@ -0,0 +1,914 @@
+<?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 10.2.0" />
+<title>nvme-get-lba-status(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-get-lba-status(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-get-lba-status -
+ Get LBA Status from 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 get-lba-status</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--start-lba=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--max-dw=&lt;max-dw&gt; | -m &lt;max-dw&gt;]
+ [--action=&lt;action-type&gt; | -a &lt;action-type&gt;]
+ [--range-len=&lt;range-len&gt; | -l &lt;range-len&gt;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Get LBA Status admin command
+and provides the results.</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 get lba data structure may be returned in one of
+several ways depending on the option flags; the structure may parsed by
+the program and printed in a readable format or the raw buffer may be
+printed to stdout for another program to parse.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Send the Get LBA Status command for the specified nsid. This can be
+ used to override the default value for either character device
+ (unspecified) or the block device (result from NVME_IOCTL_ID).
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-lba=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Starting LBA(SLBA) in 64-bit address of the first logical block addressed
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;max-dw&gt;
+</dt>
+<dt class="hdlist1">
+--max-dw=&lt;max-dw&gt;
+</dt>
+<dd>
+<p>
+ Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;action-type&gt;
+</dt>
+<dt class="hdlist1">
+--action=&lt;action-type&gt;
+</dt>
+<dd>
+<p>
+ Action Type(ATYPE) specifies the mechanism it uses in determining the LBA Status Descriptors.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;range-len&gt;
+</dt>
+<dt class="hdlist1">
+--range-len=&lt;range-len&gt;
+</dt>
+<dd>
+<p>
+ Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 LBA Status of the device using all defaults:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-lba-status /dev/nvme0n1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get LBA Status of the namespace 1 from SLBA 10 for the max Dwords of 0x1000
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-lba-status /dev/nvme0 --namespace-id=1 --start-lba=10 --max-dw=0x1000</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-lba-status.txt b/Documentation/nvme-get-lba-status.txt
new file mode 100644
index 0000000..9ef9d59
--- /dev/null
+++ b/Documentation/nvme-get-lba-status.txt
@@ -0,0 +1,86 @@
+nvme-get-lba-status(1)
+======================
+
+NAME
+----
+nvme-get-lba-status - Get LBA Status from NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme get-lba-status' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--start-lba=<slba> | -s <slba>]
+ [--max-dw=<max-dw> | -m <max-dw>]
+ [--action=<action-type> | -a <action-type>]
+ [--range-len=<range-len> | -l <range-len>]
+ [--timeout=<timeout> | -t <timeout>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an nvme Get LBA Status admin command
+and provides the results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the returned get lba data structure may be returned in one of
+several ways depending on the option flags; the structure may parsed by
+the program and printed in a readable format or the raw buffer may be
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Send the Get LBA Status command for the specified nsid. This can be
+ used to override the default value for either character device
+ (unspecified) or the block device (result from NVME_IOCTL_ID).
+
+-s <slba>::
+--start-lba=<slba>::
+ Starting LBA(SLBA) in 64-bit address of the first logical block addressed
+
+-m <max-dw>::
+--max-dw=<max-dw>::
+ Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return
+
+-a <action-type>::
+--action=<action-type>::
+ Action Type(ATYPE) specifies the mechanism it uses in determining the LBA Status Descriptors.
+
+-l <range-len>::
+--range-len=<range-len>::
+ Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Get the LBA Status of the device using all defaults:
++
+------------
+# nvme get-lba-status /dev/nvme0n1
+------------
++
+
+* Get LBA Status of the namespace 1 from SLBA 10 for the max Dwords of 0x1000
++
+------------
+# nvme get-lba-status /dev/nvme0 --namespace-id=1 --start-lba=10 --max-dw=0x1000
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-get-log.1 b/Documentation/nvme-get-log.1
new file mode 100644
index 0000000..1f189c3
--- /dev/null
+++ b/Documentation/nvme-get-log.1
@@ -0,0 +1,181 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-LOG" "1" "02/14/2024" "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-get-log \- Retrieves a log page from an NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-log\fR <device> [\-\-log\-id=<log\-id> | \-i <log\-id>]
+ [\-\-log\-len=<log\-len> | \-l <log\-len>]
+ [\-\-aen=<aen> | \-a <aen>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-raw\-binary | \-b]
+ [\-\-lpo=<offset> | \-L <offset>]
+ [\-\-lsp=<field> | \-s <field>]
+ [\-\-lsi=<field> | \-S <field>]
+ [\-\-rae | \-r]
+ [\-\-csi=<command_set_identifier> | \-y <command_set_identifier>]
+ [\-\-ot=<offset_type> | \-O <offset_type>]
+ [\-\-xfer\-len=<length> | \-x <length>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves an arbitrary NVMe 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 log structure may be returned in one of several ways depending on the option flags; the structure may be displayed in hex by the program or the raw buffer may be printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.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\&.
+.RE
+.PP
+\-i <log\-id>, \-\-log\-id=<log\-id>
+.RS 4
+Sets the commands requested log\-id to <log\-id>\&. Defaults to 0\&.
+.RE
+.PP
+\-a <aen>, \-\-aen=<aen>
+.RS 4
+Convenience field for extracting log information based on an asynchronous event notification result\&. This will override log\-id and log\-len, if set\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if not given\&. This option may not affect anything depending on the log page, which may or may not be specific to a namespace\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw log buffer to stdout\&.
+.RE
+.PP
+\-L <offset>, \-\-lpo=<offset>
+.RS 4
+The log page offset specifies the location within a log page to start returning data from\&. It\(cqs Dword\-aligned and 64\-bits\&.
+.RE
+.PP
+\-s <field>, \-\-lsp=<field>
+.RS 4
+The log specified field of LID\&.
+.RE
+.PP
+\-S <field>, \-\-lsi=<field>
+.RS 4
+The log specified field of Log Specific Identifier\&.
+.RE
+.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.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
+\-O, \-\-ot
+.RS 4
+This field specifies the offset type\&. If set to false, the Log Page Offset Lower field and the Log Page Offset Upper field specify the byte offset into the log page to be returned\&. If set to true, the Log Page Offset Lower field and the Log Page Offset Upper field specify the index into the list of data structures in the log page to be returned\&. The default is byte offset\&. If the option is specified the index mode is used\&.
+.RE
+.PP
+\-x <length>
+.RS 4
+\-\-xfer\-len <length>: Specify the read chunk size\&. The length argument is expected to be a multiple of 4096\&. The default size is 4096\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get 512 bytes from log page 2
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-log /dev/nvme0 \-\-log\-id=2 \-\-log\-len=512
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The above example will get log page 2 (SMART), and request 512 bytes\&. On success, the returned log will be dumped in hex and not interpreted by the program\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw log page in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-log /dev/nvme0 \-log\-id=2 \-\-log\-len=512 \-\-raw\-binary > log_page_2\&.raw
+# nvme get\-log /dev/nvme0 \-i 2 \-l 512 \-b > log_page_2\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is not a good idea to not redirect stdout when using this mode\&.
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-get-log.html b/Documentation/nvme-get-log.html
new file mode 100644
index 0000000..0d86eb2
--- /dev/null
+++ b/Documentation/nvme-get-log.html
@@ -0,0 +1,1004 @@
+<?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 10.2.0" />
+<title>nvme-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 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-get-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-get-log -
+ Retrieves a log page from 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 get-log</em> &lt;device&gt; [--log-id=&lt;log-id&gt; | -i &lt;log-id&gt;]
+ [--log-len=&lt;log-len&gt; | -l &lt;log-len&gt;]
+ [--aen=&lt;aen&gt; | -a &lt;aen&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--raw-binary | -b]
+ [--lpo=&lt;offset&gt; | -L &lt;offset&gt;]
+ [--lsp=&lt;field&gt; | -s &lt;field&gt;]
+ [--lsi=&lt;field&gt; | -S &lt;field&gt;]
+ [--rae | -r]
+ [--csi=&lt;command_set_identifier&gt; | -y &lt;command_set_identifier&gt;]
+ [--ot=&lt;offset_type&gt; | -O &lt;offset_type&gt;]
+ [--xfer-len=&lt;length&gt; | -x &lt;length&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves an arbitrary NVMe 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 log structure may be returned in one of several
+ways depending on the option flags; the structure may be displayed in
+hex by the program 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">
+-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.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;log-id&gt;
+</dt>
+<dt class="hdlist1">
+--log-id=&lt;log-id&gt;
+</dt>
+<dd>
+<p>
+ Sets the commands requested log-id to &lt;log-id&gt;. Defaults to 0.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;aen&gt;
+</dt>
+<dt class="hdlist1">
+--aen=&lt;aen&gt;
+</dt>
+<dd>
+<p>
+ Convenience field for extracting log information based on an
+ asynchronous event notification result. This will override log-id and
+ log-len, if set.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the command&#8217;s nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-L &lt;offset&gt;
+</dt>
+<dt class="hdlist1">
+--lpo=&lt;offset&gt;
+</dt>
+<dd>
+<p>
+ The log page offset specifies the location within a log page to start
+ returning data from. It&#8217;s Dword-aligned and 64-bits.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;field&gt;
+</dt>
+<dt class="hdlist1">
+--lsp=&lt;field&gt;
+</dt>
+<dd>
+<p>
+ The log specified field of LID.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;field&gt;
+</dt>
+<dt class="hdlist1">
+--lsi=&lt;field&gt;
+</dt>
+<dd>
+<p>
+ The log specified field of Log Specific Identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</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">
+-O
+</dt>
+<dt class="hdlist1">
+--ot
+</dt>
+<dd>
+<p>
+ This field specifies the offset type. If set to false, the
+ Log Page Offset Lower field and the Log Page Offset Upper
+ field specify the byte offset into the log page to be returned.
+ If set to true, the Log Page Offset Lower field and the Log
+ Page Offset Upper field specify the index into the list of
+ data structures in the log page to be returned.
+ The default is byte offset. If the option is specified
+ the index mode is used.
+</p>
+</dd>
+<dt class="hdlist1">
+-x &lt;length&gt;
+</dt>
+<dd>
+<p>
+--xfer-len &lt;length&gt;:
+ Specify the read chunk size. The length argument is expected to be
+ a multiple of 4096. The default size is 4096.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get 512 bytes from log page 2
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-log /dev/nvme0 --log-id=2 --log-len=512</code></pre>
+</div></div>
+<div class="paragraph"><p>The above example will get log page 2 (SMART), and request 512
+bytes. On success, the returned log will be dumped in hex and not
+interpreted by the program.</p></div>
+</li>
+<li>
+<p>
+Have the program return the raw log page in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-log /dev/nvme0 -log-id=2 --log-len=512 --raw-binary &gt; log_page_2.raw
+# nvme get-log /dev/nvme0 -i 2 -l 512 -b &gt; log_page_2.raw</code></pre>
+</div></div>
+<div class="paragraph"><p>It is not a good 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-log.txt b/Documentation/nvme-get-log.txt
new file mode 100644
index 0000000..98b1f9c
--- /dev/null
+++ b/Documentation/nvme-get-log.txt
@@ -0,0 +1,137 @@
+nvme-get-log(1)
+===============
+
+NAME
+----
+nvme-get-log - Retrieves a log page from an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme get-log' <device> [--log-id=<log-id> | -i <log-id>]
+ [--log-len=<log-len> | -l <log-len>]
+ [--aen=<aen> | -a <aen>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--raw-binary | -b]
+ [--lpo=<offset> | -L <offset>]
+ [--lsp=<field> | -s <field>]
+ [--lsi=<field> | -S <field>]
+ [--rae | -r]
+ [--csi=<command_set_identifier> | -y <command_set_identifier>]
+ [--ot=<offset_type> | -O <offset_type>]
+ [--xfer-len=<length> | -x <length>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves an arbitrary NVMe 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 log structure may be returned in one of several
+ways depending on the option flags; the structure may be displayed in
+hex by the program or the raw buffer may be printed to stdout for another
+program to parse.
+
+OPTIONS
+-------
+-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.
+
+-i <log-id>::
+--log-id=<log-id>::
+ Sets the commands requested log-id to <log-id>. Defaults to 0.
+
+-a <aen>::
+--aen=<aen>::
+ Convenience field for extracting log information based on an
+ asynchronous event notification result. This will override log-id and
+ log-len, if set.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the command's nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+
+-b::
+--raw-binary::
+ Print the raw log buffer to stdout.
+
+-L <offset>::
+--lpo=<offset>::
+ The log page offset specifies the location within a log page to start
+ returning data from. It's Dword-aligned and 64-bits.
+
+-s <field>::
+--lsp=<field>::
+ The log specified field of LID.
+
+-S <field>::
+--lsi=<field>::
+ The log specified field of Log Specific Identifier.
+
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+-y <command_set_identifier>::
+--csi=<command_set_identifier>::
+ This field specifies the identifier of command set.
+ if not issued, NVM Command Set will be selected.
+
+-O::
+--ot::
+ This field specifies the offset type. If set to false, the
+ Log Page Offset Lower field and the Log Page Offset Upper
+ field specify the byte offset into the log page to be returned.
+ If set to true, the Log Page Offset Lower field and the Log
+ Page Offset Upper field specify the index into the list of
+ data structures in the log page to be returned.
+ The default is byte offset. If the option is specified
+ the index mode is used.
+
+-x <length>::
+--xfer-len <length>:
+ Specify the read chunk size. The length argument is expected to be
+ a multiple of 4096. The default size is 4096.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Get 512 bytes from log page 2
++
+------------
+# nvme get-log /dev/nvme0 --log-id=2 --log-len=512
+------------
++
+The above example will get log page 2 (SMART), and request 512
+bytes. On success, the returned log will be dumped in hex and not
+interpreted by the program.
+
+* Have the program return the raw log page in binary:
++
+------------
+# nvme get-log /dev/nvme0 -log-id=2 --log-len=512 --raw-binary > log_page_2.raw
+# nvme get-log /dev/nvme0 -i 2 -l 512 -b > log_page_2.raw
+------------
++
+It is not a good idea to not redirect stdout when using this mode.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-get-ns-id.1 b/Documentation/nvme-get-ns-id.1
new file mode 100644
index 0000000..cb12425
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.1
@@ -0,0 +1,79 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-NS\-ID" "1" "02/14/2024" "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-get-ns-id \- Retrieves the namespace ID for an NVMe block device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-ns\-id\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the namespace ID for an NVMe block device\&. The <device> param is mandatory and must be an NVMe block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Shows the namespace id for the given block device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-ns\-id /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-get-ns-id.html b/Documentation/nvme-get-ns-id.html
new file mode 100644
index 0000000..07e9814
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.html
@@ -0,0 +1,825 @@
+<?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 10.2.0" />
+<title>nvme-get-ns-id(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-get-ns-id(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-get-ns-id -
+ Retrieves the namespace ID for an NVMe block 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 get-ns-id</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 namespace ID for an NVMe block device. The &lt;device&gt; param
+is mandatory and must be an NVMe 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">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Shows the namespace id for the given block device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-ns-id /dev/nvme0n1</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-ns-id.txt b/Documentation/nvme-get-ns-id.txt
new file mode 100644
index 0000000..8516cb8
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.txt
@@ -0,0 +1,39 @@
+nvme-get-ns-id(1)
+=================
+
+NAME
+----
+nvme-get-ns-id - Retrieves the namespace ID for an NVMe block device
+
+SYNOPSIS
+--------
+[verse]
+'nvme get-ns-id' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the namespace ID for an NVMe block device. The <device> param
+is mandatory and must be an NVMe block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Shows the namespace id for the given block device:
++
+------------
+# nvme get-ns-id /dev/nvme0n1
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-get-property.1 b/Documentation/nvme-get-property.1
new file mode 100644
index 0000000..8053cc1
--- /dev/null
+++ b/Documentation/nvme-get-property.1
@@ -0,0 +1,138 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-PROPERTY" "1" "02/14/2024" "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-get-property \- Reads and shows the defined NVMe controller property for NVMe over Fabric
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-property\fR <device> [\-\-offset=<offset> | \-O <offset>]
+ [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Reads and shows the defined NVMe controller property for NVMe over Fabric\&.
+.SH "OPTIONS"
+.PP
+\-O, \-\-offset
+.RS 4
+The offset of the property\&. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20
+.RE
+.PP
+\-H
+.RS 4
+\-\-human\-readable: Show the fields packed in the property
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+The following will run the get\-property command with offset 0
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme get\-property /dev/nvme0 \-\-offset=0x0 \-\-human\-readable
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "BUGS"
+.sp
+Currently the CAP value is truncated to 32 bits due to a limitation in the ioctl interface\&.
+.sp
+In a recent enough kernel, the 64 bit value is shown in kernel traces\&.
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+First enable traces by this command
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# echo 1 > /sys/kernel/debug/tracing/events/nvme/enable
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Then look for NVMe Fabrics command (0x7f) at trace
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/sys/kernel/debug/tracing/trace
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-get-property.html b/Documentation/nvme-get-property.html
new file mode 100644
index 0000000..f19907c
--- /dev/null
+++ b/Documentation/nvme-get-property.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 10.2.0" />
+<title>nvme-get-property(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-get-property(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-get-property -
+ Reads and shows the defined NVMe controller property for NVMe over Fabric
+</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 get-property</em> &lt;device&gt; [--offset=&lt;offset&gt; | -O &lt;offset&gt;]
+ [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Reads and shows the defined NVMe controller property for NVMe over Fabric.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-O
+</dt>
+<dt class="hdlist1">
+--offset
+</dt>
+<dd>
+<p>
+ The offset of the property. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dd>
+<p>
+--human-readable:
+ Show the fields packed in the property
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+The following will run the get-property command with offset 0
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme get-property /dev/nvme0 --offset=0x0 --human-readable</code></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_bugs">BUGS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Currently the CAP value is truncated to 32 bits due to a limitation in
+the ioctl interface.</p></div>
+<div class="paragraph"><p>In a recent enough kernel, the 64 bit value is shown in kernel traces.</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+First enable traces by this command
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># echo 1 &gt; /sys/kernel/debug/tracing/events/nvme/enable</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Then look for NVMe Fabrics command (0x7f) at trace
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code>/sys/kernel/debug/tracing/trace</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-property.txt b/Documentation/nvme-get-property.txt
new file mode 100644
index 0000000..601b8a4
--- /dev/null
+++ b/Documentation/nvme-get-property.txt
@@ -0,0 +1,68 @@
+nvme-get-property(1)
+====================
+
+NAME
+----
+nvme-get-property - Reads and shows the defined NVMe controller property
+for NVMe over Fabric
+
+SYNOPSIS
+--------
+[verse]
+'nvme get-property' <device> [--offset=<offset> | -O <offset>]
+ [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Reads and shows the defined NVMe controller property for NVMe over Fabric.
+
+OPTIONS
+-------
+-O::
+--offset::
+ The offset of the property. One of CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20
+
+-H::
+--human-readable:
+ Show the fields packed in the property
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* The following will run the get-property command with offset 0
++
+------------
+# nvme get-property /dev/nvme0 --offset=0x0 --human-readable
+------------
+
+BUGS
+----
+Currently the CAP value is truncated to 32 bits due to a limitation in
+the ioctl interface.
+
+In a recent enough kernel, the 64 bit value is shown in kernel traces.
+
+* First enable traces by this command
++
+------------
+# echo 1 > /sys/kernel/debug/tracing/events/nvme/enable
+------------
+
+* Then look for NVMe Fabrics command (0x7f) at trace
++
+------------
+/sys/kernel/debug/tracing/trace
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-help.1 b/Documentation/nvme-help.1
new file mode 100644
index 0000000..f88439a
--- /dev/null
+++ b/Documentation/nvme-help.1
@@ -0,0 +1,69 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-HELP" "1" "02/14/2024" "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-help \- Help information\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme help\fR [<command>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Provides help information, with detailed information about the given command if provided\&.
+.SH "OPTIONS"
+.sp
+No Options
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show help for nvme smart log:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme help smart\-log
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Not much to it
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-help.html b/Documentation/nvme-help.html
new file mode 100644
index 0000000..ef591a7
--- /dev/null
+++ b/Documentation/nvme-help.html
@@ -0,0 +1,801 @@
+<?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 10.2.0" />
+<title>nvme-help(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-help(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-help -
+ Help information.
+</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 help</em> [&lt;command&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Provides help information, with detailed information about the given command if provided.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Options</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Show help for nvme smart log:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme help smart-log</code></pre>
+</div></div>
+<div class="paragraph"><p>Not much to it</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-help.txt b/Documentation/nvme-help.txt
new file mode 100644
index 0000000..0c0c4cd
--- /dev/null
+++ b/Documentation/nvme-help.txt
@@ -0,0 +1,33 @@
+nvme-help(1)
+=============
+
+NAME
+----
+nvme-help - Help information.
+
+SYNOPSIS
+--------
+[verse]
+'nvme help' [<command>]
+
+DESCRIPTION
+-----------
+Provides help information, with detailed information about the given command if provided.
+
+OPTIONS
+-------
+No Options
+
+EXAMPLES
+--------
+* Show help for nvme smart log:
++
+------------
+# nvme help smart-log
+------------
++
+Not much to it
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-huawei-id-ctrl.1 b/Documentation/nvme-huawei-id-ctrl.1
new file mode 100644
index 0000000..39c7a01
--- /dev/null
+++ b/Documentation/nvme-huawei-id-ctrl.1
@@ -0,0 +1,97 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-HUAWEI\-ID\-CT" "1" "02/14/2024" "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-huawei-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme huawei id\-ctrl\fR <device> [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an 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
+This will only work on Huawei devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.sp
+If having the program decode the output for readability, this version will decode Huawei vendor unique portions of the structure\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-v, \-\-vendor\-specific
+.RS 4
+In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii interpretation\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 huawei id\-ctrl /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-huawei-id-ctrl.html b/Documentation/nvme-huawei-id-ctrl.html
new file mode 100644
index 0000000..b04dd72
--- /dev/null
+++ b/Documentation/nvme-huawei-id-ctrl.html
@@ -0,0 +1,862 @@
+<?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 10.2.0" />
+<title>nvme-huawei-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 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-huawei-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-huawei-id-ctrl -
+ Send NVMe 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 huawei id-ctrl</em> &lt;device&gt; [--vendor-specific | -v] [--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>For the NVMe device given, sends an 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>This will only work on Huawei devices supporting this feature.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+<div class="paragraph"><p>If having the program decode the output for readability, this version
+will decode Huawei vendor unique portions of the structure.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--vendor-specific
+</dt>
+<dd>
+<p>
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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 huawei id-ctrl /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-huawei-id-ctrl.txt b/Documentation/nvme-huawei-id-ctrl.txt
new file mode 100644
index 0000000..47225d1
--- /dev/null
+++ b/Documentation/nvme-huawei-id-ctrl.txt
@@ -0,0 +1,66 @@
+nvme-huawei-id-ctrl(1)
+======================
+
+NAME
+----
+nvme-huawei-id-ctrl - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme huawei id-ctrl' <device> [--vendor-specific | -v] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an 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).
+
+This will only work on Huawei devices supporting this feature.
+Results for any other device are undefined.
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+If having the program decode the output for readability, this version
+will decode Huawei vendor unique portions of the structure.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-v::
+--vendor-specific::
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ 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 huawei id-ctrl /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-huawei-list.1 b/Documentation/nvme-huawei-list.1
new file mode 100644
index 0000000..f3c0bb2
--- /dev/null
+++ b/Documentation/nvme-huawei-list.1
@@ -0,0 +1,54 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST" "1" "02/14/2024" "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-huawei-list \- List all recognized Huawei NVMe devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme huawei list\fR [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Scan the sysfs tree for NVM Express devices and return the /dev node for those Huawei devices as well as some pertinent information about them\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+or
+\fIjson\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-huawei-list.html b/Documentation/nvme-huawei-list.html
new file mode 100644
index 0000000..5d3bbaa
--- /dev/null
+++ b/Documentation/nvme-huawei-list.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 10.2.0" />
+<title>nvme-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 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-list(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-huawei-list -
+ List all recognized Huawei NVMe devices
+</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 huawei list</em> [--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>Scan the sysfs tree for NVM Express devices and return the /dev node
+for those Huawei devices as well as some pertinent information about them.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> or <em>json</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="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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-huawei-list.txt b/Documentation/nvme-huawei-list.txt
new file mode 100644
index 0000000..95f1099
--- /dev/null
+++ b/Documentation/nvme-huawei-list.txt
@@ -0,0 +1,31 @@
+nvme-list(1)
+============
+
+NAME
+----
+nvme-huawei-list - List all recognized Huawei NVMe devices
+
+SYNOPSIS
+--------
+[verse]
+'nvme huawei list' [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Scan the sysfs tree for NVM Express devices and return the /dev node
+for those Huawei devices as well as some pertinent information about them.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json'. Only one output
+ format can be used at a time.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-ctrl.1 b/Documentation/nvme-id-ctrl.1
new file mode 100644
index 0000000..97214b6
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.1
@@ -0,0 +1,202 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-CTRL" "1" "02/14/2024" "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-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-ctrl\fR <device> [\-\-vendor\-specific | \-V] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-V, \-\-vendor\-specific
+.RS 4
+In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii interpretation\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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 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
+.\}
+In addition to showing the known fields, has the program to display the vendor unique field:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ctrl /dev/nvme0 \-\-vendor\-specific
+# nvme id\-ctrl /dev/nvme0 \-V
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The above will dump the
+\fIvs\fR
+buffer in hex since it doesn\(cqt know how to interpret it\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ctrl /dev/nvme0 \-\-raw\-binary > id_ctrl\&.raw
+# nvme id\-ctrl /dev/nvme0 \-b > id_ctrl\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Alternatively you may want to send the data to another program that can parse the raw buffer\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ctrl /dev/nvme0 \-\-raw\-binary | nvme_parse_id_ctrl
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The parse program in the above example can be a program that shows the structure in a way you like\&. The following program is such an example that will parse it and can accept the output through a pipe,
+\*(Aq|\*(Aq, as shown in the above example, or you can
+\*(Aqcat\*(Aq
+a saved output buffer to it\&.
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/* File: nvme_parse_id_ctrl\&.c */
+
+#include <linux/nvme\&.h>
+#include <stdio\&.h>
+#include <unistd\&.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ctrl)];
+ struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("vid : %#x\en", ctrl\->vid);
+ printf("ssvid : %#x\en", ctrl\->ssvid);
+ return 0;
+}
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-ctrl.html b/Documentation/nvme-id-ctrl.html
new file mode 100644
index 0000000..9c00c75
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.html
@@ -0,0 +1,928 @@
+<?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 10.2.0" />
+<title>nvme-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 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-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-ctrl -
+ Send NVMe 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 id-ctrl</em> &lt;device&gt; [--vendor-specific | -V] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dt class="hdlist1">
+--vendor-specific
+</dt>
+<dd>
+<p>
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 id-ctrl /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+In addition to showing the known fields, has the program to display
+the vendor unique field:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ctrl /dev/nvme0 --vendor-specific
+# nvme id-ctrl /dev/nvme0 -V</code></pre>
+</div></div>
+<div class="paragraph"><p>The above will dump the <em>vs</em> buffer in hex since it doesn&#8217;t know how to
+interpret it.</p></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ctrl /dev/nvme0 --raw-binary &gt; id_ctrl.raw
+# nvme id-ctrl /dev/nvme0 -b &gt; id_ctrl.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>
+<li>
+<p>
+Alternatively you may want to send the data to another program that
+can parse the raw buffer.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ctrl /dev/nvme0 --raw-binary | nvme_parse_id_ctrl</code></pre>
+</div></div>
+<div class="paragraph"><p>The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, <code>'|'</code>,
+as shown in the above example, or you can <code>'cat'</code> a saved output buffer to it.</p></div>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>/* File: nvme_parse_id_ctrl.c */
+
+#include &lt;linux/nvme.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;unistd.h&gt;
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ctrl)];
+ struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("vid : %#x\n", ctrl-&gt;vid);
+ printf("ssvid : %#x\n", ctrl-&gt;ssvid);
+ return 0;
+}</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-ctrl.txt b/Documentation/nvme-id-ctrl.txt
new file mode 100644
index 0000000..3667c63
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.txt
@@ -0,0 +1,117 @@
+nvme-id-ctrl(1)
+===============
+
+NAME
+----
+nvme-id-ctrl - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ctrl' <device> [--vendor-specific | -V] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-V::
+--vendor-specific::
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme id-ctrl /dev/nvme0
+------------
++
+
+* In addition to showing the known fields, has the program to display
+the vendor unique field:
++
+------------
+# nvme id-ctrl /dev/nvme0 --vendor-specific
+# nvme id-ctrl /dev/nvme0 -V
+------------
++
+The above will dump the 'vs' buffer in hex since it doesn't know how to
+interpret it.
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme id-ctrl /dev/nvme0 --raw-binary > id_ctrl.raw
+# nvme id-ctrl /dev/nvme0 -b > id_ctrl.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+* Alternatively you may want to send the data to another program that
+can parse the raw buffer.
++
+------------
+# nvme id-ctrl /dev/nvme0 --raw-binary | nvme_parse_id_ctrl
+------------
++
+The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, `'|'`,
+as shown in the above example, or you can `'cat'` a saved output buffer to it.
+------------
+/* File: nvme_parse_id_ctrl.c */
+
+#include <linux/nvme.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ctrl)];
+ struct nvme_id_ctrl *ctrl = (struct nvme_id_ctrl *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("vid : %#x\n", ctrl->vid);
+ printf("ssvid : %#x\n", ctrl->ssvid);
+ return 0;
+}
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-domain.1 b/Documentation/nvme-id-domain.1
new file mode 100644
index 0000000..f905dd6
--- /dev/null
+++ b/Documentation/nvme-id-domain.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-id-domain
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-DOMAIN" "1" "02/14/2024" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-id-domain \- Send NVMe Identify Domain List, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-domain\fR <device> [\-\-dom\-id=<domian_id> | \-d <domian_id>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send an identify command and return the domain list 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
+\-d <domian_id>, \-\-dom\-id=<domian_id>
+.RS 4
+Retrieve the identify domain list data structure for the given domain id\&. If this value is not given, domain id will be 0xffff\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-domain.html b/Documentation/nvme-id-domain.html
new file mode 100644
index 0000000..dffc249
--- /dev/null
+++ b/Documentation/nvme-id-domain.html
@@ -0,0 +1,830 @@
+<?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 10.2.0" />
+<title>nvme-id-domain(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-id-domain(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-domain -
+ Send NVMe Identify Domain List, 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-domain</em> &lt;device&gt; [--dom-id=&lt;domian_id&gt; | -d &lt;domian_id&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 domain list
+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">
+-d &lt;domian_id&gt;
+</dt>
+<dt class="hdlist1">
+--dom-id=&lt;domian_id&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify domain list data structure for the given
+ domain id. If this value is not given, domain id will be 0xffff.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-domain.txt b/Documentation/nvme-id-domain.txt
new file mode 100644
index 0000000..1d6ec48
--- /dev/null
+++ b/Documentation/nvme-id-domain.txt
@@ -0,0 +1,44 @@
+nvme-id-domain(1)
+=================
+
+NAME
+----
+nvme-id-domain - Send NVMe Identify Domain List, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-domain' <device> [--dom-id=<domian_id> | -d <domian_id>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send an identify command and return the domain list
+data structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-d <domian_id>::
+--dom-id=<domian_id>::
+ Retrieve the identify domain list data structure for the given
+ domain id. If this value is not given, domain id will be 0xffff.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-iocs.1 b/Documentation/nvme-id-iocs.1
new file mode 100644
index 0000000..e6918cd
--- /dev/null
+++ b/Documentation/nvme-id-iocs.1
@@ -0,0 +1,113 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-IOCS" "1" "02/14/2024" "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>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.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
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+show the fields in human readable format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-iocs /dev/nvme0 \-H
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-iocs.html b/Documentation/nvme-id-iocs.html
new file mode 100644
index 0000000..704ddae
--- /dev/null
+++ b/Documentation/nvme-id-iocs.html
@@ -0,0 +1,862 @@
+<?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 10.2.0" />
+<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 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-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;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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>
+<li>
+<p>
+show the fields in human readable format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-iocs /dev/nvme0 -H</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-iocs.txt b/Documentation/nvme-id-iocs.txt
new file mode 100644
index 0000000..bb85aef
--- /dev/null
+++ b/Documentation/nvme-id-iocs.txt
@@ -0,0 +1,58 @@
+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>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+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.
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Have the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme id-iocs /dev/nvme0
+------------
++
+* show the fields in human readable format
++
+------------
+# nvme id-iocs /dev/nvme0 -H
+------------
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-ns-granularity.txt b/Documentation/nvme-id-ns-granularity.txt
new file mode 100755
index 0000000..67006c3
--- /dev/null
+++ b/Documentation/nvme-id-ns-granularity.txt
@@ -0,0 +1,46 @@
+nvme-id-ns-granularity(1)
+=========================
+
+NAME
+----
+nvme-id-ns-granularity - Send a Identify Namespace Granularity List command to
+the specified device
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ns-granularity' <device>
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send a Identify Namespace Granularity List command command to the specified
+device, return results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a id-ns-granularity to display structure.
++
+------------
+# nvme id-ns-granularity /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-id-ns-lba-format.1 b/Documentation/nvme-id-ns-lba-format.1
new file mode 100644
index 0000000..cb6c2a9
--- /dev/null
+++ b/Documentation/nvme-id-ns-lba-format.1
@@ -0,0 +1,172 @@
+'\" t
+.\" Title: nvme-id-ns-lba-format
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 01/07/2022
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS\-LBA\-F" "1" "01/07/2022" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-id-ns-lba-format \- Send NVMe Identify Namespace for the specified LBA Format index, display structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-ns\fR <device> [\-\-uuid\-index=<uuid\-index> | \-U <uuid_index>]
+ [\-\-lba\-format\-index=<lba_format_index> | \-i <lba_format_index>]
+ [\-v | \-\-verbose]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify namespace for the specified LBA Format index command and provides the result that is include capability field only 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-U <uuid\-index>, \-\-uuid\-index=<uuid\-index>
+.RS 4
+UUID Index of the feature
+.RE
+.PP
+\-i <lba_format_index>, \-\-lba\-format\-index=<lba_format_index>
+.RS 4
+This field specifies the index into the LBA Format list identifying the LBA Format capabilities that are to be returned
+.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 id\-ns\-lba\-format /dev/nvme0n1 \-i 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns\-lba\-format /dev/nvme0n1 \-i 0 \-o binary > id_ns\&.raw
+# nvme id\-ns\-lba\-format /dev/nvme0n1 \-i 0 \-\-output\-format=binary > id_ns\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Alternatively you may want to send the data to another program that can parse the raw buffer\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns\-lba\-format /dev/nvme0n1 \-i 0 \-\-raw\-binary | nvme_parse_id_ns
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The parse program in the above example can be a program that shows the structure in a way you like\&. The following program is such an example that will parse it and can accept the output through a pipe,
+\*(Aq|\*(Aq, as shown in the above example, or you can
+\*(Aqcat\*(Aq
+a saved output buffer to it\&.
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/* File: nvme_parse_id_ns_lba_format\&.c */
+
+#include <linux/nvme\&.h>
+#include <stdio\&.h>
+#include <unistd\&.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\en", ns\->nlbaf);
+ printf("ncap : %#llx\en", ns\->mc);
+ return 0;
+}
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-ns-lba-format.html b/Documentation/nvme-id-ns-lba-format.html
new file mode 100644
index 0000000..1a4b83f
--- /dev/null
+++ b/Documentation/nvme-id-ns-lba-format.html
@@ -0,0 +1,901 @@
+<!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-id-ns-lba-format(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 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-id-ns-lba-format(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-ns-lba-format -
+ Send NVMe Identify Namespace for the specified LBA Format index, display 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-ns</em> &lt;device&gt; [--uuid-index=&lt;uuid-index&gt; | -U &lt;uuid_index&gt;]
+ [--lba-format-index=&lt;lba_format_index&gt; | -i &lt;lba_format_index&gt;]
+ [-v | --verbose]
+ [--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 an identify namespace for
+the specified LBA Format index command and provides the result
+that is include capability field only 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-U &lt;uuid-index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid-index=&lt;uuid-index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index of the feature
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;lba_format_index&gt;
+</dt>
+<dt class="hdlist1">
+--lba-format-index=&lt;lba_format_index&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the index into the LBA Format list identifying
+ the LBA Format capabilities that are to be returned
+</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 id-ns-lba-format /dev/nvme0n1 -i 0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns-lba-format /dev/nvme0n1 -i 0 -o binary &gt; id_ns.raw
+# nvme id-ns-lba-format /dev/nvme0n1 -i 0 --output-format=binary &gt; id_ns.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>
+<li>
+<p>
+Alternatively you may want to send the data to another program that
+can parse the raw buffer.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns-lba-format /dev/nvme0n1 -i 0 --raw-binary | nvme_parse_id_ns</code></pre>
+</div></div>
+<div class="paragraph"><p>The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, <code>'|'</code>,
+as shown in the above example, or you can <code>'cat'</code> a saved output buffer
+to it.</p></div>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>/* File: nvme_parse_id_ns_lba_format.c */
+
+#include &lt;linux/nvme.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;unistd.h&gt;
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\n", ns-&gt;nlbaf);
+ printf("ncap : %#llx\n", ns-&gt;mc);
+ return 0;
+}</code></pre>
+</div></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 2022-01-07 13:48:12 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-ns-lba-format.txt b/Documentation/nvme-id-ns-lba-format.txt
new file mode 100644
index 0000000..514ba48
--- /dev/null
+++ b/Documentation/nvme-id-ns-lba-format.txt
@@ -0,0 +1,102 @@
+nvme-id-ns-lba-format(1)
+========================
+
+NAME
+----
+nvme-id-ns-lba-format - Send NVMe Identify Namespace for the specified LBA Format index, display structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ns' <device> [--uuid-index=<uuid-index> | -U <uuid_index>]
+ [--lba-format-index=<lba_format_index> | -i <lba_format_index>]
+ [--verbose | -v]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify namespace for
+the specified LBA Format index command and provides the result
+that is include capability field only and returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-U <uuid-index>::
+--uuid-index=<uuid-index>::
+ UUID Index of the feature
+
+-i <lba_format_index>::
+--lba-format-index=<lba_format_index>::
+ This field specifies the index into the LBA Format list identifying
+ the LBA Format capabilities that are to be returned
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+-o <fmt>::
+--output-format=<fmt>::
+ 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 id-ns-lba-format /dev/nvme0n1 -i 0
+------------
++
+* Have the program return the raw structure in binary:
++
+------------
+# nvme id-ns-lba-format /dev/nvme0n1 -i 0 -o binary > id_ns.raw
+# nvme id-ns-lba-format /dev/nvme0n1 -i 0 --output-format=binary > id_ns.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+* Alternatively you may want to send the data to another program that
+can parse the raw buffer.
++
+------------
+# nvme id-ns-lba-format /dev/nvme0n1 -i 0 --raw-binary | nvme_parse_id_ns
+------------
++
+The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, `'|'`,
+as shown in the above example, or you can `'cat'` a saved output buffer
+to it.
+------------
+/* File: nvme_parse_id_ns_lba_format.c */
+
+#include <linux/nvme.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\n", ns->nlbaf);
+ printf("ncap : %#llx\n", ns->mc);
+ return 0;
+}
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-ns.1 b/Documentation/nvme-id-ns.1
new file mode 100644
index 0000000..1a44058
--- /dev/null
+++ b/Documentation/nvme-id-ns.1
@@ -0,0 +1,235 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "02/14/2024" "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-ns \- Send NVMe Identify Namespace, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-ns\fR <device> [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>] [\-\-force]
+ [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify namespace 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)\&. If the character device is given, the \*(Aq\-\-namespace\-id\*(Aq option is mandatory, otherwise it will use the ns\-id of the namespace for the block device you opened\&. For block devices, the ns\-id used can be overridden with the same option\&.
+.sp
+On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the identify namespace structure for the given nsid\&. This is required for the character devices, or overrides the block nsid if given\&. If the controller supports namespace management capability and 0xFFFFFFFF is given, then the controller returns the identify namespace structure that specifies common capabilities across namespaces for the controller\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Request controller return the identify namespace structure even if the namespace is not attached to the controller\&. This is valid only for controllers at or newer than revision 1\&.2\&. Controllers at revision lower than this may interpret the command incorrectly\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-V, \-\-vendor\-specific
+.RS 4
+In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii interpretation\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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 id\-ns /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If using the character device or overriding namespace id:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns /dev/nvme0 \-n 1
+# nvme id\-ns /dev/nvme0n1 \-n 1
+# nvme id\-ns /dev/nvme0 \-\-namespace\-id=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+In addition to showing the known fields, have the program to display the vendor unique field:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns /dev/nvme0n1 \-\-vendor\-specific
+# nvme id\-ns /dev/nvme0n1 \-V
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The above will dump the \*(Aqvs\*(Aq buffer in hex since it doesn\(cqt know how to interpret it\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns /dev/nvme0n1 \-\-raw\-binary > id_ns\&.raw
+# nvme id\-ns /dev/nvme0n1 \-b > id_ns\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Alternatively you may want to send the data to another program that can parse the raw buffer\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-ns /dev/nvme0n1 \-\-raw\-binary | nvme_parse_id_ns
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The parse program in the above example can be a program that shows the structure in a way you like\&. The following program is such an example that will parse it and can accept the output through a pipe,
+\*(Aq|\*(Aq, as shown in the above example, or you can
+\*(Aqcat\*(Aq
+a saved output buffer to it\&.
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+/* File: nvme_parse_id_ns\&.c */
+
+#include <linux/nvme\&.h>
+#include <stdio\&.h>
+#include <unistd\&.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\en", ns\->nsze);
+ printf("ncap : %#llx\en", ns\->ncap);
+ return 0;
+}
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-ns.html b/Documentation/nvme-id-ns.html
new file mode 100644
index 0000000..20044bc
--- /dev/null
+++ b/Documentation/nvme-id-ns.html
@@ -0,0 +1,973 @@
+<?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 10.2.0" />
+<title>nvme-id-ns(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-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-ns -
+ Send NVMe Identify Namespace, 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-ns</em> &lt;device&gt; [--vendor-specific | -v] [--raw-binary | -b]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;] [--force]
+ [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify namespace 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).
+If the character device is given, the <code>'--namespace-id'</code> option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.</p></div>
+<div class="paragraph"><p>On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify namespace structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given. If the controller supports namespace management capability
+ and 0xFFFFFFFF is given, then the controller returns the identify
+ namespace structure that specifies common capabilities across
+ namespaces for the controller.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Request controller return the identify namespace structure even
+ if the namespace is not attached to the controller. This is valid
+ only for controllers at or newer than revision 1.2. Controllers
+ at revision lower than this may interpret the command incorrectly.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dt class="hdlist1">
+--vendor-specific
+</dt>
+<dd>
+<p>
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 id-ns /dev/nvme0n1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+If using the character device or overriding namespace id:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns /dev/nvme0 -n 1
+# nvme id-ns /dev/nvme0n1 -n 1
+# nvme id-ns /dev/nvme0 --namespace-id=1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+In addition to showing the known fields, have the program to display
+the vendor unique field:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns /dev/nvme0n1 --vendor-specific
+# nvme id-ns /dev/nvme0n1 -V</code></pre>
+</div></div>
+<div class="paragraph"><p>The above will dump the 'vs' buffer in hex since it doesn&#8217;t know how to
+interpret it.</p></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns /dev/nvme0n1 --raw-binary &gt; id_ns.raw
+# nvme id-ns /dev/nvme0n1 -b &gt; id_ns.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>
+<li>
+<p>
+Alternatively you may want to send the data to another program that
+can parse the raw buffer.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-ns /dev/nvme0n1 --raw-binary | nvme_parse_id_ns</code></pre>
+</div></div>
+<div class="paragraph"><p>The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, <code>'|'</code>,
+as shown in the above example, or you can <code>'cat'</code> a saved output buffer
+to it.</p></div>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>/* File: nvme_parse_id_ns.c */
+
+#include &lt;linux/nvme.h&gt;
+#include &lt;stdio.h&gt;
+#include &lt;unistd.h&gt;
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\n", ns-&gt;nsze);
+ printf("ncap : %#llx\n", ns-&gt;ncap);
+ return 0;
+}</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-ns.txt b/Documentation/nvme-id-ns.txt
new file mode 100644
index 0000000..0791250
--- /dev/null
+++ b/Documentation/nvme-id-ns.txt
@@ -0,0 +1,148 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-id-ns - Send NVMe Identify Namespace, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ns' <device> [--vendor-specific | -v] [--raw-binary | -b]
+ [--namespace-id=<nsid> | -n <nsid>] [--force]
+ [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify namespace 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).
+If the character device is given, the `'--namespace-id'` option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the identify namespace structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given. If the controller supports namespace management capability
+ and 0xFFFFFFFF is given, then the controller returns the identify
+ namespace structure that specifies common capabilities across
+ namespaces for the controller.
+
+--force::
+ Request controller return the identify namespace structure even
+ if the namespace is not attached to the controller. This is valid
+ only for controllers at or newer than revision 1.2. Controllers
+ at revision lower than this may interpret the command incorrectly.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-V::
+--vendor-specific::
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme id-ns /dev/nvme0n1
+------------
++
+
+* If using the character device or overriding namespace id:
++
+------------
+# nvme id-ns /dev/nvme0 -n 1
+# nvme id-ns /dev/nvme0n1 -n 1
+# nvme id-ns /dev/nvme0 --namespace-id=1
+------------
++
+
+* In addition to showing the known fields, have the program to display
+the vendor unique field:
++
+------------
+# nvme id-ns /dev/nvme0n1 --vendor-specific
+# nvme id-ns /dev/nvme0n1 -V
+------------
++
+The above will dump the \'vs' buffer in hex since it doesn't know how to
+interpret it.
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme id-ns /dev/nvme0n1 --raw-binary > id_ns.raw
+# nvme id-ns /dev/nvme0n1 -b > id_ns.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+* Alternatively you may want to send the data to another program that
+can parse the raw buffer.
++
+------------
+# nvme id-ns /dev/nvme0n1 --raw-binary | nvme_parse_id_ns
+------------
++
+The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, `'|'`,
+as shown in the above example, or you can `'cat'` a saved output buffer
+to it.
+------------
+/* File: nvme_parse_id_ns.c */
+
+#include <linux/nvme.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ unsigned char buf[sizeof(struct nvme_id_ns)];
+ struct nvme_id_ns *ns = (struct nvme_id_ns *)buf;
+
+ if (read(STDIN_FILENO, buf, sizeof(buf)))
+ return 1;
+
+ printf("nsze : %#llx\n", ns->nsze);
+ printf("ncap : %#llx\n", ns->ncap);
+ return 0;
+}
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-nvmset.1 b/Documentation/nvme-id-nvmset.1
new file mode 100644
index 0000000..4a5f82c
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.1
@@ -0,0 +1,148 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NVMSET" "1" "02/14/2024" "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-nvmset \- Send NVMe Identify NVM Set List, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-nvmset\fR <device> [\-\-nvmset_id=<id> | \-i <id>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify NVM set list 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-i <id>, \-\-nvmset_id=<id>
+.RS 4
+This field specifies the identifier of the NVM Set\&. If given, NVM set identifier whose entry is to be in result data will be greater than or equal to this value\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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 id\-nvmset /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
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-nvmset /dev/nvme0 \-\-output\-format=binary > id_nvmset\&.raw
+# nvme id\-nvmset /dev/nvme0 \-o binary > id_nvmset\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Alternatively you may want to send the data to another program that can parse the raw buffer\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme id\-nvmset /dev/nvme0 \-o binary | nvme_parse_id_nvmset
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+The parse program in the above example can be a program that shows the structure in a way you like\&. The following program is such an example that will parse it and can accept the output through a pipe,
+\*(Aq|\*(Aq, as shown in the above example, or you can
+\*(Aqcat\*(Aq
+a saved output buffer to it\&.
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+NVME
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-id-nvmset.html b/Documentation/nvme-id-nvmset.html
new file mode 100644
index 0000000..535bb73
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.html
@@ -0,0 +1,869 @@
+<?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 10.2.0" />
+<title>nvme-id-nvmset(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-id-nvmset(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-id-nvmset -
+ Send NVMe Identify NVM Set List, 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-nvmset</em> &lt;device&gt; [--nvmset_id=&lt;id&gt; | -i &lt;id&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify NVM set list 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-i &lt;id&gt;
+</dt>
+<dt class="hdlist1">
+--nvmset_id=&lt;id&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the identifier of the NVM Set. If given, NVM set
+ identifier whose entry is to be in result data will be greater than or
+ equal to this value.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 id-nvmset /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-nvmset /dev/nvme0 --output-format=binary &gt; id_nvmset.raw
+# nvme id-nvmset /dev/nvme0 -o binary &gt; id_nvmset.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>
+<li>
+<p>
+Alternatively you may want to send the data to another program that
+can parse the raw buffer.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme id-nvmset /dev/nvme0 -o binary | nvme_parse_id_nvmset</code></pre>
+</div></div>
+<div class="paragraph"><p>The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, <code>'|'</code>,
+as shown in the above example, or you can <code>'cat'</code> a saved output buffer to it.</p></div>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>NVME</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-nvmset.txt b/Documentation/nvme-id-nvmset.txt
new file mode 100644
index 0000000..e2894e3
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.txt
@@ -0,0 +1,77 @@
+nvme-id-nvmset(1)
+=================
+
+NAME
+----
+nvme-id-nvmset - Send NVMe Identify NVM Set List, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-nvmset' <device> [--nvmset_id=<id> | -i <id>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify NVM set list command and
+provides the result and returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-i <id>::
+--nvmset_id=<id>::
+ This field specifies the identifier of the NVM Set. If given, NVM set
+ identifier whose entry is to be in result data will be greater than or
+ equal to this value.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme id-nvmset /dev/nvme0
+------------
++
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme id-nvmset /dev/nvme0 --output-format=binary > id_nvmset.raw
+# nvme id-nvmset /dev/nvme0 -o binary > id_nvmset.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+* Alternatively you may want to send the data to another program that
+can parse the raw buffer.
++
+------------
+# nvme id-nvmset /dev/nvme0 -o binary | nvme_parse_id_nvmset
+------------
++
+The parse program in the above example can be a program that shows the
+structure in a way you like. The following program is such an example
+that will parse it and can accept the output through a pipe, `'|'`,
+as shown in the above example, or you can `'cat'` a saved output buffer to it.
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-id-uuid.txt b/Documentation/nvme-id-uuid.txt
new file mode 100755
index 0000000..f7cc1c0
--- /dev/null
+++ b/Documentation/nvme-id-uuid.txt
@@ -0,0 +1,55 @@
+nvme-id-uuid(1)
+===============
+
+NAME
+----
+nvme-id-uuid - Send a Identify UUID List command to the specified device
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-uuid' <device> [--raw-binary | -b] [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send a Identify UUID List command command to the specified device, return
+results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a id-uuid to display structure.
++
+------------
+# nvme id-uuid /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-inspur-nvme-vendor-log.1 b/Documentation/nvme-inspur-nvme-vendor-log.1
new file mode 100644
index 0000000..4ccea25
--- /dev/null
+++ b/Documentation/nvme-inspur-nvme-vendor-log.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-inspur-nvme-vendor-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INSPUR\-NVME\-" "1" "02/14/2024" "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-inspur-nvme-vendor-log \- Send NVMe Inspur Device Vendor log page request, returns result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme inspur nvme\-vendor\-log\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Inspur Device Vendor log page from the 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, vendor log structure are printed in a readable format\&.
+.SH "OPTIONS"
+.sp
+none
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Inspur Device Vendor log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme inspur nvme\-vendor\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-inspur-nvme-vendor-log.html b/Documentation/nvme-inspur-nvme-vendor-log.html
new file mode 100644
index 0000000..424c26d
--- /dev/null
+++ b/Documentation/nvme-inspur-nvme-vendor-log.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 10.2.0" />
+<title>nvme-inspur-nvme-vendor-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 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-inspur-nvme-vendor-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-inspur-nvme-vendor-log -
+ Send NVMe Inspur Device Vendor log page request, returns 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 inspur nvme-vendor-log</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>Retrieves the NVMe Inspur Device Vendor log page from the 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, vendor log structure are printed in a readable format.</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>
+Print the Inspur Device Vendor log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme inspur nvme-vendor-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-inspur-nvme-vendor-log.txt b/Documentation/nvme-inspur-nvme-vendor-log.txt
new file mode 100644
index 0000000..c860497
--- /dev/null
+++ b/Documentation/nvme-inspur-nvme-vendor-log.txt
@@ -0,0 +1,36 @@
+nvme-inspur-nvme-vendor-log(1)
+==============================
+
+NAME
+----
+nvme-inspur-nvme-vendor-log - Send NVMe Inspur Device Vendor log page request, returns result
+
+SYNOPSIS
+--------
+[verse]
+'nvme inspur nvme-vendor-log' <device>
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Inspur Device Vendor log page from the 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, vendor log structure are printed in a readable format.
+
+OPTIONS
+-------
+none
+
+EXAMPLES
+--------
+* Print the Inspur Device Vendor log page in a human readable format:
++
+------------
+# nvme inspur nvme-vendor-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-intel-id-ctrl.1 b/Documentation/nvme-intel-id-ctrl.1
new file mode 100644
index 0000000..2c1a4d9
--- /dev/null
+++ b/Documentation/nvme-intel-id-ctrl.1
@@ -0,0 +1,95 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-ID\-CTR" "1" "02/14/2024" "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-intel-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel id\-ctrl\fR <device> [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.sp
+If having the program decode the output for readability, this version will decode Intel vendor unique portions of the structure\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-v, \-\-vendor\-specific
+.RS 4
+In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii interpretation\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 intel id\-ctrl /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-intel-id-ctrl.html b/Documentation/nvme-intel-id-ctrl.html
new file mode 100644
index 0000000..aabaa2f
--- /dev/null
+++ b/Documentation/nvme-intel-id-ctrl.html
@@ -0,0 +1,860 @@
+<?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 10.2.0" />
+<title>nvme-intel-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 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-intel-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-id-ctrl -
+ Send NVMe 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 intel id-ctrl</em> &lt;device&gt; [--vendor-specific | -v] [--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>For the NVMe device given, sends an 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+<div class="paragraph"><p>If having the program decode the output for readability, this version
+will decode Intel vendor unique portions of the structure.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--vendor-specific
+</dt>
+<dd>
+<p>
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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 intel id-ctrl /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-id-ctrl.txt b/Documentation/nvme-intel-id-ctrl.txt
new file mode 100644
index 0000000..469d60e
--- /dev/null
+++ b/Documentation/nvme-intel-id-ctrl.txt
@@ -0,0 +1,63 @@
+nvme-intel-id-ctrl(1)
+=====================
+
+NAME
+----
+nvme-intel-id-ctrl - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel id-ctrl' <device> [--vendor-specific | -v] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+If having the program decode the output for readability, this version
+will decode Intel vendor unique portions of the structure.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-v::
+--vendor-specific::
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ 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 intel id-ctrl /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-intel-internal-log.1 b/Documentation/nvme-intel-internal-log.1
new file mode 100644
index 0000000..0bec162
--- /dev/null
+++ b/Documentation/nvme-intel-internal-log.1
@@ -0,0 +1,120 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-INTERNA" "1" "02/14/2024" "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-intel-internal-log \- Retrieve Intel device\*(Aqs internal log and save to file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\*(Aqnvme intel internal\-log \*(Aq <device> [\-\-log=<NUM>, \-l <NUM>]
+ [\-\-region=<NUM>, r <NUM>]
+ [\-\-nlognum=<NUM>, m <NUM>]
+ [\-\-namespace\-id=<NUM>, \-n <NUM>]
+ [\-\-output\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Intel vendor unique device log request and saves the result to a file\&.
+.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)\&. If using the character device, the namespace id parameter is mandatory\&.
+.sp
+This will only work on Intel devices supporting this feature which includes (but not limited to) all the Intel DC P3xxx family of controllers\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.PP
+\-l <NUM>, \-\-log=<NUM>
+.RS 4
+Log type: 0, 1, or 2 for nlog, event log, and assert log, respectively\&.
+.RE
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Namespace to use\&.
+.RE
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device name provided
+.RE
+.PP
+\-r <NUM>, \-\-region=<NUM>
+.RS 4
+Select which core region to retrieve the log from\&. \-1 for all available, if supported by the device\&.
+.RE
+.PP
+\-m <NUM>, \-\-nlognum=<NUM>
+.RS 4
+When used with
+\fInlog\fR, this specifies which nlog to read\&. \-1 for all, if supported by the device\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the nlog from the device and saves to default file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel internal\-log /dev/nvme0 \-\-namespace\-id=1 \-\-log=0
+.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 event log from the device and saves to defined file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel internal\-log /dev/nvme0 \-\-namespace\-id=1 \-\-log=1 \-\-output\-file=MyAwesomeEventLog
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-intel-internal-log.html b/Documentation/nvme-intel-internal-log.html
new file mode 100644
index 0000000..aca2133
--- /dev/null
+++ b/Documentation/nvme-intel-internal-log.html
@@ -0,0 +1,880 @@
+<?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 10.2.0" />
+<title>nvme-intel-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 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-intel-internal-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-internal-log -
+ Retrieve Intel device's internal log and save to file.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">'nvme intel internal-log ' &lt;device&gt; [--log=&lt;NUM&gt;, -l &lt;NUM&gt;]
+ [--region=&lt;NUM&gt;, r &lt;NUM&gt;]
+ [--nlognum=&lt;NUM&gt;, m &lt;NUM&gt;]
+ [--namespace-id=&lt;NUM&gt;, -n &lt;NUM&gt;]
+ [--output-file=&lt;FILE&gt;, -o &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, sends the Intel vendor unique device log
+request and saves the result to a file.</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). If using the character device, the namespace id parameter
+is mandatory.</p></div>
+<div class="paragraph"><p>This will only work on Intel devices supporting this feature which
+includes (but not limited to) all the Intel DC P3xxx family of
+controllers. 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;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--log=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Log type: 0, 1, or 2 for nlog, event log, and assert log,
+ respectively.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Namespace to use.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output file; defaults to device name provided
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--region=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Select which core region to retrieve the log from. -1 for all
+ available, if supported by the device.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--nlognum=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ When used with <em>nlog</em>, this specifies which nlog to read. -1
+ for all, if supported by the device.
+</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 nlog from the device and saves to default file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel internal-log /dev/nvme0 --namespace-id=1 --log=0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the event log from the device and saves to defined file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel internal-log /dev/nvme0 --namespace-id=1 --log=1 --output-file=MyAwesomeEventLog</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-internal-log.txt b/Documentation/nvme-intel-internal-log.txt
new file mode 100644
index 0000000..a1e1792
--- /dev/null
+++ b/Documentation/nvme-intel-internal-log.txt
@@ -0,0 +1,73 @@
+nvme-intel-internal-log(1)
+==========================
+
+NAME
+----
+nvme-intel-internal-log - Retrieve Intel device's internal log and save to file.
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel internal-log ' <device> [--log=<NUM>, -l <NUM>]
+ [--region=<NUM>, r <NUM>]
+ [--nlognum=<NUM>, m <NUM>]
+ [--namespace-id=<NUM>, -n <NUM>]
+ [--output-file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Intel vendor unique device log
+request and saves the result to a file.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1). If using the character device, the namespace id parameter
+is mandatory.
+
+This will only work on Intel devices supporting this feature which
+includes (but not limited to) all the Intel DC P3xxx family of
+controllers. Results for any other device are undefined.
+
+OPTIONS
+-------
+-l <NUM>::
+--log=<NUM>::
+ Log type: 0, 1, or 2 for nlog, event log, and assert log,
+ respectively.
+
+-n <NUM>::
+--namespace-id=<NUM>::
+ Namespace to use.
+
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device name provided
+
+-r <NUM>::
+--region=<NUM>::
+ Select which core region to retrieve the log from. -1 for all
+ available, if supported by the device.
+
+-m <NUM>::
+--nlognum=<NUM>::
+ When used with 'nlog', this specifies which nlog to read. -1
+ for all, if supported by the device.
+
+EXAMPLES
+--------
+* Gets the nlog from the device and saves to default file:
++
+------------
+# nvme intel internal-log /dev/nvme0 --namespace-id=1 --log=0
+------------
++
+
+* Gets the event log from the device and saves to defined file:
++
+------------
+# nvme intel internal-log /dev/nvme0 --namespace-id=1 --log=1 --output-file=MyAwesomeEventLog
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-intel-lat-stats.1 b/Documentation/nvme-intel-lat-stats.1
new file mode 100644
index 0000000..7b04288
--- /dev/null
+++ b/Documentation/nvme-intel-lat-stats.1
@@ -0,0 +1,100 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-LAT\-ST" "1" "02/14/2024" "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-intel-lat-stats \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel lat\-stats\fR <device> [\-\-write | \-w] [\-\-raw\-binary | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, retrieves intel vendor specific latency statistics 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-w, \-\-write
+.RS 4
+Get write statistics\&. Read statistics are returned by default\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the read statistics
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel lat\-stats /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
+.\}
+Get the write statistics
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel lat\-stats /dev/nvme0 \-w
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-intel-lat-stats.html b/Documentation/nvme-intel-lat-stats.html
new file mode 100644
index 0000000..837e17e
--- /dev/null
+++ b/Documentation/nvme-intel-lat-stats.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 10.2.0" />
+<title>nvme-intel-lat-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-intel-lat-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-lat-stats -
+ Send NVMe 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 intel lat-stats</em> &lt;device&gt; [--write | -w] [--raw-binary | -b]</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, retrieves intel vendor specific latency statistics 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--write
+</dt>
+<dd>
+<p>
+ Get write statistics. Read statistics are returned by default.
+</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 read statistics
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel lat-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get the write statistics
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel lat-stats /dev/nvme0 -w</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-lat-stats.txt b/Documentation/nvme-intel-lat-stats.txt
new file mode 100644
index 0000000..767cf92
--- /dev/null
+++ b/Documentation/nvme-intel-lat-stats.txt
@@ -0,0 +1,53 @@
+nvme-intel-lat-stats(1)
+=======================
+
+NAME
+----
+nvme-intel-lat-stats - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel lat-stats' <device> [--write | -w] [--raw-binary | -b]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves intel vendor specific latency statistics and
+provides the result and returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-w::
+--write::
+ Get write statistics. Read statistics are returned by default.
+
+EXAMPLES
+--------
+* Get the read statistics
++
+------------
+# nvme intel lat-stats /dev/nvme0
+------------
++
+
+* Get the write statistics
++
+------------
+# nvme intel lat-stats /dev/nvme0 -w
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-intel-market-name.1 b/Documentation/nvme-intel-market-name.1
new file mode 100644
index 0000000..b77c38b
--- /dev/null
+++ b/Documentation/nvme-intel-market-name.1
@@ -0,0 +1,74 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-MARKET\" "1" "02/14/2024" "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-intel-market-name \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel market\-name\fR <device> [\-\-raw\-binary | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, retrieves intel vendor specific marketing name log page and provides the result and returned structure\&. The output is simply the marketing name used to identify what kind of device it is\&.
+.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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the marketing name
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel market\-name /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-intel-market-name.html b/Documentation/nvme-intel-market-name.html
new file mode 100644
index 0000000..817a255
--- /dev/null
+++ b/Documentation/nvme-intel-market-name.html
@@ -0,0 +1,820 @@
+<?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 10.2.0" />
+<title>nvme-intel-market-name(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-intel-market-name(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-market-name -
+ Send NVMe 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 intel market-name</em> &lt;device&gt; [--raw-binary | -b]</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, retrieves intel vendor specific marketing name
+log page and provides the result and returned structure. The output is
+simply the marketing name used to identify what kind of device it is.</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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</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 marketing name
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel market-name /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-market-name.txt b/Documentation/nvme-intel-market-name.txt
new file mode 100644
index 0000000..0b4b96a
--- /dev/null
+++ b/Documentation/nvme-intel-market-name.txt
@@ -0,0 +1,43 @@
+nvme-intel-market-name(1)
+=========================
+
+NAME
+----
+nvme-intel-market-name - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel market-name' <device> [--raw-binary | -b]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves intel vendor specific marketing name
+log page and provides the result and returned structure. The output is
+simply the marketing name used to identify what kind of device it is.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+EXAMPLES
+--------
+* Get the marketing name
++
+------------
+# nvme intel market-name /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-intel-smart-log-add.1 b/Documentation/nvme-intel-smart-log-add.1
new file mode 100644
index 0000000..539d9bf
--- /dev/null
+++ b/Documentation/nvme-intel-smart-log-add.1
@@ -0,0 +1,108 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-SMART\-" "1" "02/14/2024" "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-intel-smart-log-add \- Send NVMe Intel Additional SMART log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel smart\-log\-add\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-raw\-binary | \-b] [\-\-json | \-j]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Intel Additional SMART log page from the 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 smart 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
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the Additional SMART log for the given nsid\&. This is optional and its success may depend on the device\(cqs capabilities to provide this log on a per\-namespace basis (see the NVMe Identify Controller for this capability)\&. The default nsid to use is 0xffffffff for the device global SMART log\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw Intel Additional SMART log buffer to stdout\&.
+.RE
+.PP
+\-j, \-\-json
+.RS 4
+Dump output in json format\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Intel Additional SMART log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel smart\-log\-add /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 Intel Additional SMART log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel smart\-log\-add /dev/nvme0 \-\-raw\-binary > smart_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-intel-smart-log-add.html b/Documentation/nvme-intel-smart-log-add.html
new file mode 100644
index 0000000..f5b1b5e
--- /dev/null
+++ b/Documentation/nvme-intel-smart-log-add.html
@@ -0,0 +1,856 @@
+<?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 10.2.0" />
+<title>nvme-intel-smart-log-add(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-intel-smart-log-add(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-smart-log-add -
+ Send NVMe Intel Additional SMART 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 intel smart-log-add</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--raw-binary | -b] [--json | -j]</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 Intel Additional SMART log page from the 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 smart 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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the Additional SMART log for the given nsid. This is
+ optional and its success may depend on the device&#8217;s capabilities
+ to provide this log on a per-namespace basis (see the NVMe
+ Identify Controller for this capability). The default nsid to
+ use is 0xffffffff for the device global SMART log.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw Intel Additional SMART log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-j
+</dt>
+<dt class="hdlist1">
+--json
+</dt>
+<dd>
+<p>
+ Dump output in json format.
+</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 Intel Additional SMART log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel smart-log-add /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw Intel Additional SMART log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel smart-log-add /dev/nvme0 --raw-binary &gt; smart_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-smart-log-add.txt b/Documentation/nvme-intel-smart-log-add.txt
new file mode 100644
index 0000000..0ed1f10
--- /dev/null
+++ b/Documentation/nvme-intel-smart-log-add.txt
@@ -0,0 +1,65 @@
+nvme-intel-smart-log-add(1)
+===========================
+
+NAME
+----
+nvme-intel-smart-log-add - Send NVMe Intel Additional SMART log page request,
+returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel smart-log-add' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--raw-binary | -b] [--json | -j]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Intel Additional SMART log page from the 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 smart 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
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the Additional SMART log for the given nsid. This is
+ optional and its success may depend on the device's capabilities
+ to provide this log on a per-namespace basis (see the NVMe
+ Identify Controller for this capability). The default nsid to
+ use is 0xffffffff for the device global SMART log.
+
+-b::
+--raw-binary::
+ Print the raw Intel Additional SMART log buffer to stdout.
+
+-j::
+--json::
+ Dump output in json format.
+
+EXAMPLES
+--------
+* Print the Intel Additional SMART log page in a human readable format:
++
+------------
+# nvme intel smart-log-add /dev/nvme0
+------------
++
+
+* Print the raw Intel Additional SMART log to a file:
++
+------------
+# nvme intel smart-log-add /dev/nvme0 --raw-binary > smart_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-intel-temp-stats.1 b/Documentation/nvme-intel-temp-stats.1
new file mode 100644
index 0000000..15434bb
--- /dev/null
+++ b/Documentation/nvme-intel-temp-stats.1
@@ -0,0 +1,97 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-TEMP\-S" "1" "02/14/2024" "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-intel-temp-stats \- Send NVMe SMART log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel temp\-stats\fR <device> [\-\-raw\-binary | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Intel Additional SMART log page from the 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 smart 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
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw temperature stats log buffer to stdout\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the temperature stats log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel temp\-stats /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 SMART log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme intel temp\-stats /dev/nvme0 \-\-raw\-binary > temp_stats_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-intel-temp-stats.html b/Documentation/nvme-intel-temp-stats.html
new file mode 100644
index 0000000..c03b0a0
--- /dev/null
+++ b/Documentation/nvme-intel-temp-stats.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 10.2.0" />
+<title>nvme-intel-temp-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-intel-temp-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-intel-temp-stats -
+ Send NVMe SMART 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 intel temp-stats</em> &lt;device&gt; [--raw-binary | -b]</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 Intel Additional SMART log page from the 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 smart 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">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw temperature stats log buffer to stdout.
+</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 temperature stats log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel temp-stats /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw SMART log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme intel temp-stats /dev/nvme0 --raw-binary &gt; temp_stats_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-intel-temp-stats.txt b/Documentation/nvme-intel-temp-stats.txt
new file mode 100644
index 0000000..656422f
--- /dev/null
+++ b/Documentation/nvme-intel-temp-stats.txt
@@ -0,0 +1,51 @@
+nvme-intel-temp-stats(1)
+========================
+
+NAME
+----
+nvme-intel-temp-stats - Send NVMe SMART log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme intel temp-stats' <device> [--raw-binary | -b]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Intel Additional SMART log page from the 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 smart 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
+-------
+-b::
+--raw-binary::
+ Print the raw temperature stats log buffer to stdout.
+
+EXAMPLES
+--------
+* Print the temperature stats log page in a human readable format:
++
+------------
+# nvme intel temp-stats /dev/nvme0
+------------
++
+
+* Print the raw SMART log to a file:
++
+------------
+# nvme intel temp-stats /dev/nvme0 --raw-binary > temp_stats_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-io-mgmt-recv.1 b/Documentation/nvme-io-mgmt-recv.1
new file mode 100644
index 0000000..df8eda9
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-recv.1
@@ -0,0 +1,86 @@
+'\" t
+.\" Title: nvme-io-mgmt-recv
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-IO\-MGMT\-RECV" "1" "02/14/2024" "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-io-mgmt-recv \- I/O Management Receive command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme io\-mgmt\-recv\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-mos=<NUM> | \-s <NUM>] [\-\-mo=<NUM> | \-m <NUM>]
+ [\-\-data=<FILE> | \-d <FILE>]
+ [\-\-data\-len=<NUM> | \-l <NUM>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the I/O Management Receive command with the requested management operation (mo) and management operation specific parameter (mos)\&. This is the generic interface provided for forward compatibility as new operations are added 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
+\-d <FILE>, \-\-data=<FILE>
+.RS 4
+File to write received data into\&. If unspecified, received data will be hex dumped to the standard output stream\&.
+.RE
+.PP
+\-l <NUM>, \-\-data\-len=<NUM>
+.RS 4
+Received data buffer length
+.RE
+.PP
+\-m <NUM>, \-\-mo <NUM>
+.RS 4
+Management Operation to perform\&.
+.RE
+.PP
+\-s <NUM>, \-\-mos=<NUM>
+.RS 4
+Management Operation Specific parameter\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-io-mgmt-recv.html b/Documentation/nvme-io-mgmt-recv.html
new file mode 100644
index 0000000..bed1c31
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-recv.html
@@ -0,0 +1,876 @@
+<?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 10.2.0" />
+<title>nvme-io-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 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-io-mgmt-recv(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-io-mgmt-recv -
+ I/O 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 io-mgmt-recv</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--mos=&lt;NUM&gt; | -s &lt;NUM&gt;] [--mo=&lt;NUM&gt; | -m &lt;NUM&gt;]
+ [--data=&lt;FILE&gt; | -d &lt;FILE&gt;]
+ [--data-len=&lt;NUM&gt; | -l &lt;NUM&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 I/O Management Receive command with the
+requested management operation (mo) and management operation specific parameter
+(mos). This is the generic interface provided for forward compatibility as new
+operations are added 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">
+-d &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ File to write received data into. If unspecified, received data will be
+ hex dumped to the standard output stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Received data buffer length
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--mo &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Management Operation to perform.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--mos=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Management Operation Specific parameter.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-io-mgmt-recv.txt b/Documentation/nvme-io-mgmt-recv.txt
new file mode 100644
index 0000000..332d0bb
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-recv.txt
@@ -0,0 +1,63 @@
+nvme-io-mgmt-recv(1)
+====================
+
+NAME
+----
+nvme-io-mgmt-recv - I/O Management Receive command
+
+SYNOPSIS
+--------
+[verse]
+'nvme io-mgmt-recv' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--mos=<NUM> | -s <NUM>] [--mo=<NUM> | -m <NUM>]
+ [--data=<FILE> | -d <FILE>]
+ [--data-len=<NUM> | -l <NUM>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the I/O Management Receive command with the
+requested management operation (mo) and management operation specific parameter
+(mos). This is the generic interface provided for forward compatibility as new
+operations are added 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.
+
+-d <FILE>::
+--data=<FILE>::
+ File to write received data into. If unspecified, received data will be
+ hex dumped to the standard output stream.
+
+-l <NUM>::
+--data-len=<NUM>::
+ Received data buffer length
+
+-m <NUM>::
+--mo <NUM>::
+ Management Operation to perform.
+
+-s <NUM>::
+--mos=<NUM>::
+ Management Operation Specific parameter.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-io-mgmt-send.1 b/Documentation/nvme-io-mgmt-send.1
new file mode 100644
index 0000000..3206738
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-send.1
@@ -0,0 +1,86 @@
+'\" t
+.\" Title: nvme-io-mgmt-send
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-IO\-MGMT\-SEND" "1" "02/14/2024" "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-io-mgmt-send \- I/O Management Send command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme io\-mgmt\-send\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-mos=<NUM> | \-s <NUM>] [\-\-mo=<NUM> | \-m <NUM>]
+ [\-\-data=<FILE> | \-d <FILE>]
+ [\-\-data\-len=<NUM> | \-l <NUM>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the I/O Management Send command with the requested management operation (mo) and management operation specific parameter (mos)\&. This is the generic interface provided for forward compatibility as new operations are added that this program isn\(cqt aware of at the time of its development\&. As such, this is a generic command that does not provide any convenience parameters to produce the binary payload\&.
+.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
+\-d <FILE>, \-\-data=<FILE>
+.RS 4
+File to read payload from\&. If unspecified, data will be read from the standard input stream\&.
+.RE
+.PP
+\-l <NUM>, \-\-data\-len=<NUM>
+.RS 4
+Payload data buffer length
+.RE
+.PP
+\-m <NUM>, \-\-mo <NUM>
+.RS 4
+Management Operation to perform\&.
+.RE
+.PP
+\-s <NUM>, \-\-mos=<NUM>
+.RS 4
+Management Operation Specific parameter\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-io-mgmt-send.html b/Documentation/nvme-io-mgmt-send.html
new file mode 100644
index 0000000..42e1548
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-send.html
@@ -0,0 +1,875 @@
+<?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 10.2.0" />
+<title>nvme-io-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 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-io-mgmt-send(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-io-mgmt-send -
+ I/O 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 io-mgmt-send</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--mos=&lt;NUM&gt; | -s &lt;NUM&gt;] [--mo=&lt;NUM&gt; | -m &lt;NUM&gt;]
+ [--data=&lt;FILE&gt; | -d &lt;FILE&gt;]
+ [--data-len=&lt;NUM&gt; | -l &lt;NUM&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 I/O Management Send command with the
+requested management operation (mo) and management operation specific parameter
+(mos). This is the generic interface provided for forward compatibility as new
+operations are added that this program isn&#8217;t aware of at the time of its
+development. As such, this is a generic command that does not provide any
+convenience parameters to produce the binary payload.</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">
+-d &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ File to read payload from. If unspecified, data will be read from the
+ standard input stream.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Payload data buffer length
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--mo &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Management Operation to perform.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--mos=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Management Operation Specific parameter.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-io-mgmt-send.txt b/Documentation/nvme-io-mgmt-send.txt
new file mode 100644
index 0000000..f7e8f6d
--- /dev/null
+++ b/Documentation/nvme-io-mgmt-send.txt
@@ -0,0 +1,62 @@
+nvme-io-mgmt-send(1)
+====================
+
+NAME
+----
+nvme-io-mgmt-send - I/O Management Send command
+
+SYNOPSIS
+--------
+[verse]
+'nvme io-mgmt-send' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--mos=<NUM> | -s <NUM>] [--mo=<NUM> | -m <NUM>]
+ [--data=<FILE> | -d <FILE>]
+ [--data-len=<NUM> | -l <NUM>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the I/O Management Send command with the
+requested management operation (mo) and management operation specific parameter
+(mos). This is the generic interface provided for forward compatibility as new
+operations are added that this program isn't aware of at the time of its
+development. As such, this is a generic command that does not provide any
+convenience parameters to produce the binary payload.
+
+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.
+
+-d <FILE>::
+--data=<FILE>::
+ File to read payload from. If unspecified, data will be read from the
+ standard input stream.
+
+-l <NUM>::
+--data-len=<NUM>::
+ Payload data buffer length
+
+-m <NUM>::
+--mo <NUM>::
+ Management Operation to perform.
+
+-s <NUM>::
+--mos=<NUM>::
+ Management Operation Specific parameter.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme-io-passthru.1 b/Documentation/nvme-io-passthru.1
new file mode 100644
index 0000000..a5c6d39
--- /dev/null
+++ b/Documentation/nvme-io-passthru.1
@@ -0,0 +1,158 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-IO\-PASSTHRU" "1" "02/14/2024" "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-io-passthru \- Submit an arbitrary io command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-io\-passthru\fR <device> [\-\-opcode=<opcode> | \-O <opcode>]
+ [\-\-flags=<flags> | \-f <flags>] [\-rsvd=<rsvd> | \-R <rsvd>]
+ [\-\-namespace\-id=<nsid> | \-nsid <nsid>]
+ [\-\-cdw2=<cdw2>] [\-\-cdw3=<cdw3>] [\-\-cdw10=<cdw10>]
+ [\-\-cdw11=<cdw11>] [\-\-cdw12=<cdw12>] [\-\-cdw13=<cdw13>]
+ [\-\-cdw14=<cdw14>] [\-\-cdw15=<cdw15>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-metadata\-len=<len> | \-m <len>]
+ [\-\-read | \-r] [\-\-write | \-w]
+ [\-\-input\-file=<file> | \-i <file>]
+ [\-\-metadata=<file> | \-M <file>]
+ [\-\-timeout=<to> | \-t <to>] [\-\-show\-command | \-s]
+ [\-\-dry\-run | \-d] [\-\-raw\-binary | \-b]
+ [\-\-prefill=<prefill> | \-p <prefill>]
+ [\-\-latency | \-T]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an arbitrary NVMe IO command and returns the applicable results\&. This may be the simply the command\(cqs result and status, or may also include a buffer if the command returns one\&. This command does no interpretation of the opcodes or options\&.
+.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 structure (if applicable) may be returned in one of several ways depending on the option flags; the structure may printed by the program as a hex dump, or may be returned as a raw buffer printed to stdout for another program to parse\&.
+.SH "OPTIONS"
+.PP
+\-O <opcode>, \-\-opcode=<opcode>
+.RS 4
+The NVMe opcode to send to the device in the command
+.RE
+.PP
+\-f <flags>, \-\-flags=<flags>
+.RS 4
+The NVMe command flags to send to the device in the command
+.RE
+.PP
+\-R <rsvd>, \-\-rsvd=<rsvd>
+.RS 4
+The value for the reserved field in the command\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The value for the ns\-id in the command\&. Defaults to
+\fI0\fR\&.
+.RE
+.PP
+\-\-cdw[2\-3,10\-15]=<cdw>
+.RS 4
+Specifies the command dword value for that specified entry in the command
+.RE
+.PP
+\-r, \-\-read, \-w, \-\-write
+.RS 4
+Used for the data\-direction for the command and required for commands sending/receiving data\&. Don\(cqt use both read and write at the same time\&.
+.RE
+.PP
+\-i <file>, \-\-input\-file=<file>
+.RS 4
+If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&. If the command is a data\-in (read) command, the data returned from the device will be saved here\&.
+.RE
+.PP
+\-M <file>, \-\-metadata=<file>
+.RS 4
+If the command is a data\-out (write) command, use this file to fill the metadata buffer sent to the device\&. If no file is given, assumed to use STDIN\&. If the command is a data\-in (read) command, the metadata returned from the device will be saved here\&.
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer used for this command\&.
+.RE
+.PP
+\-m <data\-len>, \-\-metadata\-len=<data\-len>
+.RS 4
+The metadata length for the buffer used for this command\&.
+.RE
+.PP
+\-s, \-\-show\-cmd
+.RS 4
+Print out the command to be sent\&.
+.RE
+.PP
+\-d, \-\-dry\-run
+.RS 4
+Do not actually send the command\&. If want to use \-\-dry\-run option, \-\-show\-cmd option
+\fImust\fR
+be set\&. Otherwise \-\-dry\-run option will be
+\fIignored\fR\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw returned buffer to stdout if the command returns data or a structure\&.
+.RE
+.PP
+\-p <prefill>, \-\-prefill <prefill>
+.RS 4
+Prefill the buffer with a predetermined byte value\&. Defaults to 0\&. This may be useful if the data you are writing is shorter than the required buffer, and you need to pad it with a known value\&. It may also be useful if you need to confirm if a device is overwriting a buffer on a data\-in command\&.
+.RE
+.PP
+\-T, \-\-latency
+.RS 4
+Print out the latency the IOCTL took (in us)\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+nvme io\-passthru /dev/nvme0n1 \-\-opcode=2 \-\-namespace\-id=1 \-\-data\-len=4096 \-\-read \-\-cdw10=0 \-\-cdw11=0 \-\-cdw12=0x70000 \-\-raw\-binary
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-io-passthru.html b/Documentation/nvme-io-passthru.html
new file mode 100644
index 0000000..da443ea
--- /dev/null
+++ b/Documentation/nvme-io-passthru.html
@@ -0,0 +1,1022 @@
+<?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 10.2.0" />
+<title>nvme-io-passthru(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-io-passthru(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-io-passthru -
+ Submit an arbitrary io command, return 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-io-passthru</em> &lt;device&gt; [--opcode=&lt;opcode&gt; | -O &lt;opcode&gt;]
+ [--flags=&lt;flags&gt; | -f &lt;flags&gt;] [-rsvd=&lt;rsvd&gt; | -R &lt;rsvd&gt;]
+ [--namespace-id=&lt;nsid&gt; | -nsid &lt;nsid&gt;]
+ [--cdw2=&lt;cdw2&gt;] [--cdw3=&lt;cdw3&gt;] [--cdw10=&lt;cdw10&gt;]
+ [--cdw11=&lt;cdw11&gt;] [--cdw12=&lt;cdw12&gt;] [--cdw13=&lt;cdw13&gt;]
+ [--cdw14=&lt;cdw14&gt;] [--cdw15=&lt;cdw15&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--metadata-len=&lt;len&gt; | -m &lt;len&gt;]
+ [--read | -r] [--write | -w]
+ [--input-file=&lt;file&gt; | -i &lt;file&gt;]
+ [--metadata=&lt;file&gt; | -M &lt;file&gt;]
+ [--timeout=&lt;to&gt; | -t &lt;to&gt;] [--show-command | -s]
+ [--dry-run | -d] [--raw-binary | -b]
+ [--prefill=&lt;prefill&gt; | -p &lt;prefill&gt;]
+ [--latency | -T]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an arbitrary NVMe IO command and returns the applicable
+results. This may be the simply the command&#8217;s result and status, or may
+also include a buffer if the command returns one. This command does no
+interpretation of the opcodes or options.</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 structure (if applicable) may be returned in
+one of several ways depending on the option flags; the structure may
+printed by the program as a hex dump, or may be returned as a raw buffer
+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;opcode&gt;
+</dt>
+<dt class="hdlist1">
+--opcode=&lt;opcode&gt;
+</dt>
+<dd>
+<p>
+ The NVMe opcode to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;flags&gt;
+</dt>
+<dt class="hdlist1">
+--flags=&lt;flags&gt;
+</dt>
+<dd>
+<p>
+ The NVMe command flags to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-R &lt;rsvd&gt;
+</dt>
+<dt class="hdlist1">
+--rsvd=&lt;rsvd&gt;
+</dt>
+<dd>
+<p>
+ The value for the reserved field in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The value for the ns-id in the command. Defaults to <em>0</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+--cdw[2-3,10-15]=&lt;cdw&gt;
+</dt>
+<dd>
+<p>
+ Specifies the command dword value for that specified entry in
+ the command
+</p>
+</dd>
+<dt class="hdlist1">
+-r
+</dt>
+<dt class="hdlist1">
+--read
+</dt>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--write
+</dt>
+<dd>
+<p>
+ Used for the data-direction for the command and required for
+ commands sending/receiving data. Don&#8217;t use both read and write
+ at the same time.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--input-file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given, assumed to
+ use STDIN. If the command is a data-in (read) command, the data
+ returned from the device will be saved here.
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--metadata=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ If the command is a data-out (write) command, use this file
+ to fill the metadata buffer sent to the device. If no file is given,
+ assumed to use STDIN. If the command is a data-in (read) command, the
+ metadata returned from the device will be saved here.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The metadata length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-s
+</dt>
+<dt class="hdlist1">
+--show-cmd
+</dt>
+<dd>
+<p>
+ Print out the command to be sent.
+</p>
+</dd>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--dry-run
+</dt>
+<dd>
+<p>
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option <em>must</em> be set. Otherwise --dry-run option will be
+ <em>ignored</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw returned buffer to stdout if the command returns
+ data or a structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prefill&gt;
+</dt>
+<dt class="hdlist1">
+--prefill &lt;prefill&gt;
+</dt>
+<dd>
+<p>
+ Prefill the buffer with a predetermined byte value. Defaults to 0.
+ This may be useful if the data you are writing is shorter
+ than the required buffer, and you need to pad it with a known
+ value. It may also be useful if you need to confirm if a device
+ is overwriting a buffer on a data-in command.
+</p>
+</dd>
+<dt class="hdlist1">
+-T
+</dt>
+<dt class="hdlist1">
+--latency
+</dt>
+<dd>
+<p>
+ Print out the latency the IOCTL took (in us).
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme io-passthru /dev/nvme0n1 --opcode=2 --namespace-id=1 --data-len=4096 --read --cdw10=0 --cdw11=0 --cdw12=0x70000 --raw-binary</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-io-passthru.txt b/Documentation/nvme-io-passthru.txt
new file mode 100644
index 0000000..3ad5231
--- /dev/null
+++ b/Documentation/nvme-io-passthru.txt
@@ -0,0 +1,138 @@
+nvme-io-passthru(1)
+===================
+
+NAME
+----
+nvme-io-passthru - Submit an arbitrary io command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-io-passthru' <device> [--opcode=<opcode> | -O <opcode>]
+ [--flags=<flags> | -f <flags>] [-rsvd=<rsvd> | -R <rsvd>]
+ [--namespace-id=<nsid> | -nsid <nsid>]
+ [--cdw2=<cdw2>] [--cdw3=<cdw3>] [--cdw10=<cdw10>]
+ [--cdw11=<cdw11>] [--cdw12=<cdw12>] [--cdw13=<cdw13>]
+ [--cdw14=<cdw14>] [--cdw15=<cdw15>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--metadata-len=<len> | -m <len>]
+ [--read | -r] [--write | -w]
+ [--input-file=<file> | -i <file>]
+ [--metadata=<file> | -M <file>]
+ [--timeout=<to> | -t <to>] [--show-command | -s]
+ [--dry-run | -d] [--raw-binary | -b]
+ [--prefill=<prefill> | -p <prefill>]
+ [--latency | -T]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an arbitrary NVMe IO command and returns the applicable
+results. This may be the simply the command's result and status, or may
+also include a buffer if the command returns one. This command does no
+interpretation of the opcodes or options.
+
+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 structure (if applicable) may be returned in
+one of several ways depending on the option flags; the structure may
+printed by the program as a hex dump, or may be returned as a raw buffer
+printed to stdout for another program to parse.
+
+OPTIONS
+-------
+-O <opcode>::
+--opcode=<opcode>::
+ The NVMe opcode to send to the device in the command
+
+-f <flags>::
+--flags=<flags>::
+ The NVMe command flags to send to the device in the command
+
+-R <rsvd>::
+--rsvd=<rsvd>::
+ The value for the reserved field in the command.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ The value for the ns-id in the command. Defaults to '0'.
+
+--cdw[2-3,10-15]=<cdw>::
+ Specifies the command dword value for that specified entry in
+ the command
+
+-r::
+--read::
+-w::
+--write::
+ Used for the data-direction for the command and required for
+ commands sending/receiving data. Don't use both read and write
+ at the same time.
+
+-i <file>::
+--input-file=<file>::
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given, assumed to
+ use STDIN. If the command is a data-in (read) command, the data
+ returned from the device will be saved here.
+
+-M <file>::
+--metadata=<file>::
+ If the command is a data-out (write) command, use this file
+ to fill the metadata buffer sent to the device. If no file is given,
+ assumed to use STDIN. If the command is a data-in (read) command, the
+ metadata returned from the device will be saved here.
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer used for this command.
+
+-m <data-len>::
+--metadata-len=<data-len>::
+ The metadata length for the buffer used for this command.
+
+-s::
+--show-cmd::
+ Print out the command to be sent.
+
+-d::
+--dry-run::
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option _must_ be set. Otherwise --dry-run option will be
+ _ignored_.
+
+-b::
+--raw-binary::
+ Print the raw returned buffer to stdout if the command returns
+ data or a structure.
+
+-p <prefill>::
+--prefill <prefill>::
+ Prefill the buffer with a predetermined byte value. Defaults to 0.
+ This may be useful if the data you are writing is shorter
+ than the required buffer, and you need to pad it with a known
+ value. It may also be useful if you need to confirm if a device
+ is overwriting a buffer on a data-in command.
+
+-T::
+--latency::
+ Print out the latency the IOCTL took (in us).
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+
+nvme io-passthru /dev/nvme0n1 --opcode=2 --namespace-id=1 --data-len=4096 --read --cdw10=0 --cdw11=0 --cdw12=0x70000 --raw-binary
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lba-status-log.1 b/Documentation/nvme-lba-status-log.1
new file mode 100644
index 0000000..a6466d3
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.1
@@ -0,0 +1,112 @@
+'\" t
+.\" Title: nvme-lba-status-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LBA\-STATUS\-L" "1" "02/14/2024" "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>] [\-\-verbose | \-v]
+.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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..2f60ffb
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.html
@@ -0,0 +1,850 @@
+<?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 10.2.0" />
+<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 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-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;] [--verbose | -v]</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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</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..7d6efbd
--- /dev/null
+++ b/Documentation/nvme-lba-status-log.txt
@@ -0,0 +1,59 @@
+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>] [--verbose | -v]
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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
new file mode 100644
index 0000000..e504b78
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.1
@@ -0,0 +1,76 @@
+'\" t
+.\" Title: nvme-list-ctrl
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST\-CTRL" "1" "02/14/2024" "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-list-ctrl \- Send NVMe Identify List Controllers, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\-ctrl\fR <device> [\-\-cntid=<cntid> | \-c <cntid>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify command for controller list and provides the result and returned structure\&. This uses either mode 12h or 13h depending on the requested namespace identifier\&.
+.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)\&. The starting controller in the list always begins with 0 unless the \*(Aq\-\-cntid\*(Aq option is given to override\&.
+.sp
+On success, the controller array is printed for each index and controller identifier\&.
+.SH "OPTIONS"
+.PP
+\-c <cntid>, \-\-cntid=<cntid>
+.RS 4
+Retrieve the identify list structure starting with the given controller id\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+If provided, will request the controllers attached to the specified namespace\&. If no namespace is given, or set to 0, the command requests the controller list for the entire subsystem, whether or not they are attached to namespace(s)\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-list-ctrl.html b/Documentation/nvme-list-ctrl.html
new file mode 100644
index 0000000..b0f1a16
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.html
@@ -0,0 +1,849 @@
+<?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 10.2.0" />
+<title>nvme-list-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 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-list-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-list-ctrl -
+ Send NVMe Identify List Controllers, 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 list-ctrl</em> &lt;device&gt; [--cntid=&lt;cntid&gt; | -c &lt;cntid&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify command for controller list
+and provides the result and returned structure. This uses either mode
+12h or 13h depending on the requested namespace identifier.</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).
+The starting controller in the list always begins with 0 unless the
+<code>'--cntid'</code> option is given to override.</p></div>
+<div class="paragraph"><p>On success, the controller array is printed for each index and controller
+identifier.</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">
+--cntid=&lt;cntid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify list structure starting with the given controller id.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ If provided, will request the controllers attached to the
+ specified namespace. If no namespace is given, or set to 0, the
+ command requests the controller list for the entire subsystem,
+ whether or not they are attached to namespace(s).
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-ctrl.txt b/Documentation/nvme-list-ctrl.txt
new file mode 100644
index 0000000..6cd5c01
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.txt
@@ -0,0 +1,57 @@
+nvme-list-ctrl(1)
+=================
+
+NAME
+----
+nvme-list-ctrl - Send NVMe Identify List Controllers, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-ctrl' <device> [--cntid=<cntid> | -c <cntid>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify command for controller list
+and provides the result and returned structure. This uses either mode
+12h or 13h depending on the requested namespace identifier.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+The starting controller in the list always begins with 0 unless the
+`'--cntid'` option is given to override.
+
+On success, the controller array is printed for each index and controller
+identifier.
+
+OPTIONS
+-------
+-c <cntid>::
+--cntid=<cntid>::
+ Retrieve the identify list structure starting with the given controller id.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ If provided, will request the controllers attached to the
+ specified namespace. If no namespace is given, or set to 0, the
+ command requests the controller list for the entire subsystem,
+ whether or not they are attached to namespace(s).
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-list-endgrp.1 b/Documentation/nvme-list-endgrp.1
new file mode 100644
index 0000000..345eb9e
--- /dev/null
+++ b/Documentation/nvme-list-endgrp.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-list-endgrp
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST\-ENDGRP" "1" "02/14/2024" "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-list-endgrp \- Send NVMe Identify Endurance Group List, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\-endgrp\fR <device> [\-\-endgrp\-id=<endgrp\-id> | \-i <endgrp\-id>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify command for endurance group list 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)\&. An Endurance Group List of up to 2,047 Endurance Group Identifiers in increasing order is returned containing an Endurance Group Identifier greater than or equal to the value specified in the CDW11\&.ENDGID field\&.
+.SH "OPTIONS"
+.PP
+\-i <endgrp\-id>, \-\-endgrp\-id=<endgrp\-id>
+.RS 4
+Retrieve the identify endurance group list structure starting for the given endurance group id\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-list-endgrp.html b/Documentation/nvme-list-endgrp.html
new file mode 100644
index 0000000..eb2a318
--- /dev/null
+++ b/Documentation/nvme-list-endgrp.html
@@ -0,0 +1,833 @@
+<?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 10.2.0" />
+<title>nvme-list-endgrp(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-list-endgrp(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-list-endgrp -
+ Send NVMe Identify Endurance Group List, 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 list-endgrp</em> &lt;device&gt; [--endgrp-id=&lt;endgrp-id&gt; | -i &lt;endgrp-id&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify command for endurance group list
+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).
+An Endurance Group List of up to 2,047 Endurance Group Identifiers in
+increasing order is returned containing an Endurance Group Identifier greater
+than or equal to the value specified in the CDW11.ENDGID field.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-i &lt;endgrp-id&gt;
+</dt>
+<dt class="hdlist1">
+--endgrp-id=&lt;endgrp-id&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify endurance group list structure starting for the
+ given endurance group id.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-endgrp.txt b/Documentation/nvme-list-endgrp.txt
new file mode 100644
index 0000000..2d7724d
--- /dev/null
+++ b/Documentation/nvme-list-endgrp.txt
@@ -0,0 +1,48 @@
+nvme-list-endgrp(1)
+===================
+
+NAME
+----
+nvme-list-endgrp - Send NVMe Identify Endurance Group List, return result and
+structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-endgrp' <device> [--endgrp-id=<endgrp-id> | -i <endgrp-id>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify command for endurance group list
+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).
+An Endurance Group List of up to 2,047 Endurance Group Identifiers in
+increasing order is returned containing an Endurance Group Identifier greater
+than or equal to the value specified in the CDW11.ENDGID field.
+
+OPTIONS
+-------
+-i <endgrp-id>::
+--endgrp-id=<endgrp-id>::
+ Retrieve the identify endurance group list structure starting for the
+ given endurance group id.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-list-ns.1 b/Documentation/nvme-list-ns.1
new file mode 100644
index 0000000..49cabd4
--- /dev/null
+++ b/Documentation/nvme-list-ns.1
@@ -0,0 +1,122 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "02/14/2024" "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-list-ns \- Send NVMe Identify List Namespaces, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-csi=<command_set_identifier> | \-y <command_set_identifier>]
+ [\-\-all | \-a]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify command for namespace list 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)\&. If the starting namespace in the list always begins with 0 unless the \*(Aq\-\-namespace\-id\*(Aq option is given to override\&.
+.sp
+On success, the namespace array is printed for each index and nsid for a valid nsid\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+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 specified 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\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the namespaces present for zoned command set in JSON format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme list\-ns /dev/nvme0 \-y 2 \-a \-o json
+.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 namespaces present for NVM Command Set in normal format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme list\-ns /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-list-ns.html b/Documentation/nvme-list-ns.html
new file mode 100644
index 0000000..7d7ffdc
--- /dev/null
+++ b/Documentation/nvme-list-ns.html
@@ -0,0 +1,878 @@
+<?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 10.2.0" />
+<title>nvme-id-ns(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-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-list-ns -
+ Send NVMe Identify List Namespaces, 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 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]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify command for namespace list
+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).
+If the starting namespace in the list always begins with 0 unless the
+<code>'--namespace-id'</code> option is given to override.</p></div>
+<div class="paragraph"><p>On success, the namespace array is printed for each index and nsid for
+a valid nsid.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify list structure starting with the given nsid.
+</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 specified I/O command set.
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--all
+</dt>
+<dd>
+<p>
+ Retrieve the identify list structure for all namespaces in the
+ subsystem, whether attached or inactive.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 namespaces present for zoned command set in JSON format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme list-ns /dev/nvme0 -y 2 -a -o json</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the namespaces present for NVM Command Set in normal format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme list-ns /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-ns.txt b/Documentation/nvme-list-ns.txt
new file mode 100644
index 0000000..d241287
--- /dev/null
+++ b/Documentation/nvme-list-ns.txt
@@ -0,0 +1,70 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-list-ns - Send NVMe Identify List Namespaces, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--csi=<command_set_identifier> | -y <command_set_identifier>]
+ [--all | -a]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify command for namespace list
+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).
+If the starting namespace in the list always begins with 0 unless the
+`'--namespace-id'` option is given to override.
+
+On success, the namespace array is printed for each index and nsid for
+a valid nsid.
+
+OPTIONS
+-------
+-n <nsid>::
+--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 specified I/O command set.
+
+-a::
+--all::
+ Retrieve the identify list structure for all namespaces in the
+ subsystem, whether attached or inactive.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the namespaces present for zoned command set in JSON format
++
+------------
+# nvme list-ns /dev/nvme0 -y 2 -a -o json
+------------
+
+* Print the namespaces present for NVM Command Set in normal format
++
+------------
+# nvme list-ns /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-list-secondary.txt b/Documentation/nvme-list-secondary.txt
new file mode 100755
index 0000000..88fbf42
--- /dev/null
+++ b/Documentation/nvme-list-secondary.txt
@@ -0,0 +1,54 @@
+nvme-list-secondary(1)
+======================
+
+NAME
+----
+nvme-list-secondary - Show secondary controller list associated with the primary
+controller of the given device
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-secondary' <device> [--cntid=<cntid> | -c <cntid>]
+ [--num-entries=<entries> | -e <entries>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Show secondary controller list associated with the primary of the given device
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success, the secondary controller list is printed.
+
+OPTIONS
+-------
+-c <cntid>::
+--cntid=<cntid>::
+ Lowest controller identifier to display.
+
+-e <entries>::
+--num-entries=<entries>::
+ Number of entries to retrieve.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a list-secondary to display list.
++
+------------
+# nvme list-secondary /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-list-subsys.1 b/Documentation/nvme-list-subsys.1
new file mode 100644
index 0000000..15212a1
--- /dev/null
+++ b/Documentation/nvme-list-subsys.1
@@ -0,0 +1,132 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST\-SUBSYS" "1" "02/14/2024" "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-list-subsys \- List all NVMe subsystems
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\-subsys\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Scan the sysfs tree for NVM Express subsystems and return the controllers for those subsystems as well as some pertinent information about them\&. If a device is given, print out only the values for the controllers and subsystems leading to the device\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\m[blue]\fBroot@host\fR\m[]\&\s-2\u[1]\d\s+2# nvme list\-subsys
+nvme\-subsys0 \- NQN=nvmf\-test
+\e
+ +\- nvme0 rdma traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.1
+ +\- nvme1 rdma traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.2
+nvme\-subsys1 \- NQN=nvmf\-test2
+\e
+ +\- nvme2 rdma traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.2
+ +\- nvme3 rdma traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\m[blue]\fBroot@host\fR\m[]\&\s-2\u[1]\d\s+2# nvme list\-subsys \-o json
+{
+ "Subsystems" : [
+ {
+ "Name" : "nvme\-subsys0",
+ "NQN" : "nvmf\-test"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme0",
+ "Transport" : "rdma",
+ "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.1"
+ },
+ {
+ "Name" : "nvme1",
+ "Transport" : "rdma",
+ "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.2"
+ }
+ ]
+ },
+ {
+ "Name" : "nvme\-subsys1",
+ "NQN" : "nvmf\-test2"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme2",
+ "Transport" : "rdma",
+ "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.2"
+ },
+ {
+ "Name" : "nvme3",
+ "Transport" : "rdma",
+ "Address" : "traddr=1\&.1\&.1\&.3,trsvcid=4420,host_traddr=1\&.1\&.1\&.1"
+ }
+ ]
+ }
+ ]
+}
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
+.SH "NOTES"
+.IP " 1." 4
+root@host
+.RS 4
+\%mailto:root@host
+.RE
diff --git a/Documentation/nvme-list-subsys.html b/Documentation/nvme-list-subsys.html
new file mode 100644
index 0000000..eb55027
--- /dev/null
+++ b/Documentation/nvme-list-subsys.html
@@ -0,0 +1,872 @@
+<?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 10.2.0" />
+<title>nvme-list-subsys(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-list-subsys(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-list-subsys -
+ List all NVMe subsystems
+</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 list-subsys</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Scan the sysfs tree for NVM Express subsystems and return the controllers
+for those subsystems as well as some pertinent information about them.
+If a device is given, print out only the values for the controllers
+and subsystems leading to the device.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content"><a href="mailto:root@host">root@host</a># nvme list-subsys
+nvme-subsys0 - NQN=nvmf-test
+\
+ +- nvme0 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1
+ +- nvme1 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2
+nvme-subsys1 - NQN=nvmf-test2
+\
+ +- nvme2 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2
+ +- nvme3 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1</pre>
+<div class="attribution">
+</div></div>
+<div class="verseblock">
+<pre class="content"><a href="mailto:root@host">root@host</a># nvme list-subsys -o json
+{
+ "Subsystems" : [
+ {
+ "Name" : "nvme-subsys0",
+ "NQN" : "nvmf-test"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme0",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1"
+ },
+ {
+ "Name" : "nvme1",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2"
+ }
+ ]
+ },
+ {
+ "Name" : "nvme-subsys1",
+ "NQN" : "nvmf-test2"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme2",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2"
+ },
+ {
+ "Name" : "nvme3",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1"
+ }
+ ]
+ }
+ ]
+}</pre>
+<div class="attribution">
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-subsys.txt b/Documentation/nvme-list-subsys.txt
new file mode 100644
index 0000000..a5d2d48
--- /dev/null
+++ b/Documentation/nvme-list-subsys.txt
@@ -0,0 +1,89 @@
+nvme-list-subsys(1)
+===================
+
+NAME
+----
+nvme-list-subsys - List all NVMe subsystems
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-subsys' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Scan the sysfs tree for NVM Express subsystems and return the controllers
+for those subsystems as well as some pertinent information about them.
+If a device is given, print out only the values for the controllers
+and subsystems leading to the device.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+[verse]
+root@host# nvme list-subsys
+nvme-subsys0 - NQN=nvmf-test
+\
+ +- nvme0 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1
+ +- nvme1 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2
+nvme-subsys1 - NQN=nvmf-test2
+\
+ +- nvme2 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2
+ +- nvme3 rdma traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1
+
+[verse]
+root@host# nvme list-subsys -o json
+{
+ "Subsystems" : [
+ {
+ "Name" : "nvme-subsys0",
+ "NQN" : "nvmf-test"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme0",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1"
+ },
+ {
+ "Name" : "nvme1",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2"
+ }
+ ]
+ },
+ {
+ "Name" : "nvme-subsys1",
+ "NQN" : "nvmf-test2"
+ },
+ {
+ "Paths" : [
+ {
+ "Name" : "nvme2",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.2"
+ },
+ {
+ "Name" : "nvme3",
+ "Transport" : "rdma",
+ "Address" : "traddr=1.1.1.3,trsvcid=4420,host_traddr=1.1.1.1"
+ }
+ ]
+ }
+ ]
+}
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-list.1 b/Documentation/nvme-list.1
new file mode 100644
index 0000000..400aefa
--- /dev/null
+++ b/Documentation/nvme-list.1
@@ -0,0 +1,63 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST" "1" "02/14/2024" "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-list \- List all recognized NVMe devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\fR [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Scan the sysfs tree for NVM Express devices and return the /dev node for those devices as well as some pertinent information about them\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information in the output, showing nvme subsystems, controllers and namespaces separately and how they\(cqre related to each other\&.
+.RE
+.SH "ENVIRONMENT"
+.sp
+PCI_IDS_PATH \- Full path of pci\&.ids file in case nvme could not find it in common locations\&.
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-list.html b/Documentation/nvme-list.html
new file mode 100644
index 0000000..c90b3eb
--- /dev/null
+++ b/Documentation/nvme-list.html
@@ -0,0 +1,823 @@
+<?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 10.2.0" />
+<title>nvme-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 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-list(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-list -
+ List all recognized NVMe devices
+</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 list</em> [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Scan the sysfs tree for NVM Express devices and return the /dev node
+for those devices as well as some pertinent information about them.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information in the output, showing nvme subsystems,
+ controllers and namespaces separately and how they&#8217;re related to each
+ other.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_environment">ENVIRONMENT</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>PCI_IDS_PATH - Full path of pci.ids file in case nvme could not find it in common locations.</p></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list.txt b/Documentation/nvme-list.txt
new file mode 100644
index 0000000..a8c5428
--- /dev/null
+++ b/Documentation/nvme-list.txt
@@ -0,0 +1,41 @@
+nvme-list(1)
+============
+
+NAME
+----
+nvme-list - List all recognized NVMe devices
+
+SYNOPSIS
+--------
+[verse]
+'nvme list' [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Scan the sysfs tree for NVM Express devices and return the /dev node
+for those devices as well as some pertinent information about them.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information in the output, showing nvme subsystems,
+ controllers and namespaces separately and how they're related to each
+ other.
+
+ENVIRONMENT
+-----------
+PCI_IDS_PATH - Full path of pci.ids file in case nvme could not find it in common locations.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lockdown.1 b/Documentation/nvme-lockdown.1
new file mode 100644
index 0000000..48fe02a
--- /dev/null
+++ b/Documentation/nvme-lockdown.1
@@ -0,0 +1,90 @@
+'\" t
+.\" Title: nvme-lockdown
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LOCKDOWN" "1" "02/14/2024" "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-lockdown \- Send an NVMe Lockdown command to prohibit or allow the execution of command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-lockdown\fR <device> [\-\-ofi=<ofi> | \-O <ofi>]
+ [\-\-ifc=<ifc> | \-f <ifc>]
+ [\-\-prhbt=<prhbt> | \-p <prhbt>]
+ [\-\-scp=<scp> | \-s <scp>]
+ [\-\-uuid=<UUID_Index> | \-U <UUID_Index>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Lockdown command is used to control the Command and Feature Lockdown capability which configures the prohibition or allowance of execution of the specified command or Set Features command targeting a specific Feature Identifier\&.
+.SH "OPTIONS"
+.PP
+\-O <ofi>, \-\-ofi=<ofi>
+.RS 4
+Opcode or Feature Identifier(OFI) specifies the command opcode or Set Features Feature Identifier identified by the Scope field\&.
+.RE
+.PP
+\-f <ifc>, \-\-ifc=<ifc>
+.RS 4
+Interface (INF) field identifies the interfaces affected by this command\&.
+.RE
+.PP
+\-p <prhbt>, \-\-prhbt=<prhbt>
+.RS 4
+Prohibit (PRHBT) bit specifies whether to prohibit or allow the command opcode or Set Features Feature Identifier specified by this command\&.
+.RE
+.PP
+\-s <scp>, \-\-scp=<scp>
+.RS 4
+Scope (SCP) field specifies the contents of the Opcode or Feature Identifier field\&.
+.RE
+.PP
+\-U <UUID_Index>, \-\-uuid=<UUID_Index>
+.RS 4
+UUID Index \- If this field is set to a non\-zero value, then the value of this field is the index of a UUID in the UUID List that is used by the command\&. If this field is cleared to 0h,then no UUID index is specified\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lockdown.html b/Documentation/nvme-lockdown.html
new file mode 100644
index 0000000..d04aa9d
--- /dev/null
+++ b/Documentation/nvme-lockdown.html
@@ -0,0 +1,881 @@
+<?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 10.2.0" />
+<title>nvme-lockdown(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-lockdown(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lockdown -
+ Send an NVMe Lockdown command to prohibit or allow the execution of 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-lockdown</em> &lt;device&gt; [--ofi=&lt;ofi&gt; | -O &lt;ofi&gt;]
+ [--ifc=&lt;ifc&gt; | -f &lt;ifc&gt;]
+ [--prhbt=&lt;prhbt&gt; | -p &lt;prhbt&gt;]
+ [--scp=&lt;scp&gt; | -s &lt;scp&gt;]
+ [--uuid=&lt;UUID_Index&gt; | -U &lt;UUID_Index&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Lockdown command is used to control the Command and Feature Lockdown
+capability which configures the prohibition or allowance of execution of the
+specified command or Set Features command targeting a specific Feature
+Identifier.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-O &lt;ofi&gt;
+</dt>
+<dt class="hdlist1">
+--ofi=&lt;ofi&gt;
+</dt>
+<dd>
+<p>
+ Opcode or Feature Identifier(OFI) specifies the command opcode or Set
+ Features Feature Identifier identified by the Scope field.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;ifc&gt;
+</dt>
+<dt class="hdlist1">
+--ifc=&lt;ifc&gt;
+</dt>
+<dd>
+<p>
+ Interface (INF) field identifies the interfaces affected by this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prhbt&gt;
+</dt>
+<dt class="hdlist1">
+--prhbt=&lt;prhbt&gt;
+</dt>
+<dd>
+<p>
+ Prohibit (PRHBT) bit specifies whether to prohibit or allow the command
+ opcode or Set Features Feature Identifier specified by this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;scp&gt;
+</dt>
+<dt class="hdlist1">
+--scp=&lt;scp&gt;
+</dt>
+<dd>
+<p>
+ Scope (SCP) field specifies the contents of the Opcode or Feature Identifier field.
+</p>
+</dd>
+<dt class="hdlist1">
+-U &lt;UUID_Index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid=&lt;UUID_Index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index - If this field is set to a non-zero value, then the value of
+ this field is the index of a UUID in the UUID List that is used by the command.
+ If this field is cleared to 0h,then no UUID index is specified.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lockdown.txt b/Documentation/nvme-lockdown.txt
new file mode 100644
index 0000000..e17ac70
--- /dev/null
+++ b/Documentation/nvme-lockdown.txt
@@ -0,0 +1,65 @@
+nvme-lockdown(1)
+================
+
+NAME
+----
+nvme-lockdown - Send an NVMe Lockdown command to prohibit or allow the execution of command
+
+SYNOPSIS
+--------
+[verse]
+'nvme-lockdown' <device> [--ofi=<ofi> | -O <ofi>]
+ [--ifc=<ifc> | -f <ifc>]
+ [--prhbt=<prhbt> | -p <prhbt>]
+ [--scp=<scp> | -s <scp>]
+ [--uuid=<UUID_Index> | -U <UUID_Index>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Lockdown command is used to control the Command and Feature Lockdown
+capability which configures the prohibition or allowance of execution of the
+specified command or Set Features command targeting a specific Feature
+Identifier.
+
+OPTIONS
+-------
+-O <ofi>::
+--ofi=<ofi>::
+ Opcode or Feature Identifier(OFI) specifies the command opcode or Set
+ Features Feature Identifier identified by the Scope field.
+
+-f <ifc>::
+--ifc=<ifc>::
+ Interface (INF) field identifies the interfaces affected by this command.
+
+-p <prhbt>::
+--prhbt=<prhbt>::
+ Prohibit (PRHBT) bit specifies whether to prohibit or allow the command
+ opcode or Set Features Feature Identifier specified by this command.
+
+-s <scp>::
+--scp=<scp>::
+ Scope (SCP) field specifies the contents of the Opcode or Feature Identifier field.
+-U <UUID_Index>::
+--uuid=<UUID_Index>::
+ UUID Index - If this field is set to a non-zero value, then the value of
+ this field is the index of a UUID in the UUID List that is used by the command.
+ If this field is cleared to 0h,then no UUID index is specified.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-media-unit-stat-log.1 b/Documentation/nvme-media-unit-stat-log.1
new file mode 100644
index 0000000..21d49d8
--- /dev/null
+++ b/Documentation/nvme-media-unit-stat-log.1
@@ -0,0 +1,67 @@
+'\" t
+.\" Title: nvme-media-unit-stat-log
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
+.\" Date: 11/11/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MEDIA\-LOG" "1" "11/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-media-unit-stat-log \- Send NVMe Media unit status log pages request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme media\-log\-pages\fR <device> [\-d | \-\-dom\-id]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+ [\-\-raw\-binary | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Media unit status log pages details from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and should be the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned Media unit status log pages log structure will be printed \&.
+.SH "OPTIONS"
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+This option will set the reporting format to normal, json, or binary\&. Only one output format can be used at a time\&.
+.RE
+.PP
+\-d, \-\-dom\-id
+.RS 4
+This option is to get the domain ID\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+This option is to get raw binary data\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples provided yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite \ No newline at end of file
diff --git a/Documentation/nvme-media-unit-stat-log.html b/Documentation/nvme-media-unit-stat-log.html
new file mode 100644
index 0000000..5042ba9
--- /dev/null
+++ b/Documentation/nvme-media-unit-stat-log.html
@@ -0,0 +1,831 @@
+<?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-media-unit-stat-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-media-unit-stat-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-media-unit-stat-log -
+ Send NVMe Supported Log pages 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 supported-log-pages</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
+ [-b | --raw-binary]</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 supportd log pages details from an NVMe device and provides
+the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success, the returned supportd log pages log structure will be printed
+for each command that is supported.</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>
+ This option will set the reporting format to normal, json, or binary.
+ Only one output format can be used at a time.
+</p>
+</dd>
+<dt class="hdlist1">
+ -b
+ </dt>
+ <dt class="hdlist1">
+ --raw-binary
+ </dt>
+ <dd>
+ <p>
+ This option will get the data in raw binary format.
+ </p>
+ </dd>
+<dt class="hdlist1">
+ -d
+ </dt>
+ <dt class="hdlist1">
+ --dom-id
+ </dt>
+ <dd>
+ <p>
+ This option is to get the domain ID.
+ </p>
+ </dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No examples provided 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
+ 2021-08-13 22:37:48 IST
+</div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/Documentation/nvme-media-unit-stat-log.txt b/Documentation/nvme-media-unit-stat-log.txt
new file mode 100644
index 0000000..997a497
--- /dev/null
+++ b/Documentation/nvme-media-unit-stat-log.txt
@@ -0,0 +1,47 @@
+nvme-media-unit-stat-log(1)
+===========================
+
+NAME
+----
+nvme-media-unit-stat-log - Send NVMe Media unit status Log pages
+request, returns result and log.
+
+SYNOPSIS
+--------
+[verse]
+'nvme media-unit-stat-log' <device> [--dom-id | -d] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Media unit status log pages details from
+an NVMe device and provides the returned structure.
+
+The <device> parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).
+
+On success, the returned Media unit status log pages log structure will be printed.
+
+OPTIONS
+-------
+
+-o <fmt>::
+--output-format=<fmt>::
+ This option will set the reporting format to normal, json, or binary.
+ Only one output format can be used at a time.
+
+-d::
+--dom-id::
+ To get the domain ID.
+
+-b::
+--raw-binary::
+ To show raw binary data.
+
+EXAMPLES
+--------
+No examples provided yet.
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-mi-cmd-support-effects-log.1 b/Documentation/nvme-mi-cmd-support-effects-log.1
new file mode 100644
index 0000000..8d18e62
--- /dev/null
+++ b/Documentation/nvme-mi-cmd-support-effects-log.1
@@ -0,0 +1,70 @@
+'\" t
+.\" Title: nvme-mi-cmd-support-effects-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MI\-CMD\-SUPPO" "1" "02/14/2024" "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-mi-cmd-support-effects-log \- Send NVMe MI Command Support and Effects log, returns results and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-mi\-cmd\-support\-effects\-log\fR <device> [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an MI Command Support and Effects log (id 13h) and provides the result and returned log 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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+nvme mi\-cmd\-support\-effects\-log /dev/nvme0 \-H
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-mi-cmd-support-effects-log.html b/Documentation/nvme-mi-cmd-support-effects-log.html
new file mode 100644
index 0000000..c70a8b0
--- /dev/null
+++ b/Documentation/nvme-mi-cmd-support-effects-log.html
@@ -0,0 +1,833 @@
+<?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 10.2.0" />
+<title>nvme-mi-cmd-support-effects-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 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-mi-cmd-support-effects-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-mi-cmd-support-effects-log -
+ Send NVMe MI Command Support and Effects log, returns results 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-mi-cmd-support-effects-log</em> &lt;device&gt; [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an MI Command Support and Effects log (id 13h)
+and provides the result and returned log 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme mi-cmd-support-effects-log /dev/nvme0 -H</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-mi-cmd-support-effects-log.txt b/Documentation/nvme-mi-cmd-support-effects-log.txt
new file mode 100644
index 0000000..2221804
--- /dev/null
+++ b/Documentation/nvme-mi-cmd-support-effects-log.txt
@@ -0,0 +1,49 @@
+nvme-mi-cmd-support-effects-log(1)
+==================================
+
+NAME
+----
+nvme-mi-cmd-support-effects-log - Send NVMe MI Command Support and Effects log,
+returns results and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme-mi-cmd-support-effects-log' <device> [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an MI Command Support and Effects log (id 13h)
+and provides the result and returned log structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+nvme mi-cmd-support-effects-log /dev/nvme0 -H
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-clear-pcie-errors.1 b/Documentation/nvme-micron-clear-pcie-errors.1
new file mode 100644
index 0000000..3d76b45
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-CLEAR\" "1" "02/14/2024" "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 correctable 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..b7b9e1a
--- /dev/null
+++ b/Documentation/nvme-micron-clear-pcie-errors.html
@@ -0,0 +1,805 @@
+<?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 10.2.0" />
+<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 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-micron-clear-pcie-errors(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-clear-pcie-errors -
+ Clears correctable PCIe correctable errors of given Micron 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 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 correctable 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
+ 2024-02-14 10:43:42 CET
+</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..4df0e8a
--- /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 correctable 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..97428fd
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-INTERN" "1" "02/14/2024" "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 specified zip file\&. These vendor unique logs can be analyzed 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..6e288c1
--- /dev/null
+++ b/Documentation/nvme-micron-internal-log.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<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 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-micron-internal-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-internal-log -
+ Retrieve Micron device's internal logs and save to given zip file.
+</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 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
+specified zip file. These vendor unique logs can be analyzed 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
+ 2024-02-14 10:43:42 CET
+</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..b8e9228
--- /dev/null
+++ b/Documentation/nvme-micron-internal-log.txt
@@ -0,0 +1,45 @@
+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
+specified zip file. These vendor unique logs can be analyzed 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..bb73919
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-NAND\-" "1" "02/14/2024" "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..57806b0
--- /dev/null
+++ b/Documentation/nvme-micron-nand-stats.html
@@ -0,0 +1,806 @@
+<?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 10.2.0" />
+<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 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-micron-nand-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-nand-stats -
+ Retrieves NAND statistics of given micron 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 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
+ 2024-02-14 10:43:42 CET
+</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..3c1875a
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-PCIE\-" "1" "02/14/2024" "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..d81e4a7
--- /dev/null
+++ b/Documentation/nvme-micron-pcie-stats.html
@@ -0,0 +1,806 @@
+<?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 10.2.0" />
+<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 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-micron-pcie-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-pcie-stats -
+ Retrieves pcie error statistics for given micron 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 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
+ 2024-02-14 10:43:42 CET
+</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..da20310
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.1
@@ -0,0 +1,140 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-SELECT" "1" "02/14/2024" "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 select which firmware binary to update for 9200 devices\&. This requires power cycle 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 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 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..84774ec
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.html
@@ -0,0 +1,876 @@
+<?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 10.2.0" />
+<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 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-micron-selective-download(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-selective-download -
+ Performs selective firmware download that allows user select which firmware binary to update for 9200 devices. This requires power cycle the update completes.
+</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 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 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 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
+ 2024-02-14 10:43:42 CET
+</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..c20af74
--- /dev/null
+++ b/Documentation/nvme-micron-selective-download.txt
@@ -0,0 +1,66 @@
+nvme-micron-selective-download(1)
+=================================
+
+NAME
+----
+nvme-micron-selective-download - Performs selective firmware download that
+allows user select which firmware binary to update for 9200 devices. This
+requires power cycle 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 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 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-smart-add-log.1 b/Documentation/nvme-micron-smart-add-log.1
new file mode 100644
index 0000000..3ef3f17
--- /dev/null
+++ b/Documentation/nvme-micron-smart-add-log.1
@@ -0,0 +1,90 @@
+'\" t
+.\" Title: nvme-micron-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-SMART\" "1" "02/14/2024" "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-smart-add-log \- Retrieves NAND statistics (2200 model drives) or Extended SMART information (OCP complaint models) of given micron device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme micron vs\-smart\-add\-log\fR <device> \-f <json|normal>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command prints NAND information (Total bytes written, Bad block count and Erase failures etc) for the given micron device if its of 2200 model controller\&. For OCP complaint controllers this command print extended SMART health data along with NAND information (if available)
+.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
+The \fI\-f\fR option controls the displayed output data format based on the option value\&. If the option value is \fIjson\fR (which is enabled by default), output data is printed in JSON format\&. If option value is \fInormal\fR the output is displayed in non\-JSON format\&.
+.sp
+This will only work on Micron devices devices of model numbers 54XX and OCP complaint controllers\&. Support for new devices may be added subsequently\&.
+.SH "OPTIONS"
+.PP
+\-f <json|normal>
+.RS 4
+Controls the format of displayed output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve NAND/extended SMART data and display in json format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme micron vs\-nand\-stats /dev/nvme0
+
+* Retrieve NAND/extended SMART data and display in non\-json format
++
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+# nvme micron vs\-nand\-stats /dev/nvme0 \-f normal
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+NVME
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-micron-smart-add-log.html b/Documentation/nvme-micron-smart-add-log.html
new file mode 100644
index 0000000..34a21dd
--- /dev/null
+++ b/Documentation/nvme-micron-smart-add-log.html
@@ -0,0 +1,824 @@
+<?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 10.2.0" />
+<title>nvme-micron-smart-add-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 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-micron-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-smart-add-log -
+ Retrieves NAND statistics (2200 model drives) or Extended SMART information (OCP complaint models) of given micron 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 micron vs-smart-add-log</em> &lt;device&gt; -f &lt;json|normal&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 if its of 2200 model controller.
+For OCP complaint controllers this command print extended SMART health data
+along with NAND information (if available)</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>The <em>-f</em> option controls the displayed output data format based on the option
+value. If the option value is <em>json</em> (which is enabled by default), output data
+is printed in JSON format. If option value is <em>normal</em> the output is displayed
+in non-JSON format.</p></div>
+<div class="paragraph"><p>This will only work on Micron devices devices of model numbers 54XX and OCP
+complaint controllers. 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="dlist"><dl>
+<dt class="hdlist1">
+-f &lt;json|normal&gt;
+</dt>
+<dd>
+<p>
+ Controls the format of displayed output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve NAND/extended SMART data and display in json format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme micron vs-nand-stats /dev/nvme0
+
+* Retrieve NAND/extended SMART data and display in non-json format
++</code></pre>
+</div></div>
+</li>
+</ul></div>
+<div class="paragraph"><p># nvme micron vs-nand-stats /dev/nvme0 -f normal</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>NVME</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-micron-smart-add-log.txt b/Documentation/nvme-micron-smart-add-log.txt
new file mode 100644
index 0000000..13e0d96
--- /dev/null
+++ b/Documentation/nvme-micron-smart-add-log.txt
@@ -0,0 +1,54 @@
+nvme-micron-smart-add-log(1)
+============================
+
+NAME
+----
+nvme-micron-smart-add-log - Retrieves NAND statistics (2200 model drives)
+or Extended SMART information (OCP complaint models) of given micron device
+
+SYNOPSIS
+--------
+[verse]
+'nvme micron vs-smart-add-log' <device> -f <json|normal>
+
+DESCRIPTION
+-----------
+This command prints NAND information (Total bytes written, Bad block count and
+Erase failures etc) for the given micron device if its of 2200 model controller.
+For OCP complaint controllers this command print extended SMART health data
+along with NAND information (if available)
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+The '-f' option controls the displayed output data format based on the option
+value. If the option value is 'json' (which is enabled by default), output data
+is printed in JSON format. If option value is 'normal' the output is displayed
+in non-JSON format.
+
+This will only work on Micron devices devices of model numbers 54XX and OCP
+complaint controllers. Support for new devices may be added subsequently.
+
+OPTIONS
+-------
+-f <json|normal>::
+ Controls the format of displayed output.
+
+EXAMPLES
+--------
+* Retrieve NAND/extended SMART data and display in json format
++
+------------
+# nvme micron vs-nand-stats /dev/nvme0
+
+* Retrieve NAND/extended SMART data and display in non-json format
++
+------------
+# nvme micron vs-nand-stats /dev/nvme0 -f normal
+
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-micron-temperature-stats.1 b/Documentation/nvme-micron-temperature-stats.1
new file mode 100644
index 0000000..ee8a62b
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-micron-temperature-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-MICRON\-TEMPER" "1" "02/14/2024" "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..7fa023f
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.html
@@ -0,0 +1,806 @@
+<?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 10.2.0" />
+<title>nvme-micron-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-micron-temperature-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-micron-temperature-stats -
+ Retrieves temperature information of given micron 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 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
+ 2024-02-14 10:43:42 CET
+</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..8b013d9
--- /dev/null
+++ b/Documentation/nvme-micron-temperature-stats.txt
@@ -0,0 +1,40 @@
+nvme-micron-temperature-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
new file mode 100644
index 0000000..0dda702
--- /dev/null
+++ b/Documentation/nvme-netapp-ontapdevices.1
@@ -0,0 +1,74 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NETAPP\-ONTAPD" "1" "02/14/2024" "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-netapp-ontapdevices \- Display information about ONTAP devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme netapp ontapdevices\fR [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Display information about ONTAP devices on the host\&. The ONTAP devices are identified using the Identify Controller data\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+(default),
+\fIcolumn\fR, or
+\fIjson\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
+.\}
+Display information, in a column\-based format, for ONTAP devices\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme netapp ontapdevices \-o column
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-netapp-ontapdevices.html b/Documentation/nvme-netapp-ontapdevices.html
new file mode 100644
index 0000000..38ef119
--- /dev/null
+++ b/Documentation/nvme-netapp-ontapdevices.html
@@ -0,0 +1,814 @@
+<?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 10.2.0" />
+<title>nvme-netapp-ontapdevices(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-netapp-ontapdevices(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-netapp-ontapdevices -
+ Display information about ONTAP devices
+</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 netapp ontapdevices</em> [--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>Display information about ONTAP devices on the host. The ONTAP devices are
+identified using the Identify Controller data.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> (default), <em>column</em>, or
+ <em>json</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>
+Display information, in a column-based format, for ONTAP devices.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme netapp ontapdevices -o column</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-netapp-ontapdevices.txt b/Documentation/nvme-netapp-ontapdevices.txt
new file mode 100644
index 0000000..fc28947
--- /dev/null
+++ b/Documentation/nvme-netapp-ontapdevices.txt
@@ -0,0 +1,35 @@
+nvme-netapp-ontapdevices(1)
+===========================
+
+NAME
+----
+nvme-netapp-ontapdevices - Display information about ONTAP devices
+
+SYNOPSIS
+--------
+[verse]
+'nvme netapp ontapdevices' [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Display information about ONTAP devices on the host. The ONTAP devices are
+identified using the Identify Controller data.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' (default), 'column', or
+ 'json'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Display information, in a column-based format, for ONTAP devices.
++
+------------
+# nvme netapp ontapdevices -o column
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-netapp-smdevices.1 b/Documentation/nvme-netapp-smdevices.1
new file mode 100644
index 0000000..8f19522
--- /dev/null
+++ b/Documentation/nvme-netapp-smdevices.1
@@ -0,0 +1,74 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NETAPP\-SMDEVI" "1" "02/14/2024" "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-netapp-smdevices \- Display information for each NVMe path to an E\-Series volume
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme netapp smdevices\fR [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Display vendor\-specific information for each NVMe path to an E\-Series namespace currently connected to the host\&. The E\-Series paths are identified from the NVMe nodes in /dev by sending an Identify Controller\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+(default),
+\fIcolumn\fR, or
+\fIjson\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
+.\}
+Display information, in a column\-based format, for each path to an E\-Series namespace\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme netapp smdevices \-o column
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-netapp-smdevices.html b/Documentation/nvme-netapp-smdevices.html
new file mode 100644
index 0000000..2fb4830
--- /dev/null
+++ b/Documentation/nvme-netapp-smdevices.html
@@ -0,0 +1,816 @@
+<?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 10.2.0" />
+<title>nvme-netapp-smdevices(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-netapp-smdevices(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-netapp-smdevices -
+ Display information for each NVMe path to an E-Series volume
+</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 netapp smdevices</em> [--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>Display vendor-specific information for each NVMe path to an E-Series namespace
+currently connected to the host. The E-Series paths are identified from the
+NVMe nodes in /dev by sending an Identify Controller.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> (default), <em>column</em>, or
+ <em>json</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>
+Display information, in a column-based format, for each path to an E-Series
+namespace.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme netapp smdevices -o column</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-netapp-smdevices.txt b/Documentation/nvme-netapp-smdevices.txt
new file mode 100644
index 0000000..cb68acf
--- /dev/null
+++ b/Documentation/nvme-netapp-smdevices.txt
@@ -0,0 +1,37 @@
+nvme-netapp-smdevices(1)
+========================
+
+NAME
+----
+nvme-netapp-smdevices - Display information for each NVMe path to an E-Series volume
+
+SYNOPSIS
+--------
+[verse]
+'nvme netapp smdevices' [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+Display vendor-specific information for each NVMe path to an E-Series namespace
+currently connected to the host. The E-Series paths are identified from the
+NVMe nodes in /dev by sending an Identify Controller.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' (default), 'column', or
+ 'json'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Display information, in a column-based format, for each path to an E-Series
+namespace.
++
+------------
+# nvme netapp smdevices -o column
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-ns-descs.1 b/Documentation/nvme-ns-descs.1
new file mode 100644
index 0000000..cc5a192
--- /dev/null
+++ b/Documentation/nvme-ns-descs.1
@@ -0,0 +1,120 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NS\-DESCS" "1" "02/14/2024" "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-ns-descs \- Send NVMe Identify for a list of Namespace Identification Descriptor structure, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ns\-descs\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify for a list of namespace identification descriptor structures 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)\&. If the character device is given, the \*(Aq\-\-namespace\-id\*(Aq option is mandatory, otherwise it will use the ns\-id of the namespace for the block device you opened\&. For block devices, the ns\-id used can be overridden with the same option\&.
+.sp
+On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the identify namespace identification descriptor structure for the given nsid\&. This is required for the character devices, or overrides the block nsid if given\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If using the character device or overriding namespace #2:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ns\-descs /dev/nvme0 \-n 1
+# nvme ns\-descs /dev/nvme0n1 \-n 2
+# nvme ns\-descs /dev/nvme0 \-\-namespace\-id=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ns\-descs /dev/nvme0n1 \-\-raw\-binary > ns_descs\&.raw
+# nvme ns\-descs /dev/nvme0n1 \-b > ns_descs\&.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-ns-descs.html b/Documentation/nvme-ns-descs.html
new file mode 100644
index 0000000..02dc1fc
--- /dev/null
+++ b/Documentation/nvme-ns-descs.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 10.2.0" />
+<title>nvme-ns-descs(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-ns-descs(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ns-descs -
+ Send NVMe Identify for a list of Namespace Identification Descriptor structure, 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 ns-descs</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify for a list of namespace
+identification descriptor structures 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).
+If the character device is given, the <code>'--namespace-id'</code> option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.</p></div>
+<div class="paragraph"><p>On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the identify namespace identification descriptor structure
+ for the given nsid. This is required for the character devices, or
+ overrides the block nsid if given.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+If using the character device or overriding namespace #2:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ns-descs /dev/nvme0 -n 1
+# nvme ns-descs /dev/nvme0n1 -n 2
+# nvme ns-descs /dev/nvme0 --namespace-id=1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ns-descs /dev/nvme0n1 --raw-binary &gt; ns_descs.raw
+# nvme ns-descs /dev/nvme0n1 -b &gt; ns_descs.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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ns-descs.txt b/Documentation/nvme-ns-descs.txt
new file mode 100644
index 0000000..04c6e51
--- /dev/null
+++ b/Documentation/nvme-ns-descs.txt
@@ -0,0 +1,76 @@
+nvme-ns-descs(1)
+================
+
+NAME
+----
+nvme-ns-descs - Send NVMe Identify for a list of Namespace Identification
+ Descriptor structure, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme ns-descs' <device> [--namespace-id=<nsid> | -n <nsid>] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify for a list of namespace
+identification descriptor structures 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).
+If the character device is given, the `'--namespace-id'` option is
+mandatory, otherwise it will use the ns-id of the namespace for the block
+device you opened. For block devices, the ns-id used can be overridden
+with the same option.
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the identify namespace identification descriptor structure
+ for the given nsid. This is required for the character devices, or
+ overrides the block nsid if given.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* If using the character device or overriding namespace #2:
++
+------------
+# nvme ns-descs /dev/nvme0 -n 1
+# nvme ns-descs /dev/nvme0n1 -n 2
+# nvme ns-descs /dev/nvme0 --namespace-id=1
+------------
++
+
+* Have the program return the raw structure in binary:
++
+------------
+# nvme ns-descs /dev/nvme0n1 --raw-binary > ns_descs.raw
+# nvme ns-descs /dev/nvme0n1 -b > ns_descs.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-ns-rescan.1 b/Documentation/nvme-ns-rescan.1
new file mode 100644
index 0000000..4d62049
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.1
@@ -0,0 +1,79 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NS\-RESCAN" "1" "02/14/2024" "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-ns-rescan \- Rescans the nvme namespaces\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ns\-rescan\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Requests NVMe controller rescans the namespaces\&. The <device> param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Rescans the nvme namespaces\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ns\-rescan /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-ns-rescan.html b/Documentation/nvme-ns-rescan.html
new file mode 100644
index 0000000..622dfbd
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.html
@@ -0,0 +1,825 @@
+<?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 10.2.0" />
+<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 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-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; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ns-rescan.txt b/Documentation/nvme-ns-rescan.txt
new file mode 100644
index 0000000..5681eab
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.txt
@@ -0,0 +1,39 @@
+nvme-ns-rescan(1)
+=================
+
+NAME
+----
+nvme-ns-rescan - Rescans the nvme namespaces.
+
+SYNOPSIS
+--------
+[verse]
+'nvme ns-rescan' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Requests NVMe controller rescans the namespaces. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Rescans the nvme namespaces.
++
+------------
+# nvme ns-rescan /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-nvm-id-ctrl.1 b/Documentation/nvme-nvm-id-ctrl.1
new file mode 100644
index 0000000..343724d
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.1
@@ -0,0 +1,104 @@
+'\" t
+.\" Title: nvme-nvm-id-ctrl
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVM\-ID\-CTRL" "1" "02/14/2024" "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> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..4024a80
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.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 10.2.0" />
+<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 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-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; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</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..eabc4b1
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ctrl.txt
@@ -0,0 +1,53 @@
+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> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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-nvm-id-ns-lba-format.1 b/Documentation/nvme-nvm-id-ns-lba-format.1
new file mode 100644
index 0000000..86723f0
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns-lba-format.1
@@ -0,0 +1,117 @@
+'\" t
+.\" Title: nvme-nvm-id-ns-lba-format
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 01/07/2022
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVM\-ID\-NS\-L" "1" "01/07/2022" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-nvm-id-ns-lba-format \- Send NVMe Identify NVM Command Set specific Namespace data structure for specified LBA format, display structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme nvm\-id\-ns\-lba\-format\fR <device> [\-\-uuid\-index=<uuid\-index> | \-U <uuid_index>]
+ [\-\-lba\-format\-index=<lba_format_index> | \-i <lba_format_index>]
+ [\-v | \-\-verbose]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Identify NVM Command Set specific Namespace data structure for the specified LBA format index for the NVM Command Set specified in the CSI field\&.
+.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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-U <uuid\-index>, \-\-uuid\-index=<uuid\-index>
+.RS 4
+UUID Index of the feature
+.RE
+.PP
+\-i <lba_format_index>, \-\-lba\-format\-index=<lba_format_index>
+.RS 4
+This field specifies the index into the LBA Format list identifying the LBA Format capabilities that are to be returned
+.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 nvm\-id\-ns\-lba\-format /dev/nvme0n1 \-i 0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvm\-id\-ns\-lba\-format /dev/nvme0 \-i 0 \-o binary > nvm_id_ns\&.raw
+# nvme nvm\-id\-ns\-lba\-format /dev/nvme0n1 \-i 0 \-\-output\-format=binary > nvm_id_ns\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-nvm-id-ns-lba-format.html b/Documentation/nvme-nvm-id-ns-lba-format.html
new file mode 100644
index 0000000..09ac1c4
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns-lba-format.html
@@ -0,0 +1,863 @@
+<!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-nvm-id-ns-lba-format(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 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-nvm-id-ns-lba-format(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-nvm-id-ns-lba-format -
+ Send NVMe Identify NVM Command Set specific Namespace data structure for specified LBA format, display 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-ns-lba-format</em> &lt;device&gt; [--uuid-index=&lt;uuid-index&gt; | -U &lt;uuid_index&gt;]
+ [--lba-format-index=&lt;lba_format_index&gt; | -i &lt;lba_format_index&gt;]
+ [-v | --verbose]
+ [--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>Identify NVM Command Set specific Namespace data structure for the specified
+LBA format index for the NVM Command Set specified in the CSI field.</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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-U &lt;uuid-index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid-index=&lt;uuid-index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index of the feature
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;lba_format_index&gt;
+</dt>
+<dt class="hdlist1">
+--lba-format-index=&lt;lba_format_index&gt;
+</dt>
+<dd>
+<p>
+ This field specifies the index into the LBA Format list identifying
+ the LBA Format capabilities that are to be returned
+</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 nvm-id-ns-lba-format /dev/nvme0n1 -i 0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvm-id-ns-lba-format /dev/nvme0 -i 0 -o binary &gt; nvm_id_ns.raw
+# nvme nvm-id-ns-lba-format /dev/nvme0n1 -i 0 --output-format=binary &gt; nvm_id_ns.raw</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 2022-01-07 19:00:31 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvm-id-ns-lba-format.txt b/Documentation/nvme-nvm-id-ns-lba-format.txt
new file mode 100644
index 0000000..1048995
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns-lba-format.txt
@@ -0,0 +1,66 @@
+nvme-nvm-id-ns-lba-format(1)
+============================
+
+NAME
+----
+nvme-nvm-id-ns-lba-format - Send NVMe Identify NVM Command Set specific
+Namespace data structure for specified LBA format, display structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme nvm-id-ns-lba-format' <device> [--uuid-index=<uuid-index> | -U <uuid_index>]
+ [--lba-format-index=<lba_format_index> | -i <lba_format_index>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Identify NVM Command Set specific Namespace data structure for the specified
+LBA format index for the NVM Command Set specified in the CSI field.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-U <uuid-index>::
+--uuid-index=<uuid-index>::
+ UUID Index of the feature
+
+-i <lba_format_index>::
+--lba-format-index=<lba_format_index>::
+ This field specifies the index into the LBA Format list identifying
+ the LBA Format capabilities that are to be returned
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme nvm-id-ns-lba-format /dev/nvme0n1 -i 0
+------------
++
+* Have the program return the raw structure in binary:
++
+------------
+# nvme nvm-id-ns-lba-format /dev/nvme0 -i 0 -o binary > nvm_id_ns.raw
+# nvme nvm-id-ns-lba-format /dev/nvme0n1 -i 0 --output-format=binary > nvm_id_ns.raw
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-nvm-id-ns.1 b/Documentation/nvme-nvm-id-ns.1
new file mode 100644
index 0000000..fde30b7
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns.1
@@ -0,0 +1,162 @@
+'\" t
+.\" Title: nvme-nvm-id-ns
+.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 01/07/2022
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVM\-ID\-NS" "1" "01/07/2022" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-nvm-id-ns \- Send NVMe Identify NVM Command Set specific Namespace data structure, display structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme nvm\-id\-ns\fR <device> [\-\-uuid\-index=<uuid\-index> | \-U <uuid_index>]
+ [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-v | \-\-verbose]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Identify NVM Command Set specific Namespace data structure for the specified NSID for the NVM Command Set specified in the CSI field\&.
+.sp
+The <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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-n <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
+\-U <uuid\-index>, \-\-uuid\-index=<uuid\-index>
+.RS 4
+UUID Index of the feature
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.PP
+\-o <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\-ns /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+If using the character device or overriding namespace id:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvm\-id\-ns /dev/nvme0 \-n 1
+# nvme nvm\-id\-ns /dev/nvme0n1 \-n 1
+# nvme nvm\-id\-ns /dev/nvme0 \-\-namespace\-id=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Have the program return the raw structure in binary:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvm\-id\-ns /dev/nvme0n1 \-o binary > id_ns\&.raw
+# nvme nvm\-id\-ns /dev/nvme0n1 \-\-output\-format=binary > id_ns\&.raw
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+It is probably a bad idea to not redirect stdout when using this mode\&.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Alternatively you may want to send the data to another program that can parse the raw buffer\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+NVME
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-nvm-id-ns.html b/Documentation/nvme-nvm-id-ns.html
new file mode 100644
index 0000000..82645dc
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns.html
@@ -0,0 +1,881 @@
+<!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-nvm-id-ns(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 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-nvm-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-nvm-id-ns -
+ Send NVMe Identify NVM Command Set specific Namespace data structure, display 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-ns</em> &lt;device&gt; [--uuid-index=&lt;uuid-index&gt; | -U &lt;uuid_index&gt;]
+ [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [-v | --verbose]
+ [--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>Identify NVM Command Set specific Namespace data structure for the specified
+NSID for the NVM Command Set specified in the CSI field.</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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</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">
+-U &lt;uuid-index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid-index=&lt;uuid-index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index of the feature
+</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 nvm-id-ns /dev/nvme0n1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+If using the character device or overriding namespace id:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvm-id-ns /dev/nvme0 -n 1
+# nvme nvm-id-ns /dev/nvme0n1 -n 1
+# nvme nvm-id-ns /dev/nvme0 --namespace-id=1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Have the program return the raw structure in binary:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvm-id-ns /dev/nvme0n1 -o binary &gt; id_ns.raw
+# nvme nvm-id-ns /dev/nvme0n1 --output-format=binary &gt; id_ns.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>
+<li>
+<p>
+Alternatively you may want to send the data to another program that
+can parse the raw buffer.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code>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 2022-01-07 14:55:44 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvm-id-ns.txt b/Documentation/nvme-nvm-id-ns.txt
new file mode 100644
index 0000000..5a8cb09
--- /dev/null
+++ b/Documentation/nvme-nvm-id-ns.txt
@@ -0,0 +1,82 @@
+nvme-nvm-id-ns(1)
+=================
+
+NAME
+----
+nvme-nvm-id-ns - Send NVMe Identify NVM Command Set specific Namespace data structure, display structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme nvm-id-ns' <device> [--uuid-index=<uuid-index> | -U <uuid_index>]
+ [--namespace-id=<NUM> | -n <NUM>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Identify NVM Command Set specific Namespace data structure for the specified
+NSID for the NVM Command Set specified in the CSI field.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Use the provided namespace id for the command. If not provided, the
+ namespace id of the block device will be used. If the command is issued
+ to a non-block device, the parameter is required.
+
+-U <uuid-index>::
+--uuid-index=<uuid-index>::
+ UUID Index of the feature
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme nvm-id-ns /dev/nvme0n1
+------------
++
+
+* If using the character device or overriding namespace id:
++
+------------
+# nvme nvm-id-ns /dev/nvme0 -n 1
+# nvme nvm-id-ns /dev/nvme0n1 -n 1
+# nvme nvm-id-ns /dev/nvme0 --namespace-id=1
+------------
++
+* Have the program return the raw structure in binary:
++
+------------
+# nvme nvm-id-ns /dev/nvme0n1 -o binary > id_ns.raw
+# nvme nvm-id-ns /dev/nvme0n1 --output-format=binary > id_ns.raw
+------------
++
+It is probably a bad idea to not redirect stdout when using this mode.
+
+* Alternatively you may want to send the data to another program that
+can parse the raw buffer.
++
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-nvme-mi-recv.1 b/Documentation/nvme-nvme-mi-recv.1
new file mode 100644
index 0000000..789d620
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-recv.1
@@ -0,0 +1,124 @@
+'\" t
+.\" Title: nvme-nvme-mi-recv
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVME\-MI\-RECV" "1" "02/14/2024" "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-nvme-mi-recv \- Send a NVMe\-MI Receive command to the specified device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme nvme\-mi\-recv\fR <device> [\-\-opcode=<opcode> | \-O <opcode>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-nmimt=<nmimt> | \-m <nmimt>]
+ [\-\-nmd0=<nmd0> | \-0 <nmd0>] [\-\-nmd1=<nmd1> | \-1 <nmd1>]
+ [\-\-input\-file=<file> | \-i <file>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send a NVMe\-MI Receive command to the specified device, return results\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-O <opcode>, \-\-opcode=<opcode>
+.RS 4
+The NVMe\-MI opcode to send to the device in the command
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The value for the ns\-id in the command\&.
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer used for this command\&.
+.RE
+.PP
+\-m <nmimt>, \-\-nmimt=<nmimt>
+.RS 4
+The value for the NVMe\-MI message type in the command\&.
+.RE
+.PP
+\-0 <nmd0>, \-\-nmd0=<nmd0>
+.RS 4
+The value for the NVMe management request dword 0 in the command\&.
+.RE
+.PP
+\-1 <nmd1>, \-\-nmd1=<nmd1>
+.RS 4
+The value for the NVMe management request dword 1 in the command\&.
+.RE
+.PP
+\-i <file>, \-\-input\-file=<file>
+.RS 4
+If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue a nvme\-mi\-recv to execute the VPD read\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvme\-mi\-recv /dev/nvme0n1 \-O 5 \-m 1 \-0 0 \-1 0x100 \-l 256
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-nvme-mi-recv.html b/Documentation/nvme-nvme-mi-recv.html
new file mode 100644
index 0000000..758e4fc
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-recv.html
@@ -0,0 +1,912 @@
+<?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 10.2.0" />
+<title>nvme-nvme-mi-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 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-nvme-mi-recv(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-nvme-mi-recv -
+ Send a NVMe-MI Receive command to the specified 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 nvme-mi-recv</em> &lt;device&gt; [--opcode=&lt;opcode&gt; | -O &lt;opcode&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--nmimt=&lt;nmimt&gt; | -m &lt;nmimt&gt;]
+ [--nmd0=&lt;nmd0&gt; | -0 &lt;nmd0&gt;] [--nmd1=&lt;nmd1&gt; | -1 &lt;nmd1&gt;]
+ [--input-file=&lt;file&gt; | -i &lt;file&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send a NVMe-MI Receive command to the specified device, return results.</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 block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success it returns 0, 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;opcode&gt;
+</dt>
+<dt class="hdlist1">
+--opcode=&lt;opcode&gt;
+</dt>
+<dd>
+<p>
+ The NVMe-MI opcode to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The value for the ns-id in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;nmimt&gt;
+</dt>
+<dt class="hdlist1">
+--nmimt=&lt;nmimt&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe-MI message type in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-0 &lt;nmd0&gt;
+</dt>
+<dt class="hdlist1">
+--nmd0=&lt;nmd0&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe management request dword 0 in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-1 &lt;nmd1&gt;
+</dt>
+<dt class="hdlist1">
+--nmd1=&lt;nmd1&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe management request dword 1 in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--input-file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 issue a nvme-mi-recv to execute the VPD read.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvme-mi-recv /dev/nvme0n1 -O 5 -m 1 -0 0 -1 0x100 -l 256</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvme-mi-recv.txt b/Documentation/nvme-nvme-mi-recv.txt
new file mode 100755
index 0000000..152bbe6
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-recv.txt
@@ -0,0 +1,79 @@
+nvme-nvme-mi-recv(1)
+====================
+
+NAME
+----
+nvme-nvme-mi-recv - Send a NVMe-MI Receive command to the specified device
+
+SYNOPSIS
+--------
+[verse]
+'nvme nvme-mi-recv' <device> [--opcode=<opcode> | -O <opcode>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--nmimt=<nmimt> | -m <nmimt>]
+ [--nmd0=<nmd0> | -0 <nmd0>] [--nmd1=<nmd1> | -1 <nmd1>]
+ [--input-file=<file> | -i <file>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send a NVMe-MI Receive command to the specified device, return results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-O <opcode>::
+--opcode=<opcode>::
+ The NVMe-MI opcode to send to the device in the command
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ The value for the ns-id in the command.
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer used for this command.
+
+-m <nmimt>::
+--nmimt=<nmimt>::
+ The value for the NVMe-MI message type in the command.
+
+-0 <nmd0>::
+--nmd0=<nmd0>::
+ The value for the NVMe management request dword 0 in the command.
+
+-1 <nmd1>::
+--nmd1=<nmd1>::
+ The value for the NVMe management request dword 1 in the command.
+
+-i <file>::
+--input-file=<file>::
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a nvme-mi-recv to execute the VPD read.
++
+------------
+# nvme nvme-mi-recv /dev/nvme0n1 -O 5 -m 1 -0 0 -1 0x100 -l 256
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-nvme-mi-send.1 b/Documentation/nvme-nvme-mi-send.1
new file mode 100644
index 0000000..31317d8
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-send.1
@@ -0,0 +1,124 @@
+'\" t
+.\" Title: nvme-nvme-mi-send
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NVME\-MI\-SEND" "1" "02/14/2024" "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-nvme-mi-send \- Send a NVMe\-MI Send command to the specified device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme nvme\-mi\-send\fR <device> [\-\-opcode=<opcode> | \-O <opcode>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-nmimt=<nmimt> | \-m <nmimt>]
+ [\-\-nmd0=<nmd0> | \-0 <nmd0>] [\-\-nmd1=<nmd1> | \-1 <nmd1>]
+ [\-\-input\-file=<file> | \-i <file>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send a NVMe\-MI Send command to the specified device, return results\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-O <opcode>, \-\-opcode=<opcode>
+.RS 4
+The NVMe\-MI opcode to send to the device in the command
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+The value for the ns\-id in the command\&.
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer used for this command\&.
+.RE
+.PP
+\-m <nmimt>, \-\-nmimt=<nmimt>
+.RS 4
+The value for the NVMe\-MI message type in the command\&.
+.RE
+.PP
+\-0 <nmd0>, \-\-nmd0=<nmd0>
+.RS 4
+The value for the NVMe management request dword 0 in the command\&.
+.RE
+.PP
+\-1 <nmd1>, \-\-nmd1=<nmd1>
+.RS 4
+The value for the NVMe management request dword 1 in the command\&.
+.RE
+.PP
+\-i <file>, \-\-input\-file=<file>
+.RS 4
+If the command is a data\-out (write) command, use this file to fill the buffer sent to the device\&. If no file is given, assumed to use STDIN\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue a nvme\-mi\-send to execute the VPD write\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme nvme\-mi\-send /dev/nvme0n1 \-O 6 \-m 1 \-0 0 \-1 0x100 \-l 256 \-i vpd\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-nvme-mi-send.html b/Documentation/nvme-nvme-mi-send.html
new file mode 100644
index 0000000..85aef3a
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-send.html
@@ -0,0 +1,912 @@
+<?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 10.2.0" />
+<title>nvme-nvme-mi-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 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-nvme-mi-send(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-nvme-mi-send -
+ Send a NVMe-MI Send command to the specified 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 nvme-mi-send</em> &lt;device&gt; [--opcode=&lt;opcode&gt; | -O &lt;opcode&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--nmimt=&lt;nmimt&gt; | -m &lt;nmimt&gt;]
+ [--nmd0=&lt;nmd0&gt; | -0 &lt;nmd0&gt;] [--nmd1=&lt;nmd1&gt; | -1 &lt;nmd1&gt;]
+ [--input-file=&lt;file&gt; | -i &lt;file&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send a NVMe-MI Send command to the specified device, return results.</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 block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>On success it returns 0, 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;opcode&gt;
+</dt>
+<dt class="hdlist1">
+--opcode=&lt;opcode&gt;
+</dt>
+<dd>
+<p>
+ The NVMe-MI opcode to send to the device in the command
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ The value for the ns-id in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer used for this command.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;nmimt&gt;
+</dt>
+<dt class="hdlist1">
+--nmimt=&lt;nmimt&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe-MI message type in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-0 &lt;nmd0&gt;
+</dt>
+<dt class="hdlist1">
+--nmd0=&lt;nmd0&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe management request dword 0 in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-1 &lt;nmd1&gt;
+</dt>
+<dt class="hdlist1">
+--nmd1=&lt;nmd1&gt;
+</dt>
+<dd>
+<p>
+ The value for the NVMe management request dword 1 in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--input-file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 issue a nvme-mi-send to execute the VPD write.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme nvme-mi-send /dev/nvme0n1 -O 6 -m 1 -0 0 -1 0x100 -l 256 -i vpd.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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-nvme-mi-send.txt b/Documentation/nvme-nvme-mi-send.txt
new file mode 100755
index 0000000..0e80fe7
--- /dev/null
+++ b/Documentation/nvme-nvme-mi-send.txt
@@ -0,0 +1,79 @@
+nvme-nvme-mi-send(1)
+====================
+
+NAME
+----
+nvme-nvme-mi-send - Send a NVMe-MI Send command to the specified device
+
+SYNOPSIS
+--------
+[verse]
+'nvme nvme-mi-send' <device> [--opcode=<opcode> | -O <opcode>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--nmimt=<nmimt> | -m <nmimt>]
+ [--nmd0=<nmd0> | -0 <nmd0>] [--nmd1=<nmd1> | -1 <nmd1>]
+ [--input-file=<file> | -i <file>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Send a NVMe-MI Send command to the specified device, return results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-O <opcode>::
+--opcode=<opcode>::
+ The NVMe-MI opcode to send to the device in the command
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ The value for the ns-id in the command.
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer used for this command.
+
+-m <nmimt>::
+--nmimt=<nmimt>::
+ The value for the NVMe-MI message type in the command.
+
+-0 <nmd0>::
+--nmd0=<nmd0>::
+ The value for the NVMe management request dword 0 in the command.
+
+-1 <nmd1>::
+--nmd1=<nmd1>::
+ The value for the NVMe management request dword 1 in the command.
+
+-i <file>::
+--input-file=<file>::
+ If the command is a data-out (write) command, use this file
+ to fill the buffer sent to the device. If no file is given,
+ assumed to use STDIN.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a nvme-mi-send to execute the VPD write.
++
+------------
+# nvme nvme-mi-send /dev/nvme0n1 -O 6 -m 1 -0 0 -1 0x100 -l 256 -i vpd.bin
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.1 b/Documentation/nvme-ocp-clear-fw-activate-history.1
new file mode 100644
index 0000000..29e9e95
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-fw-activate-history.1
@@ -0,0 +1,78 @@
+'\" t
+.\" Title: nvme-ocp-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-OCP\-CLEAR\-FW" "1" "02/14/2024" "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-ocp-clear-fw-activate-history \- Clear the OCP Firmware Update History Log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ocp clear\-fw\-activate\-history\fR <device> [\-\-no\-uuid | \-n]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, Clear OCP Firmware Update History Log\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&.
+.sp
+This command with no option added, will try to automatically detect the parameters of the command\&. This will work successfully or fail gracefully for devices supporting UUID for Vendor Specific Information (NVMe 1\&.4 or later, OCP 2\&.0 requires NVMe 1\&.4b)\&. For devices that do not support OCP 2\&.0 the command will fail gracefully, unless the \-\-no\-uuid option is provided\&.
+.sp
+For OCP 1\&.0 devices (before NVMe 1\&.4) the \-\-no\-uuid option is required\&. When \-\-no\-uuid option is provided, results for devices before NVMe 1\&.4 without OCP support are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-n, \-\-no\-uuid
+.RS 4
+Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support)
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears OCP Firmware Activation History Log for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ocp clear\-fw\-activate\-history /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.html b/Documentation/nvme-ocp-clear-fw-activate-history.html
new file mode 100644
index 0000000..a2035db
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-fw-activate-history.html
@@ -0,0 +1,824 @@
+<?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 10.2.0" />
+<title>nvme-ocp-clear-fw-activate-history(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-ocp-clear-fw-activate-history(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ocp-clear-fw-activate-history -
+ Clear the OCP Firmware Update History 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 ocp clear-fw-activate-history</em> &lt;device&gt; [--no-uuid | -n]</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, Clear OCP Firmware Update History 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) or block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This command with no option added, will try to automatically detect the
+parameters of the command. This will work successfully or fail gracefully for
+devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later,
+OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the
+command will fail gracefully, unless the --no-uuid option is provided.</p></div>
+<div class="paragraph"><p>For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required.
+When --no-uuid option is provided, results for devices before NVMe 1.4 without
+OCP support are undefined.</p></div>
+<div class="paragraph"><p>On success it returns 0, 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">
+-n
+</dt>
+<dt class="hdlist1">
+--no-uuid
+</dt>
+<dd>
+<p>
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Clears OCP Firmware Activation History Log for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ocp clear-fw-activate-history /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ocp-clear-fw-activate-history.txt b/Documentation/nvme-ocp-clear-fw-activate-history.txt
new file mode 100644
index 0000000..335a228
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-fw-activate-history.txt
@@ -0,0 +1,49 @@
+nvme-ocp-clear-fw-activate-history(1)
+=====================================
+
+NAME
+----
+nvme-ocp-clear-fw-activate-history - Clear the OCP Firmware Update History Log
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp clear-fw-activate-history' <device> [--no-uuid | -n]
+
+DESCRIPTION
+-----------
+For the NVMe device given, Clear OCP Firmware Update History Log.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This command with no option added, will try to automatically detect the
+parameters of the command. This will work successfully or fail gracefully for
+devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later,
+OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the
+command will fail gracefully, unless the --no-uuid option is provided.
+
+For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required.
+When --no-uuid option is provided, results for devices before NVMe 1.4 without
+OCP support are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-n::
+--no-uuid::
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+
+EXAMPLES
+--------
+* Clears OCP Firmware Activation History Log for the device:
++
+------------
+# nvme ocp clear-fw-activate-history /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite. \ No newline at end of file
diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1 b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1
new file mode 100644
index 0000000..9652db5
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.1
@@ -0,0 +1,78 @@
+'\" t
+.\" Title: nvme-ocp-clear-pcie-correctable-error-counters
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-OCP\-CLEAR\-PC" "1" "02/14/2024" "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-ocp-clear-pcie-correctable-error-counters \- Clear PCIe correctable error counters
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ocp clear\-pcie\-correctable\-error\-counters\fR <device> [\-\-no\-uuid | \-n]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, Clear PCIe correctable error counters\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1)\&.
+.sp
+This command with no option added, will try to automatically detect the parameters of the command\&. This will work successfully or fail gracefully for devices supporting UUID for Vendor Specific Information (NVMe 1\&.4 or later, OCP 2\&.0 requires NVMe 1\&.4b)\&. For devices that do not support OCP 2\&.0 the command will fail gracefully, unless the \-\-no\-uuid option is provided\&.
+.sp
+For OCP 1\&.0 devices (before NVMe 1\&.4) the \-\-no\-uuid option is required\&. When \-\-no\-uuid option is provided, results for devices before NVMe 1\&.4 without OCP support are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-n, \-\-no\-uuid
+.RS 4
+Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support)
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears PCIe correctable error counters Log for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ocp clear\-pcie\-correctable\-error\-counters /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html
new file mode 100644
index 0000000..c05eb8d
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.html
@@ -0,0 +1,824 @@
+<?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 10.2.0" />
+<title>nvme-ocp-clear-pcie-correctable-error-counters(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-ocp-clear-pcie-correctable-error-counters(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ocp-clear-pcie-correctable-error-counters -
+ Clear PCIe correctable error counters
+</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 ocp clear-pcie-correctable-error-counters</em> &lt;device&gt; [--no-uuid | -n]</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, Clear PCIe correctable error counters.</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 block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This command with no option added, will try to automatically detect the
+parameters of the command. This will work successfully or fail gracefully for
+devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later,
+OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the
+command will fail gracefully, unless the --no-uuid option is provided.</p></div>
+<div class="paragraph"><p>For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required.
+When --no-uuid option is provided, results for devices before NVMe 1.4 without
+OCP support are undefined.</p></div>
+<div class="paragraph"><p>On success it returns 0, 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">
+-n
+</dt>
+<dt class="hdlist1">
+--no-uuid
+</dt>
+<dd>
+<p>
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Clears PCIe correctable error counters Log for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ocp clear-pcie-correctable-error-counters /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt
new file mode 100644
index 0000000..3d5706d
--- /dev/null
+++ b/Documentation/nvme-ocp-clear-pcie-correctable-error-counters.txt
@@ -0,0 +1,49 @@
+nvme-ocp-clear-pcie-correctable-error-counters(1)
+=================================================
+
+NAME
+----
+nvme-ocp-clear-pcie-correctable-error-counters - Clear PCIe correctable error counters
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp clear-pcie-correctable-error-counters' <device> [--no-uuid | -n]
+
+DESCRIPTION
+-----------
+For the NVMe device given, Clear PCIe correctable error counters.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This command with no option added, will try to automatically detect the
+parameters of the command. This will work successfully or fail gracefully for
+devices supporting UUID for Vendor Specific Information (NVMe 1.4 or later,
+OCP 2.0 requires NVMe 1.4b). For devices that do not support OCP 2.0 the
+command will fail gracefully, unless the --no-uuid option is provided.
+
+For OCP 1.0 devices (before NVMe 1.4) the --no-uuid option is required.
+When --no-uuid option is provided, results for devices before NVMe 1.4 without
+OCP support are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-n::
+--no-uuid::
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+
+EXAMPLES
+--------
+* Clears PCIe correctable error counters Log for the device:
++
+------------
+# nvme ocp clear-pcie-correctable-error-counters /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-device-capability-log.txt b/Documentation/nvme-ocp-device-capability-log.txt
new file mode 100644
index 0000000..d2f0761
--- /dev/null
+++ b/Documentation/nvme-ocp-device-capability-log.txt
@@ -0,0 +1,42 @@
+nvme-ocp-device-capability-log(1)
+=================================
+
+NAME
+----
+nvme-ocp-device-capability-log - Retrieves OCP Device Capability Log Page
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp device-capability-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves OCP Device Capability Log Page
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json' or 'binary'.
+ Only one output format can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* Has the program issue a device-capability-log command to retrieve the 0xC4 log page.
++
+------------
+# nvme ocp device-capability-log /dev/nvme0 -o normal
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.1 b/Documentation/nvme-ocp-eol-plp-failure-mode.1
new file mode 100644
index 0000000..dbefc04
--- /dev/null
+++ b/Documentation/nvme-ocp-eol-plp-failure-mode.1
@@ -0,0 +1,137 @@
+'\" t
+.\" Title: nvme-ocp-eol-plp-failure-mode
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-OCP\-EOL\-PLP\" "1" "02/14/2024" "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-ocp-eol-plp-failure-mode \- Define and print EOL or PLP circuitry failure mode
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ocp eol\-plp\-failure\-mode\fR <device> [\-\-mode=<mode> | \-m <mode>]
+ [\-\-no\-uuid | \-n] [\-\-save | \-s]
+ [\-\-sel=<select> | \-s <select>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Define EOL or PLP circuitry failure mode\&. No argument prints current mode\&.
+.sp
+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 OCP compliant devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-m <mode>, \-\-mode=<mode>
+.RS 4
+Set the EOL or PLP circuitry failure mode to [0\-3] (\fI0: default\fR,
+\fI1: rom\fR,
+\fI2: wtm\fR
+or
+\fI3: normal\fR)\&. Only one mode can be used at a time\&. The default is rom\&.
+.RE
+.PP
+\-n, \-\-no\-uuid
+.RS 4
+Do not try to automatically detect UUID index for this command (required for old OCP 1\&.0 support)
+.RE
+.PP
+\-s, \-\-save
+.RS 4
+Save the attribute so that it persists through all power states and resets\&.
+.RE
+.PP
+\-s <select>, \-\-sel=<select>
+.RS 4
+Select (SEL): This field specifies which value of the attributes to return in the provided data:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Select
+T}:T{
+Description
+T}
+T{
+0
+T}:T{
+Current
+T}
+T{
+1
+T}:T{
+Default
+T}
+T{
+2
+T}:T{
+Saved
+T}
+T{
+3
+T}:T{
+Supported capabilities
+T}
+T{
+4\-7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue a eol\-plp\-failure\-mode to retrieve the 0xC2 get features\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ocp eol\-plp\-failure\-mode /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.html b/Documentation/nvme-ocp-eol-plp-failure-mode.html
new file mode 100644
index 0000000..ce22f5f
--- /dev/null
+++ b/Documentation/nvme-ocp-eol-plp-failure-mode.html
@@ -0,0 +1,893 @@
+<?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 10.2.0" />
+<title>nvme-ocp-eol-plp-failure-mode(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-ocp-eol-plp-failure-mode(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ocp-eol-plp-failure-mode -
+ Define and print EOL or PLP circuitry failure mode
+</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 ocp eol-plp-failure-mode</em> &lt;device&gt; [--mode=&lt;mode&gt; | -m &lt;mode&gt;]
+ [--no-uuid | -n] [--save | -s]
+ [--sel=&lt;select&gt; | -s &lt;select&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Define EOL or PLP circuitry failure mode.
+No argument prints current mode.</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 block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on OCP compliant 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-m &lt;mode&gt;
+</dt>
+<dt class="hdlist1">
+--mode=&lt;mode&gt;
+</dt>
+<dd>
+<p>
+ Set the EOL or PLP circuitry failure mode to [0-3] (<em>0: default</em>,
+ <em>1: rom</em>, <em>2: wtm</em> or <em>3: normal</em>). Only one mode
+ can be used at a time. The default is rom.
+</p>
+</dd>
+<dt class="hdlist1">
+-n
+</dt>
+<dt class="hdlist1">
+--no-uuid
+</dt>
+<dd>
+<p>
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+</p>
+</dd>
+<dt class="hdlist1">
+-s
+</dt>
+<dt class="hdlist1">
+--save
+</dt>
+<dd>
+<p>
+ Save the attribute so that it persists through all power states and
+ resets.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;select&gt;
+</dt>
+<dt class="hdlist1">
+--sel=&lt;select&gt;
+</dt>
+<dd>
+<p>
+ Select (SEL): This field specifies which value of the attributes
+ to return in the provided data:
+</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">Select</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Current</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Default</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Saved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Supported capabilities</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4-7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</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 issue a eol-plp-failure-mode to retrieve the 0xC2 get features.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ocp eol-plp-failure-mode /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ocp-eol-plp-failure-mode.txt b/Documentation/nvme-ocp-eol-plp-failure-mode.txt
new file mode 100644
index 0000000..0ebc4ab
--- /dev/null
+++ b/Documentation/nvme-ocp-eol-plp-failure-mode.txt
@@ -0,0 +1,72 @@
+nvme-ocp-eol-plp-failure-mode(1)
+================================
+
+NAME
+----
+nvme-ocp-eol-plp-failure-mode - Define and print EOL or PLP circuitry failure
+mode
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp eol-plp-failure-mode' <device> [--mode=<mode> | -m <mode>]
+ [--no-uuid | -n] [--save | -s]
+ [--sel=<select> | -s <select>]
+
+DESCRIPTION
+-----------
+Define EOL or PLP circuitry failure mode.
+No argument prints current mode.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-m <mode>::
+--mode=<mode>::
+ Set the EOL or PLP circuitry failure mode to [0-3] ('0: default',
+ '1: rom', '2: wtm' or '3: normal'). Only one mode
+ can be used at a time. The default is rom.
+
+-n::
+--no-uuid::
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+
+-s::
+--save::
+ Save the attribute so that it persists through all power states and
+ resets.
+
+-s <select>::
+--sel=<select>::
+ Select (SEL): This field specifies which value of the attributes
+ to return in the provided data:
++
+[]
+|==================
+|Select|Description
+|0|Current
+|1|Default
+|2|Saved
+|3|Supported capabilities
+|4-7|Reserved
+|==================
+
+EXAMPLES
+--------
+* Has the program issue a eol-plp-failure-mode to retrieve the 0xC2 get features.
++
+------------
+# nvme ocp eol-plp-failure-mode /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-error-recovery-log.txt b/Documentation/nvme-ocp-error-recovery-log.txt
new file mode 100644
index 0000000..7a26150
--- /dev/null
+++ b/Documentation/nvme-ocp-error-recovery-log.txt
@@ -0,0 +1,42 @@
+nvme-ocp-error-recovery-log(1)
+==============================
+
+NAME
+----
+nvme-ocp-error-recovery-log - Retrieves OCP Error Recovery Log Page
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp error-recovery-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves OCP Error Recovery Log Page
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json' or 'binary'.
+ Only one output format can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* Has the program issue a error-recovery-log command to retrieve the 0xC1 log page.
++
+------------
+# nvme ocp error-recovery-log /dev/nvme0 -o normal
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-get-plp-health-check-interval.txt b/Documentation/nvme-ocp-get-plp-health-check-interval.txt
new file mode 100644
index 0000000..7ecd5d5
--- /dev/null
+++ b/Documentation/nvme-ocp-get-plp-health-check-interval.txt
@@ -0,0 +1,54 @@
+nvme-ocp-get-plp-health-check-interval(1)
+================================
+
+NAME
+----
+nvme-ocp-get-plp-health-check-interval - Define and print plp-health-check-interval value
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp get-plp-health-check-interval' <device> [--sel=<select> | -s <select>]
+
+DESCRIPTION
+-----------
+Define plp-health-check-interval.
+No argument prints current mode.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+
+-s <select>::
+--sel=<select>::
+ Select (SEL): This field specifies which value of the attributes
+ to return in the provided data:
++
+[]
+|==================
+|Select|Description
+|0|Current
+|1|Default
+|2|Saved
+|3|Supported capabilities
+|4-7|Reserved
+|==================
+
+EXAMPLES
+--------
+* Has the program issue a get-plp-health-check-interval to retrieve the 0xC6 get features.
++
+------------
+# nvme ocp get-plp-health-check-interval /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-latency-monitor-log.1 b/Documentation/nvme-ocp-latency-monitor-log.1
new file mode 100644
index 0000000..7fa607e
--- /dev/null
+++ b/Documentation/nvme-ocp-latency-monitor-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-ocp-latency-monitor-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-OCP\-LATENCY\-" "1" "02/14/2024" "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-ocp-latency-monitor-log \- Display latency monitor log page data in human readable format
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ocp latency\-monitor\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, latency monitor log page data\&.
+.sp
+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 OCP compliant devices supporting this log page\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+or
+\fIjson\fR\&. Only one output format can be used at a time\&. The default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Displays the get latency monitor log for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ocp latency\-monitor\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-ocp-latency-monitor-log.html b/Documentation/nvme-ocp-latency-monitor-log.html
new file mode 100644
index 0000000..a6cae12
--- /dev/null
+++ b/Documentation/nvme-ocp-latency-monitor-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 10.2.0" />
+<title>nvme-ocp-latency-monitor-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 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-ocp-latency-monitor-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ocp-latency-monitor-log -
+ Display latency monitor log page data in human readable format
+</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 ocp latency-monitor-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>For the NVMe device given, latency monitor log page data.</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 block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on OCP compliant devices supporting this log page.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns 0, 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> or <em>json</em>. Only one output format
+ can be used at a time. The default is normal.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Displays the get latency monitor log for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ocp latency-monitor-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ocp-latency-monitor-log.txt b/Documentation/nvme-ocp-latency-monitor-log.txt
new file mode 100644
index 0000000..a67c523
--- /dev/null
+++ b/Documentation/nvme-ocp-latency-monitor-log.txt
@@ -0,0 +1,44 @@
+nvme-ocp-latency-monitor-log(1)
+===============================
+
+NAME
+----
+nvme-ocp-latency-monitor-log - Display latency monitor log page data in human
+readable format
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp latency-monitor-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, latency monitor log page data.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this log page.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json'. Only one output format
+ can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* Displays the get latency monitor log for the device:
++
+------------
+# nvme ocp latency-monitor-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-set-dssd-power-state-feature.txt b/Documentation/nvme-ocp-set-dssd-power-state-feature.txt
new file mode 100644
index 0000000..c9ae578
--- /dev/null
+++ b/Documentation/nvme-ocp-set-dssd-power-state-feature.txt
@@ -0,0 +1,43 @@
+set-dssd-power-state-feature(1)
+===============================
+
+NAME
+----
+nvme-ocp-set-dssd-power-state-feature - Set DSSD Power State
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp set-dssd-power-state-feature' <device>
+ [--power-state=<fmt> | -p <fmt>] [--no-uuid | -n]
+ [--save | -s]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves OCP DSSD Power state Feature
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-p <fmt>::
+--power-state=<fmt>::
+ DSSD Power State to set in watts.
+
+EXAMPLES
+--------
+* Has the program issue a set-dssd-power-state-feature command to set DSSD Power State to set in watts.
++
+------------
+# nvme ocp set-dssd-power-state-feature /dev/nvme0 -p <value> -s <value> -n <value>
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-set-plp-health-check-interval.txt b/Documentation/nvme-ocp-set-plp-health-check-interval.txt
new file mode 100644
index 0000000..ac3acb3
--- /dev/null
+++ b/Documentation/nvme-ocp-set-plp-health-check-interval.txt
@@ -0,0 +1,53 @@
+nvme-ocp-set-plp-health-check-interval(1)
+================================
+
+NAME
+----
+nvme-ocp-set-plp-health-check-interval - Define and set PLP health check interval
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp set-plp-health-check-interval' <device> [--plp_health_interval=<plp_health_interval> | -p <plp_health_interval>] [--save | -s] [--no-uuid | -n]
+
+
+DESCRIPTION
+-----------
+Define Set PLP health check interval.
+No argument prints current mode.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-p <plp_health_interval>::
+--plp_health_interval=<plp_health_interval>::
+ Set the plp health check interval [31:16]
+
+-n::
+--no-uuid::
+ Do not try to automatically detect UUID index for this command (required
+ for old OCP 1.0 support)
+
+-s::
+--save::
+ Save the attribute so that it persists through all power states and resets.
+
+
+EXAMPLES
+--------
+* Has the program issue a set-plp-health-check-interval to retrieve the 0xC6 set features.
++
+------------
+# nvme ocp eol-plp-failure-mode /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-smart-add-log.1 b/Documentation/nvme-ocp-smart-add-log.1
new file mode 100644
index 0000000..092321e
--- /dev/null
+++ b/Documentation/nvme-ocp-smart-add-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-ocp-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-OCP\-SMART\-AD" "1" "02/14/2024" "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-ocp-smart-add-log \- Retrieves Extended SMART information of given OCP compliant device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ocp smart\-add\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a 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) or block device (ex: /dev/nvme0n1)\&.
+.sp
+This will only work on OCP compliant devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+or
+\fIjson\fR\&. Only one output format can be used at a time\&. The default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue a smart\-add\-log command to retrieve the 0xC0 log page\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme ocp smart\-add\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-ocp-smart-add-log.html b/Documentation/nvme-ocp-smart-add-log.html
new file mode 100644
index 0000000..fa10b95
--- /dev/null
+++ b/Documentation/nvme-ocp-smart-add-log.html
@@ -0,0 +1,819 @@
+<?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 10.2.0" />
+<title>nvme-ocp-smart-add-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 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-ocp-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ocp-smart-add-log -
+ Retrieves Extended SMART information of given OCP compliant 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 ocp smart-add-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>For the NVMe device given, send a smart-add-log command and
+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) or block device (ex: /dev/nvme0n1).</p></div>
+<div class="paragraph"><p>This will only work on OCP compliant 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> or <em>json</em>. Only one output format
+ can be used at a time. The default is normal.
+</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 issue a smart-add-log command to retrieve the 0xC0 log page.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme ocp smart-add-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ocp-smart-add-log.txt b/Documentation/nvme-ocp-smart-add-log.txt
new file mode 100644
index 0000000..66a55a9
--- /dev/null
+++ b/Documentation/nvme-ocp-smart-add-log.txt
@@ -0,0 +1,44 @@
+nvme-ocp-smart-add-log(1)
+=========================
+
+NAME
+----
+nvme-ocp-smart-add-log - Retrieves Extended SMART information of given OCP
+compliant device
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp smart-add-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a smart-add-log command and
+provide the additional smart log.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json'. Only one output format
+ can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* Has the program issue a smart-add-log command to retrieve the 0xC0 log page.
++
+------------
+# nvme ocp smart-add-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-telemetry-string-log-page.txt b/Documentation/nvme-ocp-telemetry-string-log-page.txt
new file mode 100644
index 0000000..76349ed
--- /dev/null
+++ b/Documentation/nvme-ocp-telemetry-string-log-page.txt
@@ -0,0 +1,43 @@
+nvme-ocp-telemetry-string-log-page(1)
+=====================================
+
+NAME
+----
+nvme-ocp-telemetry-string-log-page - Retrieve OCP Telemetry String Log page
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp telemetry-str-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, Retrieve OCP Telemetry String Log page
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ This option will set the reporting format to normal, json, or binary.
+ Only one output format can be used at a time.
+
+
+EXAMPLES
+--------
+* Has the program issue a telemetry-string-log command to get the log page data from bin file.
++
+------------
+# nvme ocp telemetry-string-log /dev/nvme0n1
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt b/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt
new file mode 100644
index 0000000..1657f6a
--- /dev/null
+++ b/Documentation/nvme-ocp-unsupported-reqs-log-pages.txt
@@ -0,0 +1,45 @@
+unsupported-reqs-log
+====================
+
+NAME
+----
+unsupported-reqs-log - Retrieves unsupported requirements log page of given OCP
+compliant device
+
+SYNOPSIS
+--------
+[verse]
+'nvme ocp unsupported-reqs-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a unsupported-reqs-log command and
+provide the unsupported requirements log page.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+This will only work on OCP compliant devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+
+-o <fmt>::
+--output-format=<fmt>::
+ This option will set the reporting format to normal, json, or binary.
+ Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program issue a unsupported-reqs-log command to retrieve the 0xC5 log page.
++
+------------
+# nvme ocp unsupported-reqs-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-persistent-event-log.1 b/Documentation/nvme-persistent-event-log.1
new file mode 100644
index 0000000..4781586
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.1
@@ -0,0 +1,123 @@
+'\" t
+.\" Title: persistent-event-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "PERSISTENT\-EVENT\-L" "1" "02/14/2024" "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>] [\-\-verbose | \-v]
+.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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..f4998f4
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.html
@@ -0,0 +1,884 @@
+<?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 10.2.0" />
+<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 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>
+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;] [--verbose | -v]</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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</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..cf1cbad
--- /dev/null
+++ b/Documentation/nvme-persistent-event-log.txt
@@ -0,0 +1,79 @@
+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>] [--verbose | -v]
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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-phy-rx-eom-log.txt b/Documentation/nvme-phy-rx-eom-log.txt
new file mode 100644
index 0000000..8a31131
--- /dev/null
+++ b/Documentation/nvme-phy-rx-eom-log.txt
@@ -0,0 +1,68 @@
+nvme-phy-rx-eom-log(1)
+======================
+
+NAME
+----
+nvme-phy-rx-eom-log - Retrieves a Physical Interface Receiver Eye Opening
+Measurement log page from an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme phy-rx-eom-log' <device> [--lsp=<field> | -s <field>]
+ [--controller=<id> | -c <id>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves a Physical Interface Receiver Eye Opening Measurement 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 it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-s <field>::
+--lsp=<field>::
+ The log specified field configuring the controller's action to take
+ during processing of the command and the measurement quality.
+
+-c <id>::
+--controller=<id>::
+ Controller ID of the controller associated with the PCIe port to be
+ measured.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Start a best quality measurement and retrieve the log page header
++
+------------
+# nvme phy-rx-eom-log /dev/nvme0 --lsp=10
+------------
+
+* Retrieve a finished best quality measurement on controller with ID 3
++
+------------
+# nvme phy-rx-eom-log /dev/nvme0 --lsp=2 --controller=3
+------------
+
+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..d3e76d9
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" Title: nvme-pred-lat-event-agg-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-PRED\-LAT\-EVE" "1" "02/14/2024" "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>] [\-\-verbose | \-v]
+.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 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
+\-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 Predictable Latency Event Aggregate log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 Predictable 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..3f18097
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.html
@@ -0,0 +1,871 @@
+<?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 10.2.0" />
+<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 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-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;] [--verbose | -v]</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 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">
+-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 Predictable Latency Event Aggregate log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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 Predictable 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
+ 2024-02-14 10:43:42 CET
+</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..6fb8acc
--- /dev/null
+++ b/Documentation/nvme-pred-lat-event-agg-log.txt
@@ -0,0 +1,73 @@
+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>] [--verbose | -v]
+
+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 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
+-------
+-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 Predictable Latency Event Aggregate log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ 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 Predictable 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..df39fd8
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" Title: nvme-predictable-lat-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-PREDICTABLE\-L" "1" "02/14/2024" "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 Predictable 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>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Predictable 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 Predictable latency per NVM set 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
+\-i <nvmset_id>, \-\-nvmset\-id=<nvmset_id>
+.RS 4
+Retrieve the Predictable 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 Predictable latency per NVM set log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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 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 Predictable 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..b4f699d
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.html
@@ -0,0 +1,868 @@
+<?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 10.2.0" />
+<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 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-predictable-lat-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-predictable-lat-log -
+ Send Predictable 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;] [--verbose | -v]</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 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 Predictable latency per NVM set 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">
+-i &lt;nvmset_id&gt;
+</dt>
+<dt class="hdlist1">
+--nvmset-id=&lt;nvmset_id&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the Predictable 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 Predictable latency per NVM set log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 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 Predictable 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
+ 2024-02-14 10:43:42 CET
+</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..f0b2ad3
--- /dev/null
+++ b/Documentation/nvme-predictable-lat-log.txt
@@ -0,0 +1,70 @@
+nvme-predictable-lat-log(1)
+===========================
+
+NAME
+----
+nvme-predictable-lat-log - Send Predictable 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>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Predictable 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 Predictable latency per NVM set 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
+-------
+-i <nvmset_id>::
+--nvmset-id=<nvmset_id>::
+ Retrieve the Predictable 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 Predictable latency per NVM set log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the Predictable latency per NVM set log page in a human readable format:
++
+------------
+# nvme predictable-lat-log /dev/nvme0
+------------
++
+
+* Print the raw Predictable 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-primary-ctrl-caps.1 b/Documentation/nvme-primary-ctrl-caps.1
new file mode 100644
index 0000000..37303b1
--- /dev/null
+++ b/Documentation/nvme-primary-ctrl-caps.1
@@ -0,0 +1,110 @@
+'\" t
+.\" Title: nvme-primary-ctrl-caps
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-PRIMARY\-CTRL\" "1" "02/14/2024" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-primary-ctrl-caps \- Send identify Primary Controller Caps, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme primary\-ctrl\-caps\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an identify primary Controller caps command and provides the result and returned structure\&.
+.sp
+The <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 structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.SH "OPTIONS"
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get Primary Ctrl Caps of the device in default format
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme primary\-ctrl\-caps /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program interpret the returned buffer and display the known fields in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme primary\-ctrl\-caps /dev/nvme0 \-\-human\-readable
+# nvme primary\-ctrl\-caps /dev/nvme0 \-H
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-primary-ctrl-caps.html b/Documentation/nvme-primary-ctrl-caps.html
new file mode 100644
index 0000000..5343c77
--- /dev/null
+++ b/Documentation/nvme-primary-ctrl-caps.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<title>nvme-primary-ctrl-caps(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-primary-ctrl-caps(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-primary-ctrl-caps -
+ Send identify Primary Controller Caps, 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 primary-ctrl-caps</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 an identify primary Controller caps 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 structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get Primary Ctrl Caps of the device in default format
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme primary-ctrl-caps /dev/nvme0</code></pre>
+</div></div>
+</li>
+<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 primary-ctrl-caps /dev/nvme0 --human-readable
+# nvme primary-ctrl-caps /dev/nvme0 -H</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-primary-ctrl-caps.txt b/Documentation/nvme-primary-ctrl-caps.txt
new file mode 100644
index 0000000..0300383
--- /dev/null
+++ b/Documentation/nvme-primary-ctrl-caps.txt
@@ -0,0 +1,57 @@
+nvme-primary-ctrl-caps(1)
+=========================
+
+NAME
+----
+nvme-primary-ctrl-caps - Send identify Primary Controller Caps, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme primary-ctrl-caps' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an identify primary Controller caps command and
+provides the result and returned structure.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0), or a namespace block device (ex: /dev/nvme0n1).
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+OPTIONS
+-------
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Get Primary Ctrl Caps of the device in default format
++
+------------
+# nvme primary-ctrl-caps /dev/nvme0
+------------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme primary-ctrl-caps /dev/nvme0 --human-readable
+# nvme primary-ctrl-caps /dev/nvme0 -H
+------------
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-read.1 b/Documentation/nvme-read.1
new file mode 100644
index 0000000..85cc1e3
--- /dev/null
+++ b/Documentation/nvme-read.1
@@ -0,0 +1,214 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-READ" "1" "02/14/2024" "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-read \- Send an NVMe Read command, provide results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-read\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-data\-size=<size> | \-z <size>]
+ [\-\-metadata\-size=<size> | \-y <size>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-data=<data\-file> | \-d <data\-file>]
+ [\-\-metadata=<metadata\-file> | \-M <metadata\-file>]
+ [\-\-prinfo=<prinfo> | \-p <prinfo>]
+ [\-\-app\-tag\-mask=<appmask> | \-m <appmask>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>]
+ [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f]
+ [\-\-dir\-type=<type> | \-T <type>]
+ [\-\-dir\-spec=<spec> | \-S <spec>] [\-\-dsm=<dsm> | \-D <dsm>]
+ [\-\-show\-command | \-V] [\-\-dry\-run | \-w] [\-\-latency | \-t]
+ [\-\-storage\-tag<storage\-tag> | \-g <storage\-tag>]
+ [\-\-storage\-tag\-check | \-C] [\-\-force]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Read command reads the logical blocks specified by the command from the medium and copies to the data data buffer provided\&. Will use stdout by default if you don\(cqt provide a file\&.
+.SH "OPTIONS"
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-c, \-\-block\-count
+.RS 4
+The number of blocks to transfer\&. This is a zeroes based value to align with the kernel\(cqs use of this field\&. (ie\&. 0 means transfer 1 block)\&.
+.RE
+.PP
+\-z <size>, \-\-data\-size=<size>
+.RS 4
+Size of data, in bytes\&.
+.RE
+.PP
+\-y <size>, \-\-metadata\-size=<size>
+.RS 4
+Size of metadata in bytes\&.
+.RE
+.PP
+\-d <data\-file>, \-\-data=<data\-file>
+.RS 4
+Data file\&. If none provided, contents are sent to STDOUT\&.
+.RE
+.PP
+\-M <metadata\-file>, \-\-metadata=<metadata\-file>
+.RS 4
+Metadata file, if necessary\&.
+.RE
+.PP
+\-p <prinfo>, \-\-prinfo=<prinfo>
+.RS 4
+Protection Information field definition\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Bit
+T}:T{
+Description
+T}
+T{
+3
+T}:T{
+PRACT: Protection Information Action\&. When set to 1, PI is stripped/inserted on read/write when the block format\(cqs metadata size is 8\&. When set to 0, metadata is passes\&.
+T}
+T{
+2:0
+T}:T{
+PRCHK: Protection Information Check:
+T}
+T{
+2
+T}:T{
+Set to 1 enables checking the guard tag
+T}
+T{
+1
+T}:T{
+Set to 1 enables checking the application tag
+T}
+T{
+0
+T}:T{
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-m <appmask>, \-\-app\-tag\-mask=<appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-f, \-\-force\-unit\-access
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-T <type>, \-\-dir\-type=<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 specification (1\&.3a) defines only one directive, 01h, for write stream identifiers\&.
+.RE
+.PP
+\-S <spec>, \-\-dir\-spec=<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
+\-D <dsm>, \-\-dsm=<dsm>
+.RS 4
+The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&.
+.RE
+.PP
+\-V, \-\-show\-cmd
+.RS 4
+Print out the command to be sent\&.
+.RE
+.PP
+\-w, \-\-dry\-run
+.RS 4
+Do not actually send the command\&. If want to use \-\-dry\-run option, \-\-show\-cmd option
+\fImust\fR
+be set\&. Otherwise \-\-dry\-run option will be
+\fIignored\fR\&.
+.RE
+.PP
+\-t, \-\-latency
+.RS 4
+Print out the latency the IOCTL took (in us)\&.
+.RE
+.PP
+\-g <storage\-tag>, \-\-storage\-tag=<storage\-tag>
+.RS 4
+Variable Sized Expected Logical Block Storage Tag(ELBST)\&.
+.RE
+.PP
+\-C, \-\-storage\-tag\-check
+.RS 4
+This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Ignore namespace is currently busy and performed the operation even though\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-read.html b/Documentation/nvme-read.html
new file mode 100644
index 0000000..ff4ab43
--- /dev/null
+++ b/Documentation/nvme-read.html
@@ -0,0 +1,1094 @@
+<?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 10.2.0" />
+<title>nvme-read(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-read(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-read -
+ Send an NVMe Read 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-read</em> &lt;device&gt; [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;]
+ [--data-size=&lt;size&gt; | -z &lt;size&gt;]
+ [--metadata-size=&lt;size&gt; | -y &lt;size&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--data=&lt;data-file&gt; | -d &lt;data-file&gt;]
+ [--metadata=&lt;metadata-file&gt; | -M &lt;metadata-file&gt;]
+ [--prinfo=&lt;prinfo&gt; | -p &lt;prinfo&gt;]
+ [--app-tag-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--dir-type=&lt;type&gt; | -T &lt;type&gt;]
+ [--dir-spec=&lt;spec&gt; | -S &lt;spec&gt;] [--dsm=&lt;dsm&gt; | -D &lt;dsm&gt;]
+ [--show-command | -V] [--dry-run | -w] [--latency | -t]
+ [--storage-tag&lt;storage-tag&gt; | -g &lt;storage-tag&gt;]
+ [--storage-tag-check | -C] [--force]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Read command reads the logical blocks specified by the command from
+the medium and copies to the data data buffer provided. Will use stdout
+by default if you don&#8217;t provide a file.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+-c
+</dt>
+<dt class="hdlist1">
+--block-count
+</dt>
+<dd>
+<p>
+ The number of blocks to transfer. This is a zeroes based value to
+ align with the kernel&#8217;s use of this field. (ie. 0 means transfer
+ 1 block).
+</p>
+</dd>
+<dt class="hdlist1">
+-z &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--data-size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of data, in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-y &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Data file. If none provided, contents are sent to STDOUT.
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;metadata-file&gt;
+</dt>
+<dt class="hdlist1">
+--metadata=&lt;metadata-file&gt;
+</dt>
+<dd>
+<p>
+ Metadata file, if necessary.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field definition.
+</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">Bit</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format&#8217;s metadata size is 8. When set to 0,
+metadata is passes.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2:0</p></td>
+<td align="left" valign="top"><p class="table">PRCHK: Protection Information Check:</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the guard tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the application tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the reference tag</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</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">
+-T &lt;type&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&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
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;spec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&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">
+-D &lt;dsm&gt;
+</dt>
+<dt class="hdlist1">
+--dsm=&lt;dsm&gt;
+</dt>
+<dd>
+<p>
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dt class="hdlist1">
+--show-cmd
+</dt>
+<dd>
+<p>
+ Print out the command to be sent.
+</p>
+</dd>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--dry-run
+</dt>
+<dd>
+<p>
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option <em>must</em> be set. Otherwise --dry-run option will be
+ <em>ignored</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-t
+</dt>
+<dt class="hdlist1">
+--latency
+</dt>
+<dd>
+<p>
+ Print out the latency the IOCTL took (in us).
+</p>
+</dd>
+<dt class="hdlist1">
+-g &lt;storage-tag&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag=&lt;storage-tag&gt;
+</dt>
+<dd>
+<p>
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+</p>
+</dd>
+<dt class="hdlist1">
+-C
+</dt>
+<dt class="hdlist1">
+--storage-tag-check
+</dt>
+<dd>
+<p>
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Ignore namespace is currently busy and performed the operation
+ even though.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-read.txt b/Documentation/nvme-read.txt
new file mode 100644
index 0000000..cecaa71
--- /dev/null
+++ b/Documentation/nvme-read.txt
@@ -0,0 +1,158 @@
+nvme-read(1)
+============
+
+NAME
+----
+nvme-read - Send an NVMe Read command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-read' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--data-size=<size> | -z <size>]
+ [--metadata-size=<size> | -y <size>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--data=<data-file> | -d <data-file>]
+ [--metadata=<metadata-file> | -M <metadata-file>]
+ [--prinfo=<prinfo> | -p <prinfo>]
+ [--app-tag-mask=<appmask> | -m <appmask>]
+ [--app-tag=<apptag> | -a <apptag>]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--dir-type=<type> | -T <type>]
+ [--dir-spec=<spec> | -S <spec>] [--dsm=<dsm> | -D <dsm>]
+ [--show-command | -V] [--dry-run | -w] [--latency | -t]
+ [--storage-tag<storage-tag> | -g <storage-tag>]
+ [--storage-tag-check | -C] [--force]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Read command reads the logical blocks specified by the command from
+the medium and copies to the data data buffer provided. Will use stdout
+by default if you don't provide a file.
+
+OPTIONS
+-------
+-s <slba>::
+--start-block=<slba>::
+ Start block.
+
+-c::
+--block-count::
+ The number of blocks to transfer. This is a zeroes based value to
+ align with the kernel's use of this field. (ie. 0 means transfer
+ 1 block).
+
+-z <size>::
+--data-size=<size>::
+ Size of data, in bytes.
+
+-y <size>::
+--metadata-size=<size>::
+ Size of metadata in bytes.
+
+-d <data-file>::
+--data=<data-file>::
+ Data file. If none provided, contents are sent to STDOUT.
+
+-M <metadata-file>::
+--metadata=<metadata-file>::
+ Metadata file, if necessary.
+
+-p <prinfo>::
+--prinfo=<prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ Optional reftag when used with protection information.
+
+-m <appmask>::
+--app-tag-mask=<appmask>::
+ Optional application tag mask when used with protection information.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-T <type>::
+--dir-type=<type>::
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+
+-S <spec>::
+--dir-spec=<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.
+
+-D <dsm>::
+--dsm=<dsm>::
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+
+-V::
+--show-cmd::
+ Print out the command to be sent.
+
+-w::
+--dry-run::
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option _must_ be set. Otherwise --dry-run option will be
+ _ignored_.
+
+-t::
+--latency::
+ Print out the latency the IOCTL took (in us).
+
+-g <storage-tag>::
+--storage-tag=<storage-tag>::
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+
+-C::
+--storage-tag-check::
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+
+--force::
+ Ignore namespace is currently busy and performed the operation
+ even though.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-reset.1 b/Documentation/nvme-reset.1
new file mode 100644
index 0000000..d9fa8e6
--- /dev/null
+++ b/Documentation/nvme-reset.1
@@ -0,0 +1,79 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESET" "1" "02/14/2024" "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-reset \- Reset the nvme controller\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme reset\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Requests NVMe controller reset\&. The <device> param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Resets the controller\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme reset /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-reset.html b/Documentation/nvme-reset.html
new file mode 100644
index 0000000..1ce4b8d
--- /dev/null
+++ b/Documentation/nvme-reset.html
@@ -0,0 +1,825 @@
+<?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 10.2.0" />
+<title>nvme-reset(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-reset(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-reset -
+ Reset the nvme controller.
+</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 reset</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 reset. 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="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Resets the controller.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme reset /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-reset.txt b/Documentation/nvme-reset.txt
new file mode 100644
index 0000000..20fcbb1
--- /dev/null
+++ b/Documentation/nvme-reset.txt
@@ -0,0 +1,39 @@
+nvme-reset(1)
+=============
+
+NAME
+----
+nvme-reset - Reset the nvme controller.
+
+SYNOPSIS
+--------
+[verse]
+'nvme reset' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Requests NVMe controller reset. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Resets the controller.
++
+------------
+# nvme reset /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-resv-acquire.1 b/Documentation/nvme-resv-acquire.1
new file mode 100644
index 0000000..f308bf3
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.1
@@ -0,0 +1,191 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-ACQUIRE" "1" "02/14/2024" "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-acquire \- Acquire an nvme reservation
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme resv\-acquire\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-crkey=<crkey> | \-c <crkey>]
+ [\-\-prkey=<prkey> | \-p <prkey>]
+ [\-\-rtype=<rtype> | \-t <rtype>]
+ [\-\-racqa=<racqa> | \-a <racqa>] [\-\-iekey | \-i]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Reservation Acquire command is used to acquire a reservation on a namespace, preempt a reservation held on a namespace, and abort a reservation held on a namespace\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Override the nsid field\&. If using the admin character device, this parameter is required\&.
+.RE
+.PP
+\-c <crkey>, \-\-crkey=<crkey>
+.RS 4
+Current Reservation Key: The field specifies the current reservation key associated with the host\&. If the IEKEY bit is set to \(oq1\(cq in the command, then the CRKEY check succeeds regardless of the value in this field\&.
+.RE
+.PP
+\-p <prkey>, \-\-prkey=<prkey>
+.RS 4
+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>, \-\-rtype=<rtype>
+.RS 4
+Reservation Type: This field specifies the type of reservation to be created\&.
+.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{
+0h
+T}:T{
+Reserved
+T}
+T{
+1h
+T}:T{
+Write Exclusive Reservation
+T}
+T{
+2h
+T}:T{
+Exclusive Access Reservation
+T}
+T{
+3h
+T}:T{
+Write Exclusive \- Registrants Only Reservation
+T}
+T{
+4h
+T}:T{
+Exclusive Access \- Registrants Only Reservation
+T}
+T{
+5h
+T}:T{
+Write Exclusive \- All Registrants Reservation
+T}
+T{
+6h
+T}:T{
+Exclusive Access \- All Registrants Reservation
+T}
+T{
+07h\-FFh
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-a <racqa>, \-\-racqa=<racqa>
+.RS 4
+Reservation Acquire Action: This field specifies the action that is performed by the command\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+Acquire
+T}
+T{
+1
+T}:T{
+Preempt
+T}
+T{
+2
+T}:T{
+Preempt and Abort
+T}
+T{
+3\-7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-i, \-\-iekey
+.RS 4
+Ignore Existing Key: If this bit is set to a
+\fI1\fR, then the Current Reservation Key (CRKEY) check is disabled and the command shall succeed regardless of the CRKEY field value\&.
+.sp
+Indicator option, defaults to
+\fI0\fR\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-resv-acquire.html b/Documentation/nvme-resv-acquire.html
new file mode 100644
index 0000000..35719ee
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.html
@@ -0,0 +1,978 @@
+<?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 10.2.0" />
+<title>nvme-resv-acquire(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-resv-acquire(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-resv-acquire -
+ Acquire an nvme reservation
+</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-acquire</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--crkey=&lt;crkey&gt; | -c &lt;crkey&gt;]
+ [--prkey=&lt;prkey&gt; | -p &lt;prkey&gt;]
+ [--rtype=&lt;rtype&gt; | -t &lt;rtype&gt;]
+ [--racqa=&lt;racqa&gt; | -a &lt;racqa&gt;] [--iekey | -i]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Reservation Acquire command is used to acquire a reservation on
+a namespace, preempt a reservation held on a namespace, and abort a
+reservation held on a namespace.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;crkey&gt;
+</dt>
+<dt class="hdlist1">
+--crkey=&lt;crkey&gt;
+</dt>
+<dd>
+<p>
+ Current Reservation Key: The field specifies the current
+ reservation key associated with the host. If the IEKEY bit is
+ set to ‘1’ in the command, then the CRKEY check succeeds
+ regardless of the value in this field.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prkey&gt;
+</dt>
+<dt class="hdlist1">
+--prkey=&lt;prkey&gt;
+</dt>
+<dd>
+<p>
+ 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.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;rtype&gt;
+</dt>
+<dt class="hdlist1">
+--rtype=&lt;rtype&gt;
+</dt>
+<dd>
+<p>
+ Reservation Type: This field specifies the type of reservation
+ to be created.
+</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">0h</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive - Registrants Only Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access - Registrants Only Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">5h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive - All Registrants Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">6h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access - All Registrants Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">07h-FFh</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-a &lt;racqa&gt;
+</dt>
+<dt class="hdlist1">
+--racqa=&lt;racqa&gt;
+</dt>
+<dd>
+<p>
+ Reservation Acquire Action: This field specifies the action that
+ is performed by the command.
+</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">Acquire</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Preempt</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Preempt and Abort</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3-7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-i
+</dt>
+<dt class="hdlist1">
+--iekey
+</dt>
+<dd>
+<p>
+ Ignore Existing Key: If this bit is set to a <em>1</em>, then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
+</p>
+<div class="paragraph"><p>Indicator option, defaults to <em>0</em>.</p></div>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-acquire.txt b/Documentation/nvme-resv-acquire.txt
new file mode 100644
index 0000000..19282c6
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.txt
@@ -0,0 +1,101 @@
+nvme-resv-acquire(1)
+====================
+
+NAME
+----
+nvme-resv-acquire - Acquire an nvme reservation
+
+SYNOPSIS
+--------
+[verse]
+'nvme resv-acquire' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--crkey=<crkey> | -c <crkey>]
+ [--prkey=<prkey> | -p <prkey>]
+ [--rtype=<rtype> | -t <rtype>]
+ [--racqa=<racqa> | -a <racqa>] [--iekey | -i]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Reservation Acquire command is used to acquire a reservation on
+a namespace, preempt a reservation held on a namespace, and abort a
+reservation held on a namespace.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+
+-c <crkey>::
+--crkey=<crkey>::
+ Current Reservation Key: The field specifies the current
+ reservation key associated with the host. If the IEKEY bit is
+ set to ‘1’ in the command, then the CRKEY check succeeds
+ regardless of the value in this field.
+
+-p <prkey>::
+--prkey=<prkey>::
+ 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.
+
+-t <rtype>::
+--rtype=<rtype>::
+ Reservation Type: This field specifies the type of reservation
+ to be created.
++
+[]
+|=================
+|Value|Definition
+|0h|Reserved
+|1h|Write Exclusive Reservation
+|2h|Exclusive Access Reservation
+|3h|Write Exclusive - Registrants Only Reservation
+|4h|Exclusive Access - Registrants Only Reservation
+|5h|Write Exclusive - All Registrants Reservation
+|6h|Exclusive Access - All Registrants Reservation
+|07h-FFh|Reserved
+|=================
+
+-a <racqa>::
+--racqa=<racqa>::
+ Reservation Acquire Action: This field specifies the action that
+ is performed by the command.
++
+[]
+|=================
+|Value|Definition
+|0|Acquire
+|1|Preempt
+|2|Preempt and Abort
+|3-7|Reserved
+|=================
+
+-i::
+--iekey::
+ Ignore Existing Key: If this bit is set to a '1', then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
++
+Indicator option, defaults to '0'.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-resv-notif-log.1 b/Documentation/nvme-resv-notif-log.1
new file mode 100644
index 0000000..655ee09
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.1
@@ -0,0 +1,104 @@
+'\" t
+.\" Title: nvme-resv-notif-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-NOTIF\-L" "1" "02/14/2024" "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>] [\-\-verbose | \-v]
+.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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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..e814928
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.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 10.2.0" />
+<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 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-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;] [--verbose | -v]</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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</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..f8d828b
--- /dev/null
+++ b/Documentation/nvme-resv-notif-log.txt
@@ -0,0 +1,55 @@
+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>] [--verbose | -v]
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+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
new file mode 100644
index 0000000..3a86f7c
--- /dev/null
+++ b/Documentation/nvme-resv-register.1
@@ -0,0 +1,167 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-REGISTER" "1" "02/14/2024" "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-register \- Register an nvme reservation
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme resv\-register\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-crkey=<crkey> | \-c <crkey>]
+ [\-\-nrkey=<nrkey> | \-k <nrkey>]
+ [\-\-rrega=<rrega> | \-r <rrega>]
+ [\-\-cptpl=<cptpl> | \-p <cptpl>] [\-\-iekey | \-i]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Reservation Register command is used to register, unregister, or replace a reservation key\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Override the nsid field\&. If using the admin character device, this parameter is required\&.
+.RE
+.PP
+\-c <crkey>, \-\-crkey=<crkey>
+.RS 4
+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
+\-k <nrkey>, \-\-nrkey=<nrkey>
+.RS 4
+New Reservation Key: If the Reservation Register Action is 000b (i\&.e\&., Register Reservation Key) or 010b (i\&.e\&., Replace Reservation Key), then this field contains the new reservation key associated with the host\&. For all other Reservation Register Action values, this field is reserved\&.
+.RE
+.PP
+\-p <cptpl>, \-\-cptpl=<cptpl>
+.RS 4
+Change Persist Through Power Loss State: This field allows the Persist Through Power Loss state associated with the namespace to be modified as a side effect of processing this command\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+No change to PTPL state
+T}
+T{
+1
+T}:T{
+Reserved
+T}
+T{
+2
+T}:T{
+Set PTPL state to \(oq0\(cq\&. Reservations are released and registrants are cleared on a power on\&.
+T}
+T{
+3
+T}:T{
+Set PTPL state to \(oq1\(cq\&. Reservations and registrants persist across a power loss\&.
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-r <rrega>, \-\-rrega=<rrega>
+.RS 4
+Reservation Register Action: This field specifies the registration action that is performed by the command\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+Register Reservation Key
+T}
+T{
+1
+T}:T{
+Unregister Reservation Key
+T}
+T{
+2
+T}:T{
+Replace Reservation Key
+T}
+T{
+3\-7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-i, \-\-iekey
+.RS 4
+Ignore Existing Key: If this bit is set to a
+\fI1\fR, then the Current Reservation Key (CRKEY) check is disabled and the command shall succeed regardless of the CRKEY field value\&.
+.sp
+Indicator option, defaults to
+\fI0\fR\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-resv-register.html b/Documentation/nvme-resv-register.html
new file mode 100644
index 0000000..fb78ac7
--- /dev/null
+++ b/Documentation/nvme-resv-register.html
@@ -0,0 +1,967 @@
+<?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 10.2.0" />
+<title>nvme-resv-register(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-resv-register(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-resv-register -
+ Register an nvme reservation
+</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-register</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--crkey=&lt;crkey&gt; | -c &lt;crkey&gt;]
+ [--nrkey=&lt;nrkey&gt; | -k &lt;nrkey&gt;]
+ [--rrega=&lt;rrega&gt; | -r &lt;rrega&gt;]
+ [--cptpl=&lt;cptpl&gt; | -p &lt;cptpl&gt;] [--iekey | -i]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Reservation Register command is used to register, unregister, or
+replace a reservation key.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;crkey&gt;
+</dt>
+<dt class="hdlist1">
+--crkey=&lt;crkey&gt;
+</dt>
+<dd>
+<p>
+ 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 ‘1’.
+</p>
+</dd>
+<dt class="hdlist1">
+-k &lt;nrkey&gt;
+</dt>
+<dt class="hdlist1">
+--nrkey=&lt;nrkey&gt;
+</dt>
+<dd>
+<p>
+ New Reservation Key: If the Reservation Register Action is
+ 000b (i.e., Register Reservation Key) or 010b (i.e., Replace
+ Reservation Key), then this field contains the new reservation
+ key associated with the host. For all other Reservation Register
+ Action values, this field is reserved.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;cptpl&gt;
+</dt>
+<dt class="hdlist1">
+--cptpl=&lt;cptpl&gt;
+</dt>
+<dd>
+<p>
+ Change Persist Through Power Loss State: This field allows the
+ Persist Through Power Loss state associated with the namespace
+ to be modified as a side effect of processing this command.
+</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">No change to PTPL state</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set PTPL state to ‘0’. Reservations are released and registrants
+are cleared on a power on.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">Set PTPL state to ‘1’. Reservations and registrants persist across
+a power loss.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-r &lt;rrega&gt;
+</dt>
+<dt class="hdlist1">
+--rrega=&lt;rrega&gt;
+</dt>
+<dd>
+<p>
+ Reservation Register Action: This field specifies the registration
+ action that is performed by the command.
+</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">Register Reservation Key</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Unregister Reservation Key</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Replace Reservation Key</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3-7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-i
+</dt>
+<dt class="hdlist1">
+--iekey
+</dt>
+<dd>
+<p>
+ Ignore Existing Key: If this bit is set to a <em>1</em>, then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
+</p>
+<div class="paragraph"><p>Indicator option, defaults to <em>0</em>.</p></div>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-register.txt b/Documentation/nvme-resv-register.txt
new file mode 100644
index 0000000..4a83050
--- /dev/null
+++ b/Documentation/nvme-resv-register.txt
@@ -0,0 +1,102 @@
+nvme-resv-register(1)
+=====================
+
+NAME
+----
+nvme-resv-register - Register an nvme reservation
+
+SYNOPSIS
+--------
+[verse]
+'nvme resv-register' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--crkey=<crkey> | -c <crkey>]
+ [--nrkey=<nrkey> | -k <nrkey>]
+ [--rrega=<rrega> | -r <rrega>]
+ [--cptpl=<cptpl> | -p <cptpl>] [--iekey | -i]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Reservation Register command is used to register, unregister, or
+replace a reservation key.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+
+-c <crkey>::
+--crkey=<crkey>::
+ 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 ‘1’.
+
+-k <nrkey>::
+--nrkey=<nrkey>::
+ New Reservation Key: If the Reservation Register Action is
+ 000b (i.e., Register Reservation Key) or 010b (i.e., Replace
+ Reservation Key), then this field contains the new reservation
+ key associated with the host. For all other Reservation Register
+ Action values, this field is reserved.
+
+-p <cptpl>::
+--cptpl=<cptpl>::
+ Change Persist Through Power Loss State: This field allows the
+ Persist Through Power Loss state associated with the namespace
+ to be modified as a side effect of processing this command.
++
+[]
+|=================
+|Value|Definition
+|0|No change to PTPL state
+|1|Reserved
+|2|Set PTPL state to ‘0’. Reservations are released and registrants
+are cleared on a power on.
+|3|Set PTPL state to ‘1’. Reservations and registrants persist across
+a power loss.
+|=================
+
+-r <rrega>::
+--rrega=<rrega>::
+ Reservation Register Action: This field specifies the registration
+ action that is performed by the command.
++
+[]
+|=================
+|Value|Definition
+|0|Register Reservation Key
+|1|Unregister Reservation Key
+|2|Replace Reservation Key
+|3-7|Reserved
+|=================
+
+-i::
+--iekey::
+ Ignore Existing Key: If this bit is set to a '1', then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
++
+Indicator option, defaults to '0'.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-resv-release.1 b/Documentation/nvme-resv-release.1
new file mode 100644
index 0000000..06ed2e7
--- /dev/null
+++ b/Documentation/nvme-resv-release.1
@@ -0,0 +1,179 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-RELEASE" "1" "02/14/2024" "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-release \- Release an nvme reservation
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme resv\-release\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-crkey=<crkey> | \-c <crkey>]
+ [\-\-rtype=<rtype> | \-t <rtype>]
+ [\-\-rrela=<rrela> | \-a <rrela>] [\-\-iekey | \-i]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Reservation Release command is used to release or clear a reservation held on a namespace\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Override the nsid field\&. If using the admin character device, this parameter is required\&.
+.RE
+.PP
+\-c <crkey>, \-\-crkey=<crkey>
+.RS 4
+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>, \-\-rtype=<rtype>
+.RS 4
+Reservation Type: This field specifies the type of reservation to be created\&.
+.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{
+0h
+T}:T{
+Reserved
+T}
+T{
+1h
+T}:T{
+Write Exclusive Reservation
+T}
+T{
+2h
+T}:T{
+Exclusive Access Reservation
+T}
+T{
+3h
+T}:T{
+Write Exclusive \- Registrants Only Reservation
+T}
+T{
+4h
+T}:T{
+Exclusive Access \- Registrants Only Reservation
+T}
+T{
+5h
+T}:T{
+Write Exclusive \- All Registrants Reservation
+T}
+T{
+6h
+T}:T{
+Exclusive Access \- All Registrants Reservation
+T}
+T{
+07h\-FFh
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-a <rrela>, \-\-rrela=<rrela>
+.RS 4
+Reservation Release Action: This field specifies the registration action that is performed by the command\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0
+T}:T{
+Release
+T}
+T{
+1
+T}:T{
+Clear
+T}
+T{
+2\-7
+T}:T{
+Reserved
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-i, \-\-iekey
+.RS 4
+Ignore Existing Key: If this bit is set to a
+\fI1\fR, then the Current Reservation Key (CRKEY) check is disabled and the command shall succeed regardless of the CRKEY field value\&.
+.sp
+Indicator option, defaults to
+\fI0\fR\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-resv-release.html b/Documentation/nvme-resv-release.html
new file mode 100644
index 0000000..d166276
--- /dev/null
+++ b/Documentation/nvme-resv-release.html
@@ -0,0 +1,960 @@
+<?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 10.2.0" />
+<title>nvme-resv-release(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-resv-release(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-resv-release -
+ Release an nvme reservation
+</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-release</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--crkey=&lt;crkey&gt; | -c &lt;crkey&gt;]
+ [--rtype=&lt;rtype&gt; | -t &lt;rtype&gt;]
+ [--rrela=&lt;rrela&gt; | -a &lt;rrela&gt;] [--iekey | -i]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Reservation Release command is used to release or clear a reservation
+held on a namespace.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;crkey&gt;
+</dt>
+<dt class="hdlist1">
+--crkey=&lt;crkey&gt;
+</dt>
+<dd>
+<p>
+ 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 ‘1’.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;rtype&gt;
+</dt>
+<dt class="hdlist1">
+--rtype=&lt;rtype&gt;
+</dt>
+<dd>
+<p>
+ Reservation Type: This field specifies the type of reservation
+ to be created.
+</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">0h</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive - Registrants Only Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">4h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access - Registrants Only Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">5h</p></td>
+<td align="left" valign="top"><p class="table">Write Exclusive - All Registrants Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">6h</p></td>
+<td align="left" valign="top"><p class="table">Exclusive Access - All Registrants Reservation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">07h-FFh</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-a &lt;rrela&gt;
+</dt>
+<dt class="hdlist1">
+--rrela=&lt;rrela&gt;
+</dt>
+<dd>
+<p>
+ Reservation Release Action: This field specifies the registration
+ action that is performed by the command.
+</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">Release</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Clear</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2-7</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-i
+</dt>
+<dt class="hdlist1">
+--iekey
+</dt>
+<dd>
+<p>
+ Ignore Existing Key: If this bit is set to a <em>1</em>, then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
+</p>
+<div class="paragraph"><p>Indicator option, defaults to <em>0</em>.</p></div>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-release.txt b/Documentation/nvme-resv-release.txt
new file mode 100644
index 0000000..c3dc90d
--- /dev/null
+++ b/Documentation/nvme-resv-release.txt
@@ -0,0 +1,93 @@
+nvme-resv-release(1)
+====================
+
+NAME
+----
+nvme-resv-release - Release an nvme reservation
+
+SYNOPSIS
+--------
+[verse]
+'nvme resv-release' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--crkey=<crkey> | -c <crkey>]
+ [--rtype=<rtype> | -t <rtype>]
+ [--rrela=<rrela> | -a <rrela>] [--iekey | -i]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Reservation Release command is used to release or clear a reservation
+held on a namespace.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Override the nsid field. If using the admin character device,
+ this parameter is required.
+
+-c <crkey>::
+--crkey=<crkey>::
+ 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 ‘1’.
+
+-t <rtype>::
+--rtype=<rtype>::
+ Reservation Type: This field specifies the type of reservation
+ to be created.
++
+[]
+|=================
+|Value|Definition
+|0h|Reserved
+|1h|Write Exclusive Reservation
+|2h|Exclusive Access Reservation
+|3h|Write Exclusive - Registrants Only Reservation
+|4h|Exclusive Access - Registrants Only Reservation
+|5h|Write Exclusive - All Registrants Reservation
+|6h|Exclusive Access - All Registrants Reservation
+|07h-FFh|Reserved
+|=================
+
+-a <rrela>::
+--rrela=<rrela>::
+ Reservation Release Action: This field specifies the registration
+ action that is performed by the command.
++
+[]
+|=================
+|Value|Definition
+|0|Release
+|1|Clear
+|2-7|Reserved
+|=================
+
+-i::
+--iekey::
+ Ignore Existing Key: If this bit is set to a '1', then the
+ Current Reservation Key (CRKEY) check is disabled and the command
+ shall succeed regardless of the CRKEY field value.
++
+Indicator option, defaults to '0'.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-resv-report.1 b/Documentation/nvme-resv-report.1
new file mode 100644
index 0000000..0b8e78c
--- /dev/null
+++ b/Documentation/nvme-resv-report.1
@@ -0,0 +1,86 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-REPORT" "1" "02/14/2024" "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-report \- Send NVMe Reservation Report, parse the result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme resv\-report\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-numd=<num\-dwords> | \-d <num\-dwords>] [\-\-eds | \-e]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Reservation Report command returns a Reservation Status data structure to host memory that describes the registration and reservation status of a namespace\&.
+.sp
+The size of the Reservation Status data structure is a function of the number of controllers in the NVM Subsystem that are associated with hosts that are registrants of the namespace (i\&.e\&., there is a Registered Controller data structure for each such controller)\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the reservation report structure for the given nsid\&. This is required for the character devices, or overrides the block nsid if given\&.
+.RE
+.PP
+\-d <num\-dwords>, \-\-numd=<num\-dwords>
+.RS 4
+Specify the number of Dwords of the Reservation Status structure to transfer\&. Defaults to 4k\&.
+.RE
+.PP
+\-e, \-\-eds
+.RS 4
+Request extended Data Structure: If this bit is set to a
+\fI1\fR, then the controller returns the Extended Data Structure\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-resv-report.html b/Documentation/nvme-resv-report.html
new file mode 100644
index 0000000..7e22653
--- /dev/null
+++ b/Documentation/nvme-resv-report.html
@@ -0,0 +1,872 @@
+<?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 10.2.0" />
+<title>nvme-resv-report(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-resv-report(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-resv-report -
+ Send NVMe Reservation Report, parse the 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 resv-report</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--numd=&lt;num-dwords&gt; | -d &lt;num-dwords&gt;] [--eds | -e]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Reservation Report command returns a Reservation Status data structure
+to host memory that describes the registration and reservation status
+of a namespace.</p></div>
+<div class="paragraph"><p>The size of the Reservation Status data structure is a function of the
+number of controllers in the NVM Subsystem that are associated with
+hosts that are registrants of the namespace (i.e., there is a Registered
+Controller data structure for each such controller).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the reservation report structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;num-dwords&gt;
+</dt>
+<dt class="hdlist1">
+--numd=&lt;num-dwords&gt;
+</dt>
+<dd>
+<p>
+ Specify the number of Dwords of the Reservation Status structure
+ to transfer. Defaults to 4k.
+</p>
+</dd>
+<dt class="hdlist1">
+-e
+</dt>
+<dt class="hdlist1">
+--eds
+</dt>
+<dd>
+<p>
+ Request extended Data Structure: If this bit is set to a <em>1</em>, then the
+ controller returns the Extended Data Structure.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-report.txt b/Documentation/nvme-resv-report.txt
new file mode 100644
index 0000000..2e12826
--- /dev/null
+++ b/Documentation/nvme-resv-report.txt
@@ -0,0 +1,65 @@
+nvme-resv-report(1)
+===================
+
+NAME
+----
+nvme-resv-report - Send NVMe Reservation Report, parse the result
+
+SYNOPSIS
+--------
+[verse]
+'nvme resv-report' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--numd=<num-dwords> | -d <num-dwords>] [--eds | -e]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Reservation Report command returns a Reservation Status data structure
+to host memory that describes the registration and reservation status
+of a namespace.
+
+The size of the Reservation Status data structure is a function of the
+number of controllers in the NVM Subsystem that are associated with
+hosts that are registrants of the namespace (i.e., there is a Registered
+Controller data structure for each such controller).
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the reservation report structure for the given nsid. This
+ is required for the character devices, or overrides the block nsid
+ if given.
+
+-d <num-dwords>::
+--numd=<num-dwords>::
+ Specify the number of Dwords of the Reservation Status structure
+ to transfer. Defaults to 4k.
+
+-e::
+--eds::
+ Request extended Data Structure: If this bit is set to a '1', then the
+ controller returns the Extended Data Structure.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-rpmb.1 b/Documentation/nvme-rpmb.1
new file mode 100644
index 0000000..cedee9a
--- /dev/null
+++ b/Documentation/nvme-rpmb.1
@@ -0,0 +1,340 @@
+'\" t
+.\" Title: nvme-rpmb
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RPMB" "1" "02/14/2024" "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>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.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\-counter \- 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 writing 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 transfer 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 transfer commands (read or write) for a specified RPMB target\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.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
+\fISecretKey\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 \*(AqSecretKey\*(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..82c503b
--- /dev/null
+++ b/Documentation/nvme-rpmb.html
@@ -0,0 +1,1031 @@
+<?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 10.2.0" />
+<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 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-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;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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-counter - 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 writing 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
+ transfer 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 transfer commands
+ (read or write) for a specified RPMB target.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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>SecretKey</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 'SecretKey'</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-rpmb.txt b/Documentation/nvme-rpmb.txt
new file mode 100644
index 0000000..9dc954d
--- /dev/null
+++ b/Documentation/nvme-rpmb.txt
@@ -0,0 +1,158 @@
+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>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+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-counter - 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 writing 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
+ transfer commands (read or write) for a specified RPMB target.
+-b::
+--blocks=<sectors>::
+ The size in 512 byte sectors to be used for data transfer commands
+ (read or write) for a specified RPMB target.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print RPMB support information of an NVMe device
++
+-----------
+# nvme rpmb /dev/nvme0 --cmd=info
+-----------
++
+* Program 'SecretKey' 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 'SecretKey'
+------------
++
+* 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
new file mode 100644
index 0000000..11ce433
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.1
@@ -0,0 +1,155 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SANITIZE\-LOG" "1" "02/14/2024" "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-sanitize-log \- Send NVMe sanitize\-log Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme sanitize\-log\fR <device> [\-\-rae | \-r] [\-\-human\-readable | \-H]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Sanitize log page from an NVMe device and provides the status of sanitize command\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+Expected status and description :\-
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Status Code
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+0x0000
+T}:T{
+.sp
+NVM subsystem has never been sanitized\&.
+T}
+T{
+.sp
+0x0001
+T}:T{
+.sp
+The most recent sanitize operation completed successfully\&.
+T}
+T{
+.sp
+0x0002
+T}:T{
+.sp
+A sanitize operation is currently in progress\&.
+T}
+T{
+.sp
+0x0003
+T}:T{
+.sp
+The most recent sanitize operation failed\&.
+T}
+T{
+.sp
+0x0100
+T}:T{
+.sp
+Global Data Erased bit If set to 1 then non\-volatile storage in the NVM subsystem has not been written to: a) since being manufactured and the NVM subsystem has never been sanitized; or b) since the most recent successful sanitize operation\&. If cleared to 0, then non\-volatile storage in the NVM subsystem has been written to: a) since being manufactured and the NVM subsystem has never been sanitized; or b) since the most recent successful sanitize operation of the NVM subsystem\&.
+T}
+.TE
+.sp 1
+.sp
+Sanitize Progress \- percentage complete
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-r, \-\-rae
+.RS 4
+Retain an Asynchronous Event\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue Sanitize\-log Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme sanitize\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-sanitize-log.html b/Documentation/nvme-sanitize-log.html
new file mode 100644
index 0000000..6872560
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.html
@@ -0,0 +1,910 @@
+<?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 10.2.0" />
+<title>nvme-sanitize-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 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-sanitize-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-sanitize-log -
+ Send NVMe sanitize-log 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 sanitize-log</em> &lt;device&gt; [--rae | -r] [--human-readable | -H]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 Sanitize log page from an NVMe device and provides the
+status of sanitize command.</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>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">Status Code </th>
+<th align="left" valign="top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table">0x0000</p></td>
+<td align="left" valign="top"><p class="table">NVM subsystem has never been sanitized.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x0001</p></td>
+<td align="left" valign="top"><p class="table">The most recent sanitize operation completed successfully.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x0002</p></td>
+<td align="left" valign="top"><p class="table">A sanitize operation is currently in progress.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x0003</p></td>
+<td align="left" valign="top"><p class="table">The most recent sanitize operation failed.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x0100</p></td>
+<td align="left" valign="top"><p class="table">Global Data Erased bit
+If set to 1 then non-volatile storage in the NVM subsystem has
+not been written to:
+ a) since being manufactured and the NVM subsystem has never been sanitized; or
+ b) since the most recent successful sanitize operation.
+If cleared to 0, then non-volatile storage in the NVM subsystem has been written to:
+ a) since being manufactured and the NVM subsystem has never been sanitized; or
+ b) since the most recent successful sanitize operation of the NVM subsystem.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+<div class="paragraph"><p>Sanitize Progress - percentage complete</p></div>
+<div class="paragraph"><p>On success it returns 0, 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">
+-r
+</dt>
+<dt class="hdlist1">
+--rae
+</dt>
+<dd>
+<p>
+ Retain an Asynchronous Event.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 issue Sanitize-log Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme sanitize-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-sanitize-log.txt b/Documentation/nvme-sanitize-log.txt
new file mode 100644
index 0000000..af45e9f
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.txt
@@ -0,0 +1,90 @@
+nvme-sanitize-log(1)
+====================
+
+NAME
+----
+nvme-sanitize-log - Send NVMe sanitize-log Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme sanitize-log' <device> [--rae | -r] [--human-readable | -H]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Sanitize log page from an NVMe device and provides the
+status of sanitize command.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+Expected status and description :-
+
+[cols="2*", options="header"]
+|===
+|Status Code |Description
+
+|0x0000
+|NVM subsystem has never been sanitized.
+
+|0x0001
+|The most recent sanitize operation completed successfully.
+
+|0x0002
+|A sanitize operation is currently in progress.
+
+|0x0003
+|The most recent sanitize operation failed.
+
+|0x0100
+|Global Data Erased bit
+If set to 1 then non-volatile storage in the NVM subsystem has
+not been written to:
+ a) since being manufactured and the NVM subsystem has never been sanitized; or
+ b) since the most recent successful sanitize operation.
+If cleared to 0, then non-volatile storage in the NVM subsystem has been written to:
+ a) since being manufactured and the NVM subsystem has never been sanitized; or
+ b) since the most recent successful sanitize operation of the NVM subsystem.
+|===
+
+Sanitize Progress - percentage complete
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue Sanitize-log Command :
++
+------------
+# nvme sanitize-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-sanitize.1 b/Documentation/nvme-sanitize.1
new file mode 100644
index 0000000..e5c815f
--- /dev/null
+++ b/Documentation/nvme-sanitize.1
@@ -0,0 +1,169 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SANITIZE" "1" "02/14/2024" "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-sanitize \- Send NVMe Sanitize Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme sanitize\fR <device> [\-\-no\-dealloc | \-d] [\-\-oipbp | \-i]
+ [\-\-owpass=<overwrite\-pass\-count> | \-n <overwrite\-pass\-count>]
+ [\-\-ause | \-u] [\-\-sanact=<action> | \-a <action>]
+ [\-\-ovrpat=<overwrite\-pattern> | \-p <overwrite\-pattern>]
+ [\-\-force]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a Sanitize command and provides the result\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-d, \-\-no\-dealloc
+.RS 4
+No Deallocate After Sanitize: If set, then the controller shall not deallocate any logical blocks as a result of successfully completing the sanitize operation\&. If cleared, then the controller should deallocate logical blocks as a result of successfully completing the sanitize operation\&. This bit shall be ignored if the Sanitize Action field is set to 001b (i\&.e\&., Exit Failure Mode)\&.
+.RE
+.PP
+\-i, \-\-oipbp
+.RS 4
+Overwrite Invert Pattern Between Passes: If set, then the Overwrite Pattern shall be inverted between passes\&. If cleared, then the overwrite pattern shall not be inverted between passes\&. This bit shall be ignored unless the Sanitize Action field is set to 011b (i\&.e\&., Overwrite)\&.
+.RE
+.PP
+\-n <overwrite\-pass\-count>, \-\-owpass=<overwrite\-pass\-count>
+.RS 4
+Overwrite Pass Count: This field specifies the number of overwrite passes (i\&.e\&., how many times the media is to be overwritten) using the data from the Overwrite Pattern field of this command\&. A value of 0 specifies 16 overwrite passes\&. This field shall be ignored unless the Sanitize Action field is set to 011b (i\&.e\&., Overwrite)\&.
+.RE
+.PP
+\-u, \-\-ause
+.RS 4
+Allow Unrestricted Sanitize Exit: If set, then the sanitize operation is performed in unrestricted completion mode\&. If cleared then the sanitize operation is performed in restricted completion mode\&. This bit shall be ignored if the Sanitize Action field is set to 001b (i\&.e\&., Exit Failure Mode)\&.
+.RE
+.PP
+\-a <action>, \-\-sanact=<action>
+.RS 4
+Sanitize Action:
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Value
+T}:T{
+Definition
+T}
+T{
+0x00
+T}:T{
+Reserved
+T}
+T{
+0x01 |
+\fIexit\-failure\fR
+T}:T{
+Exit Failure Mode
+T}
+T{
+0x02 |
+\fIstart\-block\-erase\fR
+T}:T{
+Start a Block Erase sanitize operation
+T}
+T{
+0x03 |
+\fIstart\-overwrite\fR
+T}:T{
+Start an Overwrite sanitize operation
+T}
+T{
+0x04 |
+\fIstart\-crypto\-erase\fR
+T}:T{
+Start a Crypto Erase sanitize operation
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-p <overwrite\-pattern>, \-\-ovrpat=<overwrite\-pattern>
+.RS 4
+Overwrite Pattern: This field is ignored unless the Sanitize Action field in Command Dword 10 is set to 011b (i\&.e\&., Overwrite)\&. This field specifies a 32\-bit pattern that is used for the Overwrite sanitize operation\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Ignore namespace is currently busy and performed the operation even though\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue Sanitize Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme sanitize /dev/nvme0 \-a 0x02
+# nvme sanitize /dev/nvme0 \-\-sanact=0x01
+# nvme sanitize /dev/nvme0 \-\-sanact=start\-overwrite
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-sanitize.html b/Documentation/nvme-sanitize.html
new file mode 100644
index 0000000..4469620
--- /dev/null
+++ b/Documentation/nvme-sanitize.html
@@ -0,0 +1,967 @@
+<?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 10.2.0" />
+<title>nvme-sanitize(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-sanitize(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-sanitize -
+ Send NVMe Sanitize 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 sanitize</em> &lt;device&gt; [--no-dealloc | -d] [--oipbp | -i]
+ [--owpass=&lt;overwrite-pass-count&gt; | -n &lt;overwrite-pass-count&gt;]
+ [--ause | -u] [--sanact=&lt;action&gt; | -a &lt;action&gt;]
+ [--ovrpat=&lt;overwrite-pattern&gt; | -p &lt;overwrite-pattern&gt;]
+ [--force]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 a Sanitize command and
+provides the result.</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="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--no-dealloc
+</dt>
+<dd>
+<p>
+ No Deallocate After Sanitize:
+ If set, then the controller shall not deallocate any logical
+ blocks as a result of successfully completing the sanitize
+ operation. If cleared, then the controller should deallocate
+ logical blocks as a result of successfully completing the
+ sanitize operation. This bit shall be ignored if the Sanitize
+ Action field is set to 001b (i.e., Exit Failure Mode).
+</p>
+</dd>
+<dt class="hdlist1">
+-i
+</dt>
+<dt class="hdlist1">
+--oipbp
+</dt>
+<dd>
+<p>
+ Overwrite Invert Pattern Between Passes:
+ If set, then the Overwrite Pattern shall be inverted between
+ passes. If cleared, then the overwrite pattern shall not be
+ inverted between passes. This bit shall be ignored unless the
+ Sanitize Action field is set to 011b (i.e., Overwrite).
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;overwrite-pass-count&gt;
+</dt>
+<dt class="hdlist1">
+--owpass=&lt;overwrite-pass-count&gt;
+</dt>
+<dd>
+<p>
+ Overwrite Pass Count:
+ This field specifies the number of overwrite passes (i.e.,
+ how many times the media is to be overwritten) using the data
+ from the Overwrite Pattern field of this command. A value of 0
+ specifies 16 overwrite passes. This field shall be ignored
+ unless the Sanitize Action field is set to 011b (i.e., Overwrite).
+</p>
+</dd>
+<dt class="hdlist1">
+-u
+</dt>
+<dt class="hdlist1">
+--ause
+</dt>
+<dd>
+<p>
+ Allow Unrestricted Sanitize Exit:
+ If set, then the sanitize operation is performed in unrestricted
+ completion mode. If cleared then the sanitize operation is
+ performed in restricted completion mode. This bit shall be ignored
+ if the Sanitize Action field is set to 001b (i.e., Exit Failure Mode).
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;action&gt;
+</dt>
+<dt class="hdlist1">
+--sanact=&lt;action&gt;
+</dt>
+<dd>
+<p>
+ Sanitize Action:
+</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">0x00</p></td>
+<td align="left" valign="top"><p class="table">Reserved</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x01 | <em>exit-failure</em></p></td>
+<td align="left" valign="top"><p class="table">Exit Failure Mode</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x02 | <em>start-block-erase</em></p></td>
+<td align="left" valign="top"><p class="table">Start a Block Erase sanitize operation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x03 | <em>start-overwrite</em></p></td>
+<td align="left" valign="top"><p class="table">Start an Overwrite sanitize operation</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x04 | <em>start-crypto-erase</em></p></td>
+<td align="left" valign="top"><p class="table">Start a Crypto Erase sanitize operation</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-p &lt;overwrite-pattern&gt;
+</dt>
+<dt class="hdlist1">
+--ovrpat=&lt;overwrite-pattern&gt;
+</dt>
+<dd>
+<p>
+ Overwrite Pattern:
+ This field is ignored unless the Sanitize Action field in
+ Command Dword 10 is set to 011b (i.e., Overwrite). This field
+ specifies a 32-bit pattern that is used for the Overwrite
+ sanitize operation.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Ignore namespace is currently busy and performed the operation
+ even though.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 issue Sanitize Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme sanitize /dev/nvme0 -a 0x02
+# nvme sanitize /dev/nvme0 --sanact=0x01
+# nvme sanitize /dev/nvme0 --sanact=start-overwrite</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-sanitize.txt b/Documentation/nvme-sanitize.txt
new file mode 100644
index 0000000..1e43463
--- /dev/null
+++ b/Documentation/nvme-sanitize.txt
@@ -0,0 +1,112 @@
+nvme-sanitize(1)
+================
+
+NAME
+----
+nvme-sanitize - Send NVMe Sanitize Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme sanitize' <device> [--no-dealloc | -d] [--oipbp | -i]
+ [--owpass=<overwrite-pass-count> | -n <overwrite-pass-count>]
+ [--ause | -u] [--sanact=<action> | -a <action>]
+ [--ovrpat=<overwrite-pattern> | -p <overwrite-pattern>]
+ [--force]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a Sanitize command and
+provides the result.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-d::
+--no-dealloc::
+ No Deallocate After Sanitize:
+ If set, then the controller shall not deallocate any logical
+ blocks as a result of successfully completing the sanitize
+ operation. If cleared, then the controller should deallocate
+ logical blocks as a result of successfully completing the
+ sanitize operation. This bit shall be ignored if the Sanitize
+ Action field is set to 001b (i.e., Exit Failure Mode).
+
+-i::
+--oipbp::
+ Overwrite Invert Pattern Between Passes:
+ If set, then the Overwrite Pattern shall be inverted between
+ passes. If cleared, then the overwrite pattern shall not be
+ inverted between passes. This bit shall be ignored unless the
+ Sanitize Action field is set to 011b (i.e., Overwrite).
+
+-n <overwrite-pass-count>::
+--owpass=<overwrite-pass-count>::
+ Overwrite Pass Count:
+ This field specifies the number of overwrite passes (i.e.,
+ how many times the media is to be overwritten) using the data
+ from the Overwrite Pattern field of this command. A value of 0
+ specifies 16 overwrite passes. This field shall be ignored
+ unless the Sanitize Action field is set to 011b (i.e., Overwrite).
+
+-u::
+--ause::
+ Allow Unrestricted Sanitize Exit:
+ If set, then the sanitize operation is performed in unrestricted
+ completion mode. If cleared then the sanitize operation is
+ performed in restricted completion mode. This bit shall be ignored
+ if the Sanitize Action field is set to 001b (i.e., Exit Failure Mode).
+
+-a <action>::
+--sanact=<action>::
+ Sanitize Action:
++
+[]
+|=================
+|Value|Definition
+|0x00| Reserved
+|0x01 \| 'exit-failure'| Exit Failure Mode
+|0x02 \| 'start-block-erase'| Start a Block Erase sanitize operation
+|0x03 \| 'start-overwrite'| Start an Overwrite sanitize operation
+|0x04 \| 'start-crypto-erase'| Start a Crypto Erase sanitize operation
+|=================
+
+-p <overwrite-pattern>::
+--ovrpat=<overwrite-pattern>::
+ Overwrite Pattern:
+ This field is ignored unless the Sanitize Action field in
+ Command Dword 10 is set to 011b (i.e., Overwrite). This field
+ specifies a 32-bit pattern that is used for the Overwrite
+ sanitize operation.
+
+--force::
+ Ignore namespace is currently busy and performed the operation
+ even though.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue Sanitize Command :
++
+------------
+# nvme sanitize /dev/nvme0 -a 0x02
+# nvme sanitize /dev/nvme0 --sanact=0x01
+# nvme sanitize /dev/nvme0 --sanact=start-overwrite
+
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.1 b/Documentation/nvme-seagate-clear-fw-activate-history.1
new file mode 100644
index 0000000..b5eb66a
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-fw-activate-history.1
@@ -0,0 +1,60 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-CLEAR" "1" "02/14/2024" "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-seagate-clear-fw-activate-history \- Clear the firmware activation history for a given Seagate device\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate clear\-fw\-activate\-history <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.sp
+\-s \-\-save:: specifies that the controller shall save the attribute\&.
+.SH "EXAMPLES"
+.sp
+Clear the FW Activation History for the given Seagate device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate clear\-fw\-activate\-history /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.html b/Documentation/nvme-seagate-clear-fw-activate-history.html
new file mode 100644
index 0000000..5502b59
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-fw-activate-history.html
@@ -0,0 +1,799 @@
+<?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 10.2.0" />
+<title>nvme-seagate-clear-fw-activate-history (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-seagate-clear-fw-activate-history (1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-clear-fw-activate-history -
+ Clear the firmware activation history for a given Seagate 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 seagate clear-fw-activate-history &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>-s
+--save::
+ specifies that the controller shall save the attribute.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Clear the FW Activation History for the given Seagate device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate clear-fw-activate-history /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-clear-fw-activate-history.txt b/Documentation/nvme-seagate-clear-fw-activate-history.txt
new file mode 100644
index 0000000..01f018b
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-fw-activate-history.txt
@@ -0,0 +1,37 @@
+nvme-seagate-clear-fw-activate-history (1)
+============================================
+
+NAME
+----
+nvme-seagate-clear-fw-activate-history - Clear the firmware activation history for a given Seagate device.
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate clear-fw-activate-history <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-s
+--save::
+ specifies that the controller shall save the attribute.
+
+EXAMPLES
+--------
+Clear the FW Activation History for the given Seagate device.
+
+------------
+# nvme seagate clear-fw-activate-history /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.1 b/Documentation/nvme-seagate-clear-pcie-correctable-errors.1
new file mode 100644
index 0000000..8aaf4f5
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.1
@@ -0,0 +1,63 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-CLEAR" "1" "02/14/2024" "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-seagate-clear-pcie-correctable-errors \- Clear Seagate PCIe error statistics
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate clear\-pcie\-correctable\-errors [<device>] [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0), or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-s, \-\-save
+.RS 4
+Specifies that the controller shall save the attribute
+.RE
+.SH "EXAMPLES"
+.sp
+Clears the PCIe error statistics from the device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate clear\-pcie\-correctable\-errors /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.html b/Documentation/nvme-seagate-clear-pcie-correctable-errors.html
new file mode 100644
index 0000000..08ef87d
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.html
@@ -0,0 +1,809 @@
+<?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 10.2.0" />
+<title>nvme-seagate-clear-pcie-correctable-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 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-seagate-clear-pcie-correctable-errors(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-clear-pcie-correctable-errors -
+ Clear Seagate PCIe error 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 seagate clear-pcie-correctable-errors [&lt;device&gt;] [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0), or an
+nvme 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">
+-s
+</dt>
+<dt class="hdlist1">
+--save
+</dt>
+<dd>
+<p>
+ Specifies that the controller shall save the attribute
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Clears the PCIe error statistics from the device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate clear-pcie-correctable-errors /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt b/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt
new file mode 100644
index 0000000..1239f83
--- /dev/null
+++ b/Documentation/nvme-seagate-clear-pcie-correctable-errors.txt
@@ -0,0 +1,38 @@
+nvme-seagate-clear-pcie-correctable-errors(1)
+=============================================
+
+NAME
+----
+nvme-seagate-clear-pcie-correctable-errors - Clear Seagate PCIe error statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate clear-pcie-correctable-errors [<device>] [OPTIONS]'
+
+DESCRIPTION
+-----------
+
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0), or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-s::
+--save::
+ Specifies that the controller shall save the attribute
+
+EXAMPLES
+--------
+Clears the PCIe error statistics from the device.
+
+------------
+# nvme seagate clear-pcie-correctable-errors /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.1 b/Documentation/nvme-seagate-cloud-SSD-plugin-version.1
new file mode 100644
index 0000000..88f683b
--- /dev/null
+++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.1
@@ -0,0 +1,58 @@
+'\" t
+.\" Title: nvme-seagate-cloud-SSD-plugin-version
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-CLOUD" "1" "02/14/2024" "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-seagate-cloud-SSD-plugin-version \- Shows OCP Seagate plugin\*(Aqs version information
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate cloud\-SSD\-plugin\-version\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Shows OCP Seagate plugin\(cqs version information
+.SH "OPTIONS"
+.sp
+No Options
+.SH "EXAMPLES"
+.sp
+Get the OCP plugin version of the specific nvme device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate cloud\-SSD\-plugin\-version
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.html b/Documentation/nvme-seagate-cloud-SSD-plugin-version.html
new file mode 100644
index 0000000..e8628ad
--- /dev/null
+++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.html
@@ -0,0 +1,794 @@
+<?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 10.2.0" />
+<title>nvme-seagate-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;
+}
+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-seagate-cloud-SSD-plugin-version (1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-cloud-SSD-plugin-version -
+ Shows OCP Seagate plugin's version information
+</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 seagate cloud-SSD-plugin-version</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Shows OCP Seagate plugin&#8217;s version information</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Options</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the OCP plugin version of the specific nvme device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate cloud-SSD-plugin-version</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt b/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt
new file mode 100644
index 0000000..f9a92af
--- /dev/null
+++ b/Documentation/nvme-seagate-cloud-SSD-plugin-version.txt
@@ -0,0 +1,31 @@
+nvme-seagate-cloud-SSD-plugin-version (1)
+=========================================
+
+NAME
+----
+nvme-seagate-cloud-SSD-plugin-version - Shows OCP Seagate plugin's version information
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate cloud-SSD-plugin-version'
+
+DESCRIPTION
+-----------
+Shows OCP Seagate plugin's version information
+
+OPTIONS
+-------
+No Options
+
+EXAMPLES
+--------
+Get the OCP plugin version of the specific nvme device.
+
+------------
+# nvme seagate cloud-SSD-plugin-version
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-get-ctrl-tele.1 b/Documentation/nvme-seagate-get-ctrl-tele.1
new file mode 100644
index 0000000..e4f0af6
--- /dev/null
+++ b/Documentation/nvme-seagate-get-ctrl-tele.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-seagate-get-ctrl-tele
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-GET\-" "1" "02/14/2024" "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-seagate-get-ctrl-tele \- Retrieve Seagate Controller\-Initiated Telemetry in either hex\-dump (default) or binary format
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate get\-ctrl\-tele <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \*(Aq<device>\*(Aqparameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Desired namespace
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Output in raw format
+.RE
+.SH "EXAMPLES"
+.sp
+Get the controller initiated telemetry log in hexdump or binary format for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate get\-ctrl\-tele /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-get-ctrl-tele.html b/Documentation/nvme-seagate-get-ctrl-tele.html
new file mode 100644
index 0000000..6b9e4e3
--- /dev/null
+++ b/Documentation/nvme-seagate-get-ctrl-tele.html
@@ -0,0 +1,820 @@
+<?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 10.2.0" />
+<title>nvme-seagate-get-ctrl-tele(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-seagate-get-ctrl-tele(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-get-ctrl-tele -
+ Retrieve Seagate Controller-Initiated Telemetry in either hex-dump (default) or binary format
+</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 seagate get-ctrl-tele &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The '&lt;device&gt;'parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme 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>
+ Desired namespace
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Output in raw format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the controller initiated telemetry log in hexdump or binary format for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate get-ctrl-tele /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-get-ctrl-tele.txt b/Documentation/nvme-seagate-get-ctrl-tele.txt
new file mode 100644
index 0000000..4bb7362
--- /dev/null
+++ b/Documentation/nvme-seagate-get-ctrl-tele.txt
@@ -0,0 +1,42 @@
+nvme-seagate-get-ctrl-tele(1)
+=============================
+
+NAME
+----
+nvme-seagate-get-ctrl-tele - Retrieve Seagate Controller-Initiated Telemetry in
+either hex-dump (default) or binary format
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate get-ctrl-tele <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>'parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Desired namespace
+
+-b::
+--raw-binary::
+ Output in raw format
+
+EXAMPLES
+--------
+Get the controller initiated telemetry log in hexdump or binary format for the specified device.
+
+------------
+# nvme seagate get-ctrl-tele /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-get-host-tele.1 b/Documentation/nvme-seagate-get-host-tele.1
new file mode 100644
index 0000000..398c2a4
--- /dev/null
+++ b/Documentation/nvme-seagate-get-host-tele.1
@@ -0,0 +1,73 @@
+'\" t
+.\" Title: nvme-seagate-get-host-tele
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-GET\-" "1" "02/14/2024" "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-seagate-get-host-tele \- Retrieve Seagate Host\-Initiated Telemetry in either hex\-dump (default) or binary format
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate get\-host\-tele <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+desired namespace
+.RE
+.PP
+\-i <NUM>, \-\-log_specific=<NUM>
+.RS 4
+1 \- controller shall capture Data representing the internal state of the controller at the time the command is processed\&. 0 \- controller shall not update the Telemetry Host Initiated Data\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+output in raw format
+.RE
+.SH "EXAMPLES"
+.sp
+Get the host initiated telemetry log in hexdump or binary format for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate get\-host\-tele /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-get-host-tele.html b/Documentation/nvme-seagate-get-host-tele.html
new file mode 100644
index 0000000..8549d55
--- /dev/null
+++ b/Documentation/nvme-seagate-get-host-tele.html
@@ -0,0 +1,833 @@
+<?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 10.2.0" />
+<title>nvme-seagate-get-host-tele(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-seagate-get-host-tele(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-get-host-tele -
+ Retrieve Seagate Host-Initiated Telemetry in either hex-dump (default) or binary format
+</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 seagate get-host-tele &lt;device&gt; [OPTIONS]</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This will only work on Seagate devices supporting this feature. Not all
+commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> parameter is mandatory and may be either an NVMe character device
+(ex: /dev/nvme0) or an 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>
+ desired namespace
+</p>
+</dd>
+<dt class="hdlist1">
+-i &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--log_specific=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ 1 - controller shall capture Data representing the internal state of the
+ controller at the time the command is processed.
+ 0 - controller shall not update the Telemetry Host Initiated Data.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ output in raw format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the host initiated telemetry log in hexdump or binary format for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate get-host-tele /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-get-host-tele.txt b/Documentation/nvme-seagate-get-host-tele.txt
new file mode 100644
index 0000000..83cdefc
--- /dev/null
+++ b/Documentation/nvme-seagate-get-host-tele.txt
@@ -0,0 +1,48 @@
+nvme-seagate-get-host-tele(1)
+=============================
+
+NAME
+----
+nvme-seagate-get-host-tele - Retrieve Seagate Host-Initiated Telemetry in
+either hex-dump (default) or binary format
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate get-host-tele <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This will only work on Seagate devices supporting this feature. Not all
+commands work across all product families.
+
+The '<device>' parameter is mandatory and may be either an NVMe character device
+(ex: /dev/nvme0) or an block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ desired namespace
+
+-i <NUM>::
+--log_specific=<NUM>::
+ 1 - controller shall capture Data representing the internal state of the
+ controller at the time the command is processed.
+ 0 - controller shall not update the Telemetry Host Initiated Data.
+
+-b::
+--raw-binary::
+ output in raw format
+
+EXAMPLES
+--------
+Get the host initiated telemetry log in hexdump or binary format for the specified device.
+
+------------
+# nvme seagate get-host-tele /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-help.1 b/Documentation/nvme-seagate-help.1
new file mode 100644
index 0000000..3f3a9aa
--- /dev/null
+++ b/Documentation/nvme-seagate-help.1
@@ -0,0 +1,85 @@
+'\" t
+.\" Title: nvme-seagate-help
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-HELP" "1" "02/14/2024" "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-seagate-help \- Shows the Seagate plugin\*(Aqs help information
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate help\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Provides the help information for the Seagate plugin\&.
+.SH "OPTIONS"
+.sp
+No Options
+.SH "EXAMPLES"
+.sp
+Get help information for specific seagate sub\-commands\&.
+.PP
+Seagate vendor specific extensions
+.RS 4
+The following are all implemented sub\-commands:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+vs\-temperature\-stats Retrieve Seagate temperature statistics
+vs\-log\-page\-sup Retrieve Seagate Supported Log\-pages Information
+vs\-smart\-add\-log Retrieve Seagate extended\-SMART Information
+vs\-pcie\-stats Retrieve Seagate PCIe error statistics
+clear\-pcie\-correctable\-errors Clear Seagate PCIe error statistics
+get\-host\-tele Retrieve Seagate Host\-Initiated Telemetry
+get\-ctrl\-tele Retrieve Seagate Controller\-Initiated Telemetry
+vs\-internal\-log Retrieve Seagate Controller\-Initiated Telemetry in binary format
+plugin\-version Shows Seagate plugin\*(Aqs version information
+version Shows the program version
+help Display this help
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+See \fInvme seagate help <command>\fR for more information on a specific command
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate help
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-help.html b/Documentation/nvme-seagate-help.html
new file mode 100644
index 0000000..fba2dc8
--- /dev/null
+++ b/Documentation/nvme-seagate-help.html
@@ -0,0 +1,819 @@
+<?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 10.2.0" />
+<title>nvme-seagate-help(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-seagate-help(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-help -
+ Shows the Seagate plugin's help information
+</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 seagate help</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Provides the help information for the Seagate plugin.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Options</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get help information for specific seagate sub-commands.</p></div>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+Seagate vendor specific extensions
+</dt>
+<dd>
+<p>
+The following are all implemented sub-commands:
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>vs-temperature-stats Retrieve Seagate temperature statistics
+vs-log-page-sup Retrieve Seagate Supported Log-pages Information
+vs-smart-add-log Retrieve Seagate extended-SMART Information
+vs-pcie-stats Retrieve Seagate PCIe error statistics
+clear-pcie-correctable-errors Clear Seagate PCIe error statistics
+get-host-tele Retrieve Seagate Host-Initiated Telemetry
+get-ctrl-tele Retrieve Seagate Controller-Initiated Telemetry
+vs-internal-log Retrieve Seagate Controller-Initiated Telemetry in binary format
+plugin-version Shows Seagate plugin's version information
+version Shows the program version
+help Display this help</code></pre>
+</div></div>
+</dd>
+</dl></div>
+<div class="paragraph"><p>See <em>nvme seagate help &lt;command&gt;</em> for more information on a specific command</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate help</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-help.txt b/Documentation/nvme-seagate-help.txt
new file mode 100644
index 0000000..0a077a8
--- /dev/null
+++ b/Documentation/nvme-seagate-help.txt
@@ -0,0 +1,49 @@
+nvme-seagate-help(1)
+====================
+
+NAME
+----
+nvme-seagate-help - Shows the Seagate plugin's help information
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate help'
+
+DESCRIPTION
+-----------
+Provides the help information for the Seagate plugin.
+
+OPTIONS
+-------
+No Options
+
+EXAMPLES
+--------
+Get help information for specific seagate sub-commands.
+
+Seagate vendor specific extensions::
+
+The following are all implemented sub-commands:
+
+ vs-temperature-stats Retrieve Seagate temperature statistics
+ vs-log-page-sup Retrieve Seagate Supported Log-pages Information
+ vs-smart-add-log Retrieve Seagate extended-SMART Information
+ vs-pcie-stats Retrieve Seagate PCIe error statistics
+ clear-pcie-correctable-errors Clear Seagate PCIe error statistics
+ get-host-tele Retrieve Seagate Host-Initiated Telemetry
+ get-ctrl-tele Retrieve Seagate Controller-Initiated Telemetry
+ vs-internal-log Retrieve Seagate Controller-Initiated Telemetry in binary format
+ plugin-version Shows Seagate plugin's version information
+ version Shows the program version
+ help Display this help
+
+See 'nvme seagate help <command>' for more information on a specific command
+
+------------
+# nvme seagate help
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-plugin-version.1 b/Documentation/nvme-seagate-plugin-version.1
new file mode 100644
index 0000000..702b64e
--- /dev/null
+++ b/Documentation/nvme-seagate-plugin-version.1
@@ -0,0 +1,58 @@
+'\" t
+.\" Title: nvme-seagate-plugin-version
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-PLUGI" "1" "02/14/2024" "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-seagate-plugin-version \- Shows Seagate plugin\*(Aqs version information
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate plugin\-version\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Provides the help information for the Seagate plugin\&.
+.SH "OPTIONS"
+.sp
+No Options
+.SH "EXAMPLES"
+.sp
+Get the plugin version of the specific nvme device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate plugin\-version
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-plugin-version.html b/Documentation/nvme-seagate-plugin-version.html
new file mode 100644
index 0000000..d72265a
--- /dev/null
+++ b/Documentation/nvme-seagate-plugin-version.html
@@ -0,0 +1,794 @@
+<?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 10.2.0" />
+<title>nvme-seagate-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;
+}
+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-seagate-plugin-version(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-plugin-version -
+ Shows Seagate plugin's version information
+</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 seagate plugin-version</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Provides the help information for the Seagate plugin.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Options</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the plugin version of the specific nvme device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate plugin-version</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-plugin-version.txt b/Documentation/nvme-seagate-plugin-version.txt
new file mode 100644
index 0000000..5e4a759
--- /dev/null
+++ b/Documentation/nvme-seagate-plugin-version.txt
@@ -0,0 +1,31 @@
+nvme-seagate-plugin-version(1)
+==============================
+
+NAME
+----
+nvme-seagate-plugin-version - Shows Seagate plugin's version information
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate plugin-version'
+
+DESCRIPTION
+-----------
+Provides the help information for the Seagate plugin.
+
+OPTIONS
+-------
+No Options
+
+EXAMPLES
+--------
+Get the plugin version of the specific nvme device.
+
+------------
+# nvme seagate plugin-version
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-version.1 b/Documentation/nvme-seagate-version.1
new file mode 100644
index 0000000..912d947
--- /dev/null
+++ b/Documentation/nvme-seagate-version.1
@@ -0,0 +1,58 @@
+'\" t
+.\" Title: nvme-seagate-version
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VERSI" "1" "02/14/2024" "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-seagate-version \- Shows the Seagate version information for nvme\-cli
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate version\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Provides the git version information for the Seagate version for nvme\-cli\&. This is for the nvme\-cli tool\&.
+.SH "OPTIONS"
+.sp
+No Options
+.SH "EXAMPLES"
+.sp
+Get the Seagate version information for nvme\-cli\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate version
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-version.html b/Documentation/nvme-seagate-version.html
new file mode 100644
index 0000000..44c9960
--- /dev/null
+++ b/Documentation/nvme-seagate-version.html
@@ -0,0 +1,794 @@
+<?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 10.2.0" />
+<title>nvme-seagate-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;
+}
+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-seagate-version(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-version -
+ Shows the Seagate version information for nvme-cli
+</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 seagate version</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Provides the git version information for the Seagate version for nvme-cli. This is for the nvme-cli tool.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Options</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the Seagate version information for nvme-cli.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate version</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-version.txt b/Documentation/nvme-seagate-version.txt
new file mode 100644
index 0000000..2d5c7ce
--- /dev/null
+++ b/Documentation/nvme-seagate-version.txt
@@ -0,0 +1,31 @@
+nvme-seagate-version(1)
+=======================
+
+NAME
+----
+nvme-seagate-version - Shows the Seagate version information for nvme-cli
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate version'
+
+DESCRIPTION
+-----------
+Provides the git version information for the Seagate version for nvme-cli. This is for the nvme-cli tool.
+
+OPTIONS
+-------
+No Options
+
+EXAMPLES
+--------
+Get the Seagate version information for nvme-cli.
+
+------------
+# nvme seagate version
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.1 b/Documentation/nvme-seagate-vs-fw-activate-history.1
new file mode 100644
index 0000000..cf43aa0
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-fw-activate-history.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-F" "1" "02/14/2024" "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-seagate-vs-fw-activate-history \- Retrieve Seagate vendor specific Controller\-Initiated Telemetry in binary
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-fw\-activate\-history <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Desired namespace
+.RE
+.PP
+\-f <FILE>, \-\-dump\-file=<FILE>
+.RS 4
+Dump file
+.RE
+.SH "EXAMPLES"
+.sp
+Get the Seagate vendor specific Controller\-Initiated telemetry log for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-fw\-activate\-history /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.html b/Documentation/nvme-seagate-vs-fw-activate-history.html
new file mode 100644
index 0000000..a45e9ec
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-fw-activate-history.html
@@ -0,0 +1,820 @@
+<?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 10.2.0" />
+<title>nvme-seagate-vs-fw-activate-history (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-seagate-vs-fw-activate-history (1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-fw-activate-history -
+ Retrieve Seagate vendor specific Controller-Initiated Telemetry in binary
+</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 seagate vs-fw-activate-history &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme 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>
+ Desired namespace
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--dump-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Dump file
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the Seagate vendor specific Controller-Initiated telemetry log for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-fw-activate-history /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-fw-activate-history.txt b/Documentation/nvme-seagate-vs-fw-activate-history.txt
new file mode 100644
index 0000000..8df58b4
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-fw-activate-history.txt
@@ -0,0 +1,42 @@
+nvme-seagate-vs-fw-activate-history (1)
+=======================================
+
+NAME
+----
+nvme-seagate-vs-fw-activate-history - Retrieve Seagate vendor specific
+Controller-Initiated Telemetry in binary
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-fw-activate-history <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Desired namespace
+
+-f <FILE>::
+--dump-file=<FILE>::
+ Dump file
+
+EXAMPLES
+--------
+Get the Seagate vendor specific Controller-Initiated telemetry log for the specified device.
+
+------------
+# nvme seagate vs-fw-activate-history /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-internal-log.1 b/Documentation/nvme-seagate-vs-internal-log.1
new file mode 100644
index 0000000..18c5a1b
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-internal-log.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-I" "1" "02/14/2024" "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-seagate-vs-internal-log \- Retrieve Seagate vendor specific Controller\-Initiated Telemetry in binary
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-internal\-log <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR parameter is mandatory and may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Desired namespace
+.RE
+.PP
+\-f <FILE>, \-\-dump\-file=<FILE>
+.RS 4
+Dump file
+.RE
+.SH "EXAMPLES"
+.sp
+Get the Seagate vendor specific Controller\-Initiated telemetry log for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-internal\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-internal-log.html b/Documentation/nvme-seagate-vs-internal-log.html
new file mode 100644
index 0000000..9eb5b72
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-internal-log.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<title>nvme-seagate-vs-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 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-seagate-vs-internal-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-internal-log -
+ Retrieve Seagate vendor specific Controller-Initiated Telemetry in binary
+</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 seagate vs-internal-log &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> parameter is mandatory and may be either an NVMe character device
+(ex: /dev/nvme0) or an nvme 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>
+ Desired namespace
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--dump-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Dump file
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the Seagate vendor specific Controller-Initiated telemetry log for the
+specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-internal-log /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-internal-log.txt b/Documentation/nvme-seagate-vs-internal-log.txt
new file mode 100644
index 0000000..4a895bc
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-internal-log.txt
@@ -0,0 +1,43 @@
+nvme-seagate-vs-internal-log(1)
+===============================
+
+NAME
+----
+nvme-seagate-vs-internal-log - Retrieve Seagate vendor specific
+Controller-Initiated Telemetry in binary
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-internal-log <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' parameter is mandatory and may be either an NVMe character device
+(ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-n <NUM>::
+--namespace-id=<NUM>::
+ Desired namespace
+
+-f <FILE>::
+--dump-file=<FILE>::
+ Dump file
+
+EXAMPLES
+--------
+Get the Seagate vendor specific Controller-Initiated telemetry log for the
+specified device.
+
+------------
+# nvme seagate vs-internal-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-log-page-sup.1 b/Documentation/nvme-seagate-vs-log-page-sup.1
new file mode 100644
index 0000000..470e2b5
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-log-page-sup.1
@@ -0,0 +1,75 @@
+'\" t
+.\" Title: nvme-seagate-vs-log-page-sup
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-L" "1" "02/14/2024" "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-seagate-vs-log-page-sup \- Retrieve Seagate vendor specific Supported Log\-pages Information
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-log\-page\-sup <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR may be either an NVMe character device (ex: /dev/nvme0) or an NVMe block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Output in binary format
+.RE
+.SH "EXAMPLES"
+.sp
+Get the vendor specific log page information for a particular device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-log\-page\-sup /dev/nvme0
+Output:
+Seagate Supported Log\-pages count :8
+LogPage\-Id LogPage\-Name
+
+0x1 ERROR_INFORMATION
+0x2 SMART_INFORMATION
+0x3 FW_SLOT_INFORMATION
+0x5 COMMANDS_SUPPORTED_AND_EFFECTS
+0xC8 VS_RECENT_DRIVE_HISTORY
+0xC4 VS_EXTENDED_SMART_INFO
+0xC5 VS_LIST_SUPPORTED_LOG_PAGE
+0xCB VS_PCIE_ERROR_LOG_PAGE
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-log-page-sup.html b/Documentation/nvme-seagate-vs-log-page-sup.html
new file mode 100644
index 0000000..da0d05b
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-log-page-sup.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<title>nvme-seagate-vs-log-page-sup(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-seagate-vs-log-page-sup(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-log-page-sup -
+ Retrieve Seagate vendor specific Supported Log-pages Information
+</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 seagate vs-log-page-sup &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> may be either an NVMe character device (ex: /dev/nvme0) or an
+NVMe 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">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Output in binary format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the vendor specific log page information for a particular device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-log-page-sup /dev/nvme0
+Output:
+Seagate Supported Log-pages count :8
+LogPage-Id LogPage-Name
+
+0x1 ERROR_INFORMATION
+0x2 SMART_INFORMATION
+0x3 FW_SLOT_INFORMATION
+0x5 COMMANDS_SUPPORTED_AND_EFFECTS
+0xC8 VS_RECENT_DRIVE_HISTORY
+0xC4 VS_EXTENDED_SMART_INFO
+0xC5 VS_LIST_SUPPORTED_LOG_PAGE
+0xCB VS_PCIE_ERROR_LOG_PAGE</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-log-page-sup.txt b/Documentation/nvme-seagate-vs-log-page-sup.txt
new file mode 100644
index 0000000..55c65fd
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-log-page-sup.txt
@@ -0,0 +1,50 @@
+nvme-seagate-vs-log-page-sup(1)
+===============================
+
+NAME
+----
+nvme-seagate-vs-log-page-sup - Retrieve Seagate vendor specific Supported
+Log-pages Information
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-log-page-sup <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' may be either an NVMe character device (ex: /dev/nvme0) or an
+NVMe block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Output in binary format
+
+EXAMPLES
+--------
+Get the vendor specific log page information for a particular device.
+
+------------
+# nvme seagate vs-log-page-sup /dev/nvme0
+Output:
+Seagate Supported Log-pages count :8
+LogPage-Id LogPage-Name
+
+0x1 ERROR_INFORMATION
+0x2 SMART_INFORMATION
+0x3 FW_SLOT_INFORMATION
+0x5 COMMANDS_SUPPORTED_AND_EFFECTS
+0xC8 VS_RECENT_DRIVE_HISTORY
+0xC4 VS_EXTENDED_SMART_INFO
+0xC5 VS_LIST_SUPPORTED_LOG_PAGE
+0xCB VS_PCIE_ERROR_LOG_PAGE
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-pcie-stats.1 b/Documentation/nvme-seagate-vs-pcie-stats.1
new file mode 100644
index 0000000..20650e4
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-pcie-stats.1
@@ -0,0 +1,63 @@
+'\" t
+.\" Title: nvme-seagate-vs-pcie-stats
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-P" "1" "02/14/2024" "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-seagate-vs-pcie-stats \- Retrieve Seagate vendor specific PCIe error statistics
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-pcie\-stats <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \fI<device>\fR parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Output in binary format
+.RE
+.SH "EXAMPLES"
+.sp
+Get the vendor specific PCIe error statistics for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-pcie\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-pcie-stats.html b/Documentation/nvme-seagate-vs-pcie-stats.html
new file mode 100644
index 0000000..7b8d5ec
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-pcie-stats.html
@@ -0,0 +1,809 @@
+<?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 10.2.0" />
+<title>nvme-seagate-vs-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 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-seagate-vs-pcie-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-pcie-stats -
+ Retrieve Seagate vendor specific PCIe error 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 seagate vs-pcie-stats &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The <em>&lt;device&gt;</em> parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme 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">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Output in binary format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the vendor specific PCIe error statistics for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-pcie-stats /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-pcie-stats.txt b/Documentation/nvme-seagate-vs-pcie-stats.txt
new file mode 100644
index 0000000..86f87a3
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-pcie-stats.txt
@@ -0,0 +1,38 @@
+nvme-seagate-vs-pcie-stats(1)
+=============================
+
+NAME
+----
+nvme-seagate-vs-pcie-stats - Retrieve Seagate vendor specific PCIe error
+statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-pcie-stats <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>' parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Output in binary format
+
+EXAMPLES
+--------
+Get the vendor specific PCIe error statistics for the specified device.
+
+------------
+# nvme seagate vs-pcie-stats /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-smart-add-log.1 b/Documentation/nvme-seagate-vs-smart-add-log.1
new file mode 100644
index 0000000..5a833f5
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-smart-add-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-S" "1" "02/14/2024" "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-seagate-vs-smart-add-log \- Retrieve Seagate vendor specific extended\-SMART Information
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-smart\-add\-log <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Seagate vendor log request and either saves the result to a file or dumps the content to stdout\&.
+.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
+The log contents may be associated with the controller, in which case the namespace parameter is ignored\&.
+.sp
+Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page)
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.SH "OPTIONS"
+.PP
+\-l <NUM>, \-\-log=<NUM>
+.RS 4
+Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page)
+.RE
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>
+.RS 4
+Namespace number
+.RE
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output in binary format\&. Defaults to text\-formatted dump to stdout
+.RE
+.SH "EXAMPLES"
+.sp
+Get the vendor specific extended SMART information for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-smart\-add\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-smart-add-log.html b/Documentation/nvme-seagate-vs-smart-add-log.html
new file mode 100644
index 0000000..54912cf
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-smart-add-log.html
@@ -0,0 +1,837 @@
+<?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 10.2.0" />
+<title>nvme-seagate-vs-smart-add-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 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-seagate-vs-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-smart-add-log -
+ Retrieve Seagate vendor specific extended-SMART Information
+</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 seagate vs-smart-add-log &lt;device&gt; [OPTIONS]</em></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 Seagate vendor log
+request and either saves the result to a file or dumps the content to stdout.</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>The log contents may be associated with the controller, in which case the namespace parameter is ignored.</p></div>
+<div class="paragraph"><p>Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page)</p></div>
+<div class="paragraph"><p>This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--log=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM
+ Supercap SMART log page)
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Namespace number
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output in binary format. Defaults to text-formatted dump to stdout
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get the vendor specific extended SMART information for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-smart-add-log /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-smart-add-log.txt b/Documentation/nvme-seagate-vs-smart-add-log.txt
new file mode 100644
index 0000000..836220a
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-smart-add-log.txt
@@ -0,0 +1,55 @@
+nvme-seagate-vs-smart-add-log(1)
+================================
+
+NAME
+----
+nvme-seagate-vs-smart-add-log - Retrieve Seagate vendor specific extended-SMART
+Information
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-smart-add-log <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Seagate vendor log
+request and either saves the result to a file or dumps the content to stdout.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+The log contents may be associated with the controller, in which case the namespace parameter is ignored.
+
+Two logs exist, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM Supercap SMART log page)
+
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+OPTIONS
+-------
+-l <NUM>::
+--log=<NUM>::
+ Log number, page 0xC4 (Extended SMART log page) and page 0xCF (DRAM
+ Supercap SMART log page)
+
+-n <NUM>::
+--namespace-id=<NUM>::
+ Namespace number
+
+-o <FILE>::
+--output-file=<FILE>::
+ Output in binary format. Defaults to text-formatted dump to stdout
+
+EXAMPLES
+--------
+Get the vendor specific extended SMART information for the specified device.
+
+------------
+# nvme seagate vs-smart-add-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-seagate-vs-temperature-stats.1 b/Documentation/nvme-seagate-vs-temperature-stats.1
new file mode 100644
index 0000000..0de2ec1
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-temperature-stats.1
@@ -0,0 +1,63 @@
+'\" t
+.\" Title: nvme-seagate-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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SEAGATE\-VS\-T" "1" "02/14/2024" "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-seagate-vs-temperature-stats \- Retrieve Seagate vendor specific temperature statistics
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme seagate vs\-temperature\-stats <device> [OPTIONS]\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+This command will only work on Seagate devices supporting this feature\&. Not all commands work across all product families\&.
+.sp
+The \*(Aq<device>\*(Aqparameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an nvme block device (ex: /dev/nvme0n1)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Output in binary format
+.RE
+.SH "EXAMPLES"
+.sp
+Get vendor specific temperature statistics for the specified device\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme seagate vs\-temperature\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-seagate-vs-temperature-stats.html b/Documentation/nvme-seagate-vs-temperature-stats.html
new file mode 100644
index 0000000..22f13c4
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-temperature-stats.html
@@ -0,0 +1,809 @@
+<?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 10.2.0" />
+<title>nvme-seagate-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-seagate-vs-temperature-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-seagate-vs-temperature-stats -
+ Retrieve Seagate vendor specific temperature 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 seagate vs-temperature-stats &lt;device&gt; [OPTIONS]</em></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 will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.</p></div>
+<div class="paragraph"><p>The '&lt;device&gt;'parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme 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">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Output in binary format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Get vendor specific temperature statistics for the specified device.</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme seagate vs-temperature-stats /dev/nvme0</code></pre>
+</div></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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-seagate-vs-temperature-stats.txt b/Documentation/nvme-seagate-vs-temperature-stats.txt
new file mode 100644
index 0000000..58a9f11
--- /dev/null
+++ b/Documentation/nvme-seagate-vs-temperature-stats.txt
@@ -0,0 +1,38 @@
+nvme-seagate-vs-temperature-stats(1)
+====================================
+
+NAME
+----
+nvme-seagate-vs-temperature-stats - Retrieve Seagate vendor specific
+temperature statistics
+
+SYNOPSIS
+--------
+[verse]
+'nvme seagate vs-temperature-stats <device> [OPTIONS]'
+
+DESCRIPTION
+-----------
+This command will only work on Seagate devices supporting this feature. Not
+all commands work across all product families.
+
+The '<device>'parameter is mandatory and it may be either an NVMe character device (ex: /dev/nvme0) or an
+nvme block device (ex: /dev/nvme0n1).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Output in binary format
+
+EXAMPLES
+--------
+Get vendor specific temperature statistics for the specified device.
+
+------------
+# nvme seagate vs-temperature-stats /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-security-recv.1 b/Documentation/nvme-security-recv.1
new file mode 100644
index 0000000..21503cb
--- /dev/null
+++ b/Documentation/nvme-security-recv.1
@@ -0,0 +1,105 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SECURITY\-RECV" "1" "02/14/2024" "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-security-recv \- Security Recv command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme security\-recv\fR <device> [\-\-size=<size> | \-x <size>]
+ [\-\-secp=<security\-protocol> | \-p <security\-protocol>]
+ [\-\-spsp=<protocol\-specific> | \-s <protocol\-specific>]
+ [\-\-nssf=<nvme\-specific> | \-N <nvme\-specific>]
+ [\-\-al=<allocation\-length> | \-t <allocation\-length>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>] [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Security Receive command transfers the status and data result of one or more Security Send commands that were previously submitted to the controller\&.
+.sp
+The association between a Security Receive command and previous Security Send commands is dependent on the Security Protocol\&. The format of the data to be transferred is dependent on the Security Protocol\&. Refer to SPC\-4 for Security Protocol details\&.
+.sp
+Each Security Receive command returns the appropriate data corresponding to a Security Send command as defined by the rules of the Security Protocol\&. The Security Receive command data may not be retained if there is a loss of communication between the controller and host, or if a controller reset occurs\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Target a specific namespace for this security command\&.
+.RE
+.PP
+\-N <nssf>, \-\-nssf=<nssf>
+.RS 4
+NVMe Security Specific field\&. If using security protocol EAh assigned for NVMe use, the NVMe security specific field indicates which reply memory buffer target\&.
+.RE
+.PP
+\-x <size>, \-\-size=<size>
+.RS 4
+Size of buffer to allocate\&. One success it will be printed to STDOUT\&.
+.RE
+.PP
+\-p <security\-protocol>, \-\-secp=<security\-protocol>
+.RS 4
+Security Protocol: This field specifies the security protocol as defined in SPC\-4\&. The controller shall fail the command with Invalid Parameter indicated if a reserved value of the Security Protocol is specified\&.
+.RE
+.PP
+\-s <security\-protocol\-specific>, \-\-spsp=<security\-protocol\-specific>
+.RS 4
+SP Specific: The value of this field is specific to the Security Protocol as defined in SPC\-4\&.
+.RE
+.PP
+\-t <allocation\-length>, \-\-al=<allocation\-length>
+.RS 4
+Allocation Length: The value of this field is specific to the Security Protocol as defined in SPC\-4\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Defaults to print in hex\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No Examples
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-security-recv.html b/Documentation/nvme-security-recv.html
new file mode 100644
index 0000000..58da38d
--- /dev/null
+++ b/Documentation/nvme-security-recv.html
@@ -0,0 +1,916 @@
+<?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 10.2.0" />
+<title>nvme-security-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 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-security-recv(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-security-recv -
+ Security Recv 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 security-recv</em> &lt;device&gt; [--size=&lt;size&gt; | -x &lt;size&gt;]
+ [--secp=&lt;security-protocol&gt; | -p &lt;security-protocol&gt;]
+ [--spsp=&lt;protocol-specific&gt; | -s &lt;protocol-specific&gt;]
+ [--nssf=&lt;nvme-specific&gt; | -N &lt;nvme-specific&gt;]
+ [--al=&lt;allocation-length&gt; | -t &lt;allocation-length&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;] [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Security Receive command transfers the status and data result of
+one or more Security Send commands that were previously submitted to
+the controller.</p></div>
+<div class="paragraph"><p>The association between a Security Receive command and previous Security
+Send commands is dependent on the Security Protocol. The format of the
+data to be transferred is dependent on the Security Protocol. Refer to
+SPC-4 for Security Protocol details.</p></div>
+<div class="paragraph"><p>Each Security Receive command returns the appropriate data corresponding
+to a Security Send command as defined by the rules of the Security
+Protocol. The Security Receive command data may not be retained if there
+is a loss of communication between the controller and host, or if a
+controller reset occurs.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Target a specific namespace for this security command.
+</p>
+</dd>
+<dt class="hdlist1">
+-N &lt;nssf&gt;
+</dt>
+<dt class="hdlist1">
+--nssf=&lt;nssf&gt;
+</dt>
+<dd>
+<p>
+ NVMe Security Specific field. If using security protocol EAh
+ assigned for NVMe use, the NVMe security specific field indicates
+ which reply memory buffer target.
+</p>
+</dd>
+<dt class="hdlist1">
+-x &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of buffer to allocate. One success it will be printed
+ to STDOUT.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;security-protocol&gt;
+</dt>
+<dt class="hdlist1">
+--secp=&lt;security-protocol&gt;
+</dt>
+<dd>
+<p>
+ Security Protocol: This field specifies the security protocol
+ as defined in SPC-4. The controller shall fail the command with
+ Invalid Parameter indicated if a reserved value of the Security
+ Protocol is specified.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;security-protocol-specific&gt;
+</dt>
+<dt class="hdlist1">
+--spsp=&lt;security-protocol-specific&gt;
+</dt>
+<dd>
+<p>
+ SP Specific: The value of this field is specific to the Security
+ Protocol as defined in SPC-4.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;allocation-length&gt;
+</dt>
+<dt class="hdlist1">
+--al=&lt;allocation-length&gt;
+</dt>
+<dd>
+<p>
+ Allocation Length: The value of this field is specific to the
+ Security Protocol as defined in SPC-4.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Defaults to print in hex.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Examples</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-security-recv.txt b/Documentation/nvme-security-recv.txt
new file mode 100644
index 0000000..ef77531
--- /dev/null
+++ b/Documentation/nvme-security-recv.txt
@@ -0,0 +1,89 @@
+nvme-security-recv(1)
+=====================
+
+NAME
+----
+nvme-security-recv - Security Recv command
+
+SYNOPSIS
+--------
+[verse]
+'nvme security-recv' <device> [--size=<size> | -x <size>]
+ [--secp=<security-protocol> | -p <security-protocol>]
+ [--spsp=<protocol-specific> | -s <protocol-specific>]
+ [--nssf=<nvme-specific> | -N <nvme-specific>]
+ [--al=<allocation-length> | -t <allocation-length>]
+ [--namespace-id=<nsid> | -n <nsid>] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Security Receive command transfers the status and data result of
+one or more Security Send commands that were previously submitted to
+the controller.
+
+The association between a Security Receive command and previous Security
+Send commands is dependent on the Security Protocol. The format of the
+data to be transferred is dependent on the Security Protocol. Refer to
+SPC-4 for Security Protocol details.
+
+Each Security Receive command returns the appropriate data corresponding
+to a Security Send command as defined by the rules of the Security
+Protocol. The Security Receive command data may not be retained if there
+is a loss of communication between the controller and host, or if a
+controller reset occurs.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Target a specific namespace for this security command.
+
+-N <nssf>::
+--nssf=<nssf>::
+ NVMe Security Specific field. If using security protocol EAh
+ assigned for NVMe use, the NVMe security specific field indicates
+ which reply memory buffer target.
+
+-x <size>::
+--size=<size>::
+ Size of buffer to allocate. One success it will be printed
+ to STDOUT.
+
+-p <security-protocol>::
+--secp=<security-protocol>::
+ Security Protocol: This field specifies the security protocol
+ as defined in SPC-4. The controller shall fail the command with
+ Invalid Parameter indicated if a reserved value of the Security
+ Protocol is specified.
+
+-s <security-protocol-specific>::
+--spsp=<security-protocol-specific>::
+ SP Specific: The value of this field is specific to the Security
+ Protocol as defined in SPC-4.
+
+-t <allocation-length>::
+--al=<allocation-length>::
+ Allocation Length: The value of this field is specific to the
+ Security Protocol as defined in SPC-4.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Defaults to print in hex.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-security-send.1 b/Documentation/nvme-security-send.1
new file mode 100644
index 0000000..d463f85
--- /dev/null
+++ b/Documentation/nvme-security-send.1
@@ -0,0 +1,98 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SECURITY\-SEND" "1" "02/14/2024" "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-security-send \- Security Send command
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme security\-send\fR <device> [\-\-file=<file> | \-f <file>]
+ [\-\-secp=<security\-protocol> | \-p <security\-protocol>]
+ [\-\-spsp=<protocol\-specific> | \-s <protocol\-specific>]
+ [\-\-tl=<transfer\-length> | \-t <transfer\-length>]
+ [\-\-nssf=<nvme\-specific> | \-N <nvme\-specific>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Security Send command is used to transfer security protocol data to the controller\&. The data structure transferred to the controller as part of this command contains security protocol specific commands to be performed by the controller\&. The data structure transferred may also contain data or parameters associated with the security protocol commands\&. Status and data that is to be returned to the host for the security protocol commands submitted by a Security Send command are retrieved with the Security Receive command\&.
+.sp
+The association between a Security Send command and subsequent Security Receive command is Security Protocol field dependent as defined in SPC\-4\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Target a specific namespace for this security command\&.
+.RE
+.PP
+\-N <nssf>, \-\-nssf=<nssf>
+.RS 4
+NVMe Security Specific field\&. If using security protocol EAh assigned for NVMe use, the NVMe security specific field indicates which reply memory buffer target\&.
+.RE
+.PP
+\-f <file>, \-\-file=<file>
+.RS 4
+Path to file used as the security protocol\(cqs payload\&. Required argument\&.
+.RE
+.PP
+\-p <security\-protocol>, \-\-secp=<security\-protocol>
+.RS 4
+Security Protocol: This field specifies the security protocol as defined in SPC\-4\&. The controller shall fail the command with Invalid Parameter indicated if a reserved value of the Security Protocol is specified\&.
+.RE
+.PP
+\-s <security\-protocol\-specific>, \-\-spsp=<security\-protocol\-specific>
+.RS 4
+SP Specific: The value of this field is specific to the Security Protocol as defined in SPC\-4\&.
+.RE
+.PP
+\-t <trans\-length>, \-\-tl=<trans\-length>
+.RS 4
+Transfer Length: The value of this field is specific to the Security Protocol as defined in SPC\-4\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No Examples
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-security-send.html b/Documentation/nvme-security-send.html
new file mode 100644
index 0000000..4ff43d9
--- /dev/null
+++ b/Documentation/nvme-security-send.html
@@ -0,0 +1,903 @@
+<?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 10.2.0" />
+<title>nvme-security-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 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-security-send(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-security-send -
+ Security 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 security-send</em> &lt;device&gt; [--file=&lt;file&gt; | -f &lt;file&gt;]
+ [--secp=&lt;security-protocol&gt; | -p &lt;security-protocol&gt;]
+ [--spsp=&lt;protocol-specific&gt; | -s &lt;protocol-specific&gt;]
+ [--tl=&lt;transfer-length&gt; | -t &lt;transfer-length&gt;]
+ [--nssf=&lt;nvme-specific&gt; | -N &lt;nvme-specific&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Security Send command is used to transfer security protocol data
+to the controller. The data structure transferred to the controller
+as part of this command contains security protocol specific commands
+to be performed by the controller. The data structure transferred may
+also contain data or parameters associated with the security protocol
+commands. Status and data that is to be returned to the host for the
+security protocol commands submitted by a Security Send command are
+retrieved with the Security Receive command.</p></div>
+<div class="paragraph"><p>The association between a Security Send command and subsequent Security
+Receive command is Security Protocol field dependent as defined in SPC-4.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Target a specific namespace for this security command.
+</p>
+</dd>
+<dt class="hdlist1">
+-N &lt;nssf&gt;
+</dt>
+<dt class="hdlist1">
+--nssf=&lt;nssf&gt;
+</dt>
+<dd>
+<p>
+ NVMe Security Specific field. If using security protocol EAh
+ assigned for NVMe use, the NVMe security specific field indicates
+ which reply memory buffer target.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;file&gt;
+</dt>
+<dt class="hdlist1">
+--file=&lt;file&gt;
+</dt>
+<dd>
+<p>
+ Path to file used as the security protocol&#8217;s payload. Required
+ argument.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;security-protocol&gt;
+</dt>
+<dt class="hdlist1">
+--secp=&lt;security-protocol&gt;
+</dt>
+<dd>
+<p>
+ Security Protocol: This field specifies the security protocol
+ as defined in SPC-4. The controller shall fail the command with
+ Invalid Parameter indicated if a reserved value of the Security
+ Protocol is specified.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;security-protocol-specific&gt;
+</dt>
+<dt class="hdlist1">
+--spsp=&lt;security-protocol-specific&gt;
+</dt>
+<dd>
+<p>
+ SP Specific: The value of this field is specific to the Security
+ Protocol as defined in SPC-4.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;trans-length&gt;
+</dt>
+<dt class="hdlist1">
+--tl=&lt;trans-length&gt;
+</dt>
+<dd>
+<p>
+ Transfer Length: The value of this field is specific to the
+ Security Protocol as defined in SPC-4.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No Examples</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-security-send.txt b/Documentation/nvme-security-send.txt
new file mode 100644
index 0000000..347b970
--- /dev/null
+++ b/Documentation/nvme-security-send.txt
@@ -0,0 +1,82 @@
+nvme-security-send(1)
+=====================
+
+NAME
+----
+nvme-security-send - Security Send command
+
+SYNOPSIS
+--------
+[verse]
+'nvme security-send' <device> [--file=<file> | -f <file>]
+ [--secp=<security-protocol> | -p <security-protocol>]
+ [--spsp=<protocol-specific> | -s <protocol-specific>]
+ [--tl=<transfer-length> | -t <transfer-length>]
+ [--nssf=<nvme-specific> | -N <nvme-specific>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Security Send command is used to transfer security protocol data
+to the controller. The data structure transferred to the controller
+as part of this command contains security protocol specific commands
+to be performed by the controller. The data structure transferred may
+also contain data or parameters associated with the security protocol
+commands. Status and data that is to be returned to the host for the
+security protocol commands submitted by a Security Send command are
+retrieved with the Security Receive command.
+
+The association between a Security Send command and subsequent Security
+Receive command is Security Protocol field dependent as defined in SPC-4.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Target a specific namespace for this security command.
+
+-N <nssf>::
+--nssf=<nssf>::
+ NVMe Security Specific field. If using security protocol EAh
+ assigned for NVMe use, the NVMe security specific field indicates
+ which reply memory buffer target.
+
+-f <file>::
+--file=<file>::
+ Path to file used as the security protocol's payload. Required
+ argument.
+
+-p <security-protocol>::
+--secp=<security-protocol>::
+ Security Protocol: This field specifies the security protocol
+ as defined in SPC-4. The controller shall fail the command with
+ Invalid Parameter indicated if a reserved value of the Security
+ Protocol is specified.
+
+-s <security-protocol-specific>::
+--spsp=<security-protocol-specific>::
+ SP Specific: The value of this field is specific to the Security
+ Protocol as defined in SPC-4.
+
+-t <trans-length>::
+--tl=<trans-length>::
+ Transfer Length: The value of this field is specific to the
+ Security Protocol as defined in SPC-4.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No Examples
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-self-test-log.1 b/Documentation/nvme-self-test-log.1
new file mode 100644
index 0000000..0fe2ec5
--- /dev/null
+++ b/Documentation/nvme-self-test-log.1
@@ -0,0 +1,133 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SELF\-TEST\-LO" "1" "02/14/2024" "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-self-test-log \- Retrieve the log information initiated by device\-self\-test and display it
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme self\-test\fR\-log <device> [\-\-log\-entries=<entries> | \-e <entries>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the log pages from an NVMe device corresponding to the requested self\-test by the user and provides 20\-most recent result 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 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 or the json format\&.
+.sp
+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 <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the self\-test\-log and print it in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme self\-test\-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 output to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme self\-test\-log /dev/nvme0 \-o "binary"
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the self\-test\-log and print it in a json format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme self\-test\-log /dev/nvme0 \-o "json"
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-self-test-log.html b/Documentation/nvme-self-test-log.html
new file mode 100644
index 0000000..4945aa6
--- /dev/null
+++ b/Documentation/nvme-self-test-log.html
@@ -0,0 +1,865 @@
+<?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 10.2.0" />
+<title>nvme-self-test-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 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-self-test-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-self-test-log -
+ Retrieve the log information initiated by device-self-test and display it
+</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 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;] [--verbose | -v]</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 log pages from an NVMe device corresponding to the
+requested self-test by the user and provides 20-most recent result
+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 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 or the
+json format.</p></div>
+<div class="paragraph"><p>By default the log is printed out in the normal readable format.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_option">OPTION</h2>
+<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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 self-test-log and print it in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme self-test-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw output to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme self-test-log /dev/nvme0 -o "binary"</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get the self-test-log and print it in a json format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme self-test-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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-self-test-log.txt b/Documentation/nvme-self-test-log.txt
new file mode 100644
index 0000000..d4600e8
--- /dev/null
+++ b/Documentation/nvme-self-test-log.txt
@@ -0,0 +1,71 @@
+nvme-self-test-log(1)
+=====================
+
+NAME
+----
+nvme-self-test-log - Retrieve the log information initiated by device-self-test and display it
+
+SYNOPSIS
+--------
+[verse]
+'nvme self-test'-log <device> [--log-entries=<entries> | -e <entries>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the log pages from an NVMe device corresponding to the
+requested self-test by the user and provides 20-most recent result
+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 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 or the
+json format.
+
+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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Get the self-test-log and print it in a human readable format:
++
+------------
+# nvme self-test-log /dev/nvme0
+------------
++
+
+* Print the raw output to a file:
++
+------------
+# nvme self-test-log /dev/nvme0 -o "binary"
+------------
++
+
+* Get the self-test-log and print it in a json format:
++
+------------
+# nvme self-test-log /dev/nvme0 -o "json"
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-set-feature.1 b/Documentation/nvme-set-feature.1
new file mode 100644
index 0000000..5b635c7
--- /dev/null
+++ b/Documentation/nvme-set-feature.1
@@ -0,0 +1,146 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SET\-FEATURE" "1" "02/14/2024" "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-set-feature \- Sets an NVMe feature, returns applicable results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme set\-feature\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-feature\-id=<fid> | \-f <fid>] [\-\-value=<value> | \-V <value>]
+ [\-\-uuid\-index=<uuid\-index> | \-U <uuid_index>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-data=<data\-file> | \-d <data\-file>] [\-\-save | \-s]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Submits an NVMe Set Feature admin command and returns the applicable results\&. This may be the feature\(cqs value, or may also include a feature structure if the feature requires it (ex: LBA Range Type)\&.
+.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 value sent to the device is displayed
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the feature for the given nsid\&. This is optional and most features do not use this value\&.
+.RE
+.PP
+\-f <fid>, \-\-feature\-id=<fid>
+.RS 4
+The feature id to send with the command\&. Value provided should be in hex\&.
+.RE
+.PP
+\-l <data\-len>, \-\-data\-len=<data\-len>
+.RS 4
+The data length for the buffer submitted for this feature\&. Most known features do not use this value\&. The exceptions are LBA Range Type and host identifier\&.
+.RE
+.PP
+\-d <data\-file>, \-\-data=<data\-file>
+.RS 4
+The data file for the buffer submitted for this feature\&. Most known features do not use this value\&. The exceptions is LBA Range Type and host identifier\&. This defaults to STDIN so files and echo can be piped\&.
+.RE
+.PP
+\-V <value>, \-\-value=<value>
+.RS 4
+The value for command dword 11, the value you want to set the feature to\&.
+.RE
+.PP
+\-s, \-\-save
+.RS 4
+Save the attribute so that it persists through all power states and resets\&.
+.RE
+.PP
+\-U <uuid\-index>, \-\-uuid\-index=<uuid\-index>
+.RS 4
+UUID Index of the feature
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Sets the Power State (PS) to 1 in feature id 2:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme set\-feature /dev/nvme0 \-f 2 /dev/nvme0n1 \-V 0x1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Sets the host id to the ascii string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# echo "abcdefgh" | nvme set\-feature /dev/nvme0 \-f 0x81 \-l 8
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+nvme set\-feature /dev/nvme0 \-f 0x81 \-l 8 \-U 0x1
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-set-feature.html b/Documentation/nvme-set-feature.html
new file mode 100644
index 0000000..7da6fae
--- /dev/null
+++ b/Documentation/nvme-set-feature.html
@@ -0,0 +1,929 @@
+<?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 10.2.0" />
+<title>nvme-set-feature(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-set-feature(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-set-feature -
+ Sets an NVMe feature, returns applicable 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 set-feature</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--feature-id=&lt;fid&gt; | -f &lt;fid&gt;] [--value=&lt;value&gt; | -V &lt;value&gt;]
+ [--uuid-index=&lt;uuid-index&gt; | -U &lt;uuid_index&gt;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--data=&lt;data-file&gt; | -d &lt;data-file&gt;] [--save | -s]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Submits an NVMe Set Feature admin command and returns the applicable
+results. This may be the feature&#8217;s value, or may also include a feature
+structure if the feature requires it (ex: LBA Range Type).</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 value sent to the device is displayed</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the feature for the given nsid. This is optional and
+ most features do not use this value.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;fid&gt;
+</dt>
+<dt class="hdlist1">
+--feature-id=&lt;fid&gt;
+</dt>
+<dd>
+<p>
+ The feature id to send with the command. Value provided should
+ be in hex.
+</p>
+</dd>
+<dt class="hdlist1">
+-l &lt;data-len&gt;
+</dt>
+<dt class="hdlist1">
+--data-len=&lt;data-len&gt;
+</dt>
+<dd>
+<p>
+ The data length for the buffer submitted for this feature. Most
+ known features do not use this value. The exceptions are LBA
+ Range Type and host identifier.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ The data file for the buffer submitted for this feature. Most
+ known features do not use this value. The exceptions is LBA
+ Range Type and host identifier. This defaults to STDIN so files
+ and echo can be piped.
+</p>
+</dd>
+<dt class="hdlist1">
+-V &lt;value&gt;
+</dt>
+<dt class="hdlist1">
+--value=&lt;value&gt;
+</dt>
+<dd>
+<p>
+ The value for command dword 11, the value you want to set the
+ feature to.
+</p>
+</dd>
+<dt class="hdlist1">
+-s
+</dt>
+<dt class="hdlist1">
+--save
+</dt>
+<dd>
+<p>
+ Save the attribute so that it persists through all power states and resets.
+</p>
+</dd>
+<dt class="hdlist1">
+-U &lt;uuid-index&gt;
+</dt>
+<dt class="hdlist1">
+--uuid-index=&lt;uuid-index&gt;
+</dt>
+<dd>
+<p>
+ UUID Index of the feature
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Sets the Power State (PS) to 1 in feature id 2:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -V 0x1</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Sets the host id to the ascii string.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># echo "abcdefgh" | nvme set-feature /dev/nvme0 -f 0x81 -l 8</code></pre>
+</div></div>
+<div class="paragraph"><p>nvme set-feature /dev/nvme0 -f 0x81 -l 8 -U 0x1</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-set-feature.txt b/Documentation/nvme-set-feature.txt
new file mode 100644
index 0000000..05c2210
--- /dev/null
+++ b/Documentation/nvme-set-feature.txt
@@ -0,0 +1,95 @@
+nvme-set-feature(1)
+===================
+
+NAME
+----
+nvme-set-feature - Sets an NVMe feature, returns applicable results
+
+SYNOPSIS
+--------
+[verse]
+'nvme set-feature' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--feature-id=<fid> | -f <fid>] [--value=<value> | -V <value>]
+ [--uuid-index=<uuid-index> | -U <uuid_index>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--data=<data-file> | -d <data-file>] [--save | -s]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Submits an NVMe Set Feature admin command and returns the applicable
+results. This may be the feature's value, or may also include a feature
+structure if the feature requires it (ex: LBA Range Type).
+
+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 value sent to the device is displayed
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the feature for the given nsid. This is optional and
+ most features do not use this value.
+
+-f <fid>::
+--feature-id=<fid>::
+ The feature id to send with the command. Value provided should
+ be in hex.
+
+-l <data-len>::
+--data-len=<data-len>::
+ The data length for the buffer submitted for this feature. Most
+ known features do not use this value. The exceptions are LBA
+ Range Type and host identifier.
+
+-d <data-file>::
+--data=<data-file>::
+ The data file for the buffer submitted for this feature. Most
+ known features do not use this value. The exceptions is LBA
+ Range Type and host identifier. This defaults to STDIN so files
+ and echo can be piped.
+
+-V <value>::
+--value=<value>::
+ The value for command dword 11, the value you want to set the
+ feature to.
+
+-s::
+--save::
+ Save the attribute so that it persists through all power states and resets.
+
+-U <uuid-index>::
+--uuid-index=<uuid-index>::
+ UUID Index of the feature
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Sets the Power State (PS) to 1 in feature id 2:
++
+------------
+# nvme set-feature /dev/nvme0 -f 2 /dev/nvme0n1 -V 0x1
+------------
++
+
+* Sets the host id to the ascii string.
++
+------------
+# echo "abcdefgh" | nvme set-feature /dev/nvme0 -f 0x81 -l 8
+------------
++
+nvme set-feature /dev/nvme0 -f 0x81 -l 8 -U 0x1
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-set-property.1 b/Documentation/nvme-set-property.1
new file mode 100644
index 0000000..b66fa30
--- /dev/null
+++ b/Documentation/nvme-set-property.1
@@ -0,0 +1,72 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SET\-PROPERTY" "1" "02/14/2024" "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-set-property \- Writes and shows the defined NVMe controller property for NVMe over Fabric
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme set\-property\fR <device> [\-\-offset=<offset> | \-O <offset>]
+ [\-\-value=<val> | \-V <val>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Writes and shows the defined NVMe controller property for NVMe over Fabric\&.
+.SH "OPTIONS"
+.PP
+\-O, \-\-offset
+.RS 4
+The offset of the property\&.
+.RE
+.PP
+\-V
+.RS 4
+\-\-value: The value of the property to be set\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples (yet)\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-set-property.html b/Documentation/nvme-set-property.html
new file mode 100644
index 0000000..88bda56
--- /dev/null
+++ b/Documentation/nvme-set-property.html
@@ -0,0 +1,836 @@
+<?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 10.2.0" />
+<title>nvme-set-property(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-set-property(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-set-property -
+ Writes and shows the defined NVMe controller property for NVMe over Fabric
+</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 set-property</em> &lt;device&gt; [--offset=&lt;offset&gt; | -O &lt;offset&gt;]
+ [--value=&lt;val&gt; | -V &lt;val&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Writes and shows the defined NVMe controller property for NVMe over Fabric.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-O
+</dt>
+<dt class="hdlist1">
+--offset
+</dt>
+<dd>
+<p>
+ The offset of the property.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dd>
+<p>
+--value:
+ The value of the property to be set.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-set-property.txt b/Documentation/nvme-set-property.txt
new file mode 100644
index 0000000..22a513c
--- /dev/null
+++ b/Documentation/nvme-set-property.txt
@@ -0,0 +1,45 @@
+nvme-set-property(1)
+====================
+
+NAME
+----
+nvme-set-property - Writes and shows the defined NVMe controller property
+for NVMe over Fabric
+
+SYNOPSIS
+--------
+[verse]
+'nvme set-property' <device> [--offset=<offset> | -O <offset>]
+ [--value=<val> | -V <val>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Writes and shows the defined NVMe controller property for NVMe over Fabric.
+
+OPTIONS
+-------
+-O::
+--offset::
+ The offset of the property.
+
+-V::
+--value:
+ The value of the property to be set.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples (yet).
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-show-hostnqn.1 b/Documentation/nvme-show-hostnqn.1
new file mode 100644
index 0000000..618ad0f
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.1
@@ -0,0 +1,60 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SHOW\-HOSTNQN" "1" "02/14/2024" "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-show-hostnqn \- Show the host NQN configured for the system
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme show\-hostnqn\fR [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Show the host NQN configured for the system\&. If /usr/local/etc/nvme/hostnqn is not present and systemd application\-specific machine IDs are available, this will show the systemd\-generated host NQN for the system\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+nvme show\-hostnqn
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-show-hostnqn.html b/Documentation/nvme-show-hostnqn.html
new file mode 100644
index 0000000..c948837
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.html
@@ -0,0 +1,816 @@
+<?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 10.2.0" />
+<title>nvme-show-hostnqn(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-show-hostnqn(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-show-hostnqn -
+ Show the host NQN configured for the system
+</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 show-hostnqn</em> [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Show the host NQN configured for the system. If /usr/local/etc/nvme/hostnqn is
+not present and systemd application-specific machine IDs are available,
+this will show the systemd-generated host NQN for the system.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme show-hostnqn</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-show-hostnqn.txt b/Documentation/nvme-show-hostnqn.txt
new file mode 100644
index 0000000..5074e2c
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.txt
@@ -0,0 +1,36 @@
+nvme-show-hostnqn(1)
+===================
+
+NAME
+----
+nvme-show-hostnqn - Show the host NQN configured for the system
+
+SYNOPSIS
+--------
+[verse]
+'nvme show-hostnqn' [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Show the host NQN configured for the system. If @SYSCONFDIR@/nvme/hostnqn is
+not present and systemd application-specific machine IDs are available,
+this will show the systemd-generated host NQN for the system.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+nvme show-hostnqn
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-show-regs.1 b/Documentation/nvme-show-regs.1
new file mode 100644
index 0000000..115a00d
--- /dev/null
+++ b/Documentation/nvme-show-regs.1
@@ -0,0 +1,129 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "02/14/2024" "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-show-regs \- Reads and shows the defined NVMe controller registers for NVMe over PCIe or the controller properties for NVMe over Fabrics\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme show\-regs\fR <device> [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe over PCIe device given, sends an identify namespace command and provides the result and returned structure\&. For the NVMe over Fabrics device given, sends a fabric command and provides the result and returned structure\&.
+.sp
+The <device> parameter is mandatory and must be the nvme admin character device (ex: /dev/nvme0)\&. For NVMe over PCIe, the program uses knowledge of the sysfs layout to map the device to the pci resource stored there and mmaps the memory to get access to the registers\&. For NVMe over Fabrics, the programs sends a fabric command to get the properties of the target NVMe controller\&. Only the supported properties are displayed\&.
+.SH "OPTIONS"
+.PP
+\-H, \-\-human\-readable
+.RS 4
+Display registers or supported properties in human readable format\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show the NVMe over PCIe controller registers or the NVMe over Fabric controller properties in a binary format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme show\-regs /dev/nvme0 \-o binary
+.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 NVMe over PCIe controller registers or the NVMe over Fabric controller properties in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme show\-regs /dev/nvme0 \-H
+.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 NVMe over PCIe controller registers or NVMe\-oF controller properties in a json format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme show\-regs /dev/nvme0 \-o json
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-show-regs.html b/Documentation/nvme-show-regs.html
new file mode 100644
index 0000000..0fbe431
--- /dev/null
+++ b/Documentation/nvme-show-regs.html
@@ -0,0 +1,866 @@
+<?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 10.2.0" />
+<title>nvme-id-ns(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-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-show-regs -
+ Reads and shows the defined NVMe controller registers for NVMe over PCIe or the controller properties for NVMe over Fabrics.
+</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 show-regs</em> &lt;device&gt; [--human-readable | -H]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 over PCIe device given, sends an identify namespace command and
+provides the result and returned structure.
+For the NVMe over Fabrics device given, sends a fabric command and provides
+the result and returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the nvme admin character
+device (ex: /dev/nvme0). For NVMe over PCIe, the program uses knowledge of the
+sysfs layout to map the device to the pci resource stored there and mmaps the
+memory to get access to the registers. For NVMe over Fabrics, the programs
+sends a fabric command to get the properties of the target NVMe controller.
+Only the supported properties are displayed.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ Display registers or supported properties in human readable format.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a binary format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme show-regs /dev/nvme0 -o binary</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme show-regs /dev/nvme0 -H</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Show the NVMe over PCIe controller registers or NVMe-oF controller properties
+in a json format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme show-regs /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-show-regs.txt b/Documentation/nvme-show-regs.txt
new file mode 100644
index 0000000..0460365
--- /dev/null
+++ b/Documentation/nvme-show-regs.txt
@@ -0,0 +1,67 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-show-regs - Reads and shows the defined NVMe controller registers for
+NVMe over PCIe or the controller properties for NVMe over Fabrics.
+
+SYNOPSIS
+--------
+[verse]
+'nvme show-regs' <device> [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe over PCIe device given, sends an identify namespace command and
+provides the result and returned structure.
+For the NVMe over Fabrics device given, sends a fabric command and provides
+the result and returned structure.
+
+The <device> parameter is mandatory and must be the nvme admin character
+device (ex: /dev/nvme0). For NVMe over PCIe, the program uses knowledge of the
+sysfs layout to map the device to the pci resource stored there and mmaps the
+memory to get access to the registers. For NVMe over Fabrics, the programs
+sends a fabric command to get the properties of the target NVMe controller.
+Only the supported properties are displayed.
+
+OPTIONS
+-------
+-H::
+--human-readable::
+ Display registers or supported properties in human readable format.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a binary format:
++
+------------
+# nvme show-regs /dev/nvme0 -o binary
+------------
+* Show the NVMe over PCIe controller registers or the NVMe over Fabric controller
+properties in a human readable format:
++
+------------
+# nvme show-regs /dev/nvme0 -H
+------------
+* Show the NVMe over PCIe controller registers or NVMe-oF controller properties
+in a json format:
++
+------------
+# nvme show-regs /dev/nvme0 -o json
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-show-topology.1 b/Documentation/nvme-show-topology.1
new file mode 100644
index 0000000..cde2d83
--- /dev/null
+++ b/Documentation/nvme-show-topology.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-show-topology
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SHOW\-TOPOLOGY" "1" "02/14/2024" "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-show-topology \- Show topology of all NVMe subsystems
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme show\-topology\fR [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Show the topology of all NVMe subsystems\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+or
+\fIjson\fR\&. Only one output format can be used at a time\&.
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Increase the information in the output, showing nvme subsystems, controllers and namespaces separately and how they\(cqre related to each other\&.
+.RE
+.PP
+\-r <order>, \-\-ranking=<order>
+.RS 4
+Set the ranking orer to
+\fInamespace\fR
+(default) or
+\fIctrl\fR\&. This option has only an effect for output format
+\fInormal\fR\&. The JSON output is always
+\fInamespace\fR
+ordered\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+nvme show\-topology
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-show-topology.html b/Documentation/nvme-show-topology.html
new file mode 100644
index 0000000..51196db
--- /dev/null
+++ b/Documentation/nvme-show-topology.html
@@ -0,0 +1,852 @@
+<?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 10.2.0" />
+<title>nvme-show-topology(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-show-topology(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-show-topology -
+ Show topology of all NVMe subsystems
+</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 show-topology</em> [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Show the topology of all NVMe subsystems.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> or <em>json</em>. Only one output
+ format can be used at a time.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information in the output, showing nvme subsystems,
+ controllers and namespaces separately and how they&#8217;re related to each
+ other.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;order&gt;
+</dt>
+<dt class="hdlist1">
+--ranking=&lt;order&gt;
+</dt>
+<dd>
+<p>
+ Set the ranking orer to <em>namespace</em> (default) or <em>ctrl</em>. This option
+ has only an effect for output format <em>normal</em>. The JSON output is
+ always <em>namespace</em> ordered.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme show-topology</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-show-topology.txt b/Documentation/nvme-show-topology.txt
new file mode 100644
index 0000000..32ffad1
--- /dev/null
+++ b/Documentation/nvme-show-topology.txt
@@ -0,0 +1,51 @@
+nvme-show-topology(1)
+=====================
+
+NAME
+----
+nvme-show-topology - Show topology of all NVMe subsystems
+
+SYNOPSIS
+--------
+[verse]
+'nvme show-topology' [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Show the topology of all NVMe subsystems.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json'. Only one output
+ format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information in the output, showing nvme subsystems,
+ controllers and namespaces separately and how they're related to each
+ other.
+
+-r <order>::
+--ranking=<order>::
+ Set the ranking orer to 'namespace' (default) or 'ctrl'. This option
+ has only an effect for output format 'normal'. The JSON output is
+ always 'namespace' ordered.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+nvme show-topology
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-smart-log.1 b/Documentation/nvme-smart-log.1
new file mode 100644
index 0000000..abb0ed7
--- /dev/null
+++ b/Documentation/nvme-smart-log.1
@@ -0,0 +1,118 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SMART\-LOG" "1" "02/14/2024" "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-smart-log \- Send NVMe SMART log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme smart\-log\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe SMART 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 smart 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
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Retrieve the SMART log for the given nsid\&. This is optional and its success may depend on the device\(cqs capabilities to provide this log on a per\-namespace basis (see the NVMe Identify Controller for this capability)\&. The default nsid to use is 0xffffffff for the device global SMART log\&.
+.RE
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw SMART log buffer to stdout\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the SMART log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme smart\-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 SMART log to a file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme smart\-log /dev/nvme0 \-\-raw\-binary > smart_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-smart-log.html b/Documentation/nvme-smart-log.html
new file mode 100644
index 0000000..989675d
--- /dev/null
+++ b/Documentation/nvme-smart-log.html
@@ -0,0 +1,868 @@
+<?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 10.2.0" />
+<title>nvme-smart-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 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-smart-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-smart-log -
+ Send NVMe SMART 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 smart-log</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--raw-binary | -b]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 SMART 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 smart 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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the SMART log for the given nsid. This is optional
+ and its success may depend on the device&#8217;s capabilities to
+ provide this log on a per-namespace basis (see the NVMe Identify
+ Controller for this capability). The default nsid to use is
+ 0xffffffff for the device global SMART log.
+</p>
+</dd>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw SMART log buffer to stdout.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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 SMART log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme smart-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Print the raw SMART log to a file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme smart-log /dev/nvme0 --raw-binary &gt; smart_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-smart-log.txt b/Documentation/nvme-smart-log.txt
new file mode 100644
index 0000000..c08f523
--- /dev/null
+++ b/Documentation/nvme-smart-log.txt
@@ -0,0 +1,69 @@
+nvme-smart-log(1)
+=================
+
+NAME
+----
+nvme-smart-log - Send NVMe SMART log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme smart-log' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe SMART 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 smart 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
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Retrieve the SMART log for the given nsid. This is optional
+ and its success may depend on the device's capabilities to
+ provide this log on a per-namespace basis (see the NVMe Identify
+ Controller for this capability). The default nsid to use is
+ 0xffffffff for the device global SMART log.
+
+-b::
+--raw-binary::
+ Print the raw SMART log buffer to stdout.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Print the SMART log page in a human readable format:
++
+------------
+# nvme smart-log /dev/nvme0
+------------
++
+
+* Print the raw SMART log to a file:
++
+------------
+# nvme smart-log /dev/nvme0 --raw-binary > smart_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-subsystem-reset.1 b/Documentation/nvme-subsystem-reset.1
new file mode 100644
index 0000000..7bdae5b
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.1
@@ -0,0 +1,80 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SUBSYSTEM\-RES" "1" "02/14/2024" "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-subsystem-reset \- Reset the nvme subsystem\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme subsystem\-reset\fR <device>
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Requests NVMe subsystem reset\&. The <device> param is mandatory and must be an NVMe character device (ex: /dev/nvme0)\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Resets the subsystem\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme subsystem\-reset /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-subsystem-reset.html b/Documentation/nvme-subsystem-reset.html
new file mode 100644
index 0000000..4847ad4
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.html
@@ -0,0 +1,826 @@
+<?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 10.2.0" />
+<title>nvme-subsystem-reset(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-subsystem-reset(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-subsystem-reset -
+ Reset the nvme subsystem.
+</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 subsystem-reset</em> &lt;device&gt;
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 subsystem reset. 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="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Resets the subsystem.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme subsystem-reset /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-subsystem-reset.txt b/Documentation/nvme-subsystem-reset.txt
new file mode 100644
index 0000000..cc3a139
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.txt
@@ -0,0 +1,40 @@
+nvme-subsystem-reset(1)
+=======================
+
+NAME
+----
+nvme-subsystem-reset - Reset the nvme subsystem.
+
+SYNOPSIS
+--------
+[verse]
+'nvme subsystem-reset' <device>
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Requests NVMe subsystem reset. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Resets the subsystem.
++
+------------
+# nvme subsystem-reset /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-supported-cap-config-log.txt b/Documentation/nvme-supported-cap-config-log.txt
new file mode 100644
index 0000000..b60303b
--- /dev/null
+++ b/Documentation/nvme-supported-cap-config-log.txt
@@ -0,0 +1,52 @@
+nvme-supported-cap-config-log(1)
+================================
+
+NAME
+----
+nvme-supported-cap-config-log - Send NVMe Supported Capacity
+Configuration List Log pages request, returns result and log.
+
+SYNOPSIS
+--------
+[verse]
+'nvme supported-cap-config-log' <device> [--dom-id | -d] [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the list of Supported Capacity Configuration List
+log pages details from an NVMe device and provides
+the returned structure.
+
+The <device> parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).
+
+On success, the returned Supported Capacity Configuration List log
+pages log structure will be printed.
+
+OPTIONS
+-------
+-d::
+--dom-id::
+ To get the domain ID.
+
+-b::
+--raw-binary::
+ To show raw binary data.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples provided yet.
+
+NVME
+----
+Part of the nvme-user suite \ No newline at end of file
diff --git a/Documentation/nvme-supported-log-pages.1 b/Documentation/nvme-supported-log-pages.1
new file mode 100644
index 0000000..4d2574f
--- /dev/null
+++ b/Documentation/nvme-supported-log-pages.1
@@ -0,0 +1,64 @@
+'\" t
+.\" Title: nvme-supported-log-pages
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SUPPORTED\-LOG" "1" "02/14/2024" "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-supported-log-pages \- Send NVMe Supported Log pages request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme supported\-log\-pages\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe supported log pages details from an NVMe device and provides the returned structure\&.
+.sp
+The <device> parameter is mandatory and should be the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+On success, the returned supported log pages log structure will be printed for each command that is supported\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&. Show more information including LID Supported (LSUPP) and Index Offset Supported (IOP) details\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples provided yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-supported-log-pages.html b/Documentation/nvme-supported-log-pages.html
new file mode 100644
index 0000000..5073a61
--- /dev/null
+++ b/Documentation/nvme-supported-log-pages.html
@@ -0,0 +1,820 @@
+<?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 10.2.0" />
+<title>nvme-supported-log-pages(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-supported-log-pages(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-supported-log-pages -
+ Send NVMe Supported Log pages 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 supported-log-pages</em> &lt;device&gt; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 supported log pages details from an NVMe device and provides
+the returned structure.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>On success, the returned supported log pages log structure will be printed
+for each command that is supported.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output. Show more information
+ including LID Supported (LSUPP) and Index Offset Supported (IOP) details.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No examples provided 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-supported-log-pages.txt b/Documentation/nvme-supported-log-pages.txt
new file mode 100644
index 0000000..bd17fdf
--- /dev/null
+++ b/Documentation/nvme-supported-log-pages.txt
@@ -0,0 +1,43 @@
+nvme-supported-log-pages(1)
+===========================
+
+NAME
+----
+nvme-supported-log-pages - Send NVMe Supported Log pages request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme supported-log-pages' <device> [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves the NVMe supported log pages details from an NVMe device and provides
+the returned structure.
+
+The <device> parameter is mandatory and should be the NVMe character
+device (ex: /dev/nvme0).
+
+On success, the returned supported log pages log structure will be printed
+for each command that is supported.
+
+OPTIONS
+-------
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output. Show more information
+ including LID Supported (LSUPP) and Index Offset Supported (IOP) details.
+
+EXAMPLES
+--------
+No examples provided yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-telemetry-log.1 b/Documentation/nvme-telemetry-log.1
new file mode 100644
index 0000000..4522c5b
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.1
@@ -0,0 +1,102 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TELEMETRY\-LOG" "1" "02/14/2024" "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-telemetry-log \- Retrieves a Telemetry Host\-Initiated log page from an NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme telemetry\-log\fR <device> [\-\-output\-file=<file> | \-O <file>]
+ [\-\-host\-generate=<gen> | \-g <gen>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves an Telemetry Host\-Initiated 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 log structure will be in raw binary format \fIonly\fR with \-\-output\-file option which is mandatory\&.
+.SH "OPTIONS"
+.PP
+\-O <file>, \-\-output\-file=<file>
+.RS 4
+File name to which raw binary data will be saved to\&.
+.RE
+.PP
+\-g <gen>, \-\-host\-generate=<gen>
+.RS 4
+If set to 1, controller shall capture the Telemetry Host\-Initiated data representing the internal state of the controller at the time the associated Get Log Page command is processed\&. If cleated to 0, controller shall
+\fInot\fR
+update this data\&.
+.RE
+.PP
+\-d <da>, \-\-data\-area=<da>
+.RS 4
+Retrieves the specific data area requested\&. Valid inputs are 1,2,3,4\&. If this option is not specified, the default value is 3, since data area 4 may not be supported\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve Telemetry Host\-Initiated data to telemetry_log\&.bin
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme telemetry\-log /dev/nvme0 \-\-output\-file=telemetry_log\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-telemetry-log.html b/Documentation/nvme-telemetry-log.html
new file mode 100644
index 0000000..7d5f95c
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.html
@@ -0,0 +1,869 @@
+<?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 10.2.0" />
+<title>nvme-telemetry-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 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-telemetry-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-telemetry-log -
+ Retrieves a Telemetry Host-Initiated log page from 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 telemetry-log</em> &lt;device&gt; [--output-file=&lt;file&gt; | -O &lt;file&gt;]
+ [--host-generate=&lt;gen&gt; | -g &lt;gen&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves an Telemetry Host-Initiated 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 log structure will be in raw binary format <em>only</em> with
+--output-file option which is mandatory.</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>
+ File name to which raw binary data will be saved to.
+</p>
+</dd>
+<dt class="hdlist1">
+-g &lt;gen&gt;
+</dt>
+<dt class="hdlist1">
+--host-generate=&lt;gen&gt;
+</dt>
+<dd>
+<p>
+ If set to 1, controller shall capture the Telemetry Host-Initiated data
+ representing the internal state of the controller at the time the
+ associated Get Log Page command is processed.
+ If cleated to 0, controller shall <em>not</em> update this data.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;da&gt;
+</dt>
+<dt class="hdlist1">
+--data-area=&lt;da&gt;
+</dt>
+<dd>
+<p>
+ Retrieves the specific data area requested. Valid inputs are 1,2,3,4. If
+ this option is not specified, the default value is 3, since data area
+ 4 may not be supported.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve Telemetry Host-Initiated data to telemetry_log.bin
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme telemetry-log /dev/nvme0 --output-file=telemetry_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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-telemetry-log.txt b/Documentation/nvme-telemetry-log.txt
new file mode 100644
index 0000000..4d2a494
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.txt
@@ -0,0 +1,64 @@
+nvme-telemetry-log(1)
+=====================
+
+NAME
+----
+nvme-telemetry-log - Retrieves a Telemetry Host-Initiated log page from an NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme telemetry-log' <device> [--output-file=<file> | -O <file>]
+ [--host-generate=<gen> | -g <gen>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Retrieves an Telemetry Host-Initiated 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 log structure will be in raw binary format _only_ with
+--output-file option which is mandatory.
+
+OPTIONS
+-------
+-O <file>::
+--output-file=<file>::
+ File name to which raw binary data will be saved to.
+
+-g <gen>::
+--host-generate=<gen>::
+ If set to 1, controller shall capture the Telemetry Host-Initiated data
+ representing the internal state of the controller at the time the
+ associated Get Log Page command is processed.
+ If cleated to 0, controller shall _not_ update this data.
+
+-d <da>::
+--data-area=<da>::
+ Retrieves the specific data area requested. Valid inputs are 1,2,3,4. If
+ this option is not specified, the default value is 3, since data area
+ 4 may not be supported.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Retrieve Telemetry Host-Initiated data to telemetry_log.bin
++
+------------
+# nvme telemetry-log /dev/nvme0 --output-file=telemetry_log.bin
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1 b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1
new file mode 100644
index 0000000..cfa6106
--- /dev/null
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.1
@@ -0,0 +1,66 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-CLEAR" "1" "02/14/2024" "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-toshiba-clear-pcie-correctable-errors \- Reset the PCIe correctable errors count to zero\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\*(Aqnvme toshiba clear\-pcie\-correctable\-errors \*(Aq <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Toshiba clear PCIe correctable errors request\&.
+.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 "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clear the PCIe correctable errors count:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme toshiba 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-toshiba-clear-pcie-correctable-errors.html b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html
new file mode 100644
index 0000000..94ead34
--- /dev/null
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html
@@ -0,0 +1,798 @@
+<?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 10.2.0" />
+<title>nvme-toshiba-clear-pcie-correctable-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 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-toshiba-clear-pcie-correctable-errors(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-toshiba-clear-pcie-correctable-errors -
+ Reset the PCIe correctable errors count to zero.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">'nvme toshiba clear-pcie-correctable-errors ' &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, sends the Toshiba clear PCIe correctable errors
+request.</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="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Clear the PCIe correctable errors count:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme toshiba 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt
new file mode 100644
index 0000000..862c860
--- /dev/null
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt
@@ -0,0 +1,32 @@
+nvme-toshiba-clear-pcie-correctable-errors(1)
+=============================================
+
+NAME
+----
+nvme-toshiba-clear-pcie-correctable-errors - Reset the PCIe correctable errors count to zero.
+
+SYNOPSIS
+--------
+[verse]
+'nvme toshiba clear-pcie-correctable-errors ' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Toshiba clear PCIe correctable errors
+request.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+EXAMPLES
+--------
+* Clear the PCIe correctable errors count:
++
+------------
+# nvme toshiba clear-pcie-correctable-errors /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-toshiba-vs-internal-log.1 b/Documentation/nvme-toshiba-vs-internal-log.1
new file mode 100644
index 0000000..68ba681
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-internal-log.1
@@ -0,0 +1,108 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-VS\-I" "1" "02/14/2024" "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-toshiba-vs-internal-log \- Retrieve a Toshiba device\*(Aqs vendor specific internal log and either save to file or dump the contents\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\*(Aqnvme toshiba vs\-internal\-log \*(Aq <device>
+ [\-\-output\-file=<FILE>, \-o <FILE>] (optional)
+ [\-\-saved\-log, \-s] (optional)
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Toshiba internal device log request and either saves the result to a file or dumps the content to stdout\&.
+.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
+The log is associated with the controller rather than any namespaces\&.
+.sp
+Two logs exist, the current log and the previous log\&.
+.sp
+This will only work on Toshiba devices supporting this feature\&.
+.sp
+Note: The logs are quite large \- typically 100\(cqs of MB\&. This command can take several minutes to complete\&. A progress runner is included when data is written to file and a page count is included in the stdout dump\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output binary file\&. Defaults to text\-formatted dump to stdout
+.RE
+.PP
+\-p, \-\-prev\-log
+.RS 4
+Use previous log contents\&. Defaults to the current log contents\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the current log from the device and dump it to stdout:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme toshiba internal\-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
+.\}
+Get the previous log from the device and save to a binary file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme toshiba internal\-log /dev/nvme0 \-\-output\-file=log\&.bin \-\-prev\-log
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-toshiba-vs-internal-log.html b/Documentation/nvme-toshiba-vs-internal-log.html
new file mode 100644
index 0000000..e079c4d
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-internal-log.html
@@ -0,0 +1,844 @@
+<?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 10.2.0" />
+<title>nvme-toshiba-vs-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 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-toshiba-vs-internal-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-toshiba-vs-internal-log -
+ Retrieve a Toshiba device's vendor specific internal log and either save to file or dump the contents.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">'nvme toshiba vs-internal-log ' &lt;device&gt;
+ [--output-file=&lt;FILE&gt;, -o &lt;FILE&gt;] (optional)
+ [--saved-log, -s] (optional)</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 Toshiba internal device log
+request and either saves the result to a file or dumps the content to stdout.</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>The log is associated with the controller rather than any
+namespaces.</p></div>
+<div class="paragraph"><p>Two logs exist, the current log and the previous log.</p></div>
+<div class="paragraph"><p>This will only work on Toshiba devices supporting this feature.</p></div>
+<div class="paragraph"><p>Note: The logs are quite large - typically 100&#8217;s of MB. This command can take several minutes to complete.
+A progress runner is included when data is written to file and a page count is included in the stdout dump.</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 binary file. Defaults to text-formatted dump to stdout
+</p>
+</dd>
+<dt class="hdlist1">
+-p
+</dt>
+<dt class="hdlist1">
+--prev-log
+</dt>
+<dd>
+<p>
+ Use previous log contents. Defaults to the current log contents.
+</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 current log from the device and dump it to stdout:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme toshiba internal-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get the previous log from the device and save to a binary file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme toshiba internal-log /dev/nvme0 --output-file=log.bin --prev-log</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-toshiba-vs-internal-log.txt b/Documentation/nvme-toshiba-vs-internal-log.txt
new file mode 100644
index 0000000..3cfb917
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-internal-log.txt
@@ -0,0 +1,62 @@
+nvme-toshiba-vs-internal-log(1)
+===============================
+
+NAME
+----
+nvme-toshiba-vs-internal-log - Retrieve a Toshiba device's vendor specific internal log and either save to file or dump the contents.
+
+SYNOPSIS
+--------
+[verse]
+'nvme toshiba vs-internal-log ' <device>
+ [--output-file=<FILE>, -o <FILE>] (optional)
+ [--saved-log, -s] (optional)
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Toshiba internal device log
+request and either saves the result to a file or dumps the content to stdout.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+The log is associated with the controller rather than any
+namespaces.
+
+Two logs exist, the current log and the previous log.
+
+This will only work on Toshiba devices supporting this feature.
+
+Note: The logs are quite large - typically 100's of MB. This command can take several minutes to complete.
+A progress runner is included when data is written to file and a page count is included in the stdout dump.
+
+OPTIONS
+-------
+
+-o <FILE>::
+--output-file=<FILE>::
+ Output binary file. Defaults to text-formatted dump to stdout
+
+-p::
+--prev-log::
+ Use previous log contents. Defaults to the current log contents.
+
+EXAMPLES
+--------
+* Get the current log from the device and dump it to stdout:
++
+------------
+# nvme toshiba internal-log /dev/nvme0
+------------
++
+
+* Get the previous log from the device and save to a binary file:
++
+------------
+# nvme toshiba internal-log /dev/nvme0 --output-file=log.bin --prev-log
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.1 b/Documentation/nvme-toshiba-vs-smart-add-log.1
new file mode 100644
index 0000000..22e8a18
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.1
@@ -0,0 +1,106 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-VS\-S" "1" "02/14/2024" "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-toshiba-vs-smart-add-log \- Retrieve a Toshiba device\*(Aqs vendor specific extended SMART log page contents and either save to file or dump the contents\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\*(Aqnvme toshiba vs\-smart\-add\-log \*(Aq <device> [\-\-log=<NUM>, \-l <NUM>]
+ [\-\-namespace\-id=<NUM>, \-n <NUM>]
+ [\-\-output\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Toshiba vendor log request and either saves the result to a file or dumps the content to stdout\&.
+.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
+The log contents may be associated with the controller, in which case the namespace parameter is ignored\&.
+.sp
+Two logs exist, page 0xC0 (log page directory) and page 0xCA (vendor log page)
+.sp
+This will only work on Toshiba devices supporting this feature\&.
+.SH "OPTIONS"
+.PP
+\-l <NUM>, \-\-log=<NUM>
+.RS 4
+Log page: 0xC0 or 0xCA (defaults to 0xCA)
+.RE
+.PP
+\-n <NUM>, \-\-namespace\-id=<NUM>, \-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output binary file\&. Defaults to text\-formatted dump to stdout
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the current log from the device and dumps it to stdout:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme toshiba vs\-smart\-add\-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
+.\}
+Get the contents of log page 0xC0 from the device and save to a binary file:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme toshiba vs\-smart\-add\-log /dev/nvme0 \-\-output\-file=log\&.bin \-\-log=0xC0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.html b/Documentation/nvme-toshiba-vs-smart-add-log.html
new file mode 100644
index 0000000..ef4a80b
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.html
@@ -0,0 +1,848 @@
+<?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 10.2.0" />
+<title>nvme-toshiba-vs-smart-add-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 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-toshiba-vs-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-toshiba-vs-smart-add-log -
+ Retrieve a Toshiba device's vendor specific extended SMART log page contents and either save to file or dump the contents.
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<pre class="content">'nvme toshiba vs-smart-add-log ' &lt;device&gt; [--log=&lt;NUM&gt;, -l &lt;NUM&gt;]
+ [--namespace-id=&lt;NUM&gt;, -n &lt;NUM&gt;]
+ [--output-file=&lt;FILE&gt;, -o &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, sends the Toshiba vendor log
+request and either saves the result to a file or dumps the content to stdout.</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>The log contents may be associated with the controller, in which case the
+namespace parameter is ignored.</p></div>
+<div class="paragraph"><p>Two logs exist, page 0xC0 (log page directory) and page 0xCA (vendor log page)</p></div>
+<div class="paragraph"><p>This will only work on Toshiba devices supporting this feature.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-l &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--log=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Log page: 0xC0 or 0xCA (defaults to 0xCA)
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output binary file. Defaults to text-formatted dump to stdout
+</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 current log from the device and dumps it to stdout:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme toshiba vs-smart-add-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Get the contents of log page 0xC0 from the device and save to a binary file:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme toshiba vs-smart-add-log /dev/nvme0 --output-file=log.bin --log=0xC0</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-toshiba-vs-smart-add-log.txt b/Documentation/nvme-toshiba-vs-smart-add-log.txt
new file mode 100644
index 0000000..96a13ca
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.txt
@@ -0,0 +1,63 @@
+nvme-toshiba-vs-smart-add-log(1)
+================================
+
+NAME
+----
+nvme-toshiba-vs-smart-add-log - Retrieve a Toshiba device's vendor specific
+extended SMART log page contents and either save to file or dump the contents.
+
+SYNOPSIS
+--------
+[verse]
+'nvme toshiba vs-smart-add-log ' <device> [--log=<NUM>, -l <NUM>]
+ [--namespace-id=<NUM>, -n <NUM>]
+ [--output-file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Toshiba vendor log
+request and either saves the result to a file or dumps the content to stdout.
+
+The <device> parameter is mandatory and may be either the NVMe
+character device (ex: /dev/nvme0), or a namespace block device (ex:
+/dev/nvme0n1).
+
+The log contents may be associated with the controller, in which case the
+namespace parameter is ignored.
+
+Two logs exist, page 0xC0 (log page directory) and page 0xCA (vendor log page)
+
+This will only work on Toshiba devices supporting this feature.
+
+OPTIONS
+-------
+
+-l <NUM>::
+--log=<NUM>::
+ Log page: 0xC0 or 0xCA (defaults to 0xCA)
+
+-n <NUM>::
+--namespace-id=<NUM>::
+
+-o <FILE>::
+--output-file=<FILE>::
+ Output binary file. Defaults to text-formatted dump to stdout
+
+EXAMPLES
+--------
+* Get the current log from the device and dumps it to stdout:
++
+------------
+# nvme toshiba vs-smart-add-log /dev/nvme0
+------------
++
+
+* Get the contents of log page 0xC0 from the device and save to a binary file:
++
+------------
+# nvme toshiba vs-smart-add-log /dev/nvme0 --output-file=log.bin --log=0xC0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-transcend-badblock.1 b/Documentation/nvme-transcend-badblock.1
new file mode 100644
index 0000000..86774bd
--- /dev/null
+++ b/Documentation/nvme-transcend-badblock.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TRANSCEND\-BAD" "1" "02/14/2024" "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-transcend-badblock \- Retrieve Transcend NVMe device\*(Aqs bad blocks\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme transcend badblock\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the Transcend vendor command and return the bad block of the 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
+On success, the returned value would print the amount of bad blocks\&.
+.SH "OPTIONS"
+.sp
+none
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Transcend device\(cqs bad blocks in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme transcend badblock /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-transcend-badblock.html b/Documentation/nvme-transcend-badblock.html
new file mode 100644
index 0000000..4e3130a
--- /dev/null
+++ b/Documentation/nvme-transcend-badblock.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 10.2.0" />
+<title>nvme-transcend-badblock(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-transcend-badblock(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-transcend-badblock -
+ Retrieve Transcend NVMe device's bad blocks.
+</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 transcend badblock</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, sends the Transcend vendor command and return the bad block of the 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>On success, the returned value would print the amount of bad blocks.</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>
+Print the Transcend device&#8217;s bad blocks in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme transcend badblock /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-transcend-badblock.txt b/Documentation/nvme-transcend-badblock.txt
new file mode 100644
index 0000000..9b6f671
--- /dev/null
+++ b/Documentation/nvme-transcend-badblock.txt
@@ -0,0 +1,36 @@
+nvme-transcend-badblock(1)
+==========================
+
+NAME
+----
+nvme-transcend-badblock - Retrieve Transcend NVMe device's bad blocks.
+
+SYNOPSIS
+--------
+[verse]
+'nvme transcend badblock' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the Transcend vendor command and return the bad block of the 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).
+
+On success, the returned value would print the amount of bad blocks.
+
+OPTIONS
+-------
+none
+
+EXAMPLES
+--------
+* Print the Transcend device's bad blocks in a human readable format:
++
+------------
+# nvme transcend badblock /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-transcend-healthvalue.1 b/Documentation/nvme-transcend-healthvalue.1
new file mode 100644
index 0000000..d222a03
--- /dev/null
+++ b/Documentation/nvme-transcend-healthvalue.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TRANSCEND\-HEA" "1" "02/14/2024" "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-transcend-healthvalue \- Use NVMe SMART table to analyze the health value of Transcend device\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme transcend healthvalue\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieves the NVMe Device SMART log page from the Transcend device and evaluate health status of Transcend 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
+On success, the returned value would print health percentage value\&.
+.SH "OPTIONS"
+.sp
+none
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Transcend Device health value in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme transcend healthvalue /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-transcend-healthvalue.html b/Documentation/nvme-transcend-healthvalue.html
new file mode 100644
index 0000000..8c0cf97
--- /dev/null
+++ b/Documentation/nvme-transcend-healthvalue.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 10.2.0" />
+<title>nvme-transcend-healthvalue(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-transcend-healthvalue(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-transcend-healthvalue -
+ Use NVMe SMART table to analyze the health value of Transcend 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 transcend healthvalue</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>Retrieves the NVMe Device SMART log page from the Transcend device and evaluate
+health status of Transcend 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>On success, the returned value would print health percentage value.</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>
+Print the Transcend Device health value in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme transcend healthvalue /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-transcend-healthvalue.txt b/Documentation/nvme-transcend-healthvalue.txt
new file mode 100644
index 0000000..90340ce
--- /dev/null
+++ b/Documentation/nvme-transcend-healthvalue.txt
@@ -0,0 +1,38 @@
+nvme-transcend-healthvalue(1)
+=============================
+
+NAME
+----
+nvme-transcend-healthvalue - Use NVMe SMART table to analyze the health value of
+Transcend device.
+
+SYNOPSIS
+--------
+[verse]
+'nvme transcend healthvalue' <device>
+
+DESCRIPTION
+-----------
+Retrieves the NVMe Device SMART log page from the Transcend device and evaluate
+health status of Transcend 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).
+
+On success, the returned value would print health percentage value.
+
+OPTIONS
+-------
+none
+
+EXAMPLES
+--------
+* Print the Transcend Device health value in a human readable format:
++
+------------
+# nvme transcend healthvalue /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-verify.1 b/Documentation/nvme-verify.1
new file mode 100644
index 0000000..d56d554
--- /dev/null
+++ b/Documentation/nvme-verify.1
@@ -0,0 +1,165 @@
+'\" t
+.\" Title: nvme-verify
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-VERIFY" "1" "02/14/2024" "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-verify \- Send an NVMe Verify command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-verify\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>] [\-\-limited\-retry | \-l]
+ [\-\-force\-unit\-access | \-f]
+ [\-\-prinfo=<prinfo> | \-p <prinfo>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-app\-tag\-mask=<appmask> | \-m <appmask>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>]
+ [\-\-storage\-tag<storage\-tag> | \-S <storage\-tag>]
+ [\-\-storage\-tag\-check | \-C]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Verify command verifies the integrity of the stored information by reading data and metadata\&.
+.SH "OPTIONS"
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Namespace ID use in the command\&.
+.RE
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+Start block address\&.
+.RE
+.PP
+\-c <nlb>, \-\-block\-count=<nlb>
+.RS 4
+Number of logical blocks to Verify\&.
+.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
+\-p <prinfo>, \-\-prinfo=<prinfo>
+.RS 4
+Protection Information field definition\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Bit
+T}:T{
+Description
+T}
+T{
+3
+T}:T{
+PRACT: Protection Information Action\&. When set to 1, PI is stripped/inserted on read/write when the block format\(cqs metadata size is 8\&. When set to 0, metadata is passes\&.
+T}
+T{
+2:0
+T}:T{
+PRCHK: Protection Information Check:
+T}
+T{
+2
+T}:T{
+Set to 1 enables checking the guard tag
+T}
+T{
+1
+T}:T{
+Set to 1 enables checking the application tag
+T}
+T{
+0
+T}:T{
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-m <appmask>, \-\-app\-tag\-mask=<appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-a <apptag>, \-\-app\-tag=<apptag>
+.RS 4
+Optional application tag when used with protection information\&.
+.RE
+.PP
+\-S <storage\-tag>, \-\-storage\-tag=<storage\-tag>
+.RS 4
+Variable Sized Expected Logical Block Storage Tag(ELBST)\&.
+.RE
+.PP
+\-C, \-\-storage\-tag\-check
+.RS 4
+This flag enables Storage Tag field checking as part of Verify operation\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-verify.html b/Documentation/nvme-verify.html
new file mode 100644
index 0000000..8581e22
--- /dev/null
+++ b/Documentation/nvme-verify.html
@@ -0,0 +1,983 @@
+<?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 10.2.0" />
+<title>nvme-verify(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-verify(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-verify -
+ Send an NVMe Verify command, return 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-verify</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;] [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--prinfo=&lt;prinfo&gt; | -p &lt;prinfo&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--app-tag-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]
+ [--storage-tag&lt;storage-tag&gt; | -S &lt;storage-tag&gt;]
+ [--storage-tag-check | -C]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Verify command verifies the integrity of the stored information by
+reading data and metadata.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID use in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block address.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;nlb&gt;
+</dt>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dd>
+<p>
+ Number of logical blocks to Verify.
+</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">
+-p &lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field definition.
+</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">Bit</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format&#8217;s metadata size is 8. When set to 0,
+metadata is passes.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2:0</p></td>
+<td align="left" valign="top"><p class="table">PRCHK: Protection Information Check:</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the guard tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the application tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the reference tag</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;storage-tag&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag=&lt;storage-tag&gt;
+</dt>
+<dd>
+<p>
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+</p>
+</dd>
+<dt class="hdlist1">
+-C
+</dt>
+<dt class="hdlist1">
+--storage-tag-check
+</dt>
+<dd>
+<p>
+ This flag enables Storage Tag field checking as part of Verify operation.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-verify.txt b/Documentation/nvme-verify.txt
new file mode 100644
index 0000000..01dabbf
--- /dev/null
+++ b/Documentation/nvme-verify.txt
@@ -0,0 +1,101 @@
+nvme-verify(1)
+==============
+
+NAME
+----
+nvme-verify - Send an NVMe Verify command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-verify' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>] [--limited-retry | -l]
+ [--force-unit-access | -f]
+ [--prinfo=<prinfo> | -p <prinfo>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--app-tag-mask=<appmask> | -m <appmask>]
+ [--app-tag=<apptag> | -a <apptag>]
+ [--storage-tag<storage-tag> | -S <storage-tag>]
+ [--storage-tag-check | -C]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Verify command verifies the integrity of the stored information by
+reading data and metadata.
+
+OPTIONS
+-------
+-n <nsid>::
+--namespace-id=<nsid>::
+ Namespace ID use in the command.
+
+-s <slba>::
+--start-block=<slba>::
+ Start block address.
+
+-c <nlb>::
+--block-count=<nlb>::
+ Number of logical blocks to Verify.
+
+-l::
+--limited-retry::
+ Sets the limited retry flag.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-p <prinfo>::
+--prinfo=<prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ Optional reftag when used with protection information.
+
+-m <appmask>::
+--app-tag-mask=<appmask>::
+ Optional application tag mask when used with protection information.
+
+-a <apptag>::
+--app-tag=<apptag>::
+ Optional application tag when used with protection information.
+
+-S <storage-tag>::
+--storage-tag=<storage-tag>::
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+
+-C::
+--storage-tag-check::
+ This flag enables Storage Tag field checking as part of Verify operation.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-virt-mgmt.txt b/Documentation/nvme-virt-mgmt.txt
new file mode 100755
index 0000000..5eede14
--- /dev/null
+++ b/Documentation/nvme-virt-mgmt.txt
@@ -0,0 +1,70 @@
+nvme-virt-mgmt(1)
+=================
+
+NAME
+----
+nvme-virt-mgmt - Manage flexible resources between primary and secondary
+controller
+
+SYNOPSIS
+--------
+[verse]
+'nvme virt-mgmt' <device> [--cntlid=<cntlid> | -c <cntlid>]
+ [--rt=<rt> | -r <rt>] [--act=<act> | -a <act>]
+ [--nr=<nr> | -n <nr>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+Manage flexible resources between primary and secondary controller, return
+results.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0) or block device (ex: /dev/nvme0n1).
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-c <cntlid>::
+--cntlid=<cntlid>::
+ Controller identifier (CNTLID)
+
+-r <rt>::
+--rt=<rt>::
+ Resource Type (RT): [0,1]
+ 0h: VQ Resources
+ 1h: VI Resources
+
+-a <act>::
+--act=<act>::
+ Action(ACT): [1,7,8,9]
+ 1h: Primary Flexible
+ 7h: Secondary Offline
+ 8h: Secondary Assign
+ 9h: Secondary Online
+
+-n <nr>::
+--nr=<nr>::
+ Number of controller resources (NR)
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+* Has the program issue a virt-mgmt to manage flexible resources.
++
+------------
+# nvme virt-mgmt /dev/nvme0 -c 0 -r 1 -a 1 -n 0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.1 b/Documentation/nvme-virtium-save-smart-to-vtview-log.1
new file mode 100644
index 0000000..15ba0a5
--- /dev/null
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.1
@@ -0,0 +1,138 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-VIRTIUM\-SAVE\" "1" "02/14/2024" "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-virtium-save-smart-to-vtview-log \- Periodically save smart attributes into a log file (csv format)\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme virtium save\-smart\-to\-vtview\-log\fR <device> [\-\-run\-time=<NUM> | \-r <NUM>]
+ [\-\-freq=<NUM> | \-f <NUM>]
+ [\-\-output\-file=<FILE> | \-o <FILE>]
+ [\-\-test\-name=<NAME> | \-n <NAME>]
+.fi
+.SH "DESCRIPTION"
+.sp
+This command automates the process of collecting SMART data periodically and saving the data in a ready\-to\-analyze format\&. Each entry is saved with timestamp and in csv format\&. Users can use excel to analyze the data\&. Some examples of use cases are collecting SMART data for temperature characterization, data to calculate endurance, or collecting SMART data during a test or during normal operation\&.
+.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 command generates a log file, which contains an entry for identify device (current features & settings) and periodic entries of SMART data\&.
+.sp
+This command runs for the time specified by the option <run\-time>, and collects SMART data at the frequency specified by the option <freq>\&. If the output file name is not specified, this command will generate a file name that include model string and serial number of the device\&.
+.sp
+If the test\-name option is specified, it will be recorded in the log file and be used as part of the log file name\&.
+.SH "OPTIONS"
+.PP
+\-r <NUM>, \-\-run\-time=<NUM>
+.RS 4
+(optional) Number of hours to log data (default = 20 hours)
+.RE
+.PP
+\-f <NUM>, \-\-freq=<NUM>
+.RS 4
+(optional) How often you want to log SMART data (0\&.25 = 15\*(Aq, 0\&.5 = 30\*(Aq, 1 = 1 hour, 2 = 2 hours, etc\&.)\&. Default = 10 hours\&.
+.RE
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+(optional) Name of the log file (give it a name that easy for you to remember what the test is)\&. You can leave it blank too, the file name will be generated as <model string>\-<serial number>\-<test name>\&.txt\&.
+.RE
+.PP
+\-n <NAME>, \-\-test\-name=<NAME>
+.RS 4
+(optional) Name of the test you are doing\&. We use this string as part of the name of the log file\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Temperature characterization:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme virtium save\-smart\-to\-vtview\-log /dev/yourDevice \-\-run\-time=100 \-\-record\-frequency=0\&.25 \-\-test\-name=burn\-in\-at\-(\-40)
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Endurance testing:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme virtium save\-smart\-to\-vtview\-log /dev/yourDevice \-\-run\-time=100 \-\-record\-frequency=1 \-\-test\-name=Endurance\-test\-JEDEG\-219\-workload
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Just logging: Default logging is run for 20 hours and log every 10 hours\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme virtium save\-smart\-to\-vtview\-log /dev/yourDevice
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.html b/Documentation/nvme-virtium-save-smart-to-vtview-log.html
new file mode 100644
index 0000000..5edfd37
--- /dev/null
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.html
@@ -0,0 +1,885 @@
+<?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 10.2.0" />
+<title>nvme-virtium-save-smart-to-vtview-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 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-virtium-save-smart-to-vtview-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-virtium-save-smart-to-vtview-log -
+ Periodically save smart attributes into a log file (csv format).
+</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 virtium save-smart-to-vtview-log</em> &lt;device&gt; [--run-time=&lt;NUM&gt; | -r &lt;NUM&gt;]
+ [--freq=&lt;NUM&gt; | -f &lt;NUM&gt;]
+ [--output-file=&lt;FILE&gt; | -o &lt;FILE&gt;]
+ [--test-name=&lt;NAME&gt; | -n &lt;NAME&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 automates the process of collecting SMART data periodically and
+saving the data in a ready-to-analyze format. Each entry is saved
+with timestamp and in csv format. Users can use excel to analyze the data.
+Some examples of use cases are collecting SMART data for temperature
+characterization, data to calculate endurance, or collecting SMART data during a
+test or during normal operation.</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 command generates a log file, which contains an entry for
+identify device (current features &amp; settings) and periodic entries of SMART data.</p></div>
+<div class="paragraph"><p>This command runs for the time specified by the option &lt;run-time&gt;, and collects
+SMART data at the frequency specified by the option &lt;freq&gt;. If the output file
+name is not specified, this command will generate a file name that include model
+string and serial number of the device.</p></div>
+<div class="paragraph"><p>If the test-name option is specified, it will be recorded in the log file and be
+used as part of the log file name.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-r &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--run-time=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ (optional) Number of hours to log data (default = 20 hours)
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--freq=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ (optional) How often you want to log SMART data (0.25 = 15', 0.5 = 30',
+ 1 = 1 hour, 2 = 2 hours, etc.). Default = 10 hours.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ (optional) Name of the log file (give it a name that easy for you to
+ remember what the test is). You can leave it blank too, the file name
+ will be generated as &lt;model string&gt;-&lt;serial number&gt;-&lt;test name&gt;.txt.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;NAME&gt;
+</dt>
+<dt class="hdlist1">
+--test-name=&lt;NAME&gt;
+</dt>
+<dd>
+<p>
+ (optional) Name of the test you are doing. We use this string as part of
+ the name of the log file.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Temperature characterization:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme virtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=0.25 --test-name=burn-in-at-(-40)</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Endurance testing:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme virtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=1 --test-name=Endurance-test-JEDEG-219-workload</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Just logging: Default logging is run for 20 hours and log every 10 hours.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme virtium save-smart-to-vtview-log /dev/yourDevice</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-virtium-save-smart-to-vtview-log.txt b/Documentation/nvme-virtium-save-smart-to-vtview-log.txt
new file mode 100644
index 0000000..72090c0
--- /dev/null
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.txt
@@ -0,0 +1,86 @@
+nvme-virtium-save-smart-to-vtview-log(1)
+========================================
+
+NAME
+----
+nvme-virtium-save-smart-to-vtview-log - Periodically save smart attributes into
+a log file (csv format).
+
+SYNOPSIS
+--------
+[verse]
+'nvme virtium save-smart-to-vtview-log' <device> [--run-time=<NUM> | -r <NUM>]
+ [--freq=<NUM> | -f <NUM>]
+ [--output-file=<FILE> | -o <FILE>]
+ [--test-name=<NAME> | -n <NAME>]
+
+DESCRIPTION
+-----------
+This command automates the process of collecting SMART data periodically and
+saving the data in a ready-to-analyze format. Each entry is saved
+with timestamp and in csv format. Users can use excel to analyze the data.
+Some examples of use cases are collecting SMART data for temperature
+characterization, data to calculate endurance, or collecting SMART data during a
+test or during normal operation.
+
+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 command generates a log file, which contains an entry for
+identify device (current features & settings) and periodic entries of SMART data.
+
+This command runs for the time specified by the option <run-time>, and collects
+SMART data at the frequency specified by the option <freq>. If the output file
+name is not specified, this command will generate a file name that include model
+string and serial number of the device.
+
+If the test-name option is specified, it will be recorded in the log file and be
+used as part of the log file name.
+
+OPTIONS
+-------
+-r <NUM>::
+--run-time=<NUM>::
+ (optional) Number of hours to log data (default = 20 hours)
+
+-f <NUM>::
+--freq=<NUM>::
+ (optional) How often you want to log SMART data (0.25 = 15', 0.5 = 30',
+ 1 = 1 hour, 2 = 2 hours, etc.). Default = 10 hours.
+
+-o <FILE>::
+--output-file=<FILE>::
+ (optional) Name of the log file (give it a name that easy for you to
+ remember what the test is). You can leave it blank too, the file name
+ will be generated as <model string>-<serial number>-<test name>.txt.
+
+-n <NAME>::
+--test-name=<NAME>::
+ (optional) Name of the test you are doing. We use this string as part of
+ the name of the log file.
+
+EXAMPLES
+--------
+* Temperature characterization:
++
+------------
+# nvme virtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=0.25 --test-name=burn-in-at-(-40)
+------------
++
+
+* Endurance testing:
++
+------------
+# nvme virtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=1 --test-name=Endurance-test-JEDEG-219-workload
+------------
++
+
+* Just logging: Default logging is run for 20 hours and log every 10 hours.
++
+------------
+# nvme virtium save-smart-to-vtview-log /dev/yourDevice
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-virtium-show-identify.1 b/Documentation/nvme-virtium-show-identify.1
new file mode 100644
index 0000000..10f9697
--- /dev/null
+++ b/Documentation/nvme-virtium-show-identify.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-VIRTIUM\-SHOW\" "1" "02/14/2024" "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-virtium-show-identify \- Show a complete detail of identify device information in json format\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme virtium show\-identify\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+This command prints complete detail of the identify device information\&. The details include settings and description of each feature\&. The descriptions are based on NVM Express Revision 1\&.3c specification\&.
+.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 command prints identify device in human readable format\&.
+.SH "OPTIONS"
+.sp
+none
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Show Identify Device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme virtium show\-identify /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-virtium-show-identify.html b/Documentation/nvme-virtium-show-identify.html
new file mode 100644
index 0000000..9e03e8d
--- /dev/null
+++ b/Documentation/nvme-virtium-show-identify.html
@@ -0,0 +1,805 @@
+<?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 10.2.0" />
+<title>nvme-virtium-show-identify(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-virtium-show-identify(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-virtium-show-identify -
+ Show a complete detail of identify device information in json format.
+</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 virtium show-identify</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 complete detail of the identify device information. The
+details include settings and description of each feature. The descriptions are
+based on NVM Express Revision 1.3c specification.</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 command prints identify device in human readable format.</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>
+Show Identify Device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme virtium show-identify /dev/nvme0n1</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-virtium-show-identify.txt b/Documentation/nvme-virtium-show-identify.txt
new file mode 100644
index 0000000..881824c
--- /dev/null
+++ b/Documentation/nvme-virtium-show-identify.txt
@@ -0,0 +1,38 @@
+nvme-virtium-show-identify(1)
+=============================
+
+NAME
+----
+nvme-virtium-show-identify - Show a complete detail of identify device information in json format.
+
+SYNOPSIS
+--------
+[verse]
+'nvme virtium show-identify' <device>
+
+DESCRIPTION
+-----------
+This command prints complete detail of the identify device information. The
+details include settings and description of each feature. The descriptions are
+based on NVM Express Revision 1.3c specification.
+
+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 command prints identify device in human readable format.
+
+OPTIONS
+-------
+none
+
+EXAMPLES
+--------
+* Show Identify Device:
++
+------------
+# nvme virtium show-identify /dev/nvme0n1
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-cap-diag.1 b/Documentation/nvme-wdc-cap-diag.1
new file mode 100644
index 0000000..b6a50aa
--- /dev/null
+++ b/Documentation/nvme-wdc-cap-diag.1
@@ -0,0 +1,163 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CAP\-DIAG" "1" "02/14/2024" "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-cap-diag \- Retrieve WDC device\*(Aqs diagnostic log and save to file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc cap\-diag\fR <device> [\-\-output\-file=<FILE>, \-o <FILE>] [\-\-transfer\-size=<SIZE>, \-s <SIZE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC Vendor Unique Capture\-Diagnostics request and saves the result to a file\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device serial number followed by "cap_diag" suffix
+.RE
+.PP
+\-s <SIZE>, \-\-transfer\-size=<SIZE>
+.RS 4
+Transfer size; defaults to 0x10000 (65536 decimal) bytes
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the capture diagnostics log from the device and saves to default file in current directory (e\&.g\&. STM00019F3F9cap_diag\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cap\-diag /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
+.\}
+Gets the capture diagnostics log from the device and saves to defined file in current directory (e\&.g\&. testSTM00019F3F9cap_diag\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cap\-diag /dev/nvme0 \-o test
+.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 capture diagnostics log from the device and saves to defined file with pathname (e\&.g\&. /tmp/testSTM00019F3F9cap_diag\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cap\-diag /dev/nvme0 \-o /tmp/test
+.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 capture diagnostics log from the device transferring the data in 64k chunks and saves to default file in current directory (e\&.g\&. STM00019F3F9internal_fw_log\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cap\-diag /dev/nvme0 \-s 0x10000
+.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 capture diagnostics log from the device transferring the data in 16k chunks and saves to default file in current directory (e\&.g\&. STM00019F3F9internal_fw_log\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cap\-diag /dev/nvme0 \-s 16384
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-cap-diag.html b/Documentation/nvme-wdc-cap-diag.html
new file mode 100644
index 0000000..f25b31c
--- /dev/null
+++ b/Documentation/nvme-wdc-cap-diag.html
@@ -0,0 +1,863 @@
+<?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 10.2.0" />
+<title>nvme-wdc-cap-diag(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-cap-diag(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-cap-diag -
+ Retrieve WDC device's diagnostic log and save to file.
+</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 cap-diag</em> &lt;device&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, sends the WDC Vendor Unique Capture-Diagnostics
+request and saves the result to a file.</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>
+</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; defaults to device serial number followed by "cap_diag" suffix
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;SIZE&gt;
+</dt>
+<dt class="hdlist1">
+--transfer-size=&lt;SIZE&gt;
+</dt>
+<dd>
+<p>
+ Transfer size; defaults to 0x10000 (65536 decimal) bytes
+</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 capture diagnostics log from the device and saves to default file in current directory (e.g. STM00019F3F9cap_diag.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cap-diag /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the capture diagnostics log from the device and saves to defined file in current directory (e.g. testSTM00019F3F9cap_diag.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cap-diag /dev/nvme0 -o test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the capture diagnostics log from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9cap_diag.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cap-diag /dev/nvme0 -o /tmp/test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the capture diagnostics log from the device transferring the data in 64k chunks and saves to default file in current directory (e.g. STM00019F3F9internal_fw_log.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cap-diag /dev/nvme0 -s 0x10000</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the capture diagnostics log from the device transferring the data in 16k chunks and saves to default file in current directory (e.g. STM00019F3F9internal_fw_log.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cap-diag /dev/nvme0 -s 16384</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-cap-diag.txt b/Documentation/nvme-wdc-cap-diag.txt
new file mode 100644
index 0000000..bfcde9a
--- /dev/null
+++ b/Documentation/nvme-wdc-cap-diag.txt
@@ -0,0 +1,64 @@
+nvme-wdc-cap-diag(1)
+====================
+
+NAME
+----
+nvme-wdc-cap-diag - Retrieve WDC device's diagnostic log and save to file.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc cap-diag' <device> [--output-file=<FILE>, -o <FILE>] [--transfer-size=<SIZE>, -s <SIZE>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, sends the WDC Vendor Unique Capture-Diagnostics
+request and saves the result to a file.
+
+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.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device serial number followed by "cap_diag" suffix
+
+-s <SIZE>::
+--transfer-size=<SIZE>::
+ Transfer size; defaults to 0x10000 (65536 decimal) bytes
+
+EXAMPLES
+--------
+* Gets the capture diagnostics log from the device and saves to default file in current directory (e.g. STM00019F3F9cap_diag.bin):
++
+------------
+# nvme wdc cap-diag /dev/nvme0
+------------
+* Gets the capture diagnostics log from the device and saves to defined file in current directory (e.g. testSTM00019F3F9cap_diag.bin):
++
+------------
+# nvme wdc cap-diag /dev/nvme0 -o test
+------------
+* Gets the capture diagnostics log from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9cap_diag.bin):
++
+------------
+# nvme wdc cap-diag /dev/nvme0 -o /tmp/test
+------------
+* Gets the capture diagnostics log from the device transferring the data in 64k chunks and saves to default file in current directory (e.g. STM00019F3F9internal_fw_log.bin):
++
+------------
+# nvme wdc cap-diag /dev/nvme0 -s 0x10000
+------------
+* Gets the capture diagnostics log from the device transferring the data in 16k chunks and saves to default file in current directory (e.g. STM00019F3F9internal_fw_log.bin):
++
+------------
+# nvme wdc cap-diag /dev/nvme0 -s 16384
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-capabilities.1 b/Documentation/nvme-wdc-capabilities.1
new file mode 100644
index 0000000..3bf216b
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CAPABILIT" "1" "02/14/2024" "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..5768612
--- /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 10.2.0" />
+<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
+ 2024-02-14 10:43:42 CET
+</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
new file mode 100644
index 0000000..08267d7
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-assert-dump.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-AS" "1" "02/14/2024" "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-clear-assert-dump \- Clears the assert dump (if present)\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc clear\-assert\-dump\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the wdc vendor unique clear assert dump command\&.
+.sp
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this feature\&. The command will not be executed on devices that don\(cqt support it\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears the assert dump (if present):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc clear\-assert\-dump /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-clear-assert-dump.html b/Documentation/nvme-wdc-clear-assert-dump.html
new file mode 100644
index 0000000..2a8ab95
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-assert-dump.html
@@ -0,0 +1,805 @@
+<?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 10.2.0" />
+<title>nvme-wdc-clear-assert-dump(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-clear-assert-dump(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-clear-assert-dump -
+ Clears the assert dump (if present).
+</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 clear-assert-dump</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, sends the wdc vendor unique clear assert
+dump command.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the NVMe character
+device (ex: /dev/nvme0).</p></div>
+<div class="paragraph"><p>This will only work on WDC devices supporting this feature.
+The command will not be executed on devices that don&#8217;t support it.</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>
+Clears the assert dump (if present):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc clear-assert-dump /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-clear-assert-dump.txt b/Documentation/nvme-wdc-clear-assert-dump.txt
new file mode 100644
index 0000000..60493df
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-assert-dump.txt
@@ -0,0 +1,38 @@
+nvme-wdc-clear-assert-dump(1)
+=============================
+
+NAME
+----
+nvme-wdc-clear-assert-dump - Clears the assert dump (if present).
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc clear-assert-dump' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the wdc vendor unique clear assert
+dump command.
+
+The <device> parameter is mandatory and must be the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+The command will not be executed on devices that don't support it.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Clears the assert dump (if present):
++
+------------
+# nvme wdc clear-assert-dump /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.1 b/Documentation/nvme-wdc-clear-fw-activate-history.1
new file mode 100644
index 0000000..592336d
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-fw-activate-history.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-FW" "1" "02/14/2024" "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-clear-fw-activate-history \- Clears the firmware activate history table\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc clear\-fw\-activate\-history\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the wdc vendor unique clear fw activate history command\&.
+.sp
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears the firmware activate history table:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc clear\-fw\-activate\-history /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.html b/Documentation/nvme-wdc-clear-fw-activate-history.html
new file mode 100644
index 0000000..6fc6434
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-fw-activate-history.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 10.2.0" />
+<title>nvme-wdc-clear-fw-activate-history(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-clear-fw-activate-history(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-clear-fw-activate-history -
+ Clears the firmware activate history table.
+</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 clear-fw-activate-history</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, sends the wdc vendor unique clear fw activate
+history command.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the 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>
+</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>
+Clears the firmware activate history table:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc clear-fw-activate-history /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-clear-fw-activate-history.txt b/Documentation/nvme-wdc-clear-fw-activate-history.txt
new file mode 100644
index 0000000..ddb6c26
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-fw-activate-history.txt
@@ -0,0 +1,37 @@
+nvme-wdc-clear-fw-activate-history(1)
+=====================================
+
+NAME
+----
+nvme-wdc-clear-fw-activate-history - Clears the firmware activate history table.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc clear-fw-activate-history' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the wdc vendor unique clear fw activate
+history command.
+
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Clears the firmware activate history table:
++
+------------
+# nvme wdc clear-fw-activate-history /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-clear-pcie-corr.1 b/Documentation/nvme-wdc-clear-pcie-corr.1
new file mode 100644
index 0000000..6e5989d
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-corr.1
@@ -0,0 +1,71 @@
+'\" t
+.\" Title: nvme-wdc-clear-pcie-corr
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 01/08/2019
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-PC" "1" "01/08/2019" "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-clear-pcie-corr \- Clears the pcie correctable errors field returned in the smart\-log\-add command\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc clear\-pcie\-corr\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the wdc vendor unique clear pcie correctable errors command\&.
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears the PCIe Correctable Error Count field returned in the smart\-log\-add command:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc clear\-pcie\-corr /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-clear-pcie-corr.html b/Documentation/nvme-wdc-clear-pcie-corr.html
new file mode 100644
index 0000000..3e8a4a9
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-corr.html
@@ -0,0 +1,806 @@
+<?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-clear-pcie-corr(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-clear-pcie-corr(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-clear-pcie-corr -
+ Clears the pcie correctable errors field returned in the smart-log-add 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 wdc clear-pcie-corr</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, sends the wdc vendor unique clear pcie
+correctable errors command.</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 WDC devices supporting this feature.
+Results for any other device are undefined.</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>
+Clears the PCIe Correctable Error Count field returned in the smart-log-add command:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc clear-pcie-corr /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
+ 2018-01-18 13:54:43 CST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.1 b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1
new file mode 100644
index 0000000..b3cff45
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.1
@@ -0,0 +1,71 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-PC" "1" "02/14/2024" "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-clear-pcie-correctable-errors \- Clears the pcie correctable errors field returned in the smart\-log\-add command\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc clear\-pcie\-correctable\-errors\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the wdc vendor unique clear pcie correctable errors command\&.
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.sp
+None
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Clears the PCIe Correctable Error Count field returned in the smart\-log\-add command:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc 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-wdc-clear-pcie-correctable-errors.html b/Documentation/nvme-wdc-clear-pcie-correctable-errors.html
new file mode 100644
index 0000000..30e109f
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.html
@@ -0,0 +1,806 @@
+<?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 10.2.0" />
+<title>nvme-wdc-clear-pcie-correctable-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 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-clear-pcie-correctable-errors(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-clear-pcie-correctable-errors -
+ Clears the pcie correctable errors field returned in the smart-log-add 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 wdc 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>For the NVMe device given, sends the wdc vendor unique clear pcie
+correctable errors command.</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 WDC devices supporting this feature.
+Results for any other device are undefined.</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>
+Clears the PCIe Correctable Error Count field returned in the smart-log-add command:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt b/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt
new file mode 100644
index 0000000..cecc52e
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt
@@ -0,0 +1,39 @@
+nvme-wdc-clear-pcie-correctable-errors(1)
+=========================================
+
+NAME
+----
+nvme-wdc-clear-pcie-correctable-errors - Clears the pcie correctable errors field returned in the smart-log-add command.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc clear-pcie-correctable-errors' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the wdc vendor unique clear pcie
+correctable errors command.
+
+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 WDC devices supporting this feature.
+Results for any other device are undefined.
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Clears the PCIe Correctable Error Count field returned in the smart-log-add command:
++
+------------
+# nvme wdc clear-pcie-correctable-errors /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
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..8f1147a
--- /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://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLOUD\-SS" "1" "02/14/2024" "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..314631e
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-SSD-plugin-version.html
@@ -0,0 +1,797 @@
+<?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 10.2.0" />
+<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;
+}
+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-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
+ 2024-02-14 10:43:42 CET
+</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-cloud-boot-SSD-version.1 b/Documentation/nvme-wdc-cloud-boot-SSD-version.1
new file mode 100644
index 0000000..a79a715
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-boot-SSD-version.1
@@ -0,0 +1,68 @@
+'\" t
+.\" Title: nvme-wdc-cloud-boot-SSD-version
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLOUD\-BO" "1" "02/14/2024" "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-boot-SSD-version \- Display WDC plugin Cloud Boot SSD Version
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc cloud\-boot\-SSD\-version\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, this command displays the current Cloud Hyperscale Boot 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 boot ssd version for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc cloud\-boot\-SSD\-version /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-cloud-boot-SSD-version.html b/Documentation/nvme-wdc-cloud-boot-SSD-version.html
new file mode 100644
index 0000000..7369c48
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-boot-SSD-version.html
@@ -0,0 +1,797 @@
+<?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 10.2.0" />
+<title>nvme-wdc-cloud-boot-SSD-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;
+}
+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-cloud-boot-SSD-version(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-cloud-boot-SSD-version -
+ Display WDC plugin Cloud Boot SSD 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-boot-SSD-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 Hyperscale
+Boot 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 boot ssd version for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc cloud-boot-SSD-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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-cloud-boot-SSD-version.txt b/Documentation/nvme-wdc-cloud-boot-SSD-version.txt
new file mode 100644
index 0000000..a3f105e
--- /dev/null
+++ b/Documentation/nvme-wdc-cloud-boot-SSD-version.txt
@@ -0,0 +1,33 @@
+nvme-wdc-cloud-boot-SSD-version(1)
+==================================
+
+NAME
+----
+nvme-wdc-cloud-boot-SSD-version - Display WDC plugin Cloud Boot SSD Version
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc cloud-boot-SSD-version' <device>
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, this command displays the current Cloud Hyperscale
+Boot 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 boot ssd version for the device:
++
+------------
+# nvme wdc cloud-boot-SSD-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
new file mode 100644
index 0000000..850d63b
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-essentials.1
@@ -0,0 +1,95 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-ES" "1" "02/14/2024" "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-drive-essentials \- Retrieve WDC device\*(Aqs drive essentials bin files and save to a tar file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc drive\-essentials\fR <device> [\-\-dir\-name=<DIRECTORY>, \-d <DIRECTORY>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, captures the drive essential bin files and saves them into a tar file\&. The tar file will be in the following format: DRIVE_ESSENTIALS_<Serial Num>_<FW Revision>_<Date>_<Time>\&.tar\&.gz e\&.g\&. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731\&.tar\&.gz
+.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\&.
+.SH "OPTIONS"
+.PP
+\-d <DIRECTORY>, \-\-dir\-name=<DIRECTORY>
+.RS 4
+Output directory; defaults to current working directory\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the drive essentials data files from the device and saves the tar file in current directory (e\&.g\&. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731\&.tar\&.gz):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-essentials /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
+.\}
+Gets the drive essentials data files from the device and saves the tar file to specified directory (e\&.g\&. /tmp/DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-essentials /dev/nvme0 \-d /tmp/
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-drive-essentials.html b/Documentation/nvme-wdc-drive-essentials.html
new file mode 100644
index 0000000..40dad8a
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-essentials.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 10.2.0" />
+<title>nvme-wdc-drive-essentials(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-drive-essentials(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-drive-essentials -
+ Retrieve WDC device's drive essentials bin files and save to a tar file.
+</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 drive-essentials</em> &lt;device&gt; [--dir-name=&lt;DIRECTORY&gt;, -d &lt;DIRECTORY&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, captures the drive essential bin files and saves them
+into a tar file. The tar file will be in the following format:
+DRIVE_ESSENTIALS_&lt;Serial Num&gt;_&lt;FW Revision&gt;_&lt;Date&gt;_&lt;Time&gt;.tar.gz
+ e.g. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731.tar.gz</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>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-d &lt;DIRECTORY&gt;
+</dt>
+<dt class="hdlist1">
+--dir-name=&lt;DIRECTORY&gt;
+</dt>
+<dd>
+<p>
+ Output directory; defaults to current working directory.
+</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 drive essentials data files from the device and saves the tar file in current directory
+ (e.g. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731.tar.gz):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-essentials /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the drive essentials data files from the device and saves the tar file to specified directory
+ (e.g. /tmp/DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-essentials /dev/nvme0 -d /tmp/</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-drive-essentials.txt b/Documentation/nvme-wdc-drive-essentials.txt
new file mode 100644
index 0000000..7f06040
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-essentials.txt
@@ -0,0 +1,50 @@
+nvme-wdc-drive-essentials(1)
+============================
+
+NAME
+----
+nvme-wdc-drive-essentials - Retrieve WDC device's drive essentials bin files and
+save to a tar file.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc drive-essentials' <device> [--dir-name=<DIRECTORY>, -d <DIRECTORY>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, captures the drive essential bin files and saves them
+into a tar file. The tar file will be in the following format:
+DRIVE_ESSENTIALS_<Serial Num>_<FW Revision>_<Date>_<Time>.tar.gz
+ e.g. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731.tar.gz
+
+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.
+
+OPTIONS
+-------
+-d <DIRECTORY>::
+--dir-name=<DIRECTORY>::
+ Output directory; defaults to current working directory.
+
+EXAMPLES
+--------
+* Gets the drive essentials data files from the device and saves the tar file in current directory
+ (e.g. DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731.tar.gz):
++
+------------
+# nvme wdc drive-essentials /dev/nvme0
+------------
+* Gets the drive essentials data files from the device and saves the tar file to specified directory
+ (e.g. /tmp/DRIVE_ESSENTIALS_A00FD8CA_1048_20170713_091731):
++
+------------
+# nvme wdc drive-essentials /dev/nvme0 -d /tmp/
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-drive-log.1 b/Documentation/nvme-wdc-drive-log.1
new file mode 100644
index 0000000..845e59f
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-log.1
@@ -0,0 +1,116 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-LO" "1" "02/14/2024" "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-drive-log \- Retrieve WDC device\*(Aqs drive log and save to file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc drive\-log\fR <device> [\-\-output\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the wdc vendor unique drive log request and saves the result to a file\&.
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device serial number followed by "drive_log" suffix
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the drive log from the device and saves to default file in current directory (e\&.g\&. STM00019F3F9drive_log\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-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
+.\}
+Gets the drive log from the device and saves to defined file in current directory (e\&.g\&. testSTM00019F3F9drive_log\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-log /dev/nvme0 \-o test
+.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 drive log from the device and saves to defined file with pathname (e\&.g\&. /tmp/testSTM00019F3F9drive_log\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-log /dev/nvme0 \-o /tmp/test
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-drive-log.html b/Documentation/nvme-wdc-drive-log.html
new file mode 100644
index 0000000..625c6be
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-log.html
@@ -0,0 +1,836 @@
+<?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 10.2.0" />
+<title>nvme-wdc-drive-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 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-drive-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-drive-log -
+ Retrieve WDC device's drive log and save to file.
+</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 drive-log</em> &lt;device&gt; [--output-file=&lt;FILE&gt;, -o &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, sends the wdc vendor unique drive log
+request and saves the result to a file.</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 WDC devices supporting this feature.
+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">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output file; defaults to device serial number followed by "drive_log" suffix
+</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 drive log from the device and saves to default file in current directory (e.g. STM00019F3F9drive_log.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the drive log from the device and saves to defined file in current directory (e.g. testSTM00019F3F9drive_log.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-log /dev/nvme0 -o test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the drive log from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9drive_log.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-log /dev/nvme0 -o /tmp/test</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-drive-log.txt b/Documentation/nvme-wdc-drive-log.txt
new file mode 100644
index 0000000..0587df9
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-log.txt
@@ -0,0 +1,51 @@
+nvme-wdc-drive-log(1)
+=====================
+
+NAME
+----
+nvme-wdc-drive-log - Retrieve WDC device's drive log and save to file.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc drive-log' <device> [--output-file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the wdc vendor unique drive log
+request and saves the result to a file.
+
+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 WDC devices supporting this feature.
+Results for any other device are undefined.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device serial number followed by "drive_log" suffix
+
+EXAMPLES
+--------
+* Gets the drive log from the device and saves to default file in current directory (e.g. STM00019F3F9drive_log.bin):
++
+------------
+# nvme wdc drive-log /dev/nvme0
+------------
+* Gets the drive log from the device and saves to defined file in current directory (e.g. testSTM00019F3F9drive_log.bin):
++
+------------
+# nvme wdc drive-log /dev/nvme0 -o test
+------------
+* Gets the drive log from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9drive_log.bin):
++
+------------
+# nvme wdc drive-log /dev/nvme0 -o /tmp/test
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-drive-resize.1 b/Documentation/nvme-wdc-drive-resize.1
new file mode 100644
index 0000000..4eca4e3
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-resize.1
@@ -0,0 +1,76 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-RE" "1" "02/14/2024" "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-drive-resize \- Send NVMe WDC Resize Vendor Unique Command, return result\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc drive\-resize\fR <device> [\-\-size=<sz> | \-s <sz>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a Vendor Unique WDC Resize command\&.
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-s <sz>, \-\-size=<sz>
+.RS 4
+The new size (in GB) to resize the drive to\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC Resize Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc drive\-resize /dev/nvme0n1 \-\-size=100
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-drive-resize.html b/Documentation/nvme-wdc-drive-resize.html
new file mode 100644
index 0000000..7cdc9c2
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-resize.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 10.2.0" />
+<title>nvme-wdc-drive-resize(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-drive-resize(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-drive-resize -
+ Send NVMe WDC Resize 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 drive-resize</em> &lt;device&gt; [--size=&lt;sz&gt; | -s &lt;sz&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 a Vendor Unique WDC Resize command.</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 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;sz&gt;
+</dt>
+<dt class="hdlist1">
+--size=&lt;sz&gt;
+</dt>
+<dd>
+<p>
+ The new size (in GB) to resize the drive to.
+</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 issue WDC Resize Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc drive-resize /dev/nvme0n1 --size=100</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-drive-resize.txt b/Documentation/nvme-wdc-drive-resize.txt
new file mode 100644
index 0000000..4be0cb2
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-resize.txt
@@ -0,0 +1,42 @@
+nvme-wdc-drive-resize(1)
+========================
+
+NAME
+----
+nvme-wdc-drive-resize - Send NVMe WDC Resize Vendor Unique Command,
+return result.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc drive-resize' <device> [--size=<sz> | -s <sz>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a Vendor Unique WDC Resize command.
+
+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 WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-s <sz>::
+--size=<sz>::
+ The new size (in GB) to resize the drive to.
+
+EXAMPLES
+--------
+* Has the program issue WDC Resize Vendor Unique Command :
++
+------------
+# nvme wdc drive-resize /dev/nvme0n1 --size=100
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-enc-get-log.1 b/Documentation/nvme-wdc-enc-get-log.1
new file mode 100644
index 0000000..36429ee
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.1
@@ -0,0 +1,106 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-ENC\-GET\" "1" "02/14/2024" "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..1d94744
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.html
@@ -0,0 +1,844 @@
+<?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 10.2.0" />
+<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 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-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
+ 2024-02-14 10:43:42 CET
+</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..bcff83f
--- /dev/null
+++ b/Documentation/nvme-wdc-enc-get-log.txt
@@ -0,0 +1,60 @@
+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
new file mode 100644
index 0000000..803596c
--- /dev/null
+++ b/Documentation/nvme-wdc-get-crash-dump.1
@@ -0,0 +1,116 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-CRAS" "1" "02/14/2024" "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-get-crash-dump \- Retrieve WDC device\*(Aqs crash dump\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-crash\-dump\fR <device> [\-\-output\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC vendor unique crash dump request and saves the result to file\&. In current implementation crash dump is captured if it is present\&. On success it will save the dump in file with appropriate suffix\&. Note that this command will clear the available dump from the device on success\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device serial number followed by "crash_dump" suffix
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the crash dump from the device and saves to default file in current directory (e\&.g\&. STM00019F3F9crash_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-crash\-dump /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
+.\}
+Gets the crash dump from the device and saves to defined file in current directory (e\&.g\&. testSTM00019F3F9crash_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-crash\-dump /dev/nvme0 \-o test
+.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 crash dump from the device and saves to defined file with pathname (e\&.g\&. /tmp/testSTM00019F3F9crash_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-crash\-dump /dev/nvme0 \-o /tmp/test
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-get-crash-dump.html b/Documentation/nvme-wdc-get-crash-dump.html
new file mode 100644
index 0000000..22eaaa4
--- /dev/null
+++ b/Documentation/nvme-wdc-get-crash-dump.html
@@ -0,0 +1,837 @@
+<?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 10.2.0" />
+<title>nvme-wdc-get-crash-dump(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-get-crash-dump(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-crash-dump -
+ Retrieve WDC device's crash dump.
+</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 get-crash-dump</em> &lt;device&gt; [--output-file=&lt;FILE&gt;, -o &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, sends the WDC vendor unique crash dump
+request and saves the result to file. In current implementation crash dump is
+captured if it is present. On success it will save the dump in file with
+appropriate suffix. Note that this command will clear the available
+dump from the device on success.</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>
+</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; defaults to device serial number followed by "crash_dump" suffix
+</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 crash dump from the device and saves to default file in current directory (e.g. STM00019F3F9crash_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-crash-dump /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the crash dump from the device and saves to defined file in current directory (e.g. testSTM00019F3F9crash_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-crash-dump /dev/nvme0 -o test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the crash dump from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9crash_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-crash-dump /dev/nvme0 -o /tmp/test</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-crash-dump.txt b/Documentation/nvme-wdc-get-crash-dump.txt
new file mode 100644
index 0000000..109daca
--- /dev/null
+++ b/Documentation/nvme-wdc-get-crash-dump.txt
@@ -0,0 +1,52 @@
+nvme-wdc-get-crash-dump(1)
+==========================
+
+NAME
+----
+nvme-wdc-get-crash-dump - Retrieve WDC device's crash dump.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-crash-dump' <device> [--output-file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the WDC vendor unique crash dump
+request and saves the result to file. In current implementation crash dump is
+captured if it is present. On success it will save the dump in file with
+appropriate suffix. Note that this command will clear the available
+dump from the device on success.
+
+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.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device serial number followed by "crash_dump" suffix
+
+EXAMPLES
+--------
+* Gets the crash dump from the device and saves to default file in current directory (e.g. STM00019F3F9crash_dump.bin):
++
+------------
+# nvme wdc get-crash-dump /dev/nvme0
+------------
+* Gets the crash dump from the device and saves to defined file in current directory (e.g. testSTM00019F3F9crash_dump.bin):
++
+------------
+# nvme wdc get-crash-dump /dev/nvme0 -o test
+------------
+* Gets the crash dump from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9crash_dump.bin):
++
+------------
+# nvme wdc get-crash-dump /dev/nvme0 -o /tmp/test
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.1 b/Documentation/nvme-wdc-get-dev-capabilities-log.1
new file mode 100644
index 0000000..a838f03
--- /dev/null
+++ b/Documentation/nvme-wdc-get-dev-capabilities-log.1
@@ -0,0 +1,78 @@
+'\" t
+.\" Title: nvme-wdc-get-dev-capabilities-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-DEV\" "1" "02/14/2024" "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-get-dev-capabilities-log \- Send NVMe WDC get\-dev\-capabilities\-log plugin command, return parsed log output
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-dev\-capabilities\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a WDC plugin get\-dev\-capabilities\-log command and output the device capabilities log data\&. The \-\-output\-format option will format the output as specified\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this log page\&. Results for any other device are undefined\&.
+.sp
+On success it returns the parsed device capabilities log page data, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC get\-dev\-capabilities\-log plugin command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-dev\-capabilities\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.html b/Documentation/nvme-wdc-get-dev-capabilities-log.html
new file mode 100644
index 0000000..4f1869f
--- /dev/null
+++ b/Documentation/nvme-wdc-get-dev-capabilities-log.html
@@ -0,0 +1,822 @@
+<?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 10.2.0" />
+<title>nvme-wdc-get-dev-capabilities-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 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-get-dev-capabilities-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-dev-capabilities-log -
+ Send NVMe WDC get-dev-capabilities-log plugin command, return parsed log output
+</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 get-dev-capabilities-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>For the NVMe device given, send a WDC plugin get-dev-capabilities-log command
+and output the device capabilities log data. The --output-format option will
+format the output as specified.</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>This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns the parsed device capabilities log page 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</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 issue WDC get-dev-capabilities-log plugin command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-dev-capabilities-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-dev-capabilities-log.txt b/Documentation/nvme-wdc-get-dev-capabilities-log.txt
new file mode 100644
index 0000000..cf8606a
--- /dev/null
+++ b/Documentation/nvme-wdc-get-dev-capabilities-log.txt
@@ -0,0 +1,47 @@
+nvme-wdc-get-dev-capabilities-log(1)
+====================================
+
+NAME
+----
+nvme-wdc-get-dev-capabilities-log - Send NVMe WDC get-dev-capabilities-log
+plugin command, return parsed log output
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-dev-capabilities-log' <device> [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a WDC plugin get-dev-capabilities-log command
+and output the device capabilities log data. The --output-format option will
+format the output as specified.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.
+
+On success it returns the parsed device capabilities log page data, error
+code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+EXAMPLES
+--------
+* Has the program issue WDC get-dev-capabilities-log plugin command :
++
+------------
+# nvme wdc get-dev-capabilities-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-get-drive-status.1 b/Documentation/nvme-wdc-get-drive-status.1
new file mode 100644
index 0000000..f9e44f3
--- /dev/null
+++ b/Documentation/nvme-wdc-get-drive-status.1
@@ -0,0 +1,122 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-DRIV" "1" "02/14/2024" "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-get-drive-status \- Send the NVMe WDC get\-drive\-status command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-drive\-status\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send the unique WDC get\-drive\-status command and provide the additional drive status information\&.
+.sp
+The <device> parameter is mandatory and may be either the 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
+On success it returns 0, error code otherwise\&.
+.SH "OUTPUT EXPLANATION"
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Field
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fBPercent Life Used\&.\fR
+T}:T{
+.sp
+The percentage of drive function used\&.
+T}
+T{
+.sp
+\fBEOL (End of Life) Status\fR
+T}:T{
+.sp
+The 3 possible states are : Normal, Read Only, or End of Life\&.
+T}
+T{
+.sp
+\fBAssert Dump Status\fR
+T}:T{
+.sp
+The 2 possible states are : Present or Not Present\&.
+T}
+T{
+.sp
+\fBThermal Throttling Status\fR
+T}:T{
+.sp
+The 3 possible states are : Off, On, or Unavailable\&.
+T}
+T{
+.sp
+\fBFormat Corrupt Reason\fR
+T}:T{
+.sp
+The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason\&.
+T}
+.TE
+.sp 1
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC get\-drive\-status command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-drive\-status /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-get-drive-status.html b/Documentation/nvme-wdc-get-drive-status.html
new file mode 100644
index 0000000..47df6df
--- /dev/null
+++ b/Documentation/nvme-wdc-get-drive-status.html
@@ -0,0 +1,843 @@
+<?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 10.2.0" />
+<title>nvme-wdc-get-drive-status(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-get-drive-status(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-drive-status -
+ Send the NVMe WDC get-drive-status 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 get-drive-status</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, send the unique WDC get-drive-status command and
+provide the additional drive status information.</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>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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_output_explanation">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>Percent Life Used.</strong></p></td>
+<td align="left" valign="top"><p class="table">The percentage of drive function used.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>EOL (End of Life) Status</strong></p></td>
+<td align="left" valign="top"><p class="table">The 3 possible states are : Normal, Read Only, or End of Life.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Assert Dump Status</strong></p></td>
+<td align="left" valign="top"><p class="table">The 2 possible states are : Present or Not Present.</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 3 possible states are : Off, On, or Unavailable.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Format Corrupt Reason</strong></p></td>
+<td align="left" valign="top"><p class="table">The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program issue WDC get-drive-status command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-drive-status /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-drive-status.txt b/Documentation/nvme-wdc-get-drive-status.txt
new file mode 100644
index 0000000..b1b4de4
--- /dev/null
+++ b/Documentation/nvme-wdc-get-drive-status.txt
@@ -0,0 +1,60 @@
+nvme-wdc-get-drive-status(1)
+============================
+
+NAME
+----
+nvme-wdc-get-drive-status - Send the NVMe WDC get-drive-status command, return
+result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-drive-status' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, send the unique WDC get-drive-status command and
+provide the additional drive status information.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+Output Explanation
+------------------
+[cols="2*", frame="topbot", align="center", options="header"]
+|===
+|Field |Description
+
+|*Percent Life Used.*
+|The percentage of drive function used.
+
+|*EOL (End of Life) Status*
+|The 3 possible states are : Normal, Read Only, or End of Life.
+
+|*Assert Dump Status*
+|The 2 possible states are : Present or Not Present.
+
+|*Thermal Throttling Status*
+|The 3 possible states are : Off, On, or Unavailable.
+
+|*Format Corrupt Reason*
+|The 3 possible states are : Not Corrupted, Corrupt due to FW Assert, or Corrupt for Unknown Reason.
+
+|===
+
+EXAMPLES
+--------
+* Has the program issue WDC get-drive-status command :
++
+------------
+# nvme wdc get-drive-status /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-get-error-recovery-log.1 b/Documentation/nvme-wdc-get-error-recovery-log.1
new file mode 100644
index 0000000..8b0cc43
--- /dev/null
+++ b/Documentation/nvme-wdc-get-error-recovery-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-wdc-get-error-recovery-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-ERRO" "1" "02/14/2024" "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-get-error-recovery-log \- Send NVMe WDC get\-error\-recovery\-log plugin command, return parsed log output
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-error\-recovery\-log\fR <device> [\-\-output\-format=<normal|json>
+\-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a WDC plugin get\-error\-recovery\-log command and output the error recovery log data\&. The \-\-output\-format option will format the output as specified\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this log page\&. Results for any other device are undefined\&.
+.sp
+On success it returns the parsed error recovery log page data, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC get\-error\-recovery\-log plugin command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-error\-recovery\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-get-error-recovery-log.html b/Documentation/nvme-wdc-get-error-recovery-log.html
new file mode 100644
index 0000000..342bfb9
--- /dev/null
+++ b/Documentation/nvme-wdc-get-error-recovery-log.html
@@ -0,0 +1,823 @@
+<?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 10.2.0" />
+<title>nvme-wdc-get-error-recovery-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 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-get-error-recovery-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-error-recovery-log -
+ Send NVMe WDC get-error-recovery-log plugin command, return parsed log output
+</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 get-error-recovery-log</em> &lt;device&gt; [--output-format=&lt;normal|json&gt;
+-o &lt;normal|json&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 WDC plugin get-error-recovery-log command
+and output the error recovery log data. The --output-format option will format
+the output as specified.</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>This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns the parsed error recovery log page 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</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 issue WDC get-error-recovery-log plugin command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-error-recovery-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-error-recovery-log.txt b/Documentation/nvme-wdc-get-error-recovery-log.txt
new file mode 100644
index 0000000..4998390
--- /dev/null
+++ b/Documentation/nvme-wdc-get-error-recovery-log.txt
@@ -0,0 +1,48 @@
+nvme-wdc-get-error-recovery-log(1)
+==================================
+
+NAME
+----
+nvme-wdc-get-error-recovery-log - Send NVMe WDC get-error-recovery-log plugin
+command, return parsed log output
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-error-recovery-log' <device> [--output-format=<normal|json>
+-o <normal|json>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a WDC plugin get-error-recovery-log command
+and output the error recovery log data. The --output-format option will format
+the output as specified.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.
+
+On success it returns the parsed error recovery log page data, error
+code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+EXAMPLES
+--------
+* Has the program issue WDC get-error-recovery-log plugin command :
++
+------------
+# nvme wdc get-error-recovery-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.1 b/Documentation/nvme-wdc-get-latency-monitor-log.1
new file mode 100644
index 0000000..437e9c6
--- /dev/null
+++ b/Documentation/nvme-wdc-get-latency-monitor-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-wdc-get-latency-monitor-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-LATE" "1" "02/14/2024" "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-get-latency-monitor-log \- Display latency monitor log page data in human readable format
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-latency\-monitor\-log\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, latency monitor log page data\&.
+.sp
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this log page\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR
+or
+\fIjson\fR\&. Only one output format can be used at a time\&. The default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Displays the get latency monitor log for the device:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-latency\-monitor\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.html b/Documentation/nvme-wdc-get-latency-monitor-log.html
new file mode 100644
index 0000000..092f346
--- /dev/null
+++ b/Documentation/nvme-wdc-get-latency-monitor-log.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 10.2.0" />
+<title>nvme-wdc-get-latency-monitor-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 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-get-latency-monitor-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-latency-monitor-log -
+ Display latency monitor log page data in human readable format
+</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 get-latency-monitor-log</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&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, latency monitor log page data.</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 log page.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns 0, 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em> or <em>json</em>. Only one output format
+ can be used at a time. The default is normal.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Displays the get latency monitor log for the device:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-latency-monitor-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-latency-monitor-log.txt b/Documentation/nvme-wdc-get-latency-monitor-log.txt
new file mode 100644
index 0000000..abab8e8
--- /dev/null
+++ b/Documentation/nvme-wdc-get-latency-monitor-log.txt
@@ -0,0 +1,42 @@
+nvme-wdc-get-latency-monitor-log(1)
+===================================
+
+NAME
+----
+nvme-wdc-get-latency-monitor-log - Display latency monitor log page data in human readable format
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-latency-monitor-log' <device> [--output-format=<normal|json> -o <normal|json>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, latency monitor log page data.
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal' or 'json'. Only one output format
+ can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* Displays the get latency monitor log for the device:
++
+------------
+# nvme wdc get-latency-monitor-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-get-pfail-dump.1 b/Documentation/nvme-wdc-get-pfail-dump.1
new file mode 100644
index 0000000..37ba4a1
--- /dev/null
+++ b/Documentation/nvme-wdc-get-pfail-dump.1
@@ -0,0 +1,116 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-PFAI" "1" "02/14/2024" "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-get-pfail-dump \- Retrieve WDC device\*(Aqs pfail crash dump\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-pfail\-dump\fR <device> [\-\-output\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC vendor unique pfail crash dump request and saves the result to file\&. In current implementation pfail crash dump is captured if it is present\&. On success it will save the dump in file with appropriate suffix\&. Note that this command will clear the available dump from the device on success\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device serial number followed by "pfail_dump" suffix
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the pfail crash dump from the device and saves to default file in current directory (e\&.g\&. STM00019F3F9_pfail_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-pfail\-dump /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
+.\}
+Gets the pfail crash dump from the device and saves to defined file in current directory (e\&.g\&. testSTM00019F3F9_pfail_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-pfail\-dump /dev/nvme0 \-o test
+.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 pfail crash dump from the device and saves to defined file with pathname (e\&.g\&. /tmp/testSTM00019F3F9_pfail_dump\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-pfail\-dump /dev/nvme0 \-o /tmp/test
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-get-pfail-dump.html b/Documentation/nvme-wdc-get-pfail-dump.html
new file mode 100644
index 0000000..3fd5726
--- /dev/null
+++ b/Documentation/nvme-wdc-get-pfail-dump.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 10.2.0" />
+<title>nvme-wdc-get-pfail-dump(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-get-pfail-dump(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-pfail-dump -
+ Retrieve WDC device's pfail crash dump.
+</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 get-pfail-dump</em> &lt;device&gt; [--output-file=&lt;FILE&gt;, -o &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, sends the WDC vendor unique pfail crash dump
+request and saves the result to file. In current implementation pfail crash
+dump is captured if it is present. On success it will save the dump in file
+with appropriate suffix. Note that this command will clear the available
+dump from the device on success.</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>
+</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; defaults to device serial number followed by "pfail_dump" suffix
+</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 pfail crash dump from the device and saves to default file in current directory
+(e.g. STM00019F3F9_pfail_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-pfail-dump /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the pfail crash dump from the device and saves to defined file in current directory
+(e.g. testSTM00019F3F9_pfail_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-pfail-dump /dev/nvme0 -o test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the pfail crash dump from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9_pfail_dump.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-pfail-dump /dev/nvme0 -o /tmp/test</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-pfail-dump.txt b/Documentation/nvme-wdc-get-pfail-dump.txt
new file mode 100644
index 0000000..63688c0
--- /dev/null
+++ b/Documentation/nvme-wdc-get-pfail-dump.txt
@@ -0,0 +1,54 @@
+nvme-wdc-get-pfail-dump(1)
+==========================
+
+NAME
+----
+nvme-wdc-get-pfail-dump - Retrieve WDC device's pfail crash dump.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-pfail-dump' <device> [--output-file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the WDC vendor unique pfail crash dump
+request and saves the result to file. In current implementation pfail crash
+dump is captured if it is present. On success it will save the dump in file
+with appropriate suffix. Note that this command will clear the available
+dump from the device on success.
+
+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.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device serial number followed by "pfail_dump" suffix
+
+EXAMPLES
+--------
+* Gets the pfail crash dump from the device and saves to default file in current directory
+(e.g. STM00019F3F9_pfail_dump.bin):
++
+------------
+# nvme wdc get-pfail-dump /dev/nvme0
+------------
+* Gets the pfail crash dump from the device and saves to defined file in current directory
+(e.g. testSTM00019F3F9_pfail_dump.bin):
++
+------------
+# nvme wdc get-pfail-dump /dev/nvme0 -o test
+------------
+* Gets the pfail crash dump from the device and saves to defined file with pathname (e.g. /tmp/testSTM00019F3F9_pfail_dump.bin):
++
+------------
+# nvme wdc get-pfail-dump /dev/nvme0 -o /tmp/test
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.1 b/Documentation/nvme-wdc-get-unsupported-reqs-log.1
new file mode 100644
index 0000000..f458f33
--- /dev/null
+++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.1
@@ -0,0 +1,79 @@
+'\" t
+.\" Title: nvme-wdc-get-unsupported-reqs-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-UNSU" "1" "02/14/2024" "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-get-unsupported-reqs-log \- Send NVMe WDC get\-unsupported\-reqs\-log plugin command, return parsed log output
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc get\-unsupported\-reqs\-log\fR <device> [\-\-output\-format=<normal|json>
+\-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a WDC plugin get\-unsupported\-reqs\-log command and output the unsupported requirements log data\&. The \-\-output\-format option will format the output as specified\&.
+.sp
+The <device> parameter is mandatory and may be either the NVMe character device (ex: /dev/nvme0)\&.
+.sp
+This will only work on WDC devices supporting this log page\&. Results for any other device are undefined\&.
+.sp
+On success it returns the parsed unsupported requirements log page data, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC get\-unsupported\-reqs\-log plugin command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc get\-unsupported\-reqs\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.html b/Documentation/nvme-wdc-get-unsupported-reqs-log.html
new file mode 100644
index 0000000..57cd697
--- /dev/null
+++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.html
@@ -0,0 +1,823 @@
+<?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 10.2.0" />
+<title>nvme-wdc-get-unsupported-reqs-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 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-get-unsupported-reqs-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-get-unsupported-reqs-log -
+ Send NVMe WDC get-unsupported-reqs-log plugin command, return parsed log output
+</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 get-unsupported-reqs-log</em> &lt;device&gt; [--output-format=&lt;normal|json&gt;
+-o &lt;normal|json&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 WDC plugin get-unsupported-reqs-log command
+and output the unsupported requirements log data. The --output-format option
+will format the output as specified.</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>This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.</p></div>
+<div class="paragraph"><p>On success it returns the parsed unsupported requirements log page 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</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 issue WDC get-unsupported-reqs-log plugin command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc get-unsupported-reqs-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-get-unsupported-reqs-log.txt b/Documentation/nvme-wdc-get-unsupported-reqs-log.txt
new file mode 100644
index 0000000..61f09aa
--- /dev/null
+++ b/Documentation/nvme-wdc-get-unsupported-reqs-log.txt
@@ -0,0 +1,48 @@
+nvme-wdc-get-unsupported-reqs-log(1)
+====================================
+
+NAME
+----
+nvme-wdc-get-unsupported-reqs-log - Send NVMe WDC get-unsupported-reqs-log
+ plugin command, return parsed log output
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc get-unsupported-reqs-log' <device> [--output-format=<normal|json>
+-o <normal|json>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a WDC plugin get-unsupported-reqs-log command
+and output the unsupported requirements log data. The --output-format option
+will format the output as specified.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this log page.
+Results for any other device are undefined.
+
+On success it returns the parsed unsupported requirements log page data, error
+code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+EXAMPLES
+--------
+* Has the program issue WDC get-unsupported-reqs-log plugin command :
++
+------------
+# nvme wdc get-unsupported-reqs-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-id-ctrl.1 b/Documentation/nvme-wdc-id-ctrl.1
new file mode 100644
index 0000000..c3a31da
--- /dev/null
+++ b/Documentation/nvme-wdc-id-ctrl.1
@@ -0,0 +1,98 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-ID\-CTRL" "1" "02/14/2024" "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-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc id\-ctrl\fR <device> [\-\-vendor\-specific | \-v] [\-\-raw\-binary | \-b]
+ [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an 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
+This will only work on WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success, the structure may be returned in one of several ways depending on the option flags; the structure may be parsed by the program or the raw buffer may be printed to stdout\&.
+.sp
+If having the program decode the output for readability, this version will decode WDC vendor unique portions of the structure\&.
+.SH "OPTIONS"
+.PP
+\-b, \-\-raw\-binary
+.RS 4
+Print the raw buffer to stdout\&. Structure is not parsed by program\&. This overrides the vendor specific and human readable options\&.
+.RE
+.PP
+\-v, \-\-vendor\-specific
+.RS 4
+In addition to parsing known fields, this option will dump the vendor specific region of the structure in hex with ascii interpretation\&.
+.RE
+.PP
+\-H, \-\-human\-readable
+.RS 4
+This option will parse and format many of the bit fields into human\-readable formats\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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 wdc id\-ctrl /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-wdc-id-ctrl.html b/Documentation/nvme-wdc-id-ctrl.html
new file mode 100644
index 0000000..36c535d
--- /dev/null
+++ b/Documentation/nvme-wdc-id-ctrl.html
@@ -0,0 +1,863 @@
+<?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 10.2.0" />
+<title>nvme-wdc-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 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-id-ctrl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-id-ctrl -
+ Send NVMe 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 wdc id-ctrl</em> &lt;device&gt; [--vendor-specific | -v] [--raw-binary | -b]
+ [--human-readable | -H]
+ [--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 an 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>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, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.</p></div>
+<div class="paragraph"><p>If having the program decode the output for readability, this version
+will decode WDC vendor unique portions of the structure.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-b
+</dt>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dd>
+<p>
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+</p>
+</dd>
+<dt class="hdlist1">
+-v
+</dt>
+<dt class="hdlist1">
+--vendor-specific
+</dt>
+<dd>
+<p>
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+</p>
+</dd>
+<dt class="hdlist1">
+-H
+</dt>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dd>
+<p>
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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 wdc id-ctrl /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-id-ctrl.txt b/Documentation/nvme-wdc-id-ctrl.txt
new file mode 100644
index 0000000..b62eb60
--- /dev/null
+++ b/Documentation/nvme-wdc-id-ctrl.txt
@@ -0,0 +1,67 @@
+nvme-wdc-id-ctrl(1)
+===================
+
+NAME
+----
+nvme-wdc-id-ctrl - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc id-ctrl' <device> [--vendor-specific | -v] [--raw-binary | -b]
+ [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an 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).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success, the structure may be returned in one of several ways depending
+on the option flags; the structure may be parsed by the program or the
+raw buffer may be printed to stdout.
+
+If having the program decode the output for readability, this version
+will decode WDC vendor unique portions of the structure.
+
+OPTIONS
+-------
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program. This overrides the vendor specific and human readable options.
+
+-v::
+--vendor-specific::
+ In addition to parsing known fields, this option will dump
+ the vendor specific region of the structure in hex with ascii
+ interpretation.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-o <fmt>::
+--output-format=<fmt>::
+ 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 wdc id-ctrl /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-wdc-log-page-directory.1 b/Documentation/nvme-wdc-log-page-directory.1
new file mode 100644
index 0000000..5856e24
--- /dev/null
+++ b/Documentation/nvme-wdc-log-page-directory.1
@@ -0,0 +1,79 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-LOG\-PAGE" "1" "02/14/2024" "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-log-page-directory \- Retrieves the list of Log IDs supported by the drive
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc log\-page\-directory\fR <device> [\-\-output\-format=<normal|json|binary> \-o <normal|json|binary>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, retrieves the log page directory which contains the list of log page IDs supported by the drive\&. The \-\-output\-format option will format the output as specified\&.
+.sp
+The <device> parameter is mandatory and must be the 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
+On success it returns the log page directory information, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&. The default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+WDC log\-page\-directory example command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc log\-page\-directory /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-log-page-directory.html b/Documentation/nvme-wdc-log-page-directory.html
new file mode 100644
index 0000000..2192754
--- /dev/null
+++ b/Documentation/nvme-wdc-log-page-directory.html
@@ -0,0 +1,819 @@
+<?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 10.2.0" />
+<title>nvme-wdc-log-page-directory(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-log-page-directory(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-log-page-directory -
+ Retrieves the list of Log IDs supported by the drive
+</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 log-page-directory</em> &lt;device&gt; [--output-format=&lt;normal|json|binary&gt; -o &lt;normal|json|binary&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, retrieves the log page directory which contains the list of
+log page IDs supported by the drive. The --output-format option will format the output as
+specified.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the 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>On success it returns the log page directory information, 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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. The default is normal.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+WDC log-page-directory example command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc log-page-directory /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-log-page-directory.txt b/Documentation/nvme-wdc-log-page-directory.txt
new file mode 100644
index 0000000..27b5d9e
--- /dev/null
+++ b/Documentation/nvme-wdc-log-page-directory.txt
@@ -0,0 +1,43 @@
+nvme-wdc-log-page-directory(1)
+==============================
+
+NAME
+----
+nvme-wdc-log-page-directory - Retrieves the list of Log IDs supported by the drive
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc log-page-directory' <device> [--output-format=<normal|json|binary> -o <normal|json|binary>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves the log page directory which contains the list of
+log page IDs supported by the drive. The --output-format option will format the output as
+specified.
+
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns the log page directory information, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json', or 'binary'. Only one output format
+ can be used at a time. The default is normal.
+
+EXAMPLES
+--------
+* WDC log-page-directory example command :
++
+------------
+# nvme wdc log-page-directory /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-namespace-resize.1 b/Documentation/nvme-wdc-namespace-resize.1
new file mode 100644
index 0000000..88637d9
--- /dev/null
+++ b/Documentation/nvme-wdc-namespace-resize.1
@@ -0,0 +1,101 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-NAMESPACE" "1" "02/14/2024" "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-namespace-resize \- Resizes the device\*(Aqs namespace\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc namespace\-resize\fR <device> [\-\-nsid=<NAMESPACE ID>, \-n <NAMSPACE ID>]
+ [\-\-op_option=<OP OPTION>, \-o <OP OPTION>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC Vendor Specific Command that modifies the namespace size reported the device\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-n <NAMESPACE ID>, \-\-namespace\-id=<NAMESPACE_ID>
+.RS 4
+Namespace ID; ID of the namespace to resize
+.RE
+.PP
+\-o <OP OPTION>, \-\-op\-option=<OP OPTION>
+.RS 4
+Overprovisioning Option; defaults to 0xF Valid Values: 0x1 \- 7% of Original TNVMCAP reported value 0x2 \- 28% of Original TNVMCAP reported value 0x3 \- 50% of Original TNVMCAP reported value 0xF \- 0% of Original TNVMCAP reported value (original config) All other values \- reserved
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Resizes namespace 1 to 50% of the original TNVMCAP reported value:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc namespace\-resize /dev/nvme0 \-n 1 \-o 3
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Resizes namespace 2 to 7% of the original TNVMCAP reported value:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc namespace\-resize /dev/nvme0 \-\-namespace\-id=2 \-\-op\-option=1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-namespace-resize.html b/Documentation/nvme-wdc-namespace-resize.html
new file mode 100644
index 0000000..d5fcc2b
--- /dev/null
+++ b/Documentation/nvme-wdc-namespace-resize.html
@@ -0,0 +1,843 @@
+<?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 10.2.0" />
+<title>nvme-wdc-namespace-resize(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-namespace-resize(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-namespace-resize -
+ Resizes the device's namespace.
+</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 namespace-resize</em> &lt;device&gt; [--nsid=&lt;NAMESPACE ID&gt;, -n &lt;NAMSPACE ID&gt;]
+ [--op_option=&lt;OP OPTION&gt;, -o &lt;OP OPTION&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 WDC Vendor Specific Command that modifies
+the namespace size reported 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>This will only work on WDC devices supporting this feature.
+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">
+-n &lt;NAMESPACE ID&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NAMESPACE_ID&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID; ID of the namespace to resize
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;OP OPTION&gt;
+</dt>
+<dt class="hdlist1">
+--op-option=&lt;OP OPTION&gt;
+</dt>
+<dd>
+<p>
+ Overprovisioning Option; defaults to 0xF
+ Valid Values:
+ 0x1 - 7% of Original TNVMCAP reported value
+ 0x2 - 28% of Original TNVMCAP reported value
+ 0x3 - 50% of Original TNVMCAP reported value
+ 0xF - 0% of Original TNVMCAP reported value (original config)
+ All other values - reserved
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Resizes namespace 1 to 50% of the original TNVMCAP reported value:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc namespace-resize /dev/nvme0 -n 1 -o 3</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Resizes namespace 2 to 7% of the original TNVMCAP reported value:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc namespace-resize /dev/nvme0 --namespace-id=2 --op-option=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 the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-namespace-resize.txt b/Documentation/nvme-wdc-namespace-resize.txt
new file mode 100644
index 0000000..42994ad
--- /dev/null
+++ b/Documentation/nvme-wdc-namespace-resize.txt
@@ -0,0 +1,56 @@
+nvme-wdc-namespace-resize(1)
+============================
+
+NAME
+----
+nvme-wdc-namespace-resize - Resizes the device's namespace.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc namespace-resize' <device> [--nsid=<NAMESPACE ID>, -n <NAMSPACE ID>]
+ [--op_option=<OP OPTION>, -o <OP OPTION>]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, sends the WDC Vendor Specific Command that modifies
+the namespace size reported the device.
+
+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.
+
+OPTIONS
+-------
+-n <NAMESPACE ID>::
+--namespace-id=<NAMESPACE_ID>::
+ Namespace ID; ID of the namespace to resize
+
+-o <OP OPTION>::
+--op-option=<OP OPTION>::
+ Overprovisioning Option; defaults to 0xF
+ Valid Values:
+ 0x1 - 7% of Original TNVMCAP reported value
+ 0x2 - 28% of Original TNVMCAP reported value
+ 0x3 - 50% of Original TNVMCAP reported value
+ 0xF - 0% of Original TNVMCAP reported value (original config)
+ All other values - reserved
+
+EXAMPLES
+--------
+* Resizes namespace 1 to 50% of the original TNVMCAP reported value:
++
+------------
+# nvme wdc namespace-resize /dev/nvme0 -n 1 -o 3
+------------
+* Resizes namespace 2 to 7% of the original TNVMCAP reported value:
++
+------------
+# nvme wdc namespace-resize /dev/nvme0 --namespace-id=2 --op-option=1
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-purge-monitor.1 b/Documentation/nvme-wdc-purge-monitor.1
new file mode 100644
index 0000000..e01e1c1
--- /dev/null
+++ b/Documentation/nvme-wdc-purge-monitor.1
@@ -0,0 +1,126 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-PURGE\-MO" "1" "02/14/2024" "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-purge-monitor \- Send NVMe WDC Purge\-Monitor Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc purge\-monitor\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC Purge\-Monitor command and provide the status of the purge command\&.
+.sp
+Expected status and description :\-
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Status Code
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+0x00
+T}:T{
+.sp
+Purge State Idle\&.
+T}
+T{
+.sp
+0x01
+T}:T{
+.sp
+Purge State Done\&.
+T}
+T{
+.sp
+0x02
+T}:T{
+.sp
+Purge State Busy\&.
+T}
+T{
+.sp
+0x03
+T}:T{
+.sp
+Purge State Error : Purge operation resulted in error, power cycle required\&.
+T}
+T{
+.sp
+0x04
+T}:T{
+.sp
+Purge State Error : Purge operation interrupted by power cycle or reset\&.
+T}
+.TE
+.sp 1
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.sp
+No options yet\&.
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC Purge\-Monitor Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc purge\-monitor /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-purge-monitor.html b/Documentation/nvme-wdc-purge-monitor.html
new file mode 100644
index 0000000..c25a28f
--- /dev/null
+++ b/Documentation/nvme-wdc-purge-monitor.html
@@ -0,0 +1,844 @@
+<?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 10.2.0" />
+<title>nvme-wdc-purge-monitor(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-purge-monitor(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-purge-monitor -
+ Send NVMe WDC Purge-Monitor 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 purge-monitor</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, send a Vendor Unique WDC Purge-Monitor command and
+provide the status of the purge command.</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">Status Code </th>
+<th align="left" valign="top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table">0x00</p></td>
+<td align="left" valign="top"><p class="table">Purge State Idle.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x01</p></td>
+<td align="left" valign="top"><p class="table">Purge State Done.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x02</p></td>
+<td align="left" valign="top"><p class="table">Purge State Busy.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x03</p></td>
+<td align="left" valign="top"><p class="table">Purge State Error : Purge operation resulted in error, power cycle required.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0x04</p></td>
+<td align="left" valign="top"><p class="table">Purge State Error : Purge operation interrupted by power cycle or reset.</p></td>
+</tr>
+</tbody>
+</table>
+</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 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No options yet.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program issue WDC Purge-Monitor Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc purge-monitor /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-purge-monitor.txt b/Documentation/nvme-wdc-purge-monitor.txt
new file mode 100644
index 0000000..5d44183
--- /dev/null
+++ b/Documentation/nvme-wdc-purge-monitor.txt
@@ -0,0 +1,62 @@
+nvme-wdc-purge-monitor(1)
+=========================
+
+NAME
+----
+nvme-wdc-purge-monitor - Send NVMe WDC Purge-Monitor Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc purge-monitor' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a Vendor Unique WDC Purge-Monitor command and
+provide the status of the purge command.
+
+Expected status and description :-
+
+[cols="2*", options="header"]
+|===
+|Status Code |Description
+
+|0x00
+|Purge State Idle.
+
+|0x01
+|Purge State Done.
+
+|0x02
+|Purge State Busy.
+
+|0x03
+|Purge State Error : Purge operation resulted in error, power cycle required.
+
+|0x04
+|Purge State Error : Purge operation interrupted by power cycle or reset.
+|===
+
+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 WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+No options yet.
+
+EXAMPLES
+--------
+* Has the program issue WDC Purge-Monitor Vendor Unique Command :
++
+------------
+# nvme wdc purge-monitor /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-purge.1 b/Documentation/nvme-wdc-purge.1
new file mode 100644
index 0000000..89fb3b4
--- /dev/null
+++ b/Documentation/nvme-wdc-purge.1
@@ -0,0 +1,73 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-PURGE" "1" "02/14/2024" "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-purge \- Send NVMe WDC Purge Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc purge\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends a Vendor Unique WDC Purge command and provides the result\&.
+.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 WDC devices supporting this feature\&. Results for any other device are undefined\&.
+.sp
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.sp
+No options yet\&.
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC Purge Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc purge /dev/nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-purge.html b/Documentation/nvme-wdc-purge.html
new file mode 100644
index 0000000..9afac8e
--- /dev/null
+++ b/Documentation/nvme-wdc-purge.html
@@ -0,0 +1,806 @@
+<?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 10.2.0" />
+<title>nvme-wdc-purge(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-purge(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-purge -
+ Send NVMe WDC Purge 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 purge</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, sends a Vendor Unique WDC Purge command and
+provides the result.</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 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>No options yet.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program issue WDC Purge Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc purge /dev/nvme0n1</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-purge.txt b/Documentation/nvme-wdc-purge.txt
new file mode 100644
index 0000000..95c2dd2
--- /dev/null
+++ b/Documentation/nvme-wdc-purge.txt
@@ -0,0 +1,40 @@
+nvme-wdc-purge(1)
+=================
+
+NAME
+----
+nvme-wdc-purge - Send NVMe WDC Purge Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc purge' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends a Vendor Unique WDC Purge command and
+provides the result.
+
+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 WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+No options yet.
+
+EXAMPLES
+--------
+* Has the program issue WDC Purge Vendor Unique Command :
++
+------------
+# nvme wdc purge /dev/nvme0n1
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-set-latency-monitor-feature.txt b/Documentation/nvme-wdc-set-latency-monitor-feature.txt
new file mode 100644
index 0000000..60b3e26
--- /dev/null
+++ b/Documentation/nvme-wdc-set-latency-monitor-feature.txt
@@ -0,0 +1,118 @@
+nvme-wdc-set-latency-monitor-feature(1)
+=======================================
+
+NAME
+----
+nvme-wdc-set-latency-monitor-feature - Set NVMe WDC latency monitor feature options
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc set-latency-monitor-feature' <device>
+ [--active_bucket_timer_threshold=<NUM> | -t <NUM>]
+ [--active_threshold_a=<NUM> | -a <NUM>]
+ [--active_threshold_b=<NUM> | -b <NUM>]
+ [--active_threshold_c=<NUM> | -c <NUM>]
+ [--active_threshold_d=<NUM> | -d <NUM>]
+ [--active_latency_config=<NUM> | -f <NUM>]
+ [--active_latency_minimum_window=<NUM> | -w <NUM>]
+ [--debug_log_trigger_enable=<NUM> | -r <NUM>]
+ [--discard_debug_log=<NUM> | -l <NUM>]
+ [--latency_monitor_feature_enable=<NUM> | -e <NUM>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, this command set the
+latency monitor feature options (if supported by the device).
+
+The <device> parameter is mandatory NVMe character device (ex: /dev/nvme0).
+
+Setting results can be checked with 'get-latency-monitor-log' command.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-t <NUM>::
+--active_bucket_timer_threshold=<NUM>::
+ The value that loads the Active Bucket Timer Threshold; default value is 07E0h.
+
+-a <NUM>::
+--active_threshold_a=<NUM>::
+ The value that loads into the Active Threshold A; default value is 05h.
+
+-b <NUM>::
+--active_threshold_b=<NUM>::
+ The value that loads into the Active Threshold B; default value is 13h.
+
+-c <NUM>::
+--active_threshold_c=<NUM>::
+ The value that loads into the Active Threshold C; default value is 1Eh.
+
+-d <NUM>::
+--active_threshold_d=<NUM>::
+ The value that loads into the Active Threshold D; default value is 2Eh.
+
+-f <NUM>::
+--active_latency_config=<NUM>::
+ The value that loads into the Active Latency Configuration. This
+ configures how both the Active Latency Stamp, and the Active Measured
+ Latency Fields are updated on a per I/O command (Read, Write, Deallocate)
+ counter basis; default value is 0FFFh.
+
+-w <NUM>::
+--active_latency_minimum_window=<NUM>::
+ The value that loads into the Active Latency Minimum Window; default value is 0Ah.
+
+-r <NUM>::
+--debug_log_trigger_enable=<NUM>::
+ The value that loads into the Debug Log Trigger Enable; When set to 1b
+ the first time the bucket/counter combination is incremented a debug log
+ is triggered. When cleared to 0b a debug log will not be triggered when
+ the bucket/counter combination is incremented.
+
+-l <NUM>::
+--discard_debug_log=<NUM>::
+ Discard Debug Log. When cleared to 00h the debug log, if it exists, will
+ not be cleared. When set to 01h the debug log will be discarded so
+ another log can be triggered. All the fields in the Set Features Data
+ structure are valid. When set to 02h the debug log will be discarded so
+ another log can be triggered. None of the other fields of the Set
+ Features Data structure are valid.
+
+-e <NUM>::
+--latency_monitor_feature_enable=<NUM>::
+ Latency Monitor Feature Enable; When set to 01h the Latency Monitor
+ Feature is enabled. When cleared to 00h the Latency Monitor Feature is
+ disabled.
+
+EXAMPLES
+--------
+* Set NVMe WDC latency monitor feature options enabled with default value values:
++
+------------
+# nvme wdc set-latency-monitor-feature /dev/nvme0 -e 1
+------------
+* Set NVMe WDC latency monitor feature options disabled with default value values:
++
+------------
+# nvme wdc set-latency-monitor-feature /dev/nvme0 -e 0
+------------
+* Set NVMe WDC latency monitor feature options enabled with specific values:
++
+------------
+# nvme wdc set-latency-monitor-feature /dev/nvme0 --active_bucket_timer_threshold=1 \
+ --active_threshold_a=0x0 \
+ --active_threshold_b=0x1 \
+ --active_threshold_c=0x2 \
+ --active_threshold_d=0x3 \
+ --active_latency_config=0xfff \
+ --active_latency_minimum_window=0 \
+ --debug_log_trigger_enable=0 \
+ --discard_debug_log=0 \
+ --latency_monitor_feature_enable=0x1
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-smart-add-log.1 b/Documentation/nvme-wdc-smart-add-log.1
new file mode 100644
index 0000000..fe1d3de
--- /dev/null
+++ b/Documentation/nvme-wdc-smart-add-log.1
@@ -0,0 +1,496 @@
+'\" t
+.\" Title: nvme-wdc-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: 01/08/2019
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-SMART\-AD" "1" "01/08/2019" "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-smart-add-log \- Send NVMe WDC smart\-add\-log Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc smart\-add\-log\fR <device> [\-\-interval=<NUM>, \-i <NUM>] [\-\-output\-format=<normal|json> \-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC smart\-add\-log command and provide the additional smart log\&. The \-\-interval option will return performance statistics from the specified reporting interval\&.
+.sp
+The <device> parameter is mandatory and may be either the 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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-i <NUM>, \-\-interval=<NUM>
+.RS 4
+Return the statistics from specific interval, defaults to 14
+.RE
+.PP
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.sp
+Valid Interval values and description :\-
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Value
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fB1\fR
+T}:T{
+.sp
+Most recent five (5) minute accumulated set\&.
+T}
+T{
+.sp
+\fB2\-12\fR
+T}:T{
+.sp
+Previous five (5) minute accumulated sets\&.
+T}
+T{
+.sp
+\fB13\fR
+T}:T{
+.sp
+The accumulated total of sets 1 through 12 that contain the previous hour of accumulated statistics\&.
+T}
+T{
+.sp
+\fB14\fR
+T}:T{
+.sp
+The statistical set accumulated since power\-up\&.
+T}
+T{
+.sp
+\fB15\fR
+T}:T{
+.sp
+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{
+.sp
+\fBAverage NAND Write Size\fR
+T}:T{
+.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{
+.sp
+\fBNAND Read Before Write\fR
+T}:T{
+.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"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC smart\-add\-log Vendor Unique Command with default interval (14) :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc smart\-add\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-smart-add-log.html b/Documentation/nvme-wdc-smart-add-log.html
new file mode 100644
index 0000000..e7f1d50
--- /dev/null
+++ b/Documentation/nvme-wdc-smart-add-log.html
@@ -0,0 +1,1139 @@
+<!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" />
+<title>nvme-wdc-smart-add-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 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-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-smart-add-log -
+ Send NVMe WDC smart-add-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 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>
+<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 smart-add-log command and
+provide the additional smart log. The --interval option will return performance
+statistics from the specified reporting interval.</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>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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-i &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--interval=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Return the statistics from specific interval, defaults to 14
+</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>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>Valid Interval values and description :-</p></div>
+<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">Value </th>
+<th align="left" valign="top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>1</strong></p></td>
+<td align="left" valign="top"><p class="table">Most recent five (5) minute accumulated set.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>2-12</strong></p></td>
+<td align="left" valign="top"><p class="table">Previous five (5) minute accumulated sets.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>13</strong></p></td>
+<td align="left" valign="top"><p class="table">The accumulated total of sets 1 through 12 that contain the previous hour of
+accumulated statistics.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>14</strong></p></td>
+<td align="left" valign="top"><p class="table">The statistical set accumulated since power-up.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>15</strong></p></td>
+<td align="left" valign="top"><p class="table">The statistical set accumulated during the entire lifetime of the device.</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</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>
+<li>
+<p>
+Has the program issue WDC smart-add-log Vendor Unique Command with default interval (14) :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc smart-add-log /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
+ 2018-01-17 20:47:00 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-cloud-log.1 b/Documentation/nvme-wdc-vs-cloud-log.1
new file mode 100644
index 0000000..91f4c99
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-cloud-log.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-wdc-vs-cloud-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-CLOUD" "1" "02/14/2024" "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-cloud-log \- Send NVMe WDC vs\-cloud\-log Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-cloud\-log\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC vs\-cloud\-log command and provide the smart/health log\&.
+.sp
+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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+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
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if not given\&. This option may not affect anything depending on the log page, which may or may not be specific to a namespace\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-cloud\-log Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-cloud\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-cloud-log.html b/Documentation/nvme-wdc-vs-cloud-log.html
new file mode 100644
index 0000000..f34317a
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-cloud-log.html
@@ -0,0 +1,835 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-cloud-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 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-cloud-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-cloud-log -
+ Send NVMe WDC vs-cloud-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 vs-cloud-log</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&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 vs-cloud-log command and
+provide the smart/health 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) 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the command&#8217;s nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+</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 issue WDC vs-cloud-log Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-cloud-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-cloud-log.txt b/Documentation/nvme-wdc-vs-cloud-log.txt
new file mode 100644
index 0000000..9739295
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-cloud-log.txt
@@ -0,0 +1,52 @@
+nvme-wdc-vs-cloud-log(1)
+========================
+
+NAME
+----
+nvme-wdc-vs-cloud-log - Send NVMe WDC vs-cloud-log Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-cloud-log' <device> [--output-format=<normal|json> -o <normal|json>]
+ [--namespace-id=<nsid> | -n <nsid>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a Vendor Unique WDC vs-cloud-log command and
+provide the smart/health log.
+
+The <device> parameter is mandatory and may be either the NVMe character
+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.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the command's nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-cloud-log Vendor Unique Command :
++
+------------
+# nvme wdc vs-cloud-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-device-waf.1 b/Documentation/nvme-wdc-vs-device-waf.1
new file mode 100644
index 0000000..d864c80
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-device-waf.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-wdc-vs-device-waf
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-DEVIC" "1" "02/14/2024" "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-device-waf \- Calculates the device write amplification factor and prints both TLC and SLC results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-device\-waf\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, calculates the device TLC and SLC write amplification factor\&.
+.sp
+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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+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
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if not given\&. This option may not affect anything depending on the log page, which may or may not be specific to a namespace\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-device\-waf plugin Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-device\-waf /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-device-waf.html b/Documentation/nvme-wdc-vs-device-waf.html
new file mode 100644
index 0000000..a4a90be
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-device-waf.html
@@ -0,0 +1,835 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-device-waf(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-device-waf(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-device-waf -
+ Calculates the device write amplification factor and prints both TLC and SLC 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 wdc vs-device-waf</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&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, calculates the device TLC and SLC write
+amplification factor.</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 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the command&#8217;s nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+</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 issue WDC vs-device-waf plugin Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-device-waf /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-device-waf.txt b/Documentation/nvme-wdc-vs-device-waf.txt
new file mode 100644
index 0000000..f25618d
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-device-waf.txt
@@ -0,0 +1,53 @@
+nvme-wdc-vs-device-waf(1)
+=========================
+
+NAME
+----
+nvme-wdc-vs-device-waf - Calculates the device write amplification factor and
+prints both TLC and SLC results
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-device-waf' <device> [--output-format=<normal|json> -o <normal|json>]
+ [--namespace-id=<nsid> | -n <nsid>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, calculates the device TLC and SLC write
+amplification factor.
+
+The <device> parameter is mandatory and may be either the NVMe character
+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.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the command's nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-device-waf plugin Command :
++
+------------
+# nvme wdc vs-device-waf /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-drive-info.1 b/Documentation/nvme-wdc-vs-drive-info.1
new file mode 100644
index 0000000..2816277
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.1
@@ -0,0 +1,64 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-DRIVE" "1" "02/14/2024" "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-drive-info \- Send the NVMe WDC vs\-drive\-info command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-drive\-info\fR <device>
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send the unique WDC vs\-drive\-info command and provide the additional drive information\&.
+.sp
+The <device> parameter is mandatory and must be the 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
+On success it returns 0, error code otherwise\&.
+.SH "OUTPUT EXPLANATION"
+.sp
+There are several different fields returned from this command depending on the drive:
+.sp
+Drive HW Revision
+.sp
+FTL Unit Size
+.sp
+Customer Serial Number
+.sp
+HyperScale Boot Version
+.sp
+TCG Device Ownership
+.SH "EXAMPLE"
+.sp
+# nvme wdc vs\-drive\-info /dev/nvme0
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-drive-info.html b/Documentation/nvme-wdc-vs-drive-info.html
new file mode 100644
index 0000000..ede45c7
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.html
@@ -0,0 +1,802 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-drive-info(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-drive-info(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-drive-info -
+ Send the NVMe WDC vs-drive-info 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 vs-drive-info</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, send the unique WDC vs-drive-info command and
+provide the additional drive information.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the 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>On success it returns 0, error code otherwise.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_output_explanation">Output Explanation</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>There are several different fields returned from this command depending
+on the drive:</p></div>
+<div class="paragraph"><p>Drive HW Revision</p></div>
+<div class="paragraph"><p>FTL Unit Size</p></div>
+<div class="paragraph"><p>Customer Serial Number</p></div>
+<div class="paragraph"><p>HyperScale Boot Version</p></div>
+<div class="paragraph"><p>TCG Device Ownership</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_example">EXAMPLE</h2>
+<div class="sectionbody">
+<div class="paragraph"><p># nvme wdc vs-drive-info /dev/nvme0</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-drive-info.txt b/Documentation/nvme-wdc-vs-drive-info.txt
new file mode 100644
index 0000000..bc18b17
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.txt
@@ -0,0 +1,47 @@
+nvme-wdc-vs-drive-info(1)
+=========================
+
+NAME
+----
+nvme-wdc-vs-drive-info - Send the NVMe WDC vs-drive-info command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-drive-info' <device>
+
+DESCRIPTION
+-----------
+For the NVMe device given, send the unique WDC vs-drive-info command and
+provide the additional drive information.
+
+The <device> parameter is mandatory and must be the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+Output Explanation
+------------------
+There are several different fields returned from this command depending
+on the drive:
+
+Drive HW Revision
+
+FTL Unit Size
+
+Customer Serial Number
+
+HyperScale Boot Version
+
+TCG Device Ownership
+
+EXAMPLE
+--------
+# nvme wdc vs-drive-info /dev/nvme0
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.1 b/Documentation/nvme-wdc-vs-error-reason-identifier.1
new file mode 100644
index 0000000..05e12fb
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-error-reason-identifier.1
@@ -0,0 +1,102 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-ERROR" "1" "02/14/2024" "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-error-reason-identifier \- Retrieve WDC device\*(Aqs telemetry log error reason identifier field
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-error\-reason\-identifier\fR <device> [\-\-log\-id=<NUM>, \-i <NUM>] [\-\-file=<FILE>, \-o <FILE>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, retrieve the telemetry log error reason id field for either the host generated or controller initiated log\&. The controller initiated telemetry log page option must be enabled to retrieve the error reason id for that log page id\&.
+.sp
+The <device> parameter is mandatory and must be the 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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-i <id>, \-\-log\-id=<id>
+.RS 4
+Specifies the telemetry log id of the error reason identifier to retrieve\&. Use id 7 for the host generated log page\&. Use id 8 for the controller initiated log page\&. The default is 7/host generated
+.RE
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to "<device serial number>_error_reason_identifier_host_<date>_<time>\&.bin" for the host generated log or "<device serial number>_error_reason_identifier_ctlr_<date>_<time>\&.bin" for the controller initiated log\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieves the host generated error reason identifier field and save it in file host_gen_error_reason_id\&.bin\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-error\-reason\-identifier /dev/nvme0 \-i 7 \-o host_gen_error_reason_id\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieves the controller initiated error reason identifier field and save it in file ctlr_init_error_reason_id\&.bin\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-error\-reason\-identifier /dev/nvme0 \-i 8 \-o ctlr_init_error_reason_id\&.bin
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.html b/Documentation/nvme-wdc-vs-error-reason-identifier.html
new file mode 100644
index 0000000..4c96ee8
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-error-reason-identifier.html
@@ -0,0 +1,843 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-error-reason-identifier(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-error-reason-identifier(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-error-reason-identifier -
+ Retrieve WDC device's telemetry log error reason identifier field
+</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-error-reason-identifier</em> &lt;device&gt; [--log-id=&lt;NUM&gt;, -i &lt;NUM&gt;] [--file=&lt;FILE&gt;, -o &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, retrieve the telemetry log error reason id field for either the host generated or
+controller initiated log. The controller initiated telemetry log page option must be enabled to retrieve the
+error reason id for that log page id.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the 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>On success it returns 0, 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">
+-i &lt;id&gt;
+</dt>
+<dt class="hdlist1">
+--log-id=&lt;id&gt;
+</dt>
+<dd>
+<p>
+ Specifies the telemetry log id of the error reason identifier to retrieve.
+ Use id 7 for the host generated log page.
+ Use id 8 for the controller initiated log page.
+ The default is 7/host generated
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--output-file=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Output file; defaults to "&lt;device serial number&gt;_error_reason_identifier_host_&lt;date&gt;_&lt;time&gt;.bin" for
+ the host generated log or "&lt;device serial number&gt;_error_reason_identifier_ctlr_&lt;date&gt;_&lt;time&gt;.bin" for
+ the controller initiated log.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieves the host generated error reason identifier field and save it in file host_gen_error_reason_id.bin.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-error-reason-identifier /dev/nvme0 -i 7 -o host_gen_error_reason_id.bin</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Retrieves the controller initiated error reason identifier field and save it in file ctlr_init_error_reason_id.bin.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-error-reason-identifier /dev/nvme0 -i 8 -o ctlr_init_error_reason_id.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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-error-reason-identifier.txt b/Documentation/nvme-wdc-vs-error-reason-identifier.txt
new file mode 100644
index 0000000..0c7f397
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-error-reason-identifier.txt
@@ -0,0 +1,56 @@
+nvme-wdc-vs-error-reason-identifier(1)
+======================================
+
+NAME
+----
+nvme-wdc-vs-error-reason-identifier - Retrieve WDC device's telemetry log error reason identifier field
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-error-reason-identifier' <device> [--log-id=<NUM>, -i <NUM>] [--file=<FILE>, -o <FILE>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieve the telemetry log error reason id field for either the host generated or
+controller initiated log. The controller initiated telemetry log page option must be enabled to retrieve the
+error reason id for that log page id.
+
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-i <id>::
+--log-id=<id>::
+ Specifies the telemetry log id of the error reason identifier to retrieve.
+ Use id 7 for the host generated log page.
+ Use id 8 for the controller initiated log page.
+ The default is 7/host generated
+
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to "<device serial number>_error_reason_identifier_host_<date>_<time>.bin" for
+ the host generated log or "<device serial number>_error_reason_identifier_ctlr_<date>_<time>.bin" for
+ the controller initiated log.
+
+EXAMPLES
+--------
+* Retrieves the host generated error reason identifier field and save it in file host_gen_error_reason_id.bin.
++
+--------
+# nvme wdc vs-error-reason-identifier /dev/nvme0 -i 7 -o host_gen_error_reason_id.bin
+--------
+* Retrieves the controller initiated error reason identifier field and save it in file ctlr_init_error_reason_id.bin.
++
+--------
+# nvme wdc vs-error-reason-identifier /dev/nvme0 -i 8 -o ctlr_init_error_reason_id.bin
+--------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.1 b/Documentation/nvme-wdc-vs-fw-activate-history.1
new file mode 100644
index 0000000..9fab5ae
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-fw-activate-history.1
@@ -0,0 +1,154 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-FW\-A" "1" "02/14/2024" "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-fw-activate-history \- Execute NVMe WDC vs\-fw\-activate\-history Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-fw\-activate\-history\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, read a Vendor Unique WDC log page that returns the firmware activation history\&.
+.sp
+The <device> parameter is mandatory and must be the 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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.SH "FIRMWARE ACTIVATE HISTORY 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.
+T{
+.sp
+\fBEntry Number\fR
+T}:T{
+.sp
+The number of fw activate entry\&. The most recent 20 entries will be displayed\&.
+T}
+T{
+.sp
+\fBPower on Hour\fR
+T}:T{
+.sp
+The time since the power on in hours:minutes:seconds\&.
+T}
+T{
+.sp
+\fBPower Cycle Count\fR
+T}:T{
+.sp
+The power cycle count that the firmware activation occurred\&.
+T}
+T{
+.sp
+\fBCurrent Firmware\fR
+T}:T{
+.sp
+The firmware level currently running on the SSD before the activation took place\&.
+T}
+T{
+.sp
+\fBNew Firmware\fR
+T}:T{
+.sp
+The new firmware level running on the SSD after the activation took place\&.
+T}
+T{
+.sp
+\fBSlot Number\fR
+T}:T{
+.sp
+The slot that the firmware is being activated from\&.
+T}
+T{
+.sp
+\fBCommit Action Type\fR
+T}:T{
+.sp
+The commit action type associated with the firmware activation event
+T}
+T{
+.sp
+\fBResult\fR
+T}:T{
+.sp
+The result of the firmware activation event\&. The output shall be in the format: Pass or Failed + error code
+T}
+.TE
+.sp 1
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-fw\-activate\-history Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-fw\-activate\-history /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.html b/Documentation/nvme-wdc-vs-fw-activate-history.html
new file mode 100644
index 0000000..cdae180
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-fw-activate-history.html
@@ -0,0 +1,875 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-fw-activate-history(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-fw-activate-history(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-fw-activate-history -
+ Execute NVMe WDC vs-fw-activate-history 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 vs-fw-activate-history</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&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, read a Vendor Unique WDC log page that returns the firmware activation
+history.</p></div>
+<div class="paragraph"><p>The &lt;device&gt; parameter is mandatory and must be the 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>On success it returns 0, 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_firmware_activate_history_log_page_data_output_explanation">Firmware Activate History 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>Entry Number</strong></p></td>
+<td align="left" valign="top"><p class="table">The number of fw activate entry. The most recent 20 entries will be displayed.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Power on Hour</strong></p></td>
+<td align="left" valign="top"><p class="table">The time since the power on in hours:minutes:seconds.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Power Cycle Count</strong></p></td>
+<td align="left" valign="top"><p class="table">The power cycle count that the firmware activation occurred.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Current Firmware</strong></p></td>
+<td align="left" valign="top"><p class="table">The firmware level currently running on the SSD before the activation took place.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>New Firmware</strong></p></td>
+<td align="left" valign="top"><p class="table">The new firmware level running on the SSD after the activation took place.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Slot Number</strong></p></td>
+<td align="left" valign="top"><p class="table">The slot that the firmware is being activated from.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Commit Action Type</strong></p></td>
+<td align="left" valign="top"><p class="table">The commit action type associated with the firmware activation event</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>Result</strong></p></td>
+<td align="left" valign="top"><p class="table">The result of the firmware activation event. The output shall be in the format:
+Pass or Failed + error code</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Has the program issue WDC vs-fw-activate-history Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-fw-activate-history /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-fw-activate-history.txt b/Documentation/nvme-wdc-vs-fw-activate-history.txt
new file mode 100644
index 0000000..923ff0a
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-fw-activate-history.txt
@@ -0,0 +1,75 @@
+nvme-wdc-vs-fw-activate-history(1)
+==================================
+
+NAME
+----
+nvme-wdc-vs-fw-activate-history - Execute NVMe WDC vs-fw-activate-history Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-fw-activate-history' <device> [--output-format=<normal|json> -o <normal|json>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, read a Vendor Unique WDC log page that returns the firmware activation
+history.
+
+The <device> parameter is mandatory and must be the NVMe character device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+Firmware Activate History Log Page Data Output Explanation
+-----------------------------------------------------------
+[cols="2*", frame="topbot", align="center", options="header"]
+|===
+|Field |Description
+
+|*Entry Number*
+|The number of fw activate entry. The most recent 20 entries will be displayed.
+
+|*Power on Hour*
+|The time since the power on in hours:minutes:seconds.
+
+|*Power Cycle Count*
+|The power cycle count that the firmware activation occurred.
+
+|*Current Firmware*
+|The firmware level currently running on the SSD before the activation took place.
+
+|*New Firmware*
+|The new firmware level running on the SSD after the activation took place.
+
+|*Slot Number*
+|The slot that the firmware is being activated from.
+
+|*Commit Action Type*
+|The commit action type associated with the firmware activation event
+
+|*Result*
+|The result of the firmware activation event. The output shall be in the format:
+Pass or Failed + error code
+|===
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-fw-activate-history Vendor Unique Command :
++
+------------
+# nvme wdc vs-fw-activate-history /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.1 b/Documentation/nvme-wdc-vs-hw-rev-log.1
new file mode 100644
index 0000000..abe700f
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-hw-rev-log.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-wdc-vs-hw-rev-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-HW\-R" "1" "02/14/2024" "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-hw-rev-log \- Send NVMe WDC vs\-hw\-rev\-log Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-hw\-rev\-log\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, retrieves and formats the Vendor Unique WDC hw revision log page\&.
+.sp
+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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+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
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if not given\&. This option may not affect anything depending on the log page, which may or may not be specific to a namespace\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-hw\-rev\-log plugin Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-hw\-rev\-log /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.html b/Documentation/nvme-wdc-vs-hw-rev-log.html
new file mode 100644
index 0000000..5225883
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-hw-rev-log.html
@@ -0,0 +1,834 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-hw-rev-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 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-hw-rev-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-hw-rev-log -
+ Send NVMe WDC vs-hw-rev-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 vs-hw-rev-log</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&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, retrieves and formats the Vendor Unique WDC hw revision log page.</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 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the command&#8217;s nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+</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 issue WDC vs-hw-rev-log plugin Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-hw-rev-log /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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-hw-rev-log.txt b/Documentation/nvme-wdc-vs-hw-rev-log.txt
new file mode 100644
index 0000000..b4eb4dd
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-hw-rev-log.txt
@@ -0,0 +1,51 @@
+nvme-wdc-vs-hw-rev-log(1)
+=========================
+
+NAME
+----
+nvme-wdc-vs-hw-rev-log - Send NVMe WDC vs-hw-rev-log Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-hw-rev-log' <device> [--output-format=<normal|json> -o <normal|json>]
+ [--namespace-id=<nsid> | -n <nsid>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, retrieves and formats the Vendor Unique WDC hw revision log page.
+
+The <device> parameter is mandatory and may be either the NVMe character
+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.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the command's nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-hw-rev-log plugin Command :
++
+------------
+# nvme wdc vs-hw-rev-log /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-internal-log.1 b/Documentation/nvme-wdc-vs-internal-log.1
new file mode 100644
index 0000000..0f94172
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.1
@@ -0,0 +1,258 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-INTER" "1" "02/14/2024" "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-internal-log \- Retrieve WDC device\*(Aqs internal firmware log and save to file\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-internal\-log\fR <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]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC Vendor Specific Internal Log request and saves the result to a file\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-o <FILE>, \-\-output\-file=<FILE>
+.RS 4
+Output file; defaults to device serial number followed by "\fIinternal_fw_log\fR<date>_<time>\&.bin" suffix
+.RE
+.PP
+\-s <SIZE>, \-\-transfer\-size=<SIZE>
+.RS 4
+Transfer size; defaults to 0x10000 (65536 decimal) bytes
+.RE
+.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, SN730, and SN840 devices\&.
+.RE
+.PP
+\-f <FILE SIZE>, \-\-file\-size=<FILE SIZE>
+.RS 4
+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\&.
+.RE
+.PP
+\-e <OFFSET>, \-\-offset=<OFFSET>
+.RS 4
+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\&.
+.RE
+.PP
+\-t <TYPE>, \-\-type=<TYPE>
+.RS 4
+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\&.
+.RE
+.PP
+\-v <VERBOSE>, \-\-verbose=<VERBOSE>
+.RS 4
+Provides additional debug messages for certain drives\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Gets the internal firmware log from the device and saves to default file in current directory (e\&.g\&. STM00019F3F9_internal_fw_log_20171127_095704\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-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
+.\}
+Gets the internal firmware log from the device and saves to defined file in current directory (e\&.g\&. test\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme0 \-o test\&.bin
+.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 internal firmware log from the device and saves to defined file with pathname (e\&.g\&. /tmp/test):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme0 \-o /tmp/test
+.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 internal firmware log from the device transferring the data in 64k chunks and saves to default file in current directory (e\&.g\&. STM00019F3F9_internal_fw_log_20171127_100754\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme0 \-s 0x10000
+.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 internal firmware log from the device transferring the data in 16k chunks and saves to default file in current directory (e\&.g\&. STM00019F3F9_internal_fw_log_20171127_100950\&.bin):
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme0 \-s 16384
+.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 internal firmware log up to data area 3 from the device in 3 files of 0x1000000 bytes:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme0 \-d 3 \-f 0x1000000 \-t 0x0000000 \-o /tmp/sn340_dui_data_1\&.bin
+# nvme wdc vs\-internal\-log /dev/nvme0 \-d 3 \-f 0x1000000 \-t 0x1000000 \-o /tmp/sn340_dui_data_2\&.bin
+# nvme wdc vs\-internal\-log /dev/nvme0 \-d 3 \-f 0x1000000 \-t 0x2000000 \-o /tmp/sn340_dui_data_3\&.bin
+.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 host telemetry log page to data area 3 from the device and stores it in file host\-telem\-log\-da3\&.bin:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme1 \-t host \-o host\-telem\-log\-da3\&.bin \-d 3
+.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 controller telemetry log page to data area 3 from the device and stores it in file ctlr\-telem\-log\-da3\&.bin:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-internal\-log /dev/nvme1 \-t controller \-o ctlr\-telem\-log\-da3\&.bin \-d 3
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-internal-log.html b/Documentation/nvme-wdc-vs-internal-log.html
new file mode 100644
index 0000000..e07879b
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.html
@@ -0,0 +1,965 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-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 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-internal-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-internal-log -
+ Retrieve WDC device's internal firmware log and save to file.
+</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-internal-log</em> &lt;device&gt; [--output-file=&lt;FILE&gt;, -o &lt;FILE&gt;]
+ [--transfer-size=&lt;SIZE&gt;, -s &lt;SIZE&gt;]
+ [--data-area=&lt;DATA AREA&gt;, -d &lt;DATA_AREA&gt;]
+ [--file-size=&lt;FILE SIZE&gt;, -f &lt;FILE SIZE&gt;]
+ [--offset=&lt;OFFSET&gt;, -e &lt;OFFSET&gt;]
+ [--type=&lt;TYPE&gt;, -t &lt;type&gt;] [--verbose, -v]</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 WDC Vendor Specific Internal Log request
+and saves the result to a file.</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>
+</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; defaults to device serial number followed by
+ "<em>internal_fw_log</em>&lt;date&gt;_&lt;time&gt;.bin" suffix
+</p>
+</dd>
+<dt class="hdlist1">
+-s &lt;SIZE&gt;
+</dt>
+<dt class="hdlist1">
+--transfer-size=&lt;SIZE&gt;
+</dt>
+<dd>
+<p>
+ Transfer size; defaults to 0x10000 (65536 decimal) bytes
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;DATA AREA&gt;
+</dt>
+<dt class="hdlist1">
+--data-area=&lt;DATA AREA&gt;
+</dt>
+<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, SN730, and SN840 devices.
+</p>
+</dd>
+<dt class="hdlist1">
+-f &lt;FILE SIZE&gt;
+</dt>
+<dt class="hdlist1">
+--file-size=&lt;FILE SIZE&gt;
+</dt>
+<dd>
+<p>
+ 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.
+</p>
+</dd>
+<dt class="hdlist1">
+-e &lt;OFFSET&gt;
+</dt>
+<dt class="hdlist1">
+--offset=&lt;OFFSET&gt;
+</dt>
+<dd>
+<p>
+ 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.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;TYPE&gt;
+</dt>
+<dt class="hdlist1">
+--type=&lt;TYPE&gt;
+</dt>
+<dd>
+<p>
+ 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.
+</p>
+</dd>
+<dt class="hdlist1">
+-v &lt;VERBOSE&gt;
+</dt>
+<dt class="hdlist1">
+--verbose=&lt;VERBOSE&gt;
+</dt>
+<dd>
+<p>
+ Provides additional debug messages for certain drives.
+</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 internal firmware log from the device and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_095704.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the internal firmware log from the device and saves to defined file in current directory (e.g. test.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0 -o test.bin</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the internal firmware log from the device and saves to defined file with pathname (e.g. /tmp/test):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0 -o /tmp/test</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the internal firmware log from the device transferring the data in 64k chunks and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_100754.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0 -s 0x10000</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the internal firmware log from the device transferring the data in 16k chunks and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_100950.bin):
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0 -s 16384</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the internal firmware log up to data area 3 from the device in 3 files of 0x1000000 bytes:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x0000000 -o /tmp/sn340_dui_data_1.bin
+# nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x1000000 -o /tmp/sn340_dui_data_2.bin
+# nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x2000000 -o /tmp/sn340_dui_data_3.bin</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the host telemetry log page to data area 3 from the device and stores it in file host-telem-log-da3.bin:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme1 -t host -o host-telem-log-da3.bin -d 3</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the controller telemetry log page to data area 3 from the device and stores it in file ctlr-telem-log-da3.bin:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-internal-log /dev/nvme1 -t controller -o ctlr-telem-log-da3.bin -d 3</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-internal-log.txt b/Documentation/nvme-wdc-vs-internal-log.txt
new file mode 100644
index 0000000..08f585b
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.txt
@@ -0,0 +1,119 @@
+nvme-wdc-vs-internal-log(1)
+===========================
+
+NAME
+----
+nvme-wdc-vs-internal-log - Retrieve WDC device's internal firmware log and save to file.
+
+SYNOPSIS
+--------
+[verse]
+'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]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, sends the WDC Vendor Specific Internal Log request
+and saves the result to a file.
+
+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.
+
+OPTIONS
+-------
+-o <FILE>::
+--output-file=<FILE>::
+ Output file; defaults to device serial number followed by
+ "_internal_fw_log_<date>_<time>.bin" suffix
+
+-s <SIZE>::
+--transfer-size=<SIZE>::
+ Transfer size; defaults to 0x10000 (65536 decimal) bytes
+
+-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, 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.
+
+-e <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.
+
+-t <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.
+
+-v <VERBOSE>::
+--verbose=<VERBOSE>::
+ Provides additional debug messages for certain drives.
+
+EXAMPLES
+--------
+* Gets the internal firmware log from the device and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_095704.bin):
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0
+------------
+* Gets the internal firmware log from the device and saves to defined file in current directory (e.g. test.bin):
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0 -o test.bin
+------------
+* Gets the internal firmware log from the device and saves to defined file with pathname (e.g. /tmp/test):
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0 -o /tmp/test
+------------
+* Gets the internal firmware log from the device transferring the data in 64k chunks and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_100754.bin):
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0 -s 0x10000
+------------
+* Gets the internal firmware log from the device transferring the data in 16k chunks and saves to default file in current directory (e.g. STM00019F3F9_internal_fw_log_20171127_100950.bin):
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0 -s 16384
+------------
+* Gets the internal firmware log up to data area 3 from the device in 3 files of 0x1000000 bytes:
++
+------------
+# nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x0000000 -o /tmp/sn340_dui_data_1.bin
+# nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x1000000 -o /tmp/sn340_dui_data_2.bin
+# nvme wdc vs-internal-log /dev/nvme0 -d 3 -f 0x1000000 -t 0x2000000 -o /tmp/sn340_dui_data_3.bin
+------------
+* Gets the host telemetry log page to data area 3 from the device and stores it in file host-telem-log-da3.bin:
++
+------------
+# 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:
++
+------------
+# nvme wdc vs-internal-log /dev/nvme1 -t controller -o ctlr-telem-log-da3.bin -d 3
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-nand-stats.1 b/Documentation/nvme-wdc-vs-nand-stats.1
new file mode 100644
index 0000000..7723faf
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-nand-stats.1
@@ -0,0 +1,78 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-NAND\" "1" "02/14/2024" "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-nand-stats \- Send NVMe WDC vs\-nand\-stats Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-nand\-stats\fR <device> [\-\-output\-format=<normal|json> \-o <normal|json>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC vs\-nand\-stats command and output the NAND statistics\&. The \-\-output\-format option will format the output as specified\&.
+.sp
+The <device> parameter is mandatory and may be either the 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
+On success it returns the NAND statistics, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.RS 4
+Set the reporting format to
+\fInormal\fR, or
+\fIjson\fR\&. Only one output format can be used at a time\&. Default is normal\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Has the program issue WDC vs\-nand\-stats Vendor Unique Command :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-nand\-stats /dev/nvme0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-nand-stats.html b/Documentation/nvme-wdc-vs-nand-stats.html
new file mode 100644
index 0000000..073efb0
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-nand-stats.html
@@ -0,0 +1,821 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-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 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-nand-stats(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-nand-stats -
+ Send NVMe WDC vs-nand-stats 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 vs-nand-stats</em> &lt;device&gt; [--output-format=&lt;normal|json&gt; -o &lt;normal|json&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 vs-nand-stats command and
+output the NAND statistics. The --output-format option will format the output as
+specified.</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>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 NAND statistics, 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ Default is normal.
+</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 issue WDC vs-nand-stats Vendor Unique Command :
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc 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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-nand-stats.txt b/Documentation/nvme-wdc-vs-nand-stats.txt
new file mode 100644
index 0000000..1b16daa
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-nand-stats.txt
@@ -0,0 +1,45 @@
+nvme-wdc-vs-nand-stats(1)
+=========================
+
+NAME
+----
+nvme-wdc-vs-nand-stats - Send NVMe WDC vs-nand-stats Vendor Unique Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-nand-stats' <device> [--output-format=<normal|json> -o <normal|json>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a Vendor Unique WDC vs-nand-stats command and
+output the NAND statistics. The --output-format option will format the output as
+specified.
+
+The <device> parameter is mandatory and may be either the NVMe character
+device (ex: /dev/nvme0).
+
+This will only work on WDC devices supporting this feature.
+Results for any other device are undefined.
+
+On success it returns the NAND statistics, error code otherwise.
+
+OPTIONS
+-------
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-nand-stats Vendor Unique Command :
++
+------------
+# nvme wdc vs-nand-stats /dev/nvme0
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.1 b/Documentation/nvme-wdc-vs-smart-add-log.1
new file mode 100644
index 0000000..269000a
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.1
@@ -0,0 +1,197 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-SMART" "1" "02/14/2024" "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-smart-add-log \- Send NVMe WDC vs\-smart\-add\-log Vendor Unique Command, return result
+.SH "SYNOPSIS"
+.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>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.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\&.
+.sp
+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
+On success it returns 0, error code otherwise\&.
+.SH "OPTIONS"
+.PP
+\-i <NUM>, \-\-interval=<NUM>
+.RS 4
+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 <fmt>, \-\-output\-format=<fmt>
+.RS 4
+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
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Sets the command\(cqs nsid value to the given nsid\&. Defaults to 0xffffffff if not given\&. This option may not affect anything depending on the log page, which may or may not be specific to a namespace\&.
+.RE
+.sp
+Valid Interval values and description :\-
+.TS
+allbox tab(:);
+ltB ltB.
+T{
+Value
+T}:T{
+Description
+T}
+.T&
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+\fB1\fR
+T}:T{
+.sp
+Most recent five (5) minute accumulated set\&.
+T}
+T{
+.sp
+\fB2\-12\fR
+T}:T{
+.sp
+Previous five (5) minute accumulated sets\&.
+T}
+T{
+.sp
+\fB13\fR
+T}:T{
+.sp
+The accumulated total of sets 1 through 12 that contain the previous hour of accumulated statistics\&.
+T}
+T{
+.sp
+\fB14\fR
+T}:T{
+.sp
+The statistical set accumulated since power\-up\&.
+T}
+T{
+.sp
+\fB15\fR
+T}:T{
+.sp
+The statistical set accumulated during the entire lifetime of the device\&.
+T}
+.TE
+.sp 1
+.SH "EXAMPLES"
+.sp
+.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
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-smart\-add\-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
+.\}
+Has the program issue WDC vs\-smart\-add\-log Vendor Unique Command for just the 0xCA log page :
+.sp
+.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 \{\
+\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 0xC0 and 0xCA log pages :
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-smart\-add\-log /dev/nvme0 \-p 0xCA,0xC0
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.html b/Documentation/nvme-wdc-vs-smart-add-log.html
new file mode 100644
index 0000000..34291ef
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.html
@@ -0,0 +1,935 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-smart-add-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 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-smart-add-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-smart-add-log -
+ Send NVMe WDC vs-smart-add-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 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;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&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 vs-smart-add-log command and
+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) 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>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-i &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+--interval=&lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ 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">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, or
+ <em>json</em>. Only one output format can be used at a time.
+ 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>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Sets the command&#8217;s nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>Valid Interval values and description :-</p></div>
+<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">Value </th>
+<th align="left" valign="top">Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>1</strong></p></td>
+<td align="left" valign="top"><p class="table">Most recent five (5) minute accumulated set.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>2-12</strong></p></td>
+<td align="left" valign="top"><p class="table">Previous five (5) minute accumulated sets.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>13</strong></p></td>
+<td align="left" valign="top"><p class="table">The accumulated total of sets 1 through 12 that contain the previous hour of
+accumulated statistics.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>14</strong></p></td>
+<td align="left" valign="top"><p class="table">The statistical set accumulated since power-up.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table"><strong>15</strong></p></td>
+<td align="left" valign="top"><p class="table">The statistical set accumulated during the entire lifetime 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>
+<li>
+<p>
+Has the program issue WDC vs-smart-add-log Vendor Unique Command with default interval (14) :
+</p>
+<div class="listingblock">
+<div class="content">
+<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>
+<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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-smart-add-log.txt b/Documentation/nvme-wdc-vs-smart-add-log.txt
new file mode 100644
index 0000000..925287f
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.txt
@@ -0,0 +1,107 @@
+nvme-wdc-vs-smart-add-log(1)
+============================
+
+NAME
+----
+nvme-wdc-vs-smart-add-log - Send NVMe WDC vs-smart-add-log Vendor Unique Command,
+return result
+
+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>]
+ [--namespace-id=<nsid> | -n <nsid>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a Vendor Unique WDC vs-smart-add-log command and
+provide the additional smart log.
+
+The <device> parameter is mandatory and may be either the NVMe character
+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.
+
+On success it returns 0, error code otherwise.
+
+OPTIONS
+-------
+-i <NUM>::
+--interval=<NUM>::
+ 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 <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', or
+ '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.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Sets the command's nsid value to the given nsid. Defaults to
+ 0xffffffff if not given. This option may not affect anything
+ depending on the log page, which may or may not be specific to
+ a namespace.
+
+Valid Interval values and description :-
+
+[cols="2*", frame="topbot", align="center", options="header"]
+|===
+|Value |Description
+
+|*1*
+|Most recent five (5) minute accumulated set.
+
+|*2-12*
+|Previous five (5) minute accumulated sets.
+
+|*13*
+|The accumulated total of sets 1 through 12 that contain the previous hour of
+accumulated statistics.
+
+|*14*
+|The statistical set accumulated since power-up.
+
+|*15*
+|The statistical set accumulated during the entire lifetime of the device.
+|===
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-smart-add-log Vendor Unique Command with default interval (14) :
++
+------------
+# 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
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.1 b/Documentation/nvme-wdc-vs-telemetry-controller-option.1
new file mode 100644
index 0000000..713642e
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.1
@@ -0,0 +1,130 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-TELEM" "1" "02/14/2024" "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-telemetry-controller-option \- Disable/Enable the controller initiated option of the telemetry log page\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc vs\-telemetry\-controller\-option\fR <device>
+ [\-\-disable, \-d] [\-\-enable, \-e] [\-\-status, \-s]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the WDC Vendor Specific set feature command to disable, enable or get current status the controller initiated option of the telemetry log page\&.
+.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\&.
+.SH "OPTIONS"
+.PP
+\-d, \-\-disable
+.RS 4
+Disables the controller initiated option of the telemetry log page\&.
+.RE
+.PP
+\-e, \-\-enable
+.RS 4
+Enables the controller initiated option of the telemetry log page\&.
+.RE
+.PP
+\-s, \-\-status
+.RS 4
+Returns the current status (enabled or disabled) of the controller initiated option of the telemetry log page\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Disables the controller initiated option of the telemetry log page:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-\-disable
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-d
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Enables the controller initiated option of the telemetry log page:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-\-enable
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-e
+.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 current status (enabled or disabled) of the controller initiated option of the telemetry log page:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-\-status
+# nvme wdc vs\-telemetry\-controller\-option /dev/nvme0 \-s
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of the nvme\-user suite\&.
diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.html b/Documentation/nvme-wdc-vs-telemetry-controller-option.html
new file mode 100644
index 0000000..0a0cbf8
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.html
@@ -0,0 +1,862 @@
+<?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 10.2.0" />
+<title>nvme-wdc-vs-telemetry-controller-option(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-telemetry-controller-option(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-wdc-vs-telemetry-controller-option -
+ Disable/Enable the controller initiated option of the telemetry log page.
+</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-telemetry-controller-option</em> &lt;device&gt;
+ [--disable, -d] [--enable, -e] [--status, -s]</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 WDC Vendor Specific set feature command to
+disable, enable or get current status the controller initiated option of the
+telemetry log page.</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>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-d
+</dt>
+<dt class="hdlist1">
+--disable
+</dt>
+<dd>
+<p>
+ Disables the controller initiated option of the telemetry log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-e
+</dt>
+<dt class="hdlist1">
+--enable
+</dt>
+<dd>
+<p>
+ Enables the controller initiated option of the telemetry log page.
+</p>
+</dd>
+<dt class="hdlist1">
+-s
+</dt>
+<dt class="hdlist1">
+--status
+</dt>
+<dd>
+<p>
+ Returns the current status (enabled or disabled) of the controller
+ initiated option of the telemetry log page.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Disables the controller initiated option of the telemetry log page:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-telemetry-controller-option /dev/nvme0 --disable
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -d</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Enables the controller initiated option of the telemetry log page:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-telemetry-controller-option /dev/nvme0 --enable
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -e</code></pre>
+</div></div>
+</li>
+<li>
+<p>
+Gets the current status (enabled or disabled) of the controller initiated option of the telemetry log page:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme wdc vs-telemetry-controller-option /dev/nvme0 --status
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -s</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-wdc-vs-telemetry-controller-option.txt b/Documentation/nvme-wdc-vs-telemetry-controller-option.txt
new file mode 100644
index 0000000..2353e7c
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.txt
@@ -0,0 +1,65 @@
+nvme-wdc-vs-telemetry-controller-option(1)
+==========================================
+
+NAME
+----
+nvme-wdc-vs-telemetry-controller-option - Disable/Enable the controller
+initiated option of the telemetry log page.
+
+SYNOPSIS
+--------
+[verse]
+'nvme wdc vs-telemetry-controller-option' <device>
+ [--disable, -d] [--enable, -e] [--status, -s]
+
+DESCRIPTION
+-----------
+
+For the NVMe device given, sends the WDC Vendor Specific set feature command to
+disable, enable or get current status the controller initiated option of the
+telemetry log page.
+
+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.
+
+OPTIONS
+-------
+-d::
+--disable::
+ Disables the controller initiated option of the telemetry log page.
+
+-e::
+--enable::
+ Enables the controller initiated option of the telemetry log page.
+
+-s::
+--status::
+ Returns the current status (enabled or disabled) of the controller
+ initiated option of the telemetry log page.
+
+EXAMPLES
+--------
+* Disables the controller initiated option of the telemetry log page:
++
+------------
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 --disable
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -d
+------------
+* Enables the controller initiated option of the telemetry log page:
++
+------------
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 --enable
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -e
+------------
+* Gets the current status (enabled or disabled) of the controller initiated option of the telemetry log page:
++
+------------
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 --status
+# nvme wdc vs-telemetry-controller-option /dev/nvme0 -s
+------------
+
+NVME
+----
+Part of the nvme-user suite.
diff --git a/Documentation/nvme-wdc-vs-temperature-stats.1 b/Documentation/nvme-wdc-vs-temperature-stats.1
new file mode 100644
index 0000000..4206337
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-TEMPE" "1" "02/14/2024" "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..cf2fa1d
--- /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 10.2.0" />
+<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
+ 2024-02-14 10:43:42 CET
+</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
new file mode 100644
index 0000000..1523285
--- /dev/null
+++ b/Documentation/nvme-write-uncor.1
@@ -0,0 +1,90 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-UNCOR" "1" "02/14/2024" "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-write-uncor \- Send an NVMe write uncorrectable command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-write\-uncor\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-dir\-type=<dtype> | \-T <dtype>]
+ [\-\-dir\-spec=<dspec> | \-S <dspec>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Write Uncorrectable command is used to invalidate a range of logical blocks\&.
+.SH "OPTIONS"
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-c, \-\-block\-count=<nlb>
+.RS 4
+Number of logical blocks to write uncorrectable\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Namespace ID use in the command\&.
+.RE
+.PP
+\-T <dtype>, \-\-dir\-type=<dtype>
+.RS 4
+Directive type
+.RE
+.PP
+\-S <dspec>, \-\-dir\-spec=<dspec>
+.RS 4
+Directive specific
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-write-uncor.html b/Documentation/nvme-write-uncor.html
new file mode 100644
index 0000000..f4e58a9
--- /dev/null
+++ b/Documentation/nvme-write-uncor.html
@@ -0,0 +1,875 @@
+<?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 10.2.0" />
+<title>nvme-uncor(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-uncor(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-write-uncor -
+ Send an NVMe write uncorrectable command, return 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-write-uncor</em> &lt;device&gt; [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--dir-type=&lt;dtype&gt; | -T &lt;dtype&gt;]
+ [--dir-spec=&lt;dspec&gt; | -S &lt;dspec&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Write Uncorrectable command is used to invalidate a range of logical
+blocks.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+-c
+</dt>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dd>
+<p>
+ Number of logical blocks to write uncorrectable.
+</p>
+</dd>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID use in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;dtype&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&lt;dtype&gt;
+</dt>
+<dd>
+<p>
+ Directive type
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;dspec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&lt;dspec&gt;
+</dt>
+<dd>
+<p>
+ Directive specific
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write-uncor.txt b/Documentation/nvme-write-uncor.txt
new file mode 100644
index 0000000..6e49c61
--- /dev/null
+++ b/Documentation/nvme-write-uncor.txt
@@ -0,0 +1,60 @@
+nvme-uncor(1)
+=============
+
+NAME
+----
+nvme-write-uncor - Send an NVMe write uncorrectable command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-write-uncor' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--dir-type=<dtype> | -T <dtype>]
+ [--dir-spec=<dspec> | -S <dspec>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Write Uncorrectable command is used to invalidate a range of logical
+blocks.
+
+OPTIONS
+-------
+-s <slba>::
+--start-block=<slba>::
+ Start block.
+
+-c::
+--block-count=<nlb>::
+ Number of logical blocks to write uncorrectable.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Namespace ID use in the command.
+
+-T <dtype>::
+--dir-type=<dtype>::
+ Directive type
+
+-S <dspec>::
+--dir-spec=<dspec>::
+ Directive specific
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-write-zeroes.1 b/Documentation/nvme-write-zeroes.1
new file mode 100644
index 0000000..c21c691
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.1
@@ -0,0 +1,182 @@
+'\" t
+.\" Title: nvme-write-zeroes
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WRITE\-ZEROES" "1" "02/14/2024" "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-write-zeroes \- Send an NVMe write zeroes command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-write\-zeroes\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-prinfo=<prinfo> | \-p <prinfo>]
+ [\-\-app\-tag\-mask=<appmask> | \-m <appmask>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>] [\-\-deac | \-d]
+ [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-storage\-tag<storage\-tag> | \-S <storage\-tag>]
+ [\-\-storage\-tag\-check<storage\-tag\-check> | \-C <storage\-tag\-check>]
+ [\-\-dir\-type=<dtype> | \-T <dtype>]
+ [\-\-dir\-spec=<dspec> | \-D <dspec>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Write Zeroes command is used to set a range of logical blocks to 0\&.
+.SH "OPTIONS"
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-c <nlb>, \-\-block\-count=<nlb>
+.RS 4
+Number of logical blocks to write zeroes\&.
+.RE
+.PP
+\-p <prinfo>, \-\-prinfo=<prinfo>
+.RS 4
+Protection Information field definition\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Bit
+T}:T{
+Description
+T}
+T{
+3
+T}:T{
+PRACT: Protection Information Action\&. When set to 1, PI is stripped/inserted on read/write when the block format\(cqs metadata size is 8\&. When set to 0, metadata is passes\&.
+T}
+T{
+2:0
+T}:T{
+PRCHK: Protection Information Check:
+T}
+T{
+2
+T}:T{
+Set to 1 enables checking the guard tag
+T}
+T{
+1
+T}:T{
+Set to 1 enables checking the application tag
+T}
+T{
+0
+T}:T{
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-m <appmask>, \-\-app\-tag\-mask=<appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-a <apptag>, \-\-app\-tag=<apptag>
+.RS 4
+Optional application tag when used with protection information\&.
+.RE
+.PP
+\-l, \-\-limited\-retry
+.RS 4
+Sets the limited retry flag\&.
+.RE
+.PP
+\-d, \-\-deac
+.RS 4
+Sets the DEAC bit, requesting controller deallocate the logical blocks\&.
+.RE
+.PP
+\-f, \-\-force\-unit\-access
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-n <nsid>, \-\-namespace\-id=<nsid>
+.RS 4
+Namespace ID use in the command\&.
+.RE
+.PP
+\-S <storage\-tag>, \-\-storage\-tag=<storage\-tag>
+.RS 4
+Variable Sized Logical Block Storage Tag(LBST)\&.
+.RE
+.PP
+\-C <storage\-tag\-check>, \-\-storage\-tag\-check=<storage\-tag\-check>
+.RS 4
+This bit specifies the Storage Tag field shall be checked as part of end\-to\-end data protection processing\&.
+.RE
+.PP
+\-T <dtype>, \-\-dir\-type=<dtype>
+.RS 4
+Directive type
+.RE
+.PP
+\-D <dspec>, \-\-dir\-spec=<dspec>
+.RS 4
+Directive specific
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-write-zeroes.html b/Documentation/nvme-write-zeroes.html
new file mode 100644
index 0000000..d5820b3
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.html
@@ -0,0 +1,1018 @@
+<?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 10.2.0" />
+<title>nvme-write-zeroes(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-write-zeroes(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-write-zeroes -
+ Send an NVMe write zeroes command, return 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-write-zeroes</em> &lt;device&gt; [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--prinfo=&lt;prinfo&gt; | -p &lt;prinfo&gt;]
+ [--app-tag-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;] [--deac | -d]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--storage-tag&lt;storage-tag&gt; | -S &lt;storage-tag&gt;]
+ [--storage-tag-check&lt;storage-tag-check&gt; | -C &lt;storage-tag-check&gt;]
+ [--dir-type=&lt;dtype&gt; | -T &lt;dtype&gt;]
+ [--dir-spec=&lt;dspec&gt; | -D &lt;dspec&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Write Zeroes command is used to set a range of logical blocks to 0.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+-c &lt;nlb&gt;
+</dt>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dd>
+<p>
+ Number of logical blocks to write zeroes.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field definition.
+</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">Bit</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format&#8217;s metadata size is 8. When set to 0,
+metadata is passes.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2:0</p></td>
+<td align="left" valign="top"><p class="table">PRCHK: Protection Information Check:</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the guard tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the application tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the reference tag</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</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">
+-d
+</dt>
+<dt class="hdlist1">
+--deac
+</dt>
+<dd>
+<p>
+ Sets the DEAC bit, requesting controller deallocate the logical blocks.
+</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">
+-n &lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID use in the command.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;storage-tag&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag=&lt;storage-tag&gt;
+</dt>
+<dd>
+<p>
+ Variable Sized Logical Block Storage Tag(LBST).
+</p>
+</dd>
+<dt class="hdlist1">
+-C &lt;storage-tag-check&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag-check=&lt;storage-tag-check&gt;
+</dt>
+<dd>
+<p>
+ This bit specifies the Storage Tag field shall be checked as part of end-to-end
+ data protection processing.
+</p>
+</dd>
+<dt class="hdlist1">
+-T &lt;dtype&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&lt;dtype&gt;
+</dt>
+<dd>
+<p>
+ Directive type
+</p>
+</dd>
+<dt class="hdlist1">
+-D &lt;dspec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&lt;dspec&gt;
+</dt>
+<dd>
+<p>
+ Directive specific
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write-zeroes.txt b/Documentation/nvme-write-zeroes.txt
new file mode 100644
index 0000000..0daf320
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.txt
@@ -0,0 +1,115 @@
+nvme-write-zeroes(1)
+====================
+
+NAME
+----
+nvme-write-zeroes - Send an NVMe write zeroes command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-write-zeroes' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--prinfo=<prinfo> | -p <prinfo>]
+ [--app-tag-mask=<appmask> | -m <appmask>]
+ [--app-tag=<apptag> | -a <apptag>] [--deac | -d]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--namespace-id=<nsid> | -n <nsid>]
+ [--storage-tag<storage-tag> | -S <storage-tag>]
+ [--storage-tag-check<storage-tag-check> | -C <storage-tag-check>]
+ [--dir-type=<dtype> | -T <dtype>]
+ [--dir-spec=<dspec> | -D <dspec>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Write Zeroes command is used to set a range of logical blocks to 0.
+
+OPTIONS
+-------
+-s <slba>::
+--start-block=<slba>::
+ Start block.
+
+-c <nlb>::
+--block-count=<nlb>::
+ Number of logical blocks to write zeroes.
+
+-p <prinfo>::
+--prinfo=<prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ Optional reftag when used with protection information.
+
+-m <appmask>::
+--app-tag-mask=<appmask>::
+ Optional application tag mask when used with protection information.
+
+-a <apptag>::
+--app-tag=<apptag>::
+ Optional application tag when used with protection information.
+
+-l::
+--limited-retry::
+ Sets the limited retry flag.
+
+-d::
+--deac::
+ Sets the DEAC bit, requesting controller deallocate the logical blocks.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-n <nsid>::
+--namespace-id=<nsid>::
+ Namespace ID use in the command.
+
+-S <storage-tag>::
+--storage-tag=<storage-tag>::
+ Variable Sized Logical Block Storage Tag(LBST).
+
+-C <storage-tag-check>::
+--storage-tag-check=<storage-tag-check>::
+ This bit specifies the Storage Tag field shall be checked as part of end-to-end
+ data protection processing.
+
+-T <dtype>::
+--dir-type=<dtype>::
+ Directive type
+
+-D <dspec>::
+--dir-spec=<dspec>::
+ Directive specific
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-write.1 b/Documentation/nvme-write.1
new file mode 100644
index 0000000..64757b4
--- /dev/null
+++ b/Documentation/nvme-write.1
@@ -0,0 +1,224 @@
+'\" t
+.\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WRITE" "1" "02/14/2024" "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-write \- Send an NVMe write command, provide results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-write\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-data\-size=<size> | \-z <size>]
+ [\-\-metadata\-size=<size> | \-y <size>]
+ [\-\-ref\-tag=<reftag> | \-r <reftag>]
+ [\-\-data=<data\-file> | \-d <data\-file>]
+ [\-\-metadata=<metadata\-file> | \-M <metadata\-file>]
+ [\-\-prinfo=<prinfo> | \-p <prinfo>]
+ [\-\-app\-tag\-mask=<appmask> | \-m <appmask>]
+ [\-\-app\-tag=<apptag> | \-a <apptag>]
+ [\-\-limited\-retry | \-l] [\-\-force\-unit\-access | \-f]
+ [\-\-dir\-type=<type> | \-T <type>]
+ [\-\-dir\-spec=<spec> | \-S <spec>] [\-\-dsm=<dsm> | \-D <dsm>]
+ [\-\-show\-command | \-V] [\-\-dry\-run | \-w] [\-\-latency | \-t]
+ [\-\-storage\-tag<storage\-tag> | \-g <storage\-tag>]
+ [\-\-storage\-tag\-check | \-C] [\-\-force]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Write 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\&.
+.SH "OPTIONS"
+.PP
+\-s <slba>, \-\-start\-block=<slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-c, \-\-block\-count
+.RS 4
+The number of blocks to transfer\&. This is a zeroes based value to align with the kernel\(cqs use of this field\&. (ie\&. 0 means transfer 1 block)\&.
+.RE
+.PP
+\-z <size>, \-\-data\-size=<size>
+.RS 4
+Size of data, in bytes\&.
+.RE
+.PP
+\-y <size>, \-\-metadata\-size=<size>
+.RS 4
+Size of metadata in bytes\&.
+.RE
+.PP
+\-d <data\-file>, \-\-data=<data\-file>
+.RS 4
+Data file\&. If none provided, contents are sent from STDIN\&.
+.RE
+.PP
+\-M <metadata\-file>, \-\-metadata=<metadata\-file>
+.RS 4
+Metadata file, if necessary\&.
+.RE
+.PP
+\-p <prinfo>, \-\-prinfo=<prinfo>
+.RS 4
+Protection Information field definition\&.
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+Bit
+T}:T{
+Description
+T}
+T{
+3
+T}:T{
+PRACT: Protection Information Action\&. When set to 1, PI is stripped/inserted on read/write when the block format\(cqs metadata size is 8\&. When set to 0, metadata is passes\&.
+T}
+T{
+2:0
+T}:T{
+PRCHK: Protection Information Check:
+T}
+T{
+2
+T}:T{
+Set to 1 enables checking the guard tag
+T}
+T{
+1
+T}:T{
+Set to 1 enables checking the application tag
+T}
+T{
+0
+T}:T{
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-m <appmask>, \-\-app\-tag\-mask=<appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-a <apptag>, \-\-app\-tag=<apptag>
+.RS 4
+Optional application tag when used with protection information\&.
+.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
+\-T <type>, \-\-dir\-type=<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 specification (1\&.3a) defines only one directive, 01h, for write stream identifiers\&.
+.RE
+.PP
+\-S <spec>, \-\-dir\-spec=<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
+\-D <dsm>, \-\-dsm=<dsm>
+.RS 4
+The optional data set management attributes for this command\&. The argument for this is the least significant 8 bits of the DSM field in a write command; the most significant 16 bits of the field come from the directive specific field, if used\&. This may be used to set attributes for the LBAs being written, like access frequency, type, latency, among other things, as well as yet to be defined types\&. Please consult the NVMe specification for detailed breakdown of how to use this field\&.
+.RE
+.PP
+\-V, \-\-show\-cmd
+.RS 4
+Print out the command to be sent\&.
+.RE
+.PP
+\-w, \-\-dry\-run
+.RS 4
+Do not actually send the command\&. If want to use \-\-dry\-run option, \-\-show\-cmd option
+\fImust\fR
+be set\&. Otherwise \-\-dry\-run option will be
+\fIignored\fR\&.
+.RE
+.PP
+\-t, \-\-latency
+.RS 4
+Print out the latency the IOCTL took (in us)\&.
+.RE
+.PP
+\-g <storage\-tag>, \-\-storage\-tag=<storage\-tag>
+.RS 4
+Variable Sized Expected Logical Block Storage Tag(ELBST)\&.
+.RE
+.PP
+\-C, \-\-storage\-tag\-check
+.RS 4
+This flag enables Storage Tag field checking as part of end\-to\-end data protection processing\&.
+.RE
+.PP
+\-\-force
+.RS 4
+Ignore namespace is currently busy and performed the operation even though\&.
+.RE
+.PP
+\-o <fmt>, \-\-output\-format=<fmt>
+.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
+\-v, \-\-verbose
+.RS 4
+Increase the information detail in the output\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-write.html b/Documentation/nvme-write.html
new file mode 100644
index 0000000..4471071
--- /dev/null
+++ b/Documentation/nvme-write.html
@@ -0,0 +1,1116 @@
+<?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 10.2.0" />
+<title>nvme-write(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-write(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-write -
+ 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-write</em> &lt;device&gt; [--start-block=&lt;slba&gt; | -s &lt;slba&gt;]
+ [--block-count=&lt;nlb&gt; | -c &lt;nlb&gt;]
+ [--data-size=&lt;size&gt; | -z &lt;size&gt;]
+ [--metadata-size=&lt;size&gt; | -y &lt;size&gt;]
+ [--ref-tag=&lt;reftag&gt; | -r &lt;reftag&gt;]
+ [--data=&lt;data-file&gt; | -d &lt;data-file&gt;]
+ [--metadata=&lt;metadata-file&gt; | -M &lt;metadata-file&gt;]
+ [--prinfo=&lt;prinfo&gt; | -p &lt;prinfo&gt;]
+ [--app-tag-mask=&lt;appmask&gt; | -m &lt;appmask&gt;]
+ [--app-tag=&lt;apptag&gt; | -a &lt;apptag&gt;]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--dir-type=&lt;type&gt; | -T &lt;type&gt;]
+ [--dir-spec=&lt;spec&gt; | -S &lt;spec&gt;] [--dsm=&lt;dsm&gt; | -D &lt;dsm&gt;]
+ [--show-command | -V] [--dry-run | -w] [--latency | -t]
+ [--storage-tag&lt;storage-tag&gt; | -g &lt;storage-tag&gt;]
+ [--storage-tag-check | -C] [--force]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Write 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>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+--start-block=&lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+-c
+</dt>
+<dt class="hdlist1">
+--block-count
+</dt>
+<dd>
+<p>
+ The number of blocks to transfer. This is a zeroes based value to
+ align with the kernel&#8217;s use of this field. (ie. 0 means transfer
+ 1 block).
+</p>
+</dd>
+<dt class="hdlist1">
+-z &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--data-size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of data, in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-y &lt;size&gt;
+</dt>
+<dt class="hdlist1">
+--metadata-size=&lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Data file. If none provided, contents are sent from STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+-M &lt;metadata-file&gt;
+</dt>
+<dt class="hdlist1">
+--metadata=&lt;metadata-file&gt;
+</dt>
+<dd>
+<p>
+ Metadata file, if necessary.
+</p>
+</dd>
+<dt class="hdlist1">
+-p &lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dd>
+<p>
+ Protection Information field definition.
+</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">Bit</p></td>
+<td align="left" valign="top"><p class="table">Description</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">3</p></td>
+<td align="left" valign="top"><p class="table">PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format&#8217;s metadata size is 8. When set to 0,
+metadata is passes.</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2:0</p></td>
+<td align="left" valign="top"><p class="table">PRCHK: Protection Information Check:</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">2</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the guard tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">1</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the application tag</p></td>
+</tr>
+<tr>
+<td align="left" valign="top"><p class="table">0</p></td>
+<td align="left" valign="top"><p class="table">Set to 1 enables checking the reference tag</p></td>
+</tr>
+</tbody>
+</table>
+</div>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</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">
+-T &lt;type&gt;
+</dt>
+<dt class="hdlist1">
+--dir-type=&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
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+</p>
+</dd>
+<dt class="hdlist1">
+-S &lt;spec&gt;
+</dt>
+<dt class="hdlist1">
+--dir-spec=&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">
+-D &lt;dsm&gt;
+</dt>
+<dt class="hdlist1">
+--dsm=&lt;dsm&gt;
+</dt>
+<dd>
+<p>
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+</p>
+</dd>
+<dt class="hdlist1">
+-V
+</dt>
+<dt class="hdlist1">
+--show-cmd
+</dt>
+<dd>
+<p>
+ Print out the command to be sent.
+</p>
+</dd>
+<dt class="hdlist1">
+-w
+</dt>
+<dt class="hdlist1">
+--dry-run
+</dt>
+<dd>
+<p>
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option <em>must</em> be set. Otherwise --dry-run option will be
+ <em>ignored</em>.
+</p>
+</dd>
+<dt class="hdlist1">
+-t
+</dt>
+<dt class="hdlist1">
+--latency
+</dt>
+<dd>
+<p>
+ Print out the latency the IOCTL took (in us).
+</p>
+</dd>
+<dt class="hdlist1">
+-g &lt;storage-tag&gt;
+</dt>
+<dt class="hdlist1">
+--storage-tag=&lt;storage-tag&gt;
+</dt>
+<dd>
+<p>
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+</p>
+</dd>
+<dt class="hdlist1">
+-C
+</dt>
+<dt class="hdlist1">
+--storage-tag-check
+</dt>
+<dd>
+<p>
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dd>
+<p>
+ Ignore namespace is currently busy and performed the operation
+ even though.
+</p>
+</dd>
+<dt class="hdlist1">
+-o &lt;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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">
+-v
+</dt>
+<dt class="hdlist1">
+--verbose
+</dt>
+<dd>
+<p>
+ Increase the information detail in the output.
+</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
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write.txt b/Documentation/nvme-write.txt
new file mode 100644
index 0000000..af5340e
--- /dev/null
+++ b/Documentation/nvme-write.txt
@@ -0,0 +1,166 @@
+nvme-write(1)
+=============
+
+NAME
+----
+nvme-write - Send an NVMe write command, provide results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-write' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--data-size=<size> | -z <size>]
+ [--metadata-size=<size> | -y <size>]
+ [--ref-tag=<reftag> | -r <reftag>]
+ [--data=<data-file> | -d <data-file>]
+ [--metadata=<metadata-file> | -M <metadata-file>]
+ [--prinfo=<prinfo> | -p <prinfo>]
+ [--app-tag-mask=<appmask> | -m <appmask>]
+ [--app-tag=<apptag> | -a <apptag>]
+ [--limited-retry | -l] [--force-unit-access | -f]
+ [--dir-type=<type> | -T <type>]
+ [--dir-spec=<spec> | -S <spec>] [--dsm=<dsm> | -D <dsm>]
+ [--show-command | -V] [--dry-run | -w] [--latency | -t]
+ [--storage-tag<storage-tag> | -g <storage-tag>]
+ [--storage-tag-check | -C] [--force]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+The Write 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.
+
+OPTIONS
+-------
+-s <slba>::
+--start-block=<slba>::
+ Start block.
+
+-c::
+--block-count::
+ The number of blocks to transfer. This is a zeroes based value to
+ align with the kernel's use of this field. (ie. 0 means transfer
+ 1 block).
+
+-z <size>::
+--data-size=<size>::
+ Size of data, in bytes.
+
+-y <size>::
+--metadata-size=<size>::
+ Size of metadata in bytes.
+
+-d <data-file>::
+--data=<data-file>::
+ Data file. If none provided, contents are sent from STDIN.
+
+-M <metadata-file>::
+--metadata=<metadata-file>::
+ Metadata file, if necessary.
+
+-p <prinfo>::
+--prinfo=<prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+-r <reftag>::
+--ref-tag=<reftag>::
+ Optional reftag when used with protection information.
+
+-m <appmask>::
+--app-tag-mask=<appmask>::
+ Optional application tag mask when used with protection information.
+
+-a <apptag>::
+--app-tag=<apptag>::
+ Optional application tag when used with protection information.
+
+-l::
+--limited-retry::
+ Sets the limited retry flag.
+
+-f::
+--force-unit-access::
+ Set the force-unit access flag.
+
+-T <type>::
+--dir-type=<type>::
+ Optional directive type. The nvme-cli only enforces the value
+ be in the defined range for the directive type, though the NVMe
+ specification (1.3a) defines only one directive, 01h, for write
+ stream identifiers.
+
+-S <spec>::
+--dir-spec=<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.
+
+-D <dsm>::
+--dsm=<dsm>::
+ The optional data set management attributes for this command. The argument
+ for this is the least significant 8 bits of the DSM field in a write
+ command; the most significant 16 bits of the field come from the directive
+ specific field, if used. This may be used to set attributes for
+ the LBAs being written, like access frequency, type, latency,
+ among other things, as well as yet to be defined types. Please
+ consult the NVMe specification for detailed breakdown of how to
+ use this field.
+
+-V::
+--show-cmd::
+ Print out the command to be sent.
+
+-w::
+--dry-run::
+ Do not actually send the command. If want to use --dry-run option,
+ --show-cmd option _must_ be set. Otherwise --dry-run option will be
+ _ignored_.
+
+-t::
+--latency::
+ Print out the latency the IOCTL took (in us).
+
+-g <storage-tag>::
+--storage-tag=<storage-tag>::
+ Variable Sized Expected Logical Block Storage Tag(ELBST).
+
+-C::
+--storage-tag-check::
+ This flag enables Storage Tag field checking as part of end-to-end
+ data protection processing.
+
+--force::
+ Ignore namespace is currently busy and performed the operation
+ even though.
+
+-o <fmt>::
+--output-format=<fmt>::
+ Set the reporting format to 'normal', 'json' or 'binary'. Only one
+ output format can be used at a time.
+
+-v::
+--verbose::
+ Increase the information detail in the output.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-zns-changed-zone-list.1 b/Documentation/nvme-zns-changed-zone-list.1
new file mode 100644
index 0000000..2617f59
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.1
@@ -0,0 +1,104 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-CHANGED\-" "1" "02/14/2024" "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> [\-\-output\-format=<fmt> | \-o <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 <fmt>, \-\-output\-format=<fmt>
+.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..a52942e
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.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 10.2.0" />
+<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 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-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; [--output-format=&lt;fmt&gt; | -o &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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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
+ 2024-02-14 10:43:42 CET
+</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..ad447ce
--- /dev/null
+++ b/Documentation/nvme-zns-changed-zone-list.txt
@@ -0,0 +1,53 @@
+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> [--output-format=<fmt> | -o <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 <fmt>::
+--output-format=<fmt>::
+ 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..6443d0b
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.1
@@ -0,0 +1,90 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-CLOSE\-ZO" "1" "02/14/2024" "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\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..55e4312
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<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 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-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</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]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"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>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..92c8590
--- /dev/null
+++ b/Documentation/nvme-zns-close-zone.txt
@@ -0,0 +1,54 @@
+nvme-zns-close-zone(1)
+======================
+
+NAME
+----
+nvme-zns-close-zone - Closes one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns close-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+ [--timeout=<timeout> | -t <timeout>]
+
+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
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..de7f76a
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.1
@@ -0,0 +1,90 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-FINISH\-Z" "1" "02/14/2024" "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\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..ef7bcb8
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.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 10.2.0" />
+<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 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-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</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]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"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>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..2820fd5
--- /dev/null
+++ b/Documentation/nvme-zns-finish-zone.txt
@@ -0,0 +1,55 @@
+nvme-zns-finish-zone(1)
+=======================
+
+NAME
+----
+nvme-zns-finish-zone - Finishes one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns finish-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+ [--timeout=<timeout> | -t <timeout>]
+
+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.
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..4a95484
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ID\-CTRL" "1" "02/14/2024" "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> [\-\-output\-format=<fmt> | \-o <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 <fmt>, \-\-output\-format=<fmt>
+.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..16b8914
--- /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 10.2.0" />
+<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 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-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; [--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 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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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
+ 2024-02-14 10:43:42 CET
+</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..0057159
--- /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> [--output-format=<fmt> | -o <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 <fmt>::
+--output-format=<fmt>::
+ 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..61d57b8
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.1
@@ -0,0 +1,109 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ID\-NS" "1" "02/14/2024" "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 namespace, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns id\-ns\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-output\-format=<fmt> | \-o <fmt>] [\-\-verbose | \-v]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends the zoned command set\(cqs identify namespace 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 <fmt>, \-\-output\-format=<fmt>
+.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..f099014
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<title>nvme-zns-id-ns(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-zns-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-id-ns -
+ Send NVMe Zoned Command Set Identify namespace, 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-ns</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;] [--verbose | -v]</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 namespace
+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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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-ns /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
+ 2024-02-14 10:43:42 CET
+</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..c22b5c7
--- /dev/null
+++ b/Documentation/nvme-zns-id-ns.txt
@@ -0,0 +1,61 @@
+nvme-zns-id-ns(1)
+=================
+
+NAME
+----
+nvme-zns-id-ns - Send NVMe Zoned Command Set Identify namespace, return result
+and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns id-ns' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--output-format=<fmt> | -o <fmt>] [--verbose | -v]
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends the zoned command set's identify namespace
+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 <fmt>::
+--output-format=<fmt>::
+ 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..974a77b
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.1
@@ -0,0 +1,90 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-OFFLINE\-" "1" "02/14/2024" "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\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>]
+ [\-\-select\-all | \-a]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..cb4bd39
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.html
@@ -0,0 +1,853 @@
+<?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 10.2.0" />
+<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 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-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</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]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"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>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..580a1e6
--- /dev/null
+++ b/Documentation/nvme-zns-offline-zone.txt
@@ -0,0 +1,54 @@
+nvme-zns-offline-zone(1)
+========================
+
+NAME
+----
+nvme-zns-offline-zone - Offlines one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns offline-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>]
+ [--select-all | -a]
+ [--timeout=<timeout> | -t <timeout>]
+
+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
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..6831611
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.1
@@ -0,0 +1,94 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-OPEN\-ZON" "1" "02/14/2024" "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\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<LBA> | \-s <LBA>] [\-\-zrwaa | \-r]
+ [\-\-select\-all | \-a] [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+\-r, \-\-zrwaa
+.RS 4
+Allocate Zone Random Write Area to zone
+.RE
+.PP
+\-a, \-\-select\-all
+.RS 4
+Select all zones for this action
+.RE
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..3db2fcc
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.html
@@ -0,0 +1,863 @@
+<?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 10.2.0" />
+<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 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-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</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;LBA&gt; | -s &lt;LBA&gt;] [--zrwaa | -r]
+ [--select-all | -a] [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"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">
+-r
+</dt>
+<dt class="hdlist1">
+--zrwaa
+</dt>
+<dd>
+<p>
+ Allocate Zone Random Write Area to zone
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</dt>
+<dd>
+<p>
+ Select all zones for this action
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..4639bcc
--- /dev/null
+++ b/Documentation/nvme-zns-open-zone.txt
@@ -0,0 +1,57 @@
+nvme-zns-open-zone(1)
+======================
+
+NAME
+----
+nvme-zns-open-zone - Opens one or all zones
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns open-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<LBA> | -s <LBA>] [--zrwaa | -r]
+ [--select-all | -a] [--timeout=<timeout> | -t <timeout>]
+
+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.
+
+-r::
+--zrwaa::
+ Allocate Zone Random Write Area to zone
+
+-a::
+--select-all::
+ Select all zones for this action
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..37b60a6
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-REPORT\-Z" "1" "02/14/2024" "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 <fmt>, \-\-output\-format=<fmt>
+.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..2b12d87
--- /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 10.2.0" />
+<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 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-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;fmt&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;fmt&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
+ 2024-02-14 10:43:42 CET
+</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..23dd6b4
--- /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 <fmt>::
+--output-format=<fmt>::
+ 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..51cb758
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.1
@@ -0,0 +1,90 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-RESET\-ZO" "1" "02/14/2024" "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]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..695b06c
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.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 10.2.0" />
+<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 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-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]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"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>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..b58f276
--- /dev/null
+++ b/Documentation/nvme-zns-reset-zone.txt
@@ -0,0 +1,55 @@
+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]
+ [--timeout=<timeout> | -t <timeout>]
+
+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
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..36de5fb
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.1
@@ -0,0 +1,94 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-SET\-ZONE" "1" "02/14/2024" "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 set\-zone\-desc\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-start\-lba=<IONUM>, \-s <IONUM>]
+ [\-\-zrwaa | \-r]
+ [\-\-data=<FILE>, \-d <FILE>]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the Set Zone Descriptor Extensions 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 namespace\&.
+.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
+\-r, \-\-zrwaa
+.RS 4
+Allocate Zone Random Write Area to zone\&.
+.RE
+.PP
+\-d <FILE>, \-\-data=<FILE>
+.RS 4
+Optional file for data (default stdin)
+.RE
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..53e41d6
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.html
@@ -0,0 +1,866 @@
+<?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 10.2.0" />
+<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 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-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 set-zone-desc</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--start-lba=&lt;IONUM&gt;, -s &lt;IONUM&gt;]
+ [--zrwaa | -r]
+ [--data=&lt;FILE&gt;, -d &lt;FILE&gt;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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 Extensions 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 namespace.</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">
+-r
+</dt>
+<dt class="hdlist1">
+--zrwaa
+</dt>
+<dd>
+<p>
+ Allocate Zone Random Write Area to zone.
+</p>
+</dd>
+<dt class="hdlist1">
+-d &lt;FILE&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Optional file for data (default stdin)
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..3df8c4b
--- /dev/null
+++ b/Documentation/nvme-zns-set-zone-desc.txt
@@ -0,0 +1,59 @@
+nvme-zns-set-zone-desc(1)
+=========================
+
+NAME
+----
+nvme-zns-set-zone-desc - Set extended descriptor data for a zone
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns set-zone-desc' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--start-lba=<IONUM>, -s <IONUM>]
+ [--zrwaa | -r]
+ [--data=<FILE>, -d <FILE>]
+ [--timeout=<timeout> | -t <timeout>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+Set Zone Descriptor Extensions 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 namespace.
+
+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.
+
+-r::
+--zrwaa::
+ Allocate Zone Random Write Area to zone.
+
+-d <FILE>::
+--data=<FILE>::
+ Optional file for data (default stdin)
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..fc226b7
--- /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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-APP" "1" "02/14/2024" "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 success, 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..ff514b9
--- /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 10.2.0" />
+<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 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-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 success, 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
+ 2024-02-14 10:43:42 CET
+</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..65e0fb2
--- /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 success, 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..4fa0f98
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.1
@@ -0,0 +1,119 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-MGM" "1" "02/14/2024" "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
+\-l <NUM> \-\-data\-len=<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..0cc2274
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.html
@@ -0,0 +1,887 @@
+<?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 10.2.0" />
+<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 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-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>-l &lt;NUM&gt;
+--data-len=&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
+ 2024-02-14 10:43:42 CET
+</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..5a3e2a3
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-recv.txt
@@ -0,0 +1,76 @@
+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.
+
+-l <NUM>
+--data-len=<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..9de56a2
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.1
@@ -0,0 +1,136 @@
+'\" 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: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZONE\-MGM" "1" "02/14/2024" "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>] [\-\-zsaso, \-o]
+ [\-\-select\-all, \-a] [\-\-zsa=<NUM>, \-z <NUM>]
+ [\-\-data\-len=<IONUM>, \-l <IONUM>]
+ [\-\-data=<FILE>, \-d <FILE>]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+.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
+\-o, \-\-zsaso
+.RS 4
+Zone Send Action Specific Option
+.RE
+.PP
+\-a, \-\-select\-all
+.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
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.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..1300db2
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.html
@@ -0,0 +1,921 @@
+<?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 10.2.0" />
+<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 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-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;] [--zsaso, -o]
+ [--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;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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">
+-o
+</dt>
+<dt class="hdlist1">
+--zsaso
+</dt>
+<dd>
+<p>
+ Zone Send Action Specific Option
+</p>
+</dd>
+<dt class="hdlist1">
+-a
+</dt>
+<dt class="hdlist1">
+--select-all
+</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&gt;
+</dt>
+<dt class="hdlist1">
+--data=&lt;FILE&gt;
+</dt>
+<dd>
+<p>
+ Optional file for data (default stdin)
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</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
+ 2024-02-14 10:43:42 CET
+</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..3803d27
--- /dev/null
+++ b/Documentation/nvme-zns-zone-mgmt-send.txt
@@ -0,0 +1,84 @@
+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>] [--zsaso, -o]
+ [--select-all, -a] [--zsa=<NUM>, -z <NUM>]
+ [--data-len=<IONUM>, -l <IONUM>]
+ [--data=<FILE>, -d <FILE>]
+ [--timeout=<timeout> | -t <timeout>]
+
+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
+
+-o::
+--zsaso::
+ Zone Send Action Specific Option
+
+-a::
+--select-all::
+ 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)
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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-zns-zrwa-flush-zone.1 b/Documentation/nvme-zns-zrwa-flush-zone.1
new file mode 100644
index 0000000..fb88210
--- /dev/null
+++ b/Documentation/nvme-zns-zrwa-flush-zone.1
@@ -0,0 +1,84 @@
+'\" t
+.\" Title: nvme-zns-zrwa-flush-zone
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 12/13/2021
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZNS\-ZRWA\-FLU" "1" "12/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-zns-zrwa-flush-zone \- Flush LBAs associated with a ZRWA to a zone
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme zns zrwa\-flush\-zone\fR <device> [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-lba=<LBA> | \-l <LBA>]
+ [\-\-timeout=<timeout> | \-t <timeout> ]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, issues the Zone Management Send command with the "flush Zone" action\&. This will flush the zone that is opened as zone random write area\&.
+.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
+\-l <lba>, \-\-lba=<lba>
+.RS 4
+The LBA to flush up to\&.
+.RE
+.PP
+\-t <timeout>, \-\-timeout=<timeout>
+.RS 4
+Override default timeout value\&. In milliseconds\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+flush the first zwra of first zone for zrwacg(15) on namespace 1:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme zns zrwa\-flush\-zone /dev/nvme0 \-n 1 \-l 15
+.fi
+.if n \{\
+.RE
+.\}
+.RE
+.SH "NVME"
+.sp
+Part of nvme\-cli
diff --git a/Documentation/nvme-zns-zrwa-flush-zone.html b/Documentation/nvme-zns-zrwa-flush-zone.html
new file mode 100644
index 0000000..38a013f
--- /dev/null
+++ b/Documentation/nvme-zns-zrwa-flush-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" />
+<title>nvme-zns-zrwa-flush-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 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-zns-zrwa-flush-zone(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-zns-zrwa-flush-zone -
+ Flush LBAs associated with a ZRWA to 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 zrwa-flush-zone</em> &lt;device&gt; [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--lba=&lt;LBA&gt; | -l &lt;LBA&gt;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&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
+"flush Zone" action. This will flush the zone that is opened as
+zone random write area.</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">
+-l &lt;lba&gt;
+</dt>
+<dt class="hdlist1">
+--lba=&lt;lba&gt;
+</dt>
+<dd>
+<p>
+ The LBA to flush up to.
+</p>
+</dd>
+<dt class="hdlist1">
+-t &lt;timeout&gt;
+</dt>
+<dt class="hdlist1">
+--timeout=&lt;timeout&gt;
+</dt>
+<dd>
+<p>
+ Override default timeout value. In milliseconds.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+flush the first zwra of first zone for zrwacg(15) on namespace 1:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme zns zrwa-flush-zone /dev/nvme0 -n 1 -l 15</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-12-13 19:30:31 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-zns-zrwa-flush-zone.txt b/Documentation/nvme-zns-zrwa-flush-zone.txt
new file mode 100644
index 0000000..e8f61ed
--- /dev/null
+++ b/Documentation/nvme-zns-zrwa-flush-zone.txt
@@ -0,0 +1,50 @@
+nvme-zns-zrwa-flush-zone(1)
+===========================
+
+NAME
+----
+nvme-zns-zrwa-flush-zone - Flush LBAs associated with a ZRWA to a zone
+
+SYNOPSIS
+--------
+[verse]
+'nvme zns zrwa-flush-zone' <device> [--namespace-id=<NUM> | -n <NUM>]
+ [--lba=<LBA> | -l <LBA>]
+ [--timeout=<timeout> | -t <timeout>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, issues the Zone Management Send command with the
+"flush Zone" action. This will flush the zone that is opened as
+zone random write area.
+
+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.
+
+-l <lba>::
+--lba=<lba>::
+ The LBA to flush up to.
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+EXAMPLES
+--------
+* flush the first zrwa of first zone for zrwacg(15) on namespace 1:
++
+------------
+# nvme zns zrwa-flush-zone /dev/nvme0 -n 1 -l 15
+------------
+
+NVME
+----
+Part of nvme-cli
diff --git a/Documentation/nvme.1 b/Documentation/nvme.1
new file mode 100644
index 0000000..ba7ef23
--- /dev/null
+++ b/Documentation/nvme.1
@@ -0,0 +1,886 @@
+'\" t
+.\" Title: nvme
+.\" Author: [see the "Authors" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 02/14/2024
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME" "1" "02/14/2024" "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 \- the NVMe storage command line interface utility (nvme\-cli)
+.SH "SYNOPSIS"
+.sp
+built\-in plugin:
+.sp
+.nf
+\fInvme\fR <command> <device> [<args>]
+.fi
+.sp
+extension plugins:
+.sp
+.nf
+\fInvme\fR <plugin> <command> <device> [<args>]
+.fi
+.SH "DESCRIPTION"
+.sp
+NVM\-Express is a fast, scalable host controller interface designed to address the needs for not only PCI Express based solid state drives, but also NVMe\-oF(over fabrics)\&.
+.sp
+This \fInvme\fR program is a user space utility to provide standards compliant tooling for NVM\-Express drives\&. It was made specifically for Linux as it relies on the IOCTLs defined by the mainline kernel driver\&.
+.SH "NVME COMMANDS"
+.sp
+The utility has sub\-commands for all admin and io commands defined in the specification and for displaying controller registers\&. There is also an option to submit completely arbitrary commands\&. For a list of commands available, run "nvme help"\&.
+.SH "NVME CLI SUB\-COMMANDS"
+.SS "Main commands"
+.PP
+\fBnvme-admin-passthru\fR(1)
+.RS 4
+Admin Passthrough Command
+.RE
+.PP
+\fBnvme-compare\fR(1)
+.RS 4
+IO Compare
+.RE
+.PP
+\fBnvme-error-log\fR(1)
+.RS 4
+Retrieve error logs
+.RE
+.PP
+\fBnvme-flush\fR(1)
+.RS 4
+Submit flush
+.RE
+.PP
+\fBnvme-dsm\fR(1)
+.RS 4
+Submit Data Set Management
+.RE
+.PP
+\fBnvme-format\fR(1)
+.RS 4
+Format namespace(s)
+.RE
+.PP
+\fBnvme-fw-activate\fR(1)
+.RS 4
+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)
+.RS 4
+F/W Download
+.RE
+.PP
+\fBnvme-fw-log\fR(1)
+.RS 4
+Retrieve f/w log
+.RE
+.PP
+\fBnvme-get-feature\fR(1)
+.RS 4
+Get Features
+.RE
+.PP
+\fBnvme-get-log\fR(1)
+.RS 4
+Generic Get Log
+.RE
+.PP
+\fBnvme-telemetry-log\fR(1)
+.RS 4
+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
+Retrieve ANA(Asymmetric Namespace Access) Log
+.RE
+.PP
+\fBnvme-endurance-log\fR(1)
+.RS 4
+Retrieve endurance Log
+.RE
+.PP
+\fBnvme-effects-log\fR(1)
+.RS 4
+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
+.RE
+.PP
+\fBnvme-help\fR(1)
+.RS 4
+NVMe CLI Help
+.RE
+.PP
+\fBnvme-id-ctrl\fR(1)
+.RS 4
+Identify Controller
+.RE
+.PP
+\fBnvme-id-ns\fR(1)
+.RS 4
+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
+.RE
+.PP
+\fBnvme-delete-ns\fR(1)
+.RS 4
+Delete existing namespace
+.RE
+.PP
+\fBnvme-attach-ns\fR(1)
+.RS 4
+Attach namespace
+.RE
+.PP
+\fBnvme-detach-ns\fR(1)
+.RS 4
+Detach namespace
+.RE
+.PP
+\fBnvme-io-passthru\fR(1)
+.RS 4
+IO Passthrough Command
+.RE
+.PP
+\fBnvme-list-ns\fR(1)
+.RS 4
+List all nvme namespaces
+.RE
+.PP
+\fBnvme-ns-descs\fR(1)
+.RS 4
+Identify Namespace Identification Descriptor
+.RE
+.PP
+\fBnvme-list\fR(1)
+.RS 4
+List all nvme controllers
+.RE
+.PP
+\fBnvme-list-ctrl\fR(1)
+.RS 4
+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
+.RE
+.PP
+\fBnvme-write\fR(1)
+.RS 4
+Issue IO Write Command
+.RE
+.PP
+\fBnvme-write-zeroes\fR(1)
+.RS 4
+Issue IO Write Zeroes Command
+.RE
+.PP
+\fBnvme-write-uncor\fR(1)
+.RS 4
+Issue IO Write Uncorrectable Command
+.RE
+.PP
+\fBnvme-resv-acquire\fR(1)
+.RS 4
+Acquire Namespace Reservation
+.RE
+.PP
+\fBnvme-resv-register\fR(1)
+.RS 4
+Register Namespace Reservation
+.RE
+.PP
+\fBnvme-resv-release\fR(1)
+.RS 4
+Release Namespace Reservation
+.RE
+.PP
+\fBnvme-resv-report\fR(1)
+.RS 4
+Report Reservation Capabilities
+.RE
+.PP
+\fBnvme-security-recv\fR(1)
+.RS 4
+Security Receive
+.RE
+.PP
+\fBnvme-security-send\fR(1)
+.RS 4
+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
+.RE
+.PP
+\fBnvme-show-regs\fR(1)
+.RS 4
+Show NVMe Controller Registers
+.RE
+.PP
+\fBnvme-discover\fR(1)
+.RS 4
+Send Get Log Page request to Discovery Controller
+.RE
+.PP
+\fBnvme-connect-all\fR(1)
+.RS 4
+Discover and connect to all NVMe\-over\-Fabrics subsystems
+.RE
+.PP
+\fBnvme-connect\fR(1)
+.RS 4
+Connect to an NVMe\-over\-Fabrics subsystem
+.RE
+.PP
+\fBnvme-dim\fR(1)
+.RS 4
+Send Discovery Information Management command to a Discovery Controller
+.RE
+.PP
+\fBnvme-disconnect\fR(1)
+.RS 4
+Disconnect from an NVMe\-over\-Fabrics subsystem
+.RE
+.PP
+\fBnvme-disconnect-all\fR(1)
+.RS 4
+Disconnect from all NVMe\-over\-Fabrics subsystems
+.RE
+.PP
+\fBnvme-get-property\fR(1)
+.RS 4
+Reads and shows NVMe\-over\-Fabrics controller property
+.RE
+.PP
+\fBnvme-media-unit-stat-log\fR(1)
+.RS 4
+Retrieve and show the configuration and wear of media units
+.RE
+.PP
+\fBnvme-supported-cap-config-log\fR(1)
+.RS 4
+Retrieve and show the list of Supported Capacity Configuration Descriptors
+.RE
+.PP
+\fBnvme-boot-part-log\fR(1)
+.RS 4
+Retrieve Boot Partition Log
+.RE
+.PP
+\fBnvme-capacity-mgmt\fR(1)
+.RS 4
+Capacity Management Command
+.RE
+.PP
+\fBnvme-check-dhchap-key\fR(1)
+.RS 4
+Generate NVMeoF DH\-HMAC\-CHAP host key
+.RE
+.PP
+\fBnvme-check-tls-key\fR(1)
+.RS 4
+Validate NVMeoF TLS PSK
+.RE
+.PP
+\fBnvme-cmdset-ind-id-ns\fR(1)
+.RS 4
+I/O Command Set Independent Identify Namespace
+.RE
+.PP
+\fBnvme-endurance-event-agg-log\fR(1)
+.RS 4
+Retrieve Endurance Group Event Aggregate Log
+.RE
+.PP
+\fBnvme-fid-support-effects-log\fR(1)
+.RS 4
+Retrieve FID Support and Effects log
+.RE
+.PP
+\fBnvme-gen-dhchap-key\fR(1)
+.RS 4
+Generate NVMeoF DH\-HMAC\-CHAP host key
+.RE
+.PP
+\fBnvme-gen-hostnqn\fR(1)
+.RS 4
+Generate NVMeoF host NQN
+.RE
+.PP
+\fBnvme-gen-tls-key\fR(1)
+.RS 4
+Generate NVMeoF TLS PSK
+.RE
+.PP
+\fBnvme-get-lba-status\fR(1)
+.RS 4
+Get LBA Status command
+.RE
+.PP
+\fBnvme-id-domain\fR(1)
+.RS 4
+NVMe Identify Domain List
+.RE
+.PP
+\fBnvme-id-ns-lba-format\fR(1)
+.RS 4
+NVMe Identify Namespace for the specified LBA Format index
+.RE
+.PP
+\fBnvme-lba-status-log\fR(1)
+.RS 4
+Retrieve LBA Status Information Log
+.RE
+.PP
+\fBnvme-list-endgrp\fR(1)
+.RS 4
+NVMe Identify Endurance Group List
+.RE
+.PP
+\fBnvme-ns-rescan\fR(1)
+.RS 4
+Rescans the NVME namespaces
+.RE
+.PP
+\fBnvme-nvm-id-ctrl\fR(1)
+.RS 4
+NVMe Identify Controller NVM Command Set
+.RE
+.PP
+\fBnvme-nvm-id-ns\fR(1)
+.RS 4
+NVMe Identify Namespace NVM Command Set
+.RE
+.PP
+\fBnvme-nvm-id-ns-lba-format\fR(1)
+.RS 4
+NVMe Identify Namespace NVM Command Set for the specified LBA Format index
+.RE
+.PP
+\fBnvme-persistent-event-log\fR(1)
+.RS 4
+Retrieve Persistent Event Log
+.RE
+.PP
+\fBnvme-predictable-lat-log\fR(1)
+.RS 4
+Retrieve Predictable Latency per Nvmset Log
+.RE
+.PP
+\fBnvme-pred-lat-event-agg-log\fR(1)
+.RS 4
+Retrieve Predictable Latency Event Aggregate Log
+.RE
+.PP
+\fBnvme-primary-ctrl-caps\fR(1)
+.RS 4
+NVMe Identify Primary Controller Capabilities
+.RE
+.PP
+\fBnvme-reset\fR(1)
+.RS 4
+Resets the controller
+.RE
+.PP
+\fBnvme-rpmb\fR(1)
+.RS 4
+Replay Protection Memory Block commands
+.RE
+.PP
+\fBnvme-sanitize-log\fR(1)
+.RS 4
+Retrieve sanitize log
+.RE
+.PP
+\fBnvme-set-property\fR(1)
+.RS 4
+Set a property and show the resulting value
+.RE
+.PP
+\fBnvme-show-hostnqn\fR(1)
+.RS 4
+Show NVMeoF host NQN
+.RE
+.PP
+\fBnvme-subsystem-reset\fR(1)
+.RS 4
+Resets the subsystem
+.RE
+.PP
+\fBnvme-supported-log-pages\fR(1)
+.RS 4
+Retrieve the Supported Log pages details
+.RE
+.PP
+\fBnvme-verify\fR(1)
+.RS 4
+verify command
+.RE
+.PP
+\fBnvme-show-topology\fR(1)
+.RS 4
+Show NVMe topology
+.RE
+.SS "Plugins/Vendor extension commands"
+.PP
+\fBnvme-intel-id-ctrl\fR(1)
+.RS 4
+Intel \- NVMe Identify Controller
+.RE
+.PP
+\fBnvme-intel-internal-log\fR(1)
+.RS 4
+Retrieve Intel device\(cqs internal log and save to file
+.RE
+.PP
+\fBnvme-intel-lat-stats\fR(1)
+.RS 4
+Retrieve NVMe Identify Controller, return result and structure
+.RE
+.PP
+\fBnvme-intel-market-name\fR(1)
+.RS 4
+Intel vendor specific marketing name log page
+.RE
+.PP
+\fBnvme-intel-smart-log-add\fR(1)
+.RS 4
+NVMe Intel Additional SMART log page
+.RE
+.PP
+\fBnvme-intel-temp-stats\fR(1)
+.RS 4
+NVMe Intel Additional SMART log page for temp stats
+.RE
+.PP
+\fBnvme-huawei-id-ctrl\fR(1)
+.RS 4
+NVMe huawei Identify Controller
+.RE
+.PP
+\fBnvme-huawei-list\fR(1)
+.RS 4
+List all recognized Huawei NVMe devices
+.RE
+.PP
+\fBnvme-dera-stat\fR(1)
+.RS 4
+NVMe Dera Device status and Additional SMART log page request
+.RE
+.PP
+\fBnvme-micron-clear-pcie-errors\fR(1)
+.RS 4
+Clears correctable PCIe correctable errors of given Micron device
+.RE
+.PP
+\fBnvme-micron-internal-log\fR(1)
+.RS 4
+Retrieve Micron device\(cqs internal logs and save to given zip file
+.RE
+.PP
+\fBnvme-micron-nand-stats\fR(1)
+.RS 4
+Retrieves NAND statistics of given micron device
+.RE
+.PP
+\fBnvme-micron-pcie-stats\fR(1)
+.RS 4
+Retrieves pcie error statistics for given micron device
+.RE
+.PP
+\fBnvme-micron-selective-download\fR(1)
+.RS 4
+Performs selective firmware download
+.RE
+.PP
+\fBnvme-micron-smart-add-log\fR(1)
+.RS 4
+Retrieves NAND statistics
+.RE
+.PP
+\fBnvme-micron-temperature-stats\fR(1)
+.RS 4
+Retrieves temperature information of given micron device
+.RE
+.PP
+\fBnvme-netapp-ontapdevices\fR(1)
+.RS 4
+Display information about ONTAP devices
+.RE
+.PP
+\fBnvme-netapp-smdevices\fR(1)
+.RS 4
+Display information for each NVMe path to an E\-Series volume
+.RE
+.PP
+\fBnvme-toshiba-clear-pcie-correctable-errors\fR(1)
+.RS 4
+Reset the PCIe correctable errors count to zero
+.RE
+.PP
+\fBnvme-toshiba-vs-internal-log\fR(1)
+.RS 4
+Retrieve a Toshiba device\(cqs vendor specific internal log
+.RE
+.PP
+\fBnvme-toshiba-vs-smart-add-log\fR(1)
+.RS 4
+Retrieve a Toshiba device\(cqs vendor specific extended SMART log page
+.RE
+.PP
+\fBnvme-transcend-badblock\fR(1)
+.RS 4
+Retrieve Transcend NVMe device\(cqs bad blocks
+.RE
+.PP
+\fBnvme-transcend-healthvalue\fR(1)
+.RS 4
+Use NVMe SMART table to analyze the health value of Transcend device
+.RE
+.PP
+\fBnvme-virtium-show-identify\fR(1)
+.RS 4
+Show a complete detail of identify device information in json format
+.RE
+.PP
+\fBnvme-virtium-save-smart-to-vtview-log\fR(1)
+.RS 4
+Periodically save smart attributes into a log file
+.RE
+.PP
+\fBnvme-wdc-cap-diag\fR(1)
+.RS 4
+Retrieve WDC device\(cqs diagnostic log and save to file
+.RE
+.PP
+\fBnvme-wdc-capabilities\fR(1)
+.RS 4
+Display WDC plugin command capabilities
+.RE
+.PP
+\fBnvme-wdc-clear-assert-dump\fR(1)
+.RS 4
+Clears the assert dump (if present)
+.RE
+.PP
+\fBnvme-wdc-clear-fw-activate-history\fR(1)
+.RS 4
+Clears the firmware activate history table
+.RE
+.PP
+\fBnvme-wdc-clear-pcie-corr\fR(1)
+.RS 4
+Clears the pcie correctable errors field
+.RE
+.PP
+\fBnvme-wdc-clear-pcie-correctable-errors\fR(1)
+.RS 4
+Clears the pcie correctable errors returned in the smart\-log\-add command
+.RE
+.PP
+\fBnvme-wdc-cloud-SSD-plugin-version\fR(1)
+.RS 4
+Display WDC plugin Cloud SSD Plugin Version
+.RE
+.PP
+\fBnvme-wdc-drive-essentials\fR(1)
+.RS 4
+Retrieve WDC device\(cqs drive essentials bin files
+.RE
+.PP
+\fBnvme-wdc-drive-log\fR(1)
+.RS 4
+Retrieve WDC device\(cqs drive log and save to file
+.RE
+.PP
+\fBnvme-wdc-drive-resize\fR(1)
+.RS 4
+Send NVMe WDC Resize Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-enc-get-log\fR(1)
+.RS 4
+Send NVMe WDC enc\-get\-log Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-get-crash-dump\fR(1)
+.RS 4
+Retrieve WDC device\(cqs crash dump
+.RE
+.PP
+\fBnvme-wdc-get-drive-status\fR(1)
+.RS 4
+Send the NVMe WDC get\-drive\-status command
+.RE
+.PP
+\fBnvme-wdc-get-latency-monitor-log\fR(1)
+.RS 4
+Display latency monitor log page data in human readable format
+.RE
+.PP
+\fBnvme-wdc-get-pfail-dump\fR(1)
+.RS 4
+Retrieve WDC device\(cqs pfail crash dump
+.RE
+.PP
+\fBnvme-wdc-id-ctrl\fR(1)
+.RS 4
+Send NVMe Identify Controller, return result and structure
+.RE
+.PP
+\fBnvme-wdc-log-page-directory\fR(1)
+.RS 4
+Retrieves the list of Log IDs supported by the drive
+.RE
+.PP
+\fBnvme-wdc-namespace-resize\fR(1)
+.RS 4
+Resizes the device\(cqs namespace
+.RE
+.PP
+\fBnvme-wdc-purge-monitor\fR(1)
+.RS 4
+Send NVMe WDC Purge\-Monitor Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-purge\fR(1)
+.RS 4
+Send NVMe WDC Purge Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-smart-add-log\fR(1)
+.RS 4
+Send NVMe WDC smart add log Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-vs-drive-info\fR(1)
+.RS 4
+Send the NVMe WDC vs\-drive\-info command
+.RE
+.PP
+\fBnvme-wdc-vs-error-reason-identifier\fR(1)
+.RS 4
+Retrieve WDC device\(cqs telemetry log error reason identifier field
+.RE
+.PP
+\fBnvme-wdc-vs-fw-activate-history\fR(1)
+.RS 4
+Execute NVMe WDC vs\-fw\-activate\-history Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-vs-internal-log\fR(1)
+.RS 4
+Retrieve WDC device\(cqs internal firmware log and save to file
+.RE
+.PP
+\fBnvme-wdc-vs-nand-stats\fR(1)
+.RS 4
+Send NVMe WDC vs\-nand\-stats Vendor Unique Command
+.RE
+.PP
+\fBnvme-wdc-vs-telemetry-controller-option\fR(1)
+.RS 4
+Disable/Enable the controller initiated option of the telemetry log page
+.RE
+.PP
+\fBnvme-wdc-vs-temperature-stats\fR(1)
+.RS 4
+Display temperature\-related statistics
+.RE
+.PP
+\fBnvme-zns-changed-zone-list\fR(1)
+.RS 4
+Retrieve Changed Zone log for the given device
+.RE
+.PP
+\fBnvme-zns-close-zone\fR(1)
+.RS 4
+Closes one or all zones
+.RE
+.PP
+\fBnvme-zns-finish-zone\fR(1)
+.RS 4
+Finishes one or all zones
+.RE
+.PP
+\fBnvme-zns-id-ctrl\fR(1)
+.RS 4
+Send NVMe Zoned Command Set Identify Controller
+.RE
+.PP
+\fBnvme-zns-id-ns\fR(1)
+.RS 4
+Send NVMe Zoned Command Set Identify Namespace
+.RE
+.PP
+\fBnvme-zns-offline-zone\fR(1)
+.RS 4
+Offlines one or all zones
+.RE
+.PP
+\fBnvme-zns-open-zone\fR(1)
+.RS 4
+Opens one or all zones
+.RE
+.PP
+\fBnvme-zns-report-zones\fR(1)
+.RS 4
+Retrieve and display the Report Zones data structure
+.RE
+.PP
+\fBnvme-zns-reset-zone\fR(1)
+.RS 4
+Resets one or all zones
+.RE
+.PP
+\fBnvme-zns-set-zone-desc\fR(1)
+.RS 4
+Set extended descriptor data for a zone
+.RE
+.PP
+\fBnvme-zns-zone-append\fR(1)
+.RS 4
+Send an NVMe write command, provide results
+.RE
+.PP
+\fBnvme-zns-zone-mgmt-recv\fR(1)
+.RS 4
+Zone Management Receive command
+.RE
+.PP
+\fBnvme-zns-zone-mgmt-send\fR(1)
+.RS 4
+Zone Management Send command
+.RE
+.PP
+\fBnvme-zns-zrwa-flush-zone\fR(1)
+.RS 4
+Flush LBAs associated with a ZRWA to a zone
+.RE
+.PP
+\fBnvme-inspur-nvme-vendor-log\fR(1)
+.RS 4
+NVMe Inspur Device Vendor log page request
+.RE
+.SH "RETURNS"
+.sp
+All commands will behave the same, they will return 0 on success and 1 on failure\&.
+.SH "FURTHER DOCUMENTATION"
+.sp
+See the freely available references on the \m[blue]\fBOfficial NVM\-Express Site\fR\m[]\&\s-2\u[1]\d\s+2\&.
+.SH "AUTHORS"
+.sp
+This is written and maintained by \m[blue]\fBKeith Busch\fR\m[]\&\s-2\u[2]\d\s+2\&.
+.SH "REPORTING BUGS"
+.sp
+Patches and issues may be submitted to the official repository at \m[blue]\fBhttps://github\&.com/linux\-nvme/nvme\-cli\fR\m[] or the Linux NVMe mailing list \m[blue]\fBlinux\-nvme\fR\m[]\&\s-2\u[3]\d\s+2
+.SH "NVME"
+.sp
+Part of the nvme suite
+.SH "NOTES"
+.IP " 1." 4
+Official NVM-Express Site
+.RS 4
+\%http://nvmexpress.org
+.RE
+.IP " 2." 4
+Keith Busch
+.RS 4
+\%mailto:kbusch@kernel.org
+.RE
+.IP " 3." 4
+linux-nvme
+.RS 4
+\%mailto:linux-nvme@lists.infradead.org
+.RE
diff --git a/Documentation/nvme.html b/Documentation/nvme.html
new file mode 100644
index 0000000..b92d95a
--- /dev/null
+++ b/Documentation/nvme.html
@@ -0,0 +1,2121 @@
+<?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 10.2.0" />
+<title>nvme(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(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme -
+ the NVMe storage command line interface utility (nvme-cli)
+</p>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>built-in plugin:</p></div>
+<div class="verseblock">
+<pre class="content"><em>nvme</em> &lt;command&gt; &lt;device&gt; [&lt;args&gt;]</pre>
+<div class="attribution">
+</div></div>
+<div class="paragraph"><p>extension plugins:</p></div>
+<div class="verseblock">
+<pre class="content"><em>nvme</em> &lt;plugin&gt; &lt;command&gt; &lt;device&gt; [&lt;args&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>NVM-Express is a fast, scalable host controller interface designed to
+address the needs for not only PCI Express based solid state drives, but
+also NVMe-oF(over fabrics).</p></div>
+<div class="paragraph"><p>This <em>nvme</em> program is a user space utility to provide standards compliant
+tooling for NVM-Express drives. It was made specifically for Linux as
+it relies on the IOCTLs defined by the mainline kernel driver.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme_commands">NVME COMMANDS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The utility has sub-commands for all admin and io commands defined in the
+specification and for displaying controller registers. There is also an
+option to submit completely arbitrary commands. For a list of commands
+available, run "nvme help".</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme_cli_sub_commands">nvme cli sub-commands</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_main_commands">Main commands</h3>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<a href="nvme-admin-passthru.html">nvme-admin-passthru(1)</a>
+</dt>
+<dd>
+<p>
+ Admin Passthrough Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-compare.html">nvme-compare(1)</a>
+</dt>
+<dd>
+<p>
+ IO Compare
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-error-log.html">nvme-error-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve error logs
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-flush.html">nvme-flush(1)</a>
+</dt>
+<dd>
+<p>
+ Submit flush
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-dsm.html">nvme-dsm(1)</a>
+</dt>
+<dd>
+<p>
+ Submit Data Set Management
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-format.html">nvme-format(1)</a>
+</dt>
+<dd>
+<p>
+ Format namespace(s)
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-fw-activate.html">nvme-fw-activate(1)</a>
+</dt>
+<dd>
+<p>
+ 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">
+<a href="nvme-fw-download.html">nvme-fw-download(1)</a>
+</dt>
+<dd>
+<p>
+ F/W Download
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-fw-log.html">nvme-fw-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve f/w log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-get-feature.html">nvme-get-feature(1)</a>
+</dt>
+<dd>
+<p>
+ Get Features
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-get-log.html">nvme-get-log(1)</a>
+</dt>
+<dd>
+<p>
+ Generic Get Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-telemetry-log.html">nvme-telemetry-log(1)</a>
+</dt>
+<dd>
+<p>
+ Telemetry Host-Initiated Log
+</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>
+<p>
+ Retrieve Smart Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-ana-log.html">nvme-ana-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve ANA(Asymmetric Namespace Access) Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-endurance-log.html">nvme-endurance-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve endurance Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-effects-log.html">nvme-effects-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve effects Log
+</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>
+<p>
+ Retrieve namespace identifier
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-help.html">nvme-help(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe CLI Help
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-id-ctrl.html">nvme-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ Identify Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-id-ns.html">nvme-id-ns(1)</a>
+</dt>
+<dd>
+<p>
+ Identify Namespace
+</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>
+<p>
+ Create a new namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-delete-ns.html">nvme-delete-ns(1)</a>
+</dt>
+<dd>
+<p>
+ Delete existing namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-attach-ns.html">nvme-attach-ns(1)</a>
+</dt>
+<dd>
+<p>
+ Attach namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-detach-ns.html">nvme-detach-ns(1)</a>
+</dt>
+<dd>
+<p>
+ Detach namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-io-passthru.html">nvme-io-passthru(1)</a>
+</dt>
+<dd>
+<p>
+ IO Passthrough Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-list-ns.html">nvme-list-ns(1)</a>
+</dt>
+<dd>
+<p>
+ List all nvme namespaces
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-ns-descs.html">nvme-ns-descs(1)</a>
+</dt>
+<dd>
+<p>
+ Identify Namespace Identification Descriptor
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-list.html">nvme-list(1)</a>
+</dt>
+<dd>
+<p>
+ List all nvme controllers
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-list-ctrl.html">nvme-list-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ List controller in NVMe subsystem
+</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>
+<p>
+ Issue IO Read Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-write.html">nvme-write(1)</a>
+</dt>
+<dd>
+<p>
+ Issue IO Write Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-write-zeroes.html">nvme-write-zeroes(1)</a>
+</dt>
+<dd>
+<p>
+ Issue IO Write Zeroes Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-write-uncor.html">nvme-write-uncor(1)</a>
+</dt>
+<dd>
+<p>
+ Issue IO Write Uncorrectable Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-resv-acquire.html">nvme-resv-acquire(1)</a>
+</dt>
+<dd>
+<p>
+ Acquire Namespace Reservation
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-resv-register.html">nvme-resv-register(1)</a>
+</dt>
+<dd>
+<p>
+ Register Namespace Reservation
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-resv-release.html">nvme-resv-release(1)</a>
+</dt>
+<dd>
+<p>
+ Release Namespace Reservation
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-resv-report.html">nvme-resv-report(1)</a>
+</dt>
+<dd>
+<p>
+ Report Reservation Capabilities
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-security-recv.html">nvme-security-recv(1)</a>
+</dt>
+<dd>
+<p>
+ Security Receive
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-security-send.html">nvme-security-send(1)</a>
+</dt>
+<dd>
+<p>
+ Security Send
+</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>
+<p>
+ Set Feature
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-show-regs.html">nvme-show-regs(1)</a>
+</dt>
+<dd>
+<p>
+ Show NVMe Controller Registers
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-discover.html">nvme-discover(1)</a>
+</dt>
+<dd>
+<p>
+ Send Get Log Page request to Discovery Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-connect-all.html">nvme-connect-all(1)</a>
+</dt>
+<dd>
+<p>
+ Discover and connect to all NVMe-over-Fabrics subsystems
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-connect.html">nvme-connect(1)</a>
+</dt>
+<dd>
+<p>
+ Connect to an NVMe-over-Fabrics subsystem
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-dim.html">nvme-dim(1)</a>
+</dt>
+<dd>
+<p>
+ Send Discovery Information Management command to a Discovery Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-disconnect.html">nvme-disconnect(1)</a>
+</dt>
+<dd>
+<p>
+ Disconnect from an NVMe-over-Fabrics subsystem
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-disconnect-all.html">nvme-disconnect-all(1)</a>
+</dt>
+<dd>
+<p>
+ Disconnect from all NVMe-over-Fabrics subsystems
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-get-property.html">nvme-get-property(1)</a>
+</dt>
+<dd>
+<p>
+ Reads and shows NVMe-over-Fabrics controller property
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-media-unit-stat-log.html">nvme-media-unit-stat-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve and show the configuration and wear of media units
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-supported-cap-config-log.html">nvme-supported-cap-config-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve and show the list of Supported Capacity Configuration Descriptors
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-boot-part-log.html">nvme-boot-part-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Boot Partition Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-capacity-mgmt.html">nvme-capacity-mgmt(1)</a>
+</dt>
+<dd>
+<p>
+ Capacity Management Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-check-dhchap-key.html">nvme-check-dhchap-key(1)</a>
+</dt>
+<dd>
+<p>
+ Generate NVMeoF DH-HMAC-CHAP host key
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-check-tls-key.html">nvme-check-tls-key(1)</a>
+</dt>
+<dd>
+<p>
+ Validate NVMeoF TLS PSK
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-cmdset-ind-id-ns.html">nvme-cmdset-ind-id-ns(1)</a>
+</dt>
+<dd>
+<p>
+ I/O Command Set Independent Identify Namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-endurance-event-agg-log.html">nvme-endurance-event-agg-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Endurance Group Event Aggregate Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-fid-support-effects-log.html">nvme-fid-support-effects-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve FID Support and Effects log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-gen-dhchap-key.html">nvme-gen-dhchap-key(1)</a>
+</dt>
+<dd>
+<p>
+ Generate NVMeoF DH-HMAC-CHAP host key
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-gen-hostnqn.html">nvme-gen-hostnqn(1)</a>
+</dt>
+<dd>
+<p>
+ Generate NVMeoF host NQN
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-gen-tls-key.html">nvme-gen-tls-key(1)</a>
+</dt>
+<dd>
+<p>
+ Generate NVMeoF TLS PSK
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-get-lba-status.html">nvme-get-lba-status(1)</a>
+</dt>
+<dd>
+<p>
+ Get LBA Status command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-id-domain.html">nvme-id-domain(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Domain List
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-id-ns-lba-format.html">nvme-id-ns-lba-format(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Namespace for the specified LBA Format index
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-lba-status-log.html">nvme-lba-status-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve LBA Status Information Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-list-endgrp.html">nvme-list-endgrp(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Endurance Group List
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-ns-rescan.html">nvme-ns-rescan(1)</a>
+</dt>
+<dd>
+<p>
+ Rescans the NVME namespaces
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-nvm-id-ctrl.html">nvme-nvm-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Controller NVM Command Set
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-nvm-id-ns.html">nvme-nvm-id-ns(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Namespace NVM Command Set
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-nvm-id-ns-lba-format.html">nvme-nvm-id-ns-lba-format(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Namespace NVM Command Set for the specified LBA Format index
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-persistent-event-log.html">nvme-persistent-event-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Persistent Event Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-predictable-lat-log.html">nvme-predictable-lat-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Predictable Latency per Nvmset Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-pred-lat-event-agg-log.html">nvme-pred-lat-event-agg-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Predictable Latency Event Aggregate Log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-primary-ctrl-caps.html">nvme-primary-ctrl-caps(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Identify Primary Controller Capabilities
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-reset.html">nvme-reset(1)</a>
+</dt>
+<dd>
+<p>
+ Resets the controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-rpmb.html">nvme-rpmb(1)</a>
+</dt>
+<dd>
+<p>
+ Replay Protection Memory Block commands
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-sanitize-log.html">nvme-sanitize-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve sanitize log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-set-property.html">nvme-set-property(1)</a>
+</dt>
+<dd>
+<p>
+ Set a property and show the resulting value
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-show-hostnqn.html">nvme-show-hostnqn(1)</a>
+</dt>
+<dd>
+<p>
+ Show NVMeoF host NQN
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-subsystem-reset.html">nvme-subsystem-reset(1)</a>
+</dt>
+<dd>
+<p>
+ Resets the subsystem
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-supported-log-pages.html">nvme-supported-log-pages(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve the Supported Log pages details
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-verify.html">nvme-verify(1)</a>
+</dt>
+<dd>
+<p>
+ verify command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-show-topology.html">nvme-show-topology(1)</a>
+</dt>
+<dd>
+<p>
+ Show NVMe topology
+</p>
+</dd>
+</dl></div>
+</div>
+<div class="sect2">
+<h3 id="_plugins_vendor_extension_commands">Plugins/Vendor extension commands</h3>
+<div class="dlist"><dl>
+<dt class="hdlist1">
+<a href="nvme-intel-id-ctrl.html">nvme-intel-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ Intel - NVMe Identify Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-intel-internal-log.html">nvme-intel-internal-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Intel device&#8217;s internal log and save to file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-intel-lat-stats.html">nvme-intel-lat-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve NVMe Identify Controller, return result and structure
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-intel-market-name.html">nvme-intel-market-name(1)</a>
+</dt>
+<dd>
+<p>
+ Intel vendor specific marketing name log page
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-intel-smart-log-add.html">nvme-intel-smart-log-add(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Intel Additional SMART log page
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-intel-temp-stats.html">nvme-intel-temp-stats(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Intel Additional SMART log page for temp stats
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-huawei-id-ctrl.html">nvme-huawei-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe huawei Identify Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-huawei-list.html">nvme-huawei-list(1)</a>
+</dt>
+<dd>
+<p>
+ List all recognized Huawei NVMe devices
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-dera-stat.html">nvme-dera-stat(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Dera Device status and Additional SMART log page request
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-clear-pcie-errors.html">nvme-micron-clear-pcie-errors(1)</a>
+</dt>
+<dd>
+<p>
+ Clears correctable PCIe correctable errors of given Micron device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-internal-log.html">nvme-micron-internal-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Micron device&#8217;s internal logs and save to given zip file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-nand-stats.html">nvme-micron-nand-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieves NAND statistics of given micron device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-pcie-stats.html">nvme-micron-pcie-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieves pcie error statistics for given micron device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-selective-download.html">nvme-micron-selective-download(1)</a>
+</dt>
+<dd>
+<p>
+ Performs selective firmware download
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-smart-add-log.html">nvme-micron-smart-add-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieves NAND statistics
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-micron-temperature-stats.html">nvme-micron-temperature-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieves temperature information of given micron device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-netapp-ontapdevices.html">nvme-netapp-ontapdevices(1)</a>
+</dt>
+<dd>
+<p>
+ Display information about ONTAP devices
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-netapp-smdevices.html">nvme-netapp-smdevices(1)</a>
+</dt>
+<dd>
+<p>
+ Display information for each NVMe path to an E-Series volume
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-toshiba-clear-pcie-correctable-errors.html">nvme-toshiba-clear-pcie-correctable-errors(1)</a>
+</dt>
+<dd>
+<p>
+ Reset the PCIe correctable errors count to zero
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-toshiba-vs-internal-log.html">nvme-toshiba-vs-internal-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve a Toshiba device&#8217;s vendor specific internal log
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-toshiba-vs-smart-add-log.html">nvme-toshiba-vs-smart-add-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve a Toshiba device&#8217;s vendor specific extended SMART log page
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-transcend-badblock.html">nvme-transcend-badblock(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Transcend NVMe device&#8217;s bad blocks
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-transcend-healthvalue.html">nvme-transcend-healthvalue(1)</a>
+</dt>
+<dd>
+<p>
+ Use NVMe SMART table to analyze the health value of Transcend device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-virtium-show-identify.html">nvme-virtium-show-identify(1)</a>
+</dt>
+<dd>
+<p>
+ Show a complete detail of identify device information in json format
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-virtium-save-smart-to-vtview-log.html">nvme-virtium-save-smart-to-vtview-log(1)</a>
+</dt>
+<dd>
+<p>
+ Periodically save smart attributes into a log file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-cap-diag.html">nvme-wdc-cap-diag(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s diagnostic log and save to file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-capabilities.html">nvme-wdc-capabilities(1)</a>
+</dt>
+<dd>
+<p>
+ Display WDC plugin command capabilities
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-clear-assert-dump.html">nvme-wdc-clear-assert-dump(1)</a>
+</dt>
+<dd>
+<p>
+ Clears the assert dump (if present)
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-clear-fw-activate-history.html">nvme-wdc-clear-fw-activate-history(1)</a>
+</dt>
+<dd>
+<p>
+ Clears the firmware activate history table
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-clear-pcie-corr.html">nvme-wdc-clear-pcie-corr(1)</a>
+</dt>
+<dd>
+<p>
+ Clears the pcie correctable errors field
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-clear-pcie-correctable-errors.html">nvme-wdc-clear-pcie-correctable-errors(1)</a>
+</dt>
+<dd>
+<p>
+ Clears the pcie correctable errors returned in the smart-log-add command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-cloud-SSD-plugin-version.html">nvme-wdc-cloud-SSD-plugin-version(1)</a>
+</dt>
+<dd>
+<p>
+ Display WDC plugin Cloud SSD Plugin Version
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-drive-essentials.html">nvme-wdc-drive-essentials(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s drive essentials bin files
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-drive-log.html">nvme-wdc-drive-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s drive log and save to file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-drive-resize.html">nvme-wdc-drive-resize(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC Resize Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-enc-get-log.html">nvme-wdc-enc-get-log(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC enc-get-log Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-get-crash-dump.html">nvme-wdc-get-crash-dump(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s crash dump
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-get-drive-status.html">nvme-wdc-get-drive-status(1)</a>
+</dt>
+<dd>
+<p>
+ Send the NVMe WDC get-drive-status command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-get-latency-monitor-log.html">nvme-wdc-get-latency-monitor-log(1)</a>
+</dt>
+<dd>
+<p>
+ Display latency monitor log page data in human readable format
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-get-pfail-dump.html">nvme-wdc-get-pfail-dump(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s pfail crash dump
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-id-ctrl.html">nvme-wdc-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe Identify Controller, return result and structure
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-log-page-directory.html">nvme-wdc-log-page-directory(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieves the list of Log IDs supported by the drive
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-namespace-resize.html">nvme-wdc-namespace-resize(1)</a>
+</dt>
+<dd>
+<p>
+ Resizes the device&#8217;s namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-purge-monitor.html">nvme-wdc-purge-monitor(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC Purge-Monitor Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-purge.html">nvme-wdc-purge(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC Purge Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-smart-add-log.html">nvme-wdc-smart-add-log(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC smart add log Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-drive-info.html">nvme-wdc-vs-drive-info(1)</a>
+</dt>
+<dd>
+<p>
+ Send the NVMe WDC vs-drive-info command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-error-reason-identifier.html">nvme-wdc-vs-error-reason-identifier(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s telemetry log error reason identifier field
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-fw-activate-history.html">nvme-wdc-vs-fw-activate-history(1)</a>
+</dt>
+<dd>
+<p>
+ Execute NVMe WDC vs-fw-activate-history Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-internal-log.html">nvme-wdc-vs-internal-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve WDC device&#8217;s internal firmware log and save to file
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-nand-stats.html">nvme-wdc-vs-nand-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe WDC vs-nand-stats Vendor Unique Command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-telemetry-controller-option.html">nvme-wdc-vs-telemetry-controller-option(1)</a>
+</dt>
+<dd>
+<p>
+ Disable/Enable the controller initiated option of the telemetry log page
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-wdc-vs-temperature-stats.html">nvme-wdc-vs-temperature-stats(1)</a>
+</dt>
+<dd>
+<p>
+ Display temperature-related statistics
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-changed-zone-list.html">nvme-zns-changed-zone-list(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Changed Zone log for the given device
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-close-zone.html">nvme-zns-close-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Closes one or all zones
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-finish-zone.html">nvme-zns-finish-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Finishes one or all zones
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-id-ctrl.html">nvme-zns-id-ctrl(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe Zoned Command Set Identify Controller
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-id-ns.html">nvme-zns-id-ns(1)</a>
+</dt>
+<dd>
+<p>
+ Send NVMe Zoned Command Set Identify Namespace
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-offline-zone.html">nvme-zns-offline-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Offlines one or all zones
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-open-zone.html">nvme-zns-open-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Opens one or all zones
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-report-zones.html">nvme-zns-report-zones(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve and display the Report Zones data structure
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-reset-zone.html">nvme-zns-reset-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Resets one or all zones
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-set-zone-desc.html">nvme-zns-set-zone-desc(1)</a>
+</dt>
+<dd>
+<p>
+ Set extended descriptor data for a zone
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-zone-append.html">nvme-zns-zone-append(1)</a>
+</dt>
+<dd>
+<p>
+ Send an NVMe write command, provide results
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-zone-mgmt-recv.html">nvme-zns-zone-mgmt-recv(1)</a>
+</dt>
+<dd>
+<p>
+ Zone Management Receive command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-zone-mgmt-send.html">nvme-zns-zone-mgmt-send(1)</a>
+</dt>
+<dd>
+<p>
+ Zone Management Send command
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-zns-zrwa-flush-zone.html">nvme-zns-zrwa-flush-zone(1)</a>
+</dt>
+<dd>
+<p>
+ Flush LBAs associated with a ZRWA to a zone
+</p>
+</dd>
+<dt class="hdlist1">
+<a href="nvme-inspur-nvme-vendor-log.html">nvme-inspur-nvme-vendor-log(1)</a>
+</dt>
+<dd>
+<p>
+ NVMe Inspur Device Vendor log page request
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_returns">RETURNS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>All commands will behave the same, they will return 0 on success and 1 on
+failure.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_further_documentation">FURTHER DOCUMENTATION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>See the freely available references on the <a href="http://nvmexpress.org">Official
+NVM-Express Site</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_authors">Authors</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>This is written and maintained by <a href="mailto:kbusch@kernel.org">Keith Busch</a>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_reporting_bugs">Reporting Bugs</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Patches and issues may be submitted to the official repository at
+<a href="https://github.com/linux-nvme/nvme-cli">https://github.com/linux-nvme/nvme-cli</a> or the Linux NVMe mailing list
+<a href="mailto:linux-nvme@lists.infradead.org">linux-nvme</a></p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme suite</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated
+ 2024-02-14 10:43:42 CET
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme.txt b/Documentation/nvme.txt
new file mode 100644
index 0000000..87de7b8
--- /dev/null
+++ b/Documentation/nvme.txt
@@ -0,0 +1,70 @@
+nvme(1)
+=======
+
+NAME
+----
+nvme - the NVMe storage command line interface utility (nvme-cli)
+
+SYNOPSIS
+--------
+built-in plugin:
+[verse]
+'nvme' <command> <device> [<args>]
+
+extension plugins:
+[verse]
+'nvme' <plugin> <command> <device> [<args>]
+
+DESCRIPTION
+-----------
+NVM-Express is a fast, scalable host controller interface designed to
+address the needs for not only PCI Express based solid state drives, but
+also NVMe-oF(over fabrics).
+
+This 'nvme' program is a user space utility to provide standards compliant
+tooling for NVM-Express drives. It was made specifically for Linux as
+it relies on the IOCTLs defined by the mainline kernel driver.
+
+NVME COMMANDS
+-------------
+The utility has sub-commands for all admin and io commands defined in the
+specification and for displaying controller registers. There is also an
+option to submit completely arbitrary commands. For a list of commands
+available, run "nvme help".
+
+nvme cli sub-commands
+---------------------
+
+Main commands
+~~~~~~~~~~~~~
+
+include::cmds-main.txt[]
+
+Plugins/Vendor extension commands
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+include::cmd-plugins.txt[]
+
+RETURNS
+-------
+All commands will behave the same, they will return 0 on success and 1 on
+failure.
+
+FURTHER DOCUMENTATION
+---------------------
+See the freely available references on the http://nvmexpress.org[Official
+NVM-Express Site].
+
+Authors
+-------
+This is written and maintained by mailto:kbusch@kernel.org[Keith Busch].
+
+Reporting Bugs
+--------------
+Patches and issues may be submitted to the official repository at
+https://github.com/linux-nvme/nvme-cli or the Linux NVMe mailing list
+mailto:linux-nvme@lists.infradead.org[linux-nvme]
+
+NVME
+----
+Part of the nvme suite
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d6a9326
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,340 @@
+GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ {description}
+ Copyright (C) {year} {fullname}
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ {signature of Ty Coon}, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..7f44364
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+#
+# This file is part of nvme.
+# Copyright (c) 2021 Dell Inc.
+#
+# Authors: Martin Belanger <Martin.Belanger@dell.com>
+#
+NAME := nvme
+.DEFAULT_GOAL := ${NAME}
+BUILD-DIR := .build
+
+${BUILD-DIR}:
+ meson $@
+ @echo "Configuration located in: $@"
+ @echo "-------------------------------------------------------"
+
+.PHONY: ${NAME}
+${NAME}: ${BUILD-DIR}
+ ninja -C ${BUILD-DIR}
+
+.PHONY: clean
+clean:
+ifneq ("$(wildcard ${BUILD-DIR})","")
+ ninja -C ${BUILD-DIR} -t $@
+endif
+
+.PHONY: purge
+purge:
+ifneq ("$(wildcard ${BUILD-DIR})","")
+ rm -rf ${BUILD-DIR}
+endif
+
+.PHONY: install dist
+install dist: ${BUILD-DIR}
+ cd ${BUILD-DIR} && meson $@
+
+.PHONY: uninstall
+uninstall:
+ cd ${BUILD-DIR} && meson --internal uninstall
+
+.PHONY: test
+test: ${BUILD-DIR}
+ ninja -C ${BUILD-DIR} $@
+
+.PHONY: rpm
+rpm:
+ meson ${BUILD-DIR} \
+ -Dudevrulesdir=$(shell rpm --eval '%{_udevrulesdir}') \
+ -Dsystemddir=$(shell rpm --eval '%{_unitdir}') \
+ -Ddocs=man -Ddocs-build=true
+ rpmbuild -ba ${BUILD-DIR}/nvme.spec --define "_builddir ${BUILD-DIR}" -v
+
+.PHONY: debug
+debug:
+ meson ${BUILD-DIR} --buildtype=debug
+ ninja -C ${BUILD-DIR}
+
+.PHONY: static
+static:
+ meson ${BUILD-DIR} --buildtype=release \
+ --default-library=static -Dc_link_args="-static" \
+ --wrap-mode=forcefallback \
+ -Dlibnvme:tests=false -Dlibnvme:keyutils=disabled
+ ninja -C ${BUILD-DIR}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1113b1e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,335 @@
+# nvme-cli
+![Coverity Scan Build Status](https://scan.coverity.com/projects/24883/badge.svg)
+![MesonBuild](https://github.com/linux-nvme/nvme-cli/actions/workflows/build.yml/badge.svg)
+![GitHub](https://img.shields.io/github/license/linux-nvme/nvme-cli)
+
+NVM-Express user space tooling for Linux.
+
+## Build from source
+
+nvme-cli uses meson as build system. There is more than one way to configure and
+build the project in order to mitigate meson dependency on the build
+environment.
+
+If you build on a relative modern system, either use meson directly or the
+Makefile wrapper.
+
+Older distros might ship a too old version of meson, in this case it's possible
+to build the project using [samurai](https://github.com/michaelforney/samurai)
+and [muon](https://github.com/annacrombie/muon). Both build tools have only a
+minimal dependency on the build environment. Too easy this step there is a build
+script which helps to setup a build environment.
+
+### nvme-cli dependencies:
+
+ | Library | Dependency | Notes |
+ |---------|------------|-------|
+ | libnvme, libnvme-mi| yes | be either installed or included into the build via meson fallback feature |
+ | json-c | optional | recommended, without all plugins are disabled and json-c output format is disabled |
+
+
+### Build with meson
+
+#### Configuring
+
+In case libnvme is not installed on the system, it possible to use meson's
+fallback feature to resolve the dependency.
+
+ $ meson setup --force-fallback-for=libnvme .build
+
+If the libnvme is already installed on the system meson is using pkg-config to
+find the dependency. In this case a plain setup call is enough:
+
+ $ meson setup .build
+
+With meson's --wrap-mode argument it's possible to control if the additional
+dependencies should also resolved or not. The options are
+
+ --wrap-mode {default,nofallback,nodownload,forcefallback,nopromote}
+
+Note for nvme-cli the 'default' is set to nofallback.
+
+#### Building
+
+ $ meson compile -C .build
+
+#### Installing
+
+ # meson install -C .build
+
+### Build with build.sh wrapper
+
+The `scripts/build.sh` is used for the CI build but can also be used for
+configuring and building the project.
+
+Running `scripts/build.sh` without any argument builds the project in the
+default configuration (meson, gcc and defaults)
+
+It's possible to change the compiler to clang
+
+`scripts/builds.sh -c clang`
+
+or enabling all the fallbacks
+
+`scripts/build.sh fallback`
+
+### Minimal static build with muon
+
+`scripts/build.sh -m muon` will download and build `samurai` and `muon` instead
+using `meson` to build the project. This reduces the dependency on the build
+environment to:
+- gcc
+- make
+- git
+
+Furthermore, this configuration will produce a static binary.
+
+### Build with Makefile wrapper
+
+There is a Makefile wrapper for meson for backwards compatibility
+
+ $ make
+ # make install
+
+Note in this case libnvme needs to be installed by hand first.
+
+RPM build support via Makefile that uses meson
+
+ $ make rpm
+
+Static binary(no dependency) build support via Makefile that uses meson
+
+ $ make static
+
+If not sure how to use, find the top-level documentation with:
+
+ $ man nvme
+
+Or find a short summary with:
+
+ $ nvme help
+
+## Distro Support
+
+Many popular distributions (Alpine, Arch, Debian, Fedora, FreeBSD, Gentoo,
+Ubuntu, Nix(OS), openSUSE, ...) and the usual package name is nvme-cli.
+
+#### OpenEmbedded/Yocto
+
+An [nvme-cli recipe](https://layers.openembedded.org/layerindex/recipe/88631/)
+is available as part of the `meta-openembeded` layer collection.
+
+#### Buildroot
+
+`nvme-cli` is available as [buildroot](https://buildroot.org) package. The
+package is named `nvme`.
+
+## Developers
+
+You may wish to add a new command or possibly an entirely new plug-in
+for some special extension outside the spec.
+
+This project provides macros that help generate the code for you. If
+you're interested in how that works, it is very similar to how trace
+events are created by Linux kernel's 'ftrace' component.
+
+### Add command to existing built-in
+
+The first thing to do is define a new command entry in the command
+list. This is declared in nvme-builtin.h. Simply append a new "ENTRY" into
+the list. The ENTRY normally takes three arguments: the "name" of the
+subcommand (this is what the user will type at the command line to invoke
+your command), a short help description of what your command does, and the
+name of the function callback that you're going to write. Additionally,
+You can declare an alias name of subcommand with fourth argument, if needed.
+
+After the ENTRY is defined, you need to implement the callback. It takes
+four arguments: argc, argv, the command structure associated with the
+callback, and the plug-in structure that contains that command. The
+prototype looks like this:
+
+ ```c
+ int f(int argc, char **argv, struct command *cmd, struct plugin *plugin);
+ ```
+
+The argc and argv are adjusted from the command line arguments to start
+after the sub-command. So if the command line is "nvme foo --option=bar",
+the argc is 1 and argv starts at "--option".
+
+You can then define argument parsing for your sub-command's specific
+options then do some command specific action in your callback.
+
+### Add a new plugin
+
+The nvme-cli provides macros to make define a new plug-in simpler. You
+can certainly do all this by hand if you want, but it should be easier
+to get going using the macros. To start, first create a header file
+to define your plugin. This is where you will give your plugin a name,
+description, and define all the sub-commands your plugin implements.
+
+There is a very important order on how to define the plugin. The following
+is a basic example on how to start this:
+
+File: foo-plugin.h
+```c
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/foo/foo-plugin
+
+#if !defined(FOO) || defined(CMD_HEADER_MULTI_READ)
+#define FOO
+
+#include "cmd.h"
+
+PLUGIN(NAME("foo", "Foo plugin"),
+ COMMAND_LIST(
+ ENTRY("bar", "foo bar", bar)
+ ENTRY("baz", "foo baz", baz)
+ ENTRY("qux", "foo quz", qux)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
+```
+
+In order to have the compiler generate the plugin through the xmacro
+expansion, you need to include this header in your source file, with
+pre-defining macro directive to create the commands.
+
+To get started from the above example, we just need to define "CREATE_CMD"
+and include the header:
+
+File: foo-plugin.c
+```c
+#include "nvme.h"
+
+#define CREATE_CMD
+#include "foo-plugin.h"
+```
+
+After that, you just need to implement the functions you defined in each
+ENTRY, then append the object file name to the meson.build "sources".
+
+## meson tips
+
+In case meson doesn't find libnvme header files (via pkg-config) it
+will fallback using subprojects. meson checks out libnvme in
+subprojects directory as git tree once to the commit level specified
+in the libnvme.wrap file revision parm. After this initial checkout,
+the libnvme code level will not change unless explicitly told. That
+means if the current branch is updated via git, the subprojects/libnvme
+branch will not updated accordingly. To update it, either use the
+normal git operations or the command:
+
+ $ meson subprojects update
+
+## Dependency
+
+libnvme depends on the /sys/class/nvme-subsystem interface which was
+introduced in the Linux kernel release v4.15. Hence nvme-cli 2.x is
+only working on kernels >= v4.15. For older kernels nvme-cli 1.x is
+recommended to be used.
+
+## How to contribute
+
+There are two ways to send code changes to the project. The first one
+is by sending the changes to linux-nvme@lists.infradead.org. The
+second one is by posting a pull request on github. In both cases
+please follow the Linux contributions guidelines as documented in
+
+https://docs.kernel.org/process/submitting-patches.html#
+
+That means the changes should be a clean series (no merges should be
+present in a github PR for example) and every commit should build.
+
+See also https://opensource.com/article/19/7/create-pull-request-github
+
+### How to cleanup your series before creating PR
+
+This example here assumes, the changes are in a branch called
+fix-something, which branched away from master in the past. In the
+meantime the upstream project has changed, hence the fix-something
+branch is not based on the current HEAD. Before posting the PR, the
+branch should be rebased on the current HEAD and retest everything.
+
+For example rebasing can be done by following steps
+
+```shell
+# Update master branch
+# upstream == https://github.com/linux-nvme/nvme-cli.git
+$ git switch master
+$ git fetch --all
+$ git reset --hard upstream/master
+
+# Make sure all dependencies are up to date and make a sanity build
+$ meson subprojects update
+$ ninja -C .build
+
+# Go back to the fix-something branch
+$ git switch fix-something
+
+# Rebase it to the current HEAD
+$ git rebase master
+[fixup all merge conflicts]
+[retest]
+
+# Push your changes to github and trigger a PR
+$ git push -u origin fix-something
+```
+
+## Persistent, volatile configuration
+
+Persistent configurations can be stored in two different locations: either in
+the file `/etc/nvme/discovery.conf` using the old style, or in the file
+`/etc/nvme/config.json` using the new style.
+
+On the other hand, volatile configurations, such as those obtained from
+third-party tools like `nvme-stats` or `blktests'` can be stored in the
+`/run/nvme` directory. When using the `nvme-cli` tool, all these configurations
+are combined into a single configuration that is used as input.
+
+The volatile configuration is particularly useful for coordinating access to the
+global resources among various components. For example, when executing
+`blktests` for the FC transport, the `nvme-cli` udev rules can be triggered. To
+prevent interference with a test, `blktests` can create a JSON configuration
+file in `/run/nvme` to inform `nvme-cli` that it should not perform any actions
+triggered from the udev context. This behavior can be controlled using the
+`--context` argument.
+
+For example a `blktests` volatile configuration could look like:
+
+```json
+[
+ {
+ "hostnqn": "nqn.2014-08.org.nvmexpress:uuid:242d4a24-2484-4a80-8234-d0169409c5e8",
+ "hostid": "242d4a24-2484-4a80-8234-d0169409c5e8",
+ "subsystems": [
+ {
+ "application": "blktests",
+ "nqn": "blktests-subsystem-1",
+ "ports": [
+ {
+ "transport": "fc",
+ "traddr": "nn-0x10001100aa000001:pn-0x20001100aa000001",
+ "host_traddr": "nn-0x10001100aa000002:pn-0x20001100aa000002"
+ }
+ ]
+ }
+ ]
+ }
+]
+```
+
+Note when updating the volatile configuration during runtime, it should done in
+a an atomic way. For example create a temporary file without the `.json` file
+extension in `/run/nvme` and write the contents to this file. When finished use
+`rename` to add the `'.json'` file name extension. This ensures nvme-cli only
+sees the complete file.
+
+## Testing
+
+For testing purposes a x86_64 AppImage is build from the current HEAD and is
+available here:
+
+https://monom.org/linux-nvme/upload/AppImage/nvme-cli-latest-x86_64.AppImage
diff --git a/ccan/ccan/build_assert/LICENSE b/ccan/ccan/build_assert/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/build_assert/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/build_assert/build_assert.h b/ccan/ccan/build_assert/build_assert.h
new file mode 100644
index 0000000..b9ecd84
--- /dev/null
+++ b/ccan/ccan/build_assert/build_assert.h
@@ -0,0 +1,40 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_BUILD_ASSERT_H
+#define CCAN_BUILD_ASSERT_H
+
+/**
+ * BUILD_ASSERT - assert a build-time dependency.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can only be used within a function.
+ *
+ * Example:
+ * #include <stddef.h>
+ * ...
+ * static char *foo_to_char(struct foo *foo)
+ * {
+ * // This code needs string to be at start of foo.
+ * BUILD_ASSERT(offsetof(struct foo, string) == 0);
+ * return (char *)foo;
+ * }
+ */
+#define BUILD_ASSERT(cond) \
+ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0)
+
+/**
+ * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression.
+ * @cond: the compile-time condition which must be true.
+ *
+ * Your compile will fail if the condition isn't true, or can't be evaluated
+ * by the compiler. This can be used in an expression: its value is "0".
+ *
+ * Example:
+ * #define foo_to_char(foo) \
+ * ((char *)(foo) \
+ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0))
+ */
+#define BUILD_ASSERT_OR_ZERO(cond) \
+ (sizeof(char [1 - 2*!(cond)]) - 1)
+
+#endif /* CCAN_BUILD_ASSERT_H */
diff --git a/ccan/ccan/check_type/LICENSE b/ccan/ccan/check_type/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/check_type/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/check_type/check_type.h b/ccan/ccan/check_type/check_type.h
new file mode 100644
index 0000000..837aef7
--- /dev/null
+++ b/ccan/ccan/check_type/check_type.h
@@ -0,0 +1,64 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_CHECK_TYPE_H
+#define CCAN_CHECK_TYPE_H
+#include "config.h"
+
+/**
+ * check_type - issue a warning or build failure if type is not correct.
+ * @expr: the expression whose type we should check (not evaluated).
+ * @type: the exact type we expect the expression to be.
+ *
+ * This macro is usually used within other macros to try to ensure that a macro
+ * argument is of the expected type. No type promotion of the expression is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_type() always evaluates to 0.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // They should always pass a 64-bit value to _set_some_value!
+ * #define set_some_value(expr) \
+ * _set_some_value((check_type((expr), uint64_t), (expr)))
+ */
+
+/**
+ * check_types_match - issue a warning or build failure if types are not same.
+ * @expr1: the first expression (not evaluated).
+ * @expr2: the second expression (not evaluated).
+ *
+ * This macro is usually used within other macros to try to ensure that
+ * arguments are of identical types. No type promotion of the expressions is
+ * done: an unsigned int is not the same as an int!
+ *
+ * check_types_match() always evaluates to 0.
+ *
+ * If your compiler does not support typeof, then the best we can do is fail
+ * to compile if the sizes of the types are unequal (a less complete check).
+ *
+ * Example:
+ * // Do subtraction to get to enclosing type, but make sure that
+ * // pointer is of correct type for that member.
+ * #define container_of(mbr_ptr, encl_type, mbr) \
+ * (check_types_match((mbr_ptr), &((encl_type *)0)->mbr), \
+ * ((encl_type *) \
+ * ((char *)(mbr_ptr) - offsetof(encl_type, mbr))))
+ */
+#if HAVE_TYPEOF
+#define check_type(expr, type) \
+ ((typeof(expr) *)0 != (type *)0)
+
+#define check_types_match(expr1, expr2) \
+ ((typeof(expr1) *)0 != (typeof(expr2) *)0)
+#else
+#include <ccan/build_assert/build_assert.h>
+/* Without typeof, we can only test the sizes. */
+#define check_type(expr, type) \
+ BUILD_ASSERT_OR_ZERO(sizeof(expr) == sizeof(type))
+
+#define check_types_match(expr1, expr2) \
+ BUILD_ASSERT_OR_ZERO(sizeof(expr1) == sizeof(expr2))
+#endif /* HAVE_TYPEOF */
+
+#endif /* CCAN_CHECK_TYPE_H */
diff --git a/ccan/ccan/compiler/LICENSE b/ccan/ccan/compiler/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/compiler/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/compiler/compiler.h b/ccan/ccan/compiler/compiler.h
new file mode 100644
index 0000000..562b29e
--- /dev/null
+++ b/ccan/ccan/compiler/compiler.h
@@ -0,0 +1,317 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_COMPILER_H
+#define CCAN_COMPILER_H
+#include "config.h"
+
+#ifndef COLD
+#if HAVE_ATTRIBUTE_COLD
+/**
+ * COLD - a function is unlikely to be called.
+ *
+ * Used to mark an unlikely code path and optimize appropriately.
+ * It is usually used on logging or error routines.
+ *
+ * Example:
+ * static void COLD moan(const char *reason)
+ * {
+ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
+ * }
+ */
+#define COLD __attribute__((__cold__))
+#else
+#define COLD
+#endif
+#endif
+
+#ifndef NORETURN
+#if HAVE_ATTRIBUTE_NORETURN
+/**
+ * NORETURN - a function does not return
+ *
+ * Used to mark a function which exits; useful for suppressing warnings.
+ *
+ * Example:
+ * static void NORETURN fail(const char *reason)
+ * {
+ * fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
+ * exit(1);
+ * }
+ */
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+#endif
+
+#ifndef PRINTF_FMT
+#if HAVE_ATTRIBUTE_PRINTF
+/**
+ * PRINTF_FMT - a function takes printf-style arguments
+ * @nfmt: the 1-based number of the function's format argument.
+ * @narg: the 1-based number of the function's first variable argument.
+ *
+ * This allows the compiler to check your parameters as it does for printf().
+ *
+ * Example:
+ * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...);
+ */
+#define PRINTF_FMT(nfmt, narg) \
+ __attribute__((format(__printf__, nfmt, narg)))
+#else
+#define PRINTF_FMT(nfmt, narg)
+#endif
+#endif
+
+#ifndef CONST_FUNCTION
+#if HAVE_ATTRIBUTE_CONST
+/**
+ * CONST_FUNCTION - a function's return depends only on its argument
+ *
+ * This allows the compiler to assume that the function will return the exact
+ * same value for the exact same arguments. This implies that the function
+ * must not use global variables, or dereference pointer arguments.
+ */
+#define CONST_FUNCTION __attribute__((__const__))
+#else
+#define CONST_FUNCTION
+#endif
+
+#ifndef PURE_FUNCTION
+#if HAVE_ATTRIBUTE_PURE
+/**
+ * PURE_FUNCTION - a function is pure
+ *
+ * A pure function is one that has no side effects other than it's return value
+ * and uses no inputs other than it's arguments and global variables.
+ */
+#define PURE_FUNCTION __attribute__((__pure__))
+#else
+#define PURE_FUNCTION
+#endif
+#endif
+#endif
+
+#if HAVE_ATTRIBUTE_UNUSED
+#ifndef UNNEEDED
+/**
+ * UNNEEDED - a variable/function may not be needed
+ *
+ * This suppresses warnings about unused variables or functions, but tells
+ * the compiler that if it is unused it need not emit it into the source code.
+ *
+ * Example:
+ * // With some preprocessor options, this is unnecessary.
+ * static UNNEEDED int counter;
+ *
+ * // With some preprocessor options, this is unnecessary.
+ * static UNNEEDED void add_to_counter(int add)
+ * {
+ * counter += add;
+ * }
+ */
+#define UNNEEDED __attribute__((__unused__))
+#endif
+
+#ifndef NEEDED
+#if HAVE_ATTRIBUTE_USED
+/**
+ * NEEDED - a variable/function is needed
+ *
+ * This suppresses warnings about unused variables or functions, but tells
+ * the compiler that it must exist even if it (seems) unused.
+ *
+ * Example:
+ * // Even if this is unused, these are vital for debugging.
+ * static NEEDED int counter;
+ * static NEEDED void dump_counter(void)
+ * {
+ * printf("Counter is %i\n", counter);
+ * }
+ */
+#define NEEDED __attribute__((__used__))
+#else
+/* Before used, unused functions and vars were always emitted. */
+#define NEEDED __attribute__((__unused__))
+#endif
+#endif
+
+#ifndef UNUSED
+/**
+ * UNUSED - a parameter is unused
+ *
+ * Some compilers (eg. gcc with -W or -Wunused) warn about unused
+ * function parameters. This suppresses such warnings and indicates
+ * to the reader that it's deliberate.
+ *
+ * Example:
+ * // This is used as a callback, so needs to have this prototype.
+ * static int some_callback(void *unused UNUSED)
+ * {
+ * return 0;
+ * }
+ */
+#define UNUSED __attribute__((__unused__))
+#endif
+#else
+#ifndef UNNEEDED
+#define UNNEEDED
+#endif
+#ifndef NEEDED
+#define NEEDED
+#endif
+#ifndef UNUSED
+#define UNUSED
+#endif
+#endif
+
+#ifndef IS_COMPILE_CONSTANT
+#if HAVE_BUILTIN_CONSTANT_P
+/**
+ * IS_COMPILE_CONSTANT - does the compiler know the value of this expression?
+ * @expr: the expression to evaluate
+ *
+ * When an expression manipulation is complicated, it is usually better to
+ * implement it in a function. However, if the expression being manipulated is
+ * known at compile time, it is better to have the compiler see the entire
+ * expression so it can simply substitute the result.
+ *
+ * This can be done using the IS_COMPILE_CONSTANT() macro.
+ *
+ * Example:
+ * enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON };
+ *
+ * // Out-of-line version.
+ * const char *greek_name(enum greek greek);
+ *
+ * // Inline version.
+ * static inline const char *_greek_name(enum greek greek)
+ * {
+ * switch (greek) {
+ * case ALPHA: return "alpha";
+ * case BETA: return "beta";
+ * case GAMMA: return "gamma";
+ * case DELTA: return "delta";
+ * case EPSILON: return "epsilon";
+ * default: return "**INVALID**";
+ * }
+ * }
+ *
+ * // Use inline if compiler knows answer. Otherwise call function
+ * // to avoid copies of the same code everywhere.
+ * #define greek_name(g) \
+ * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g))
+ */
+#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr)
+#else
+/* If we don't know, assume it's not. */
+#define IS_COMPILE_CONSTANT(expr) 0
+#endif
+#endif
+
+#ifndef WARN_UNUSED_RESULT
+#if HAVE_WARN_UNUSED_RESULT
+/**
+ * WARN_UNUSED_RESULT - warn if a function return value is unused.
+ *
+ * Used to mark a function where it is extremely unlikely that the caller
+ * can ignore the result, eg realloc().
+ *
+ * Example:
+ * // buf param may be freed by this; need return value!
+ * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size)
+ * {
+ * return realloc(buf, (*size) *= 2);
+ * }
+ */
+#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+#endif
+
+
+#if HAVE_ATTRIBUTE_DEPRECATED
+/**
+ * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used.
+ *
+ * Used to mark a function, type or variable should not be used.
+ *
+ * Example:
+ * WARN_DEPRECATED char *oldfunc(char *buf);
+ */
+#define WARN_DEPRECATED __attribute__((__deprecated__))
+#else
+#define WARN_DEPRECATED
+#endif
+
+
+#if HAVE_ATTRIBUTE_NONNULL
+/**
+ * NO_NULL_ARGS - specify that no arguments to this function can be NULL.
+ *
+ * The compiler will warn if any pointer args are NULL.
+ *
+ * Example:
+ * NO_NULL_ARGS char *my_copy(char *buf);
+ */
+#define NO_NULL_ARGS __attribute__((__nonnull__))
+
+/**
+ * NON_NULL_ARGS - specify that some arguments to this function can't be NULL.
+ * @...: 1-based argument numbers for which args can't be NULL.
+ *
+ * The compiler will warn if any of the specified pointer args are NULL.
+ *
+ * Example:
+ * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
+ */
+#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
+#else
+#define NO_NULL_ARGS
+#define NON_NULL_ARGS(...)
+#endif
+
+#if HAVE_ATTRIBUTE_RETURNS_NONNULL
+/**
+ * RETURNS_NONNULL - specify that this function cannot return NULL.
+ *
+ * Mainly an optimization opportunity, but can also suppress warnings.
+ *
+ * Example:
+ * RETURNS_NONNULL char *my_copy(char *buf);
+ */
+#define RETURNS_NONNULL __attribute__((__returns_nonnull__))
+#else
+#define RETURNS_NONNULL
+#endif
+
+#if HAVE_ATTRIBUTE_SENTINEL
+/**
+ * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL.
+ *
+ * The compiler will warn if the last argument isn't NULL.
+ *
+ * Example:
+ * char *join_string(char *buf, ...) LAST_ARG_NULL;
+ */
+#define LAST_ARG_NULL __attribute__((__sentinel__))
+#else
+#define LAST_ARG_NULL
+#endif
+
+#if HAVE_BUILTIN_CPU_SUPPORTS
+/**
+ * cpu_supports - test if current CPU supports the named feature.
+ *
+ * This takes a literal string, and currently only works on glibc platforms.
+ *
+ * Example:
+ * if (cpu_supports("mmx"))
+ * printf("MMX support engaged!\n");
+ */
+#define cpu_supports(x) __builtin_cpu_supports(x)
+#else
+#define cpu_supports(x) 0
+#endif /* HAVE_BUILTIN_CPU_SUPPORTS */
+
+#endif /* CCAN_COMPILER_H */
diff --git a/ccan/ccan/container_of/LICENSE b/ccan/ccan/container_of/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/container_of/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/container_of/container_of.h b/ccan/ccan/container_of/container_of.h
new file mode 100644
index 0000000..47a34d8
--- /dev/null
+++ b/ccan/ccan/container_of/container_of.h
@@ -0,0 +1,145 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_CONTAINER_OF_H
+#define CCAN_CONTAINER_OF_H
+#include <stddef.h>
+
+#include "config.h"
+#include <ccan/check_type/check_type.h>
+
+/**
+ * container_of - get pointer to enclosing structure
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info(struct foo *foo)
+ * {
+ * return container_of(foo, struct info, my_foo);
+ * }
+ */
+#define container_of(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ ((char *)(member_ptr) \
+ - container_off(containing_type, member)) \
+ + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+
+/**
+ * container_of_or_null - get pointer to enclosing structure, or NULL
+ * @member_ptr: pointer to the structure member
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type, unless it
+ * is given NULL, in which case it also returns NULL.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info_allowing_null(struct foo *foo)
+ * {
+ * return container_of_or_null(foo, struct info, my_foo);
+ * }
+ */
+static inline char *container_of_or_null_(void *member_ptr, size_t offset)
+{
+ return member_ptr ? (char *)member_ptr - offset : NULL;
+}
+#define container_of_or_null(member_ptr, containing_type, member) \
+ ((containing_type *) \
+ container_of_or_null_(member_ptr, \
+ container_off(containing_type, member)) \
+ + check_types_match(*(member_ptr), ((containing_type *)0)->member))
+
+/**
+ * container_off - get offset to enclosing structure
+ * @containing_type: the type this member is within
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does
+ * typechecking and figures out the offset to the enclosing type.
+ *
+ * Example:
+ * struct foo {
+ * int fielda, fieldb;
+ * // ...
+ * };
+ * struct info {
+ * int some_other_field;
+ * struct foo my_foo;
+ * };
+ *
+ * static struct info *foo_to_info(struct foo *foo)
+ * {
+ * size_t off = container_off(struct info, my_foo);
+ * return (void *)((char *)foo - off);
+ * }
+ */
+#define container_off(containing_type, member) \
+ offsetof(containing_type, member)
+
+/**
+ * container_of_var - get pointer to enclosing structure using a variable
+ * @member_ptr: pointer to the structure member
+ * @container_var: a pointer of same type as this member's container
+ * @member: the name of this member within the structure.
+ *
+ * Given a pointer to a member of a structure, this macro does pointer
+ * subtraction to return the pointer to the enclosing type.
+ *
+ * Example:
+ * static struct info *foo_to_i(struct foo *foo)
+ * {
+ * struct info *i = container_of_var(foo, i, my_foo);
+ * return i;
+ * }
+ */
+#if HAVE_TYPEOF
+#define container_of_var(member_ptr, container_var, member) \
+ container_of(member_ptr, typeof(*container_var), member)
+#else
+#define container_of_var(member_ptr, container_var, member) \
+ ((void *)((char *)(member_ptr) - \
+ container_off_var(container_var, member)))
+#endif
+
+/**
+ * container_off_var - get offset of a field in enclosing structure
+ * @container_var: a pointer to a container structure
+ * @member: the name of a member within the structure.
+ *
+ * Given (any) pointer to a structure and a its member name, this
+ * macro does pointer subtraction to return offset of member in a
+ * structure memory layout.
+ *
+ */
+#if HAVE_TYPEOF
+#define container_off_var(var, member) \
+ container_off(typeof(*var), member)
+#else
+#define container_off_var(var, member) \
+ ((const char *)&(var)->member - (const char *)(var))
+#endif
+
+#endif /* CCAN_CONTAINER_OF_H */
diff --git a/ccan/ccan/endian/LICENSE b/ccan/ccan/endian/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/endian/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/endian/endian.h b/ccan/ccan/endian/endian.h
new file mode 100644
index 0000000..3753f49
--- /dev/null
+++ b/ccan/ccan/endian/endian.h
@@ -0,0 +1,363 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_ENDIAN_H
+#define CCAN_ENDIAN_H
+#include <stdint.h>
+#include "config.h"
+
+/**
+ * BSWAP_16 - reverse bytes in a constant uint16_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_16(0x1234)];
+ * };
+ */
+#define BSWAP_16(val) \
+ ((((uint16_t)(val) & 0x00ff) << 8) \
+ | (((uint16_t)(val) & 0xff00) >> 8))
+
+/**
+ * BSWAP_32 - reverse bytes in a constant uint32_t value.
+ * @val: constant value whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_32(0xff000000)];
+ * };
+ */
+#define BSWAP_32(val) \
+ ((((uint32_t)(val) & 0x000000ff) << 24) \
+ | (((uint32_t)(val) & 0x0000ff00) << 8) \
+ | (((uint32_t)(val) & 0x00ff0000) >> 8) \
+ | (((uint32_t)(val) & 0xff000000) >> 24))
+
+/**
+ * BSWAP_64 - reverse bytes in a constant uint64_t value.
+ * @val: constantvalue whose bytes to swap.
+ *
+ * Designed to be usable in constant-requiring initializers.
+ *
+ * Example:
+ * struct mystruct {
+ * char buf[BSWAP_64(0xff00000000000000ULL)];
+ * };
+ */
+#define BSWAP_64(val) \
+ ((((uint64_t)(val) & 0x00000000000000ffULL) << 56) \
+ | (((uint64_t)(val) & 0x000000000000ff00ULL) << 40) \
+ | (((uint64_t)(val) & 0x0000000000ff0000ULL) << 24) \
+ | (((uint64_t)(val) & 0x00000000ff000000ULL) << 8) \
+ | (((uint64_t)(val) & 0x000000ff00000000ULL) >> 8) \
+ | (((uint64_t)(val) & 0x0000ff0000000000ULL) >> 24) \
+ | (((uint64_t)(val) & 0x00ff000000000000ULL) >> 40) \
+ | (((uint64_t)(val) & 0xff00000000000000ULL) >> 56))
+
+#if HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+/**
+ * bswap_16 - reverse bytes in a uint16_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 4 as two bytes reversed"
+ * printf("1024 is %u as two bytes reversed\n", bswap_16(1024));
+ */
+static inline uint16_t bswap_16(uint16_t val)
+{
+ return BSWAP_16(val);
+}
+
+/**
+ * bswap_32 - reverse bytes in a uint32_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 262144 as four bytes reversed"
+ * printf("1024 is %u as four bytes reversed\n", bswap_32(1024));
+ */
+static inline uint32_t bswap_32(uint32_t val)
+{
+ return BSWAP_32(val);
+}
+#endif /* !HAVE_BYTESWAP_H */
+
+#if !HAVE_BSWAP_64
+/**
+ * bswap_64 - reverse bytes in a uint64_t value.
+ * @val: value whose bytes to swap.
+ *
+ * Example:
+ * // Output contains "1024 is 1125899906842624 as eight bytes reversed"
+ * printf("1024 is %llu as eight bytes reversed\n",
+ * (unsigned long long)bswap_64(1024));
+ */
+static inline uint64_t bswap_64(uint64_t val)
+{
+ return BSWAP_64(val);
+}
+#endif
+
+/* Needed for Glibc like endiness check */
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+
+/* Sanity check the defines. We don't handle weird endianness. */
+#if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN
+#error "Unknown endian"
+#elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
+#error "Can't compile for both big and little endian."
+#elif HAVE_LITTLE_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#elif __BYTE_ORDER != __LITTLE_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __LITTLE_ENDIAN"
+#endif
+#elif HAVE_BIG_ENDIAN
+#ifndef __BYTE_ORDER
+#define __BYTE_ORDER __BIG_ENDIAN
+#elif __BYTE_ORDER != __BIG_ENDIAN
+#error "__BYTE_ORDER already defined, but not equal to __BIG_ENDIAN"
+#endif
+#endif
+
+
+#ifdef __CHECKER__
+/* sparse needs forcing to remove bitwise attribute from ccan/short_types */
+#define ENDIAN_CAST __attribute__((force))
+#define ENDIAN_TYPE __attribute__((bitwise))
+#else
+#define ENDIAN_CAST
+#define ENDIAN_TYPE
+#endif
+
+typedef uint64_t ENDIAN_TYPE leint64_t;
+typedef uint64_t ENDIAN_TYPE beint64_t;
+typedef uint32_t ENDIAN_TYPE leint32_t;
+typedef uint32_t ENDIAN_TYPE beint32_t;
+typedef uint16_t ENDIAN_TYPE leint16_t;
+typedef uint16_t ENDIAN_TYPE beint16_t;
+
+#if HAVE_LITTLE_ENDIAN
+/**
+ * CPU_TO_LE64 - convert a constant uint64_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)(native))
+
+/**
+ * CPU_TO_LE32 - convert a constant uint32_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)(native))
+
+/**
+ * CPU_TO_LE16 - convert a constant uint16_t value to little-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)(native))
+
+/**
+ * LE64_TO_CPU - convert a little-endian uint64_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * LE32_TO_CPU - convert a little-endian uint32_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * LE16_TO_CPU - convert a little-endian uint16_t constant
+ * @le_val: little-endian constant to convert
+ */
+#define LE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_BIG_ENDIAN */
+#define CPU_TO_LE64(native) ((ENDIAN_CAST leint64_t)BSWAP_64(native))
+#define CPU_TO_LE32(native) ((ENDIAN_CAST leint32_t)BSWAP_32(native))
+#define CPU_TO_LE16(native) ((ENDIAN_CAST leint16_t)BSWAP_16(native))
+#define LE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define LE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define LE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_BIG_ENDIAN */
+
+#if HAVE_BIG_ENDIAN
+/**
+ * CPU_TO_BE64 - convert a constant uint64_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)(native))
+
+/**
+ * CPU_TO_BE32 - convert a constant uint32_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)(native))
+
+/**
+ * CPU_TO_BE16 - convert a constant uint16_t value to big-endian
+ * @native: constant to convert
+ */
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)(native))
+
+/**
+ * BE64_TO_CPU - convert a big-endian uint64_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE64_TO_CPU(le_val) ((ENDIAN_CAST uint64_t)(le_val))
+
+/**
+ * BE32_TO_CPU - convert a big-endian uint32_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE32_TO_CPU(le_val) ((ENDIAN_CAST uint32_t)(le_val))
+
+/**
+ * BE16_TO_CPU - convert a big-endian uint16_t constant
+ * @le_val: big-endian constant to convert
+ */
+#define BE16_TO_CPU(le_val) ((ENDIAN_CAST uint16_t)(le_val))
+
+#else /* ... HAVE_LITTLE_ENDIAN */
+#define CPU_TO_BE64(native) ((ENDIAN_CAST beint64_t)BSWAP_64(native))
+#define CPU_TO_BE32(native) ((ENDIAN_CAST beint32_t)BSWAP_32(native))
+#define CPU_TO_BE16(native) ((ENDIAN_CAST beint16_t)BSWAP_16(native))
+#define BE64_TO_CPU(le_val) BSWAP_64((ENDIAN_CAST uint64_t)le_val)
+#define BE32_TO_CPU(le_val) BSWAP_32((ENDIAN_CAST uint32_t)le_val)
+#define BE16_TO_CPU(le_val) BSWAP_16((ENDIAN_CAST uint16_t)le_val)
+#endif /* HAVE_LITTE_ENDIAN */
+
+
+/**
+ * cpu_to_le64 - convert a uint64_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint64_t cpu_to_le64(uint64_t native)
+{
+ return CPU_TO_LE64(native);
+}
+
+/**
+ * cpu_to_le32 - convert a uint32_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint32_t cpu_to_le32(uint32_t native)
+{
+ return CPU_TO_LE32(native);
+}
+
+/**
+ * cpu_to_le16 - convert a uint16_t value to little-endian
+ * @native: value to convert
+ */
+static inline leint16_t cpu_to_le16(uint16_t native)
+{
+ return CPU_TO_LE16(native);
+}
+
+/**
+ * le64_to_cpu - convert a little-endian uint64_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint64_t le64_to_cpu(leint64_t le_val)
+{
+ return LE64_TO_CPU(le_val);
+}
+
+/**
+ * le32_to_cpu - convert a little-endian uint32_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint32_t le32_to_cpu(leint32_t le_val)
+{
+ return LE32_TO_CPU(le_val);
+}
+
+/**
+ * le16_to_cpu - convert a little-endian uint16_t value
+ * @le_val: little-endian value to convert
+ */
+static inline uint16_t le16_to_cpu(leint16_t le_val)
+{
+ return LE16_TO_CPU(le_val);
+}
+
+/**
+ * cpu_to_be64 - convert a uint64_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint64_t cpu_to_be64(uint64_t native)
+{
+ return CPU_TO_BE64(native);
+}
+
+/**
+ * cpu_to_be32 - convert a uint32_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint32_t cpu_to_be32(uint32_t native)
+{
+ return CPU_TO_BE32(native);
+}
+
+/**
+ * cpu_to_be16 - convert a uint16_t value to big endian.
+ * @native: value to convert
+ */
+static inline beint16_t cpu_to_be16(uint16_t native)
+{
+ return CPU_TO_BE16(native);
+}
+
+/**
+ * be64_to_cpu - convert a big-endian uint64_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint64_t be64_to_cpu(beint64_t be_val)
+{
+ return BE64_TO_CPU(be_val);
+}
+
+/**
+ * be32_to_cpu - convert a big-endian uint32_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint32_t be32_to_cpu(beint32_t be_val)
+{
+ return BE32_TO_CPU(be_val);
+}
+
+/**
+ * be16_to_cpu - convert a big-endian uint16_t value
+ * @be_val: big-endian value to convert
+ */
+static inline uint16_t be16_to_cpu(beint16_t be_val)
+{
+ return BE16_TO_CPU(be_val);
+}
+
+/* Whichever they include first, they get these definitions. */
+#ifdef CCAN_SHORT_TYPES_H
+/**
+ * be64/be32/be16 - 64/32/16 bit big-endian representation.
+ */
+typedef beint64_t be64;
+typedef beint32_t be32;
+typedef beint16_t be16;
+
+/**
+ * le64/le32/le16 - 64/32/16 bit little-endian representation.
+ */
+typedef leint64_t le64;
+typedef leint32_t le32;
+typedef leint16_t le16;
+#endif
+#endif /* CCAN_ENDIAN_H */
diff --git a/ccan/ccan/hash/LICENSE b/ccan/ccan/hash/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/hash/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/hash/hash.c b/ccan/ccan/hash/hash.c
new file mode 100644
index 0000000..88d88fc
--- /dev/null
+++ b/ccan/ccan/hash/hash.c
@@ -0,0 +1,926 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hash_word(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hash_word(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+//#define SELF_TEST 1
+
+#if 0
+#include <stdio.h> /* defines printf for tests */
+#include <time.h> /* defines time_t for timings in the test */
+#include <stdint.h> /* defines uint32_t etc */
+#include <sys/param.h> /* attempt to define endianness */
+
+#ifdef linux
+# include <endian.h> /* attempt to define endianness */
+#endif
+
+/*
+ * My best guess at if you are big-endian or little-endian. This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN) || \
+ (defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(__x86_64) || \
+ defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+ __BYTE_ORDER == __BIG_ENDIAN) || \
+ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# error Unknown endian
+#endif
+#endif /* old hash.c headers. */
+
+#include "hash.h"
+
+#if HAVE_LITTLE_ENDIAN
+#define HASH_LITTLE_ENDIAN 1
+#define HASH_BIG_ENDIAN 0
+#elif HAVE_BIG_ENDIAN
+#define HASH_LITTLE_ENDIAN 0
+#define HASH_BIG_ENDIAN 1
+#else
+#error Unknown endian
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function hash_word() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes. hashlittle() is more complicated than hash_word() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t hash_u32(
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t initval) /* the previous hash, or an arbitrary value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ val2 : IN: can be any 4-byte value OUT: second 32 bit hash.
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values. Note that the return value is better
+mixed than val2, so use that first.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+static uint32_t hashlittle( const void *key, size_t length, uint32_t *val2 )
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticeably faster for short strings (like English words).
+ *
+ * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
+ */
+#if 0
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ *val2 = b;
+ return c;
+}
+
+/*
+ * hashbig():
+ * This is the same as hash_word() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+static uint32_t hashbig( const void *key, size_t length, uint32_t *val2)
+{
+ uint32_t a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + *val2;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ const uint8_t *k8;
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticeably faster for short strings (like English words).
+ *
+ * Not on my testing with gcc 4.5 on an intel i5 CPU, at least --RR.
+ */
+#if 0
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
+ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
+ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
+ case 1 : a+=((uint32_t)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((uint32_t)k[0])<<24;
+ a += ((uint32_t)k[1])<<16;
+ a += ((uint32_t)k[2])<<8;
+ a += ((uint32_t)k[3]);
+ b += ((uint32_t)k[4])<<24;
+ b += ((uint32_t)k[5])<<16;
+ b += ((uint32_t)k[6])<<8;
+ b += ((uint32_t)k[7]);
+ c += ((uint32_t)k[8])<<24;
+ c += ((uint32_t)k[9])<<16;
+ c += ((uint32_t)k[10])<<8;
+ c += ((uint32_t)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ case 11: c+=((uint32_t)k[10])<<8;
+ case 10: c+=((uint32_t)k[9])<<16;
+ case 9 : c+=((uint32_t)k[8])<<24;
+ case 8 : b+=k[7];
+ case 7 : b+=((uint32_t)k[6])<<8;
+ case 6 : b+=((uint32_t)k[5])<<16;
+ case 5 : b+=((uint32_t)k[4])<<24;
+ case 4 : a+=k[3];
+ case 3 : a+=((uint32_t)k[2])<<8;
+ case 2 : a+=((uint32_t)k[1])<<16;
+ case 1 : a+=((uint32_t)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ *val2 = b;
+ return c;
+}
+
+/* I basically use hashlittle here, but use native endian within each
+ * element. This delivers least-surprise: hash such as "int arr[] = {
+ * 1, 2 }; hash_stable(arr, 2, 0);" will be the same on big and little
+ * endian machines, even though a bytewise hash wouldn't be. */
+uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base)
+{
+ const uint64_t *k = key;
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)n*8) + (base >> 32) + base;
+
+ while (n > 3) {
+ a += (uint32_t)k[0];
+ b += (uint32_t)(k[0] >> 32);
+ c += (uint32_t)k[1];
+ mix(a,b,c);
+ a += (uint32_t)(k[1] >> 32);
+ b += (uint32_t)k[2];
+ c += (uint32_t)(k[2] >> 32);
+ mix(a,b,c);
+ n -= 3;
+ k += 3;
+ }
+ switch (n) {
+ case 2:
+ a += (uint32_t)k[0];
+ b += (uint32_t)(k[0] >> 32);
+ c += (uint32_t)k[1];
+ mix(a,b,c);
+ a += (uint32_t)(k[1] >> 32);
+ break;
+ case 1:
+ a += (uint32_t)k[0];
+ b += (uint32_t)(k[0] >> 32);
+ break;
+ case 0:
+ return c;
+ }
+ final(a,b,c);
+ return ((uint64_t)b << 32) | c;
+}
+
+uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base)
+{
+ const uint32_t *k = key;
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)n*4) + (base >> 32) + base;
+
+ while (n > 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+
+ n -= 3;
+ k += 3;
+ }
+ switch (n) {
+ case 2:
+ b += (uint32_t)k[1];
+ case 1:
+ a += (uint32_t)k[0];
+ break;
+ case 0:
+ return c;
+ }
+ final(a,b,c);
+ return ((uint64_t)b << 32) | c;
+}
+
+uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base)
+{
+ const uint16_t *k = key;
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)n*2) + (base >> 32) + base;
+
+ while (n > 6) {
+ a += (uint32_t)k[0] + ((uint32_t)k[1] << 16);
+ b += (uint32_t)k[2] + ((uint32_t)k[3] << 16);
+ c += (uint32_t)k[4] + ((uint32_t)k[5] << 16);
+ mix(a,b,c);
+
+ n -= 6;
+ k += 6;
+ }
+
+ switch (n) {
+ case 5:
+ c += (uint32_t)k[4];
+ case 4:
+ b += ((uint32_t)k[3] << 16);
+ case 3:
+ b += (uint32_t)k[2];
+ case 2:
+ a += ((uint32_t)k[1] << 16);
+ case 1:
+ a += (uint32_t)k[0];
+ break;
+ case 0:
+ return c;
+ }
+ final(a,b,c);
+ return ((uint64_t)b << 32) | c;
+}
+
+uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base)
+{
+ uint32_t b32 = base + (base >> 32);
+ uint32_t lower = hashlittle(key, n, &b32);
+
+ return ((uint64_t)b32 << 32) | lower;
+}
+
+uint32_t hash_any(const void *key, size_t length, uint32_t base)
+{
+ if (HASH_BIG_ENDIAN)
+ return hashbig(key, length, &base);
+ else
+ return hashlittle(key, length, &base);
+}
+
+uint32_t hash_stable_64(const void *key, size_t n, uint32_t base)
+{
+ return hash64_stable_64(key, n, base);
+}
+
+uint32_t hash_stable_32(const void *key, size_t n, uint32_t base)
+{
+ return hash64_stable_32(key, n, base);
+}
+
+uint32_t hash_stable_16(const void *key, size_t n, uint32_t base)
+{
+ return hash64_stable_16(key, n, base);
+}
+
+uint32_t hash_stable_8(const void *key, size_t n, uint32_t base)
+{
+ return hashlittle(key, n, &base);
+}
+
+/* Jenkins' lookup8 is a 64 bit hash, but he says it's obsolete. Use
+ * the plain one and recombine into 64 bits. */
+uint64_t hash64_any(const void *key, size_t length, uint64_t base)
+{
+ uint32_t b32 = base + (base >> 32);
+ uint32_t lower;
+
+ if (HASH_BIG_ENDIAN)
+ lower = hashbig(key, length, &b32);
+ else
+ lower = hashlittle(key, length, &b32);
+
+ return ((uint64_t)b32 << 32) | lower;
+}
+
+#ifdef SELF_TEST
+
+/* used for timings */
+void driver1()
+{
+ uint8_t buf[256];
+ uint32_t i;
+ uint32_t h=0;
+ time_t a,z;
+
+ time(&a);
+ for (i=0; i<256; ++i) buf[i] = 'x';
+ for (i=0; i<1; ++i)
+ {
+ h = hashlittle(&buf[0],1,h);
+ }
+ time(&z);
+ if (z-a > 0) printf("time %d %.8x\n", z-a, h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN 1
+#define MAXPAIR 60
+#define MAXLEN 70
+void driver2()
+{
+ uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+ uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+ uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+ uint32_t x[HASHSTATE],y[HASHSTATE];
+ uint32_t hlen;
+
+ printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+ for (hlen=0; hlen < MAXLEN; ++hlen)
+ {
+ z=0;
+ for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
+ {
+ for (j=0; j<8; ++j) /*------------------------ for each input bit, */
+ {
+ for (m=1; m<8; ++m) /*------------ for several possible initvals, */
+ {
+ for (l=0; l<HASHSTATE; ++l)
+ e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+ /*---- check that every output bit is affected by that input bit */
+ for (k=0; k<MAXPAIR; k+=2)
+ {
+ uint32_t finished=1;
+ /* keys have one bit different */
+ for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+ /* have a and b be two keys differing in only one bit */
+ a[i] ^= (k<<j);
+ a[i] ^= (k>>(8-j));
+ c[0] = hashlittle(a, hlen, m);
+ b[i] ^= ((k+1)<<j);
+ b[i] ^= ((k+1)>>(8-j));
+ d[0] = hashlittle(b, hlen, m);
+ /* check every bit is 1, 0, set, and not set at least once */
+ for (l=0; l<HASHSTATE; ++l)
+ {
+ e[l] &= (c[l]^d[l]);
+ f[l] &= ~(c[l]^d[l]);
+ g[l] &= c[l];
+ h[l] &= ~c[l];
+ x[l] &= d[l];
+ y[l] &= ~d[l];
+ if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+ }
+ if (finished) break;
+ }
+ if (k>z) z=k;
+ if (k==MAXPAIR)
+ {
+ printf("Some bit didn't change: ");
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
+ e[0],f[0],g[0],h[0],x[0],y[0]);
+ printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+ }
+ if (z==MAXPAIR) goto done;
+ }
+ }
+ }
+ done:
+ if (z < MAXPAIR)
+ {
+ printf("Mix success %2d bytes %2d initvals ",i,m);
+ printf("required %d trials\n", z/2);
+ }
+ }
+ printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+void driver3()
+{
+ uint8_t buf[MAXLEN+20], *b;
+ uint32_t len;
+ uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+ uint32_t h;
+ uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+ uint32_t i;
+ uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+ uint32_t j;
+ uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+ uint32_t ref,x,y;
+ uint8_t *p;
+
+ printf("Endianness. These lines should all be the same (for values filled in):\n");
+ printf("%.8x %.8x %.8x\n",
+ hash_word((const uint32_t *)q, (sizeof(q)-1)/4, 13),
+ hash_word((const uint32_t *)q, (sizeof(q)-5)/4, 13),
+ hash_word((const uint32_t *)q, (sizeof(q)-9)/4, 13));
+ p = q;
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qq[1];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqq[2];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqqq[3];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ printf("\n");
+
+ /* check that hashlittle2 and hashlittle produce the same results */
+ i=47; j=0;
+ hashlittle2(q, sizeof(q), &i, &j);
+ if (hashlittle(q, sizeof(q), 47) != i)
+ printf("hashlittle2 and hashlittle mismatch\n");
+
+ /* check that hash_word2 and hash_word produce the same results */
+ len = 0xdeadbeef;
+ i=47, j=0;
+ hash_word2(&len, 1, &i, &j);
+ if (hash_word(&len, 1, 47) != i)
+ printf("hash_word2 and hash_word mismatch %x %x\n",
+ i, hash_word(&len, 1, 47));
+
+ /* check hashlittle doesn't read before or after the ends of the string */
+ for (h=0, b=buf+1; h<8; ++h, ++b)
+ {
+ for (i=0; i<MAXLEN; ++i)
+ {
+ len = i;
+ for (j=0; j<i; ++j) *(b+j)=0;
+
+ /* these should all be equal */
+ ref = hashlittle(b, len, (uint32_t)1);
+ *(b+i)=(uint8_t)~0;
+ *(b-1)=(uint8_t)~0;
+ x = hashlittle(b, len, (uint32_t)1);
+ y = hashlittle(b, len, (uint32_t)1);
+ if ((ref != x) || (ref != y))
+ {
+ printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
+ h, i);
+ }
+ }
+ }
+}
+
+/* check for problems with nulls */
+ void driver4()
+{
+ uint8_t buf[1];
+ uint32_t h,i,state[HASHSTATE];
+
+
+ buf[0] = ~0;
+ for (i=0; i<HASHSTATE; ++i) state[i] = 1;
+ printf("These should all be different\n");
+ for (i=0, h=0; i<8; ++i)
+ {
+ h = hashlittle(buf, 0, h);
+ printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
+ }
+}
+
+
+int main()
+{
+ driver1(); /* test that the key is hashed: used for timings */
+ driver2(); /* test that whole key is hashed thoroughly */
+ driver3(); /* test that nothing but the key is hashed */
+ driver4(); /* test hashing multiple buffers (all buffers are null) */
+ return 1;
+}
+
+#endif /* SELF_TEST */
diff --git a/ccan/ccan/hash/hash.h b/ccan/ccan/hash/hash.h
new file mode 100644
index 0000000..2170684
--- /dev/null
+++ b/ccan/ccan/hash/hash.h
@@ -0,0 +1,313 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_HASH_H
+#define CCAN_HASH_H
+#include "config.h"
+#include <stdint.h>
+#include <stdlib.h>
+#include <ccan/build_assert/build_assert.h>
+
+/* Stolen mostly from: lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+ *
+ * http://burtleburtle.net/bob/c/lookup3.c
+ */
+
+/**
+ * hash - fast hash of an array for internal use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The memory region pointed to by p is combined with the base to form
+ * a 32-bit hash.
+ *
+ * This hash will have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk).
+ *
+ * It may also change with future versions: it could even detect at runtime
+ * what the fastest hash to use is.
+ *
+ * See also: hash64, hash_stable.
+ *
+ * Example:
+ * #include <ccan/hash/hash.h>
+ * #include <err.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ *
+ * // Simple demonstration: idential strings will have the same hash, but
+ * // two different strings will probably not.
+ * int main(int argc, char *argv[])
+ * {
+ * uint32_t hash1, hash2;
+ *
+ * if (argc != 3)
+ * err(1, "Usage: %s <string1> <string2>", argv[0]);
+ *
+ * hash1 = hash(argv[1], strlen(argv[1]), 0);
+ * hash2 = hash(argv[2], strlen(argv[2]), 0);
+ * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different");
+ * return 0;
+ * }
+ */
+#define hash(p, num, base) hash_any((p), (num)*sizeof(*(p)), (base))
+
+/**
+ * hash_stable - hash of an array for external use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The array of simple integer types pointed to by p is combined with
+ * the base to form a 32-bit hash.
+ *
+ * This hash will have the same results on different machines, so can
+ * be used for external hashes (ie. hashes sent across the network or
+ * saved to disk). The results will not change in future versions of
+ * this module.
+ *
+ * Note that it is only legal to hand an array of simple integer types
+ * to this hash (ie. char, uint16_t, int64_t, etc). In these cases,
+ * the same values will have the same hash result, even though the
+ * memory representations of integers depend on the machine
+ * endianness.
+ *
+ * See also:
+ * hash64_stable
+ *
+ * Example:
+ * #include <ccan/hash/hash.h>
+ * #include <err.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * if (argc != 2)
+ * err(1, "Usage: %s <string-to-hash>", argv[0]);
+ *
+ * printf("Hash stable result is %u\n",
+ * hash_stable(argv[1], strlen(argv[1]), 0));
+ * return 0;
+ * }
+ */
+#define hash_stable(p, num, base) \
+ (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \
+ || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \
+ sizeof(*(p)) == 8 ? hash_stable_64((p), (num), (base)) \
+ : sizeof(*(p)) == 4 ? hash_stable_32((p), (num), (base)) \
+ : sizeof(*(p)) == 2 ? hash_stable_16((p), (num), (base)) \
+ : hash_stable_8((p), (num), (base)))
+
+/**
+ * hash_u32 - fast hash an array of 32-bit values for internal use
+ * @key: the array of uint32_t
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The array of uint32_t pointed to by @key is combined with the base
+ * to form a 32-bit hash. This is 2-3 times faster than hash() on small
+ * arrays, but the advantage vanishes over large hashes.
+ *
+ * This hash will have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk).
+ */
+uint32_t hash_u32(const uint32_t *key, size_t num, uint32_t base);
+
+/**
+ * hash_string - very fast hash of an ascii string
+ * @str: the nul-terminated string
+ *
+ * The string is hashed, using a hash function optimized for ASCII and
+ * similar strings. It's weaker than the other hash functions.
+ *
+ * This hash may have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk). The results will be different from the
+ * other hash functions in this module, too.
+ */
+static inline uint32_t hash_string(const char *string)
+{
+ /* This is Karl Nelson <kenelson@ece.ucdavis.edu>'s X31 hash.
+ * It's a little faster than the (much better) lookup3 hash(): 56ns vs
+ * 84ns on my 2GHz Intel Core Duo 2 laptop for a 10 char string. */
+ uint32_t ret;
+
+ for (ret = 0; *string; string++)
+ ret = (ret << 5) - ret + *string;
+
+ return ret;
+}
+
+/**
+ * hash64 - fast 64-bit hash of an array for internal use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the 64-bit base number to roll into the hash (usually 0)
+ *
+ * The memory region pointed to by p is combined with the base to form
+ * a 64-bit hash.
+ *
+ * This hash will have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk).
+ *
+ * It may also change with future versions: it could even detect at runtime
+ * what the fastest hash to use is.
+ *
+ * See also: hash.
+ *
+ * Example:
+ * #include <ccan/hash/hash.h>
+ * #include <err.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ *
+ * // Simple demonstration: idential strings will have the same hash, but
+ * // two different strings will probably not.
+ * int main(int argc, char *argv[])
+ * {
+ * uint64_t hash1, hash2;
+ *
+ * if (argc != 3)
+ * err(1, "Usage: %s <string1> <string2>", argv[0]);
+ *
+ * hash1 = hash64(argv[1], strlen(argv[1]), 0);
+ * hash2 = hash64(argv[2], strlen(argv[2]), 0);
+ * printf("Hash is %s\n", hash1 == hash2 ? "same" : "different");
+ * return 0;
+ * }
+ */
+#define hash64(p, num, base) hash64_any((p), (num)*sizeof(*(p)), (base))
+
+/**
+ * hash64_stable - 64 bit hash of an array for external use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The array of simple integer types pointed to by p is combined with
+ * the base to form a 64-bit hash.
+ *
+ * This hash will have the same results on different machines, so can
+ * be used for external hashes (ie. hashes sent across the network or
+ * saved to disk). The results will not change in future versions of
+ * this module.
+ *
+ * Note that it is only legal to hand an array of simple integer types
+ * to this hash (ie. char, uint16_t, int64_t, etc). In these cases,
+ * the same values will have the same hash result, even though the
+ * memory representations of integers depend on the machine
+ * endianness.
+ *
+ * See also:
+ * hash_stable
+ *
+ * Example:
+ * #include <ccan/hash/hash.h>
+ * #include <err.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ *
+ * int main(int argc, char *argv[])
+ * {
+ * if (argc != 2)
+ * err(1, "Usage: %s <string-to-hash>", argv[0]);
+ *
+ * printf("Hash stable result is %llu\n",
+ * (long long)hash64_stable(argv[1], strlen(argv[1]), 0));
+ * return 0;
+ * }
+ */
+#define hash64_stable(p, num, base) \
+ (BUILD_ASSERT_OR_ZERO(sizeof(*(p)) == 8 || sizeof(*(p)) == 4 \
+ || sizeof(*(p)) == 2 || sizeof(*(p)) == 1) + \
+ sizeof(*(p)) == 8 ? hash64_stable_64((p), (num), (base)) \
+ : sizeof(*(p)) == 4 ? hash64_stable_32((p), (num), (base)) \
+ : sizeof(*(p)) == 2 ? hash64_stable_16((p), (num), (base)) \
+ : hash64_stable_8((p), (num), (base)))
+
+
+/**
+ * hashl - fast 32/64-bit hash of an array for internal use
+ * @p: the array or pointer to first element
+ * @num: the number of elements to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * This is either hash() or hash64(), on 32/64 bit long machines.
+ */
+#define hashl(p, num, base) \
+ (BUILD_ASSERT_OR_ZERO(sizeof(long) == sizeof(uint32_t) \
+ || sizeof(long) == sizeof(uint64_t)) + \
+ (sizeof(long) == sizeof(uint64_t) \
+ ? hash64((p), (num), (base)) : hash((p), (num), (base))))
+
+/* Our underlying operations. */
+uint32_t hash_any(const void *key, size_t length, uint32_t base);
+uint32_t hash_stable_64(const void *key, size_t n, uint32_t base);
+uint32_t hash_stable_32(const void *key, size_t n, uint32_t base);
+uint32_t hash_stable_16(const void *key, size_t n, uint32_t base);
+uint32_t hash_stable_8(const void *key, size_t n, uint32_t base);
+uint64_t hash64_any(const void *key, size_t length, uint64_t base);
+uint64_t hash64_stable_64(const void *key, size_t n, uint64_t base);
+uint64_t hash64_stable_32(const void *key, size_t n, uint64_t base);
+uint64_t hash64_stable_16(const void *key, size_t n, uint64_t base);
+uint64_t hash64_stable_8(const void *key, size_t n, uint64_t base);
+
+/**
+ * hash_pointer - hash a pointer for internal use
+ * @p: the pointer value to hash
+ * @base: the base number to roll into the hash (usually 0)
+ *
+ * The pointer p (not what p points to!) is combined with the base to form
+ * a 32-bit hash.
+ *
+ * This hash will have different results on different machines, so is
+ * only useful for internal hashes (ie. not hashes sent across the
+ * network or saved to disk).
+ *
+ * Example:
+ * #include <ccan/hash/hash.h>
+ *
+ * // Code to keep track of memory regions.
+ * struct region {
+ * struct region *chain;
+ * void *start;
+ * unsigned int size;
+ * };
+ * // We keep a simple hash table.
+ * static struct region *region_hash[128];
+ *
+ * static void add_region(struct region *r)
+ * {
+ * unsigned int h = hash_pointer(r->start, 0);
+ *
+ * r->chain = region_hash[h];
+ * region_hash[h] = r->chain;
+ * }
+ *
+ * static struct region *find_region(const void *start)
+ * {
+ * struct region *r;
+ *
+ * for (r = region_hash[hash_pointer(start, 0)]; r; r = r->chain)
+ * if (r->start == start)
+ * return r;
+ * return NULL;
+ * }
+ */
+static inline uint32_t hash_pointer(const void *p, uint32_t base)
+{
+ if (sizeof(p) % sizeof(uint32_t) == 0) {
+ /* This convoluted union is the right way of aliasing. */
+ union {
+ uint32_t a[sizeof(p) / sizeof(uint32_t)];
+ const void *p;
+ } u;
+ u.p = p;
+ return hash_u32(u.a, sizeof(p) / sizeof(uint32_t), base);
+ } else
+ return hash(&p, 1, base);
+}
+#endif /* HASH_H */
diff --git a/ccan/ccan/htable/LICENSE b/ccan/ccan/htable/LICENSE
new file mode 120000
index 0000000..dc314ec
--- /dev/null
+++ b/ccan/ccan/htable/LICENSE
@@ -0,0 +1 @@
+../../licenses/LGPL-2.1 \ No newline at end of file
diff --git a/ccan/ccan/htable/htable.c b/ccan/ccan/htable/htable.c
new file mode 100644
index 0000000..f631ffe
--- /dev/null
+++ b/ccan/ccan/htable/htable.c
@@ -0,0 +1,491 @@
+/* Licensed under LGPLv2+ - see LICENSE file for details */
+#include <ccan/htable/htable.h>
+#include <ccan/compiler/compiler.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <string.h>
+
+/* We use 0x1 as deleted marker. */
+#define HTABLE_DELETED (0x1)
+
+/* perfect_bitnum 63 means there's no perfect bitnum */
+#define NO_PERFECT_BIT (sizeof(uintptr_t) * CHAR_BIT - 1)
+
+static void *htable_default_alloc(struct htable *ht, size_t len)
+{
+ return calloc(len, 1);
+}
+
+static void htable_default_free(struct htable *ht, void *p)
+{
+ free(p);
+}
+
+static void *(*htable_alloc)(struct htable *, size_t) = htable_default_alloc;
+static void (*htable_free)(struct htable *, void *) = htable_default_free;
+
+void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
+ void (*free)(struct htable *, void *p))
+{
+ if (!alloc)
+ alloc = htable_default_alloc;
+ if (!free)
+ free = htable_default_free;
+ htable_alloc = alloc;
+ htable_free = free;
+}
+
+/* We clear out the bits which are always the same, and put metadata there. */
+static inline uintptr_t get_extra_ptr_bits(const struct htable *ht,
+ uintptr_t e)
+{
+ return e & ht->common_mask;
+}
+
+static inline void *get_raw_ptr(const struct htable *ht, uintptr_t e)
+{
+ return (void *)((e & ~ht->common_mask) | ht->common_bits);
+}
+
+static inline uintptr_t make_hval(const struct htable *ht,
+ const void *p, uintptr_t bits)
+{
+ return ((uintptr_t)p & ~ht->common_mask) | bits;
+}
+
+static inline bool entry_is_valid(uintptr_t e)
+{
+ return e > HTABLE_DELETED;
+}
+
+static inline uintptr_t ht_perfect_mask(const struct htable *ht)
+{
+ return (uintptr_t)2 << ht->perfect_bitnum;
+}
+
+static inline uintptr_t get_hash_ptr_bits(const struct htable *ht,
+ size_t hash)
+{
+ /* Shuffling the extra bits (as specified in mask) down the
+ * end is quite expensive. But the lower bits are redundant, so
+ * we fold the value first. */
+ return (hash ^ (hash >> ht->bits))
+ & ht->common_mask & ~ht_perfect_mask(ht);
+}
+
+void htable_init(struct htable *ht,
+ size_t (*rehash)(const void *elem, void *priv), void *priv)
+{
+ struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL);
+ *ht = empty;
+ ht->rehash = rehash;
+ ht->priv = priv;
+ ht->table = &ht->common_bits;
+}
+
+/* Fill to 87.5% */
+static inline size_t ht_max(const struct htable *ht)
+{
+ return ((size_t)7 << ht->bits) / 8;
+}
+
+/* Clean deleted if we're full, and more than 12.5% deleted */
+static inline size_t ht_max_deleted(const struct htable *ht)
+{
+ return ((size_t)1 << ht->bits) / 8;
+}
+
+bool htable_init_sized(struct htable *ht,
+ size_t (*rehash)(const void *, void *),
+ void *priv, size_t expect)
+{
+ htable_init(ht, rehash, priv);
+
+ /* Don't go insane with sizing. */
+ for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) {
+ if (ht->bits == 30)
+ break;
+ }
+
+ ht->table = htable_alloc(ht, sizeof(size_t) << ht->bits);
+ if (!ht->table) {
+ ht->table = &ht->common_bits;
+ return false;
+ }
+ (void)htable_debug(ht, HTABLE_LOC);
+ return true;
+}
+
+void htable_clear(struct htable *ht)
+{
+ if (ht->table != &ht->common_bits)
+ htable_free(ht, (void *)ht->table);
+ htable_init(ht, ht->rehash, ht->priv);
+}
+
+bool htable_copy_(struct htable *dst, const struct htable *src)
+{
+ uintptr_t *htable = htable_alloc(dst, sizeof(size_t) << src->bits);
+
+ if (!htable)
+ return false;
+
+ *dst = *src;
+ dst->table = htable;
+ memcpy(dst->table, src->table, sizeof(size_t) << src->bits);
+ return true;
+}
+
+static size_t hash_bucket(const struct htable *ht, size_t h)
+{
+ return h & ((1 << ht->bits)-1);
+}
+
+static void *htable_val(const struct htable *ht,
+ struct htable_iter *i, size_t hash, uintptr_t perfect)
+{
+ uintptr_t h2 = get_hash_ptr_bits(ht, hash) | perfect;
+
+ while (ht->table[i->off]) {
+ if (ht->table[i->off] != HTABLE_DELETED) {
+ if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2)
+ return get_raw_ptr(ht, ht->table[i->off]);
+ }
+ i->off = (i->off + 1) & ((1 << ht->bits)-1);
+ h2 &= ~perfect;
+ }
+ return NULL;
+}
+
+void *htable_firstval_(const struct htable *ht,
+ struct htable_iter *i, size_t hash)
+{
+ i->off = hash_bucket(ht, hash);
+ return htable_val(ht, i, hash, ht_perfect_mask(ht));
+}
+
+void *htable_nextval_(const struct htable *ht,
+ struct htable_iter *i, size_t hash)
+{
+ i->off = (i->off + 1) & ((1 << ht->bits)-1);
+ return htable_val(ht, i, hash, 0);
+}
+
+void *htable_first_(const struct htable *ht, struct htable_iter *i)
+{
+ for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) {
+ if (entry_is_valid(ht->table[i->off]))
+ return get_raw_ptr(ht, ht->table[i->off]);
+ }
+ return NULL;
+}
+
+void *htable_next_(const struct htable *ht, struct htable_iter *i)
+{
+ for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) {
+ if (entry_is_valid(ht->table[i->off]))
+ return get_raw_ptr(ht, ht->table[i->off]);
+ }
+ return NULL;
+}
+
+void *htable_prev_(const struct htable *ht, struct htable_iter *i)
+{
+ for (;;) {
+ if (!i->off)
+ return NULL;
+ i->off--;
+ if (entry_is_valid(ht->table[i->off]))
+ return get_raw_ptr(ht, ht->table[i->off]);
+ }
+}
+
+/* Another bit currently in mask needs to be exposed, so that a bucket with p in
+ * it won't appear invalid */
+static COLD void unset_another_common_bit(struct htable *ht,
+ uintptr_t *maskdiff,
+ const void *p)
+{
+ size_t i;
+
+ for (i = sizeof(uintptr_t) * CHAR_BIT - 1; i > 0; i--) {
+ if (((uintptr_t)p & ((uintptr_t)1 << i))
+ && ht->common_mask & ~*maskdiff & ((uintptr_t)1 << i))
+ break;
+ }
+ /* There must have been one, right? */
+ assert(i > 0);
+
+ *maskdiff |= ((uintptr_t)1 << i);
+}
+
+/* We want to change the common mask: this fixes up the table */
+static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff)
+{
+ size_t i;
+ uintptr_t bitsdiff;
+
+again:
+ bitsdiff = ht->common_bits & maskdiff;
+
+ for (i = 0; i < (size_t)1 << ht->bits; i++) {
+ uintptr_t e;
+ if (!entry_is_valid(e = ht->table[i]))
+ continue;
+
+ /* Clear the bits no longer in the mask, set them as
+ * expected. */
+ e &= ~maskdiff;
+ e |= bitsdiff;
+ /* If this made it invalid, restart with more exposed */
+ if (!entry_is_valid(e)) {
+ unset_another_common_bit(ht, &maskdiff, get_raw_ptr(ht, e));
+ goto again;
+ }
+ ht->table[i] = e;
+ }
+
+ /* Take away those bits from our mask, bits and perfect bit. */
+ ht->common_mask &= ~maskdiff;
+ ht->common_bits &= ~maskdiff;
+ if (ht_perfect_mask(ht) & maskdiff)
+ ht->perfect_bitnum = NO_PERFECT_BIT;
+}
+
+/* Limited recursion */
+static void ht_add(struct htable *ht, const void *new, size_t h);
+
+/* We tried to add this entry, but it looked invalid! We need to
+ * let another pointer bit through mask */
+static COLD void update_common_fix_invalid(struct htable *ht, const void *p, size_t h)
+{
+ uintptr_t maskdiff;
+
+ assert(ht->elems != 0);
+
+ maskdiff = 0;
+ unset_another_common_bit(ht, &maskdiff, p);
+ fixup_table_common(ht, maskdiff);
+
+ /* Now won't recurse */
+ ht_add(ht, p, h);
+}
+
+/* This does not expand the hash table, that's up to caller. */
+static void ht_add(struct htable *ht, const void *new, size_t h)
+{
+ size_t i;
+ uintptr_t perfect = ht_perfect_mask(ht);
+
+ i = hash_bucket(ht, h);
+
+ while (entry_is_valid(ht->table[i])) {
+ perfect = 0;
+ i = (i + 1) & ((1 << ht->bits)-1);
+ }
+ ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect);
+ if (!entry_is_valid(ht->table[i]))
+ update_common_fix_invalid(ht, new, h);
+}
+
+static COLD bool double_table(struct htable *ht)
+{
+ unsigned int i;
+ size_t oldnum = (size_t)1 << ht->bits;
+ uintptr_t *oldtable, e;
+
+ oldtable = ht->table;
+ ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1));
+ if (!ht->table) {
+ ht->table = oldtable;
+ return false;
+ }
+ ht->bits++;
+
+ /* If we lost our "perfect bit", get it back now. */
+ if (ht->perfect_bitnum == NO_PERFECT_BIT && ht->common_mask) {
+ for (i = 0; i < sizeof(ht->common_mask) * CHAR_BIT; i++) {
+ if (ht->common_mask & ((size_t)2 << i)) {
+ ht->perfect_bitnum = i;
+ break;
+ }
+ }
+ }
+
+ if (oldtable != &ht->common_bits) {
+ for (i = 0; i < oldnum; i++) {
+ if (entry_is_valid(e = oldtable[i])) {
+ void *p = get_raw_ptr(ht, e);
+ ht_add(ht, p, ht->rehash(p, ht->priv));
+ }
+ }
+ htable_free(ht, oldtable);
+ }
+ ht->deleted = 0;
+
+ (void)htable_debug(ht, HTABLE_LOC);
+ return true;
+}
+
+static COLD void rehash_table(struct htable *ht)
+{
+ size_t start, i;
+ uintptr_t e, perfect = ht_perfect_mask(ht);
+
+ /* Beware wrap cases: we need to start from first empty bucket. */
+ for (start = 0; ht->table[start]; start++);
+
+ for (i = 0; i < (size_t)1 << ht->bits; i++) {
+ size_t h = (i + start) & ((1 << ht->bits)-1);
+ e = ht->table[h];
+ if (!e)
+ continue;
+ if (e == HTABLE_DELETED)
+ ht->table[h] = 0;
+ else if (!(e & perfect)) {
+ void *p = get_raw_ptr(ht, e);
+ ht->table[h] = 0;
+ ht_add(ht, p, ht->rehash(p, ht->priv));
+ }
+ }
+ ht->deleted = 0;
+ (void)htable_debug(ht, HTABLE_LOC);
+}
+
+/* We stole some bits, now we need to put them back... */
+static COLD void update_common(struct htable *ht, const void *p)
+{
+ uintptr_t maskdiff;
+
+ if (ht->elems == 0) {
+ ht->common_mask = -1;
+ ht->common_bits = ((uintptr_t)p & ht->common_mask);
+ ht->perfect_bitnum = 0;
+ (void)htable_debug(ht, HTABLE_LOC);
+ return;
+ }
+
+ /* Find bits which are unequal to old common set. */
+ maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask);
+
+ fixup_table_common(ht, maskdiff);
+ (void)htable_debug(ht, HTABLE_LOC);
+}
+
+bool htable_add_(struct htable *ht, size_t hash, const void *p)
+{
+ /* Cannot insert NULL, or (void *)1. */
+ assert(p);
+ assert(entry_is_valid((uintptr_t)p));
+
+ /* Getting too full? */
+ if (ht->elems+1 + ht->deleted > ht_max(ht)) {
+ /* If we're more than 1/8 deleted, clean those,
+ * otherwise double table size. */
+ if (ht->deleted > ht_max_deleted(ht))
+ rehash_table(ht);
+ else if (!double_table(ht))
+ return false;
+ }
+ if (((uintptr_t)p & ht->common_mask) != ht->common_bits)
+ update_common(ht, p);
+
+ ht_add(ht, p, hash);
+ ht->elems++;
+ return true;
+}
+
+bool htable_del_(struct htable *ht, size_t h, const void *p)
+{
+ struct htable_iter i;
+ void *c;
+
+ for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
+ if (c == p) {
+ htable_delval(ht, &i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void htable_delval_(struct htable *ht, struct htable_iter *i)
+{
+ assert(i->off < (size_t)1 << ht->bits);
+ assert(entry_is_valid(ht->table[i->off]));
+
+ ht->elems--;
+ /* Cheap test: if the next bucket is empty, don't need delete marker */
+ if (ht->table[hash_bucket(ht, i->off+1)] != 0) {
+ ht->table[i->off] = HTABLE_DELETED;
+ ht->deleted++;
+ } else
+ ht->table[i->off] = 0;
+}
+
+void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i)
+{
+ void *e;
+ struct htable_iter unwanted;
+
+ if (!i)
+ i = &unwanted;
+ i->off = seed % ((size_t)1 << ht->bits);
+ e = htable_next(ht, i);
+ if (!e)
+ e = htable_first(ht, i);
+ return e;
+}
+
+struct htable *htable_check(const struct htable *ht, const char *abortstr)
+{
+ void *p;
+ struct htable_iter i;
+ size_t n = 0;
+
+ /* Use non-DEBUG versions here, to avoid infinite recursion with
+ * CCAN_HTABLE_DEBUG! */
+ for (p = htable_first_(ht, &i); p; p = htable_next_(ht, &i)) {
+ struct htable_iter i2;
+ void *c;
+ size_t h = ht->rehash(p, ht->priv);
+ bool found = false;
+
+ n++;
+
+ /* Open-code htable_get to avoid CCAN_HTABLE_DEBUG */
+ for (c = htable_firstval_(ht, &i2, h);
+ c;
+ c = htable_nextval_(ht, &i2, h)) {
+ if (c == p) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (abortstr) {
+ fprintf(stderr,
+ "%s: element %p in position %zu"
+ " cannot find itself\n",
+ abortstr, p, i.off);
+ abort();
+ }
+ return NULL;
+ }
+ }
+ if (n != ht->elems) {
+ if (abortstr) {
+ fprintf(stderr,
+ "%s: found %zu elems, expected %zu\n",
+ abortstr, n, ht->elems);
+ abort();
+ }
+ return NULL;
+ }
+
+ return (struct htable *)ht;
+}
diff --git a/ccan/ccan/htable/htable.h b/ccan/ccan/htable/htable.h
new file mode 100644
index 0000000..faaf541
--- /dev/null
+++ b/ccan/ccan/htable/htable.h
@@ -0,0 +1,290 @@
+/* Licensed under LGPLv2+ - see LICENSE file for details */
+#ifndef CCAN_HTABLE_H
+#define CCAN_HTABLE_H
+#include "config.h"
+#include <ccan/str/str.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* Define CCAN_HTABLE_DEBUG for expensive debugging checks on each call. */
+#define HTABLE_LOC __FILE__ ":" stringify(__LINE__)
+#ifdef CCAN_HTABLE_DEBUG
+#define htable_debug(h, loc) htable_check((h), loc)
+#else
+#define htable_debug(h, loc) ((void)loc, h)
+#endif
+
+/**
+ * struct htable - private definition of a htable.
+ *
+ * It's exposed here so you can put it in your structures and so we can
+ * supply inline functions.
+ */
+struct htable {
+ size_t (*rehash)(const void *elem, void *priv);
+ void *priv;
+ unsigned int bits, perfect_bitnum;
+ size_t elems, deleted;
+ /* These are the bits which are the same in all pointers. */
+ uintptr_t common_mask, common_bits;
+ uintptr_t *table;
+};
+
+/**
+ * HTABLE_INITIALIZER - static initialization for a hash table.
+ * @name: name of this htable.
+ * @rehash: hash function to use for rehashing.
+ * @priv: private argument to @rehash function.
+ *
+ * This is useful for setting up static and global hash tables.
+ *
+ * Example:
+ * // For simplicity's sake, say hash value is contents of elem.
+ * static size_t rehash(const void *elem, void *unused)
+ * {
+ * (void)unused;
+ * return *(size_t *)elem;
+ * }
+ * static struct htable ht = HTABLE_INITIALIZER(ht, rehash, NULL);
+ */
+#define HTABLE_INITIALIZER(name, rehash, priv) \
+ { rehash, priv, 0, 0, 0, 0, -1, 0, &name.common_bits }
+
+/**
+ * htable_init - initialize an empty hash table.
+ * @ht: the hash table to initialize
+ * @rehash: hash function to use for rehashing.
+ * @priv: private argument to @rehash function.
+ */
+void htable_init(struct htable *ht,
+ size_t (*rehash)(const void *elem, void *priv), void *priv);
+
+/**
+ * htable_init_sized - initialize an empty hash table of given size.
+ * @ht: the hash table to initialize
+ * @rehash: hash function to use for rehashing.
+ * @priv: private argument to @rehash function.
+ * @size: the number of element.
+ *
+ * If this returns false, @ht is still usable, but may need to do reallocation
+ * upon an add. If this returns true, it will not need to reallocate within
+ * @size htable_adds.
+ */
+bool htable_init_sized(struct htable *ht,
+ size_t (*rehash)(const void *elem, void *priv),
+ void *priv, size_t size);
+
+/**
+ * htable_count - count number of entries in a hash table.
+ * @ht: the hash table
+ */
+static inline size_t htable_count(const struct htable *ht)
+{
+ return ht->elems;
+}
+
+/**
+ * htable_clear - empty a hash table.
+ * @ht: the hash table to clear
+ *
+ * This doesn't do anything to any pointers left in it.
+ */
+void htable_clear(struct htable *ht);
+
+
+/**
+ * htable_check - check hash table for consistency
+ * @ht: the htable
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Because hash tables have redundant information, consistency checking that
+ * each element is in the correct location can be done. This is useful as a
+ * debugging check. If @abortstr is non-NULL, that will be printed in a
+ * diagnostic if the htable is inconsistent, and the function will abort.
+ *
+ * Returns the htable if it is consistent, NULL if not (it can never return
+ * NULL if @abortstr is set).
+ */
+struct htable *htable_check(const struct htable *ht, const char *abortstr);
+
+/**
+ * htable_copy - duplicate a hash table.
+ * @dst: the hash table to overwrite
+ * @src: the hash table to copy
+ *
+ * Only fails on out-of-memory.
+ *
+ * Equivalent to (but faster than):
+ * if (!htable_init_sized(dst, src->rehash, src->priv, 1U << src->bits))
+ * return false;
+ * v = htable_first(src, &i);
+ * while (v) {
+ * htable_add(dst, v);
+ * v = htable_next(src, i);
+ * }
+ * return true;
+ */
+#define htable_copy(dst, src) htable_copy_(dst, htable_debug(src, HTABLE_LOC))
+bool htable_copy_(struct htable *dst, const struct htable *src);
+
+/**
+ * htable_add - add a pointer into a hash table.
+ * @ht: the htable
+ * @hash: the hash value of the object
+ * @p: the non-NULL pointer (also cannot be (void *)1).
+ *
+ * Also note that this can only fail due to allocation failure. Otherwise, it
+ * returns true.
+ */
+#define htable_add(ht, hash, p) \
+ htable_add_(htable_debug(ht, HTABLE_LOC), hash, p)
+bool htable_add_(struct htable *ht, size_t hash, const void *p);
+
+/**
+ * htable_del - remove a pointer from a hash table
+ * @ht: the htable
+ * @hash: the hash value of the object
+ * @p: the pointer
+ *
+ * Returns true if the pointer was found (and deleted).
+ */
+#define htable_del(ht, hash, p) \
+ htable_del_(htable_debug(ht, HTABLE_LOC), hash, p)
+bool htable_del_(struct htable *ht, size_t hash, const void *p);
+
+/**
+ * struct htable_iter - iterator or htable_first or htable_firstval etc.
+ *
+ * This refers to a location inside the hashtable.
+ */
+struct htable_iter {
+ size_t off;
+};
+
+/**
+ * htable_firstval - find a candidate for a given hash value
+ * @htable: the hashtable
+ * @i: the struct htable_iter to initialize
+ * @hash: the hash value
+ *
+ * You'll need to check the value is what you want; returns NULL if none.
+ * See Also:
+ * htable_delval()
+ */
+#define htable_firstval(htable, i, hash) \
+ htable_firstval_(htable_debug(htable, HTABLE_LOC), i, hash)
+
+void *htable_firstval_(const struct htable *htable,
+ struct htable_iter *i, size_t hash);
+
+/**
+ * htable_nextval - find another candidate for a given hash value
+ * @htable: the hashtable
+ * @i: the struct htable_iter to initialize
+ * @hash: the hash value
+ *
+ * You'll need to check the value is what you want; returns NULL if no more.
+ */
+#define htable_nextval(htable, i, hash) \
+ htable_nextval_(htable_debug(htable, HTABLE_LOC), i, hash)
+void *htable_nextval_(const struct htable *htable,
+ struct htable_iter *i, size_t hash);
+
+/**
+ * htable_get - find an entry in the hash table
+ * @ht: the hashtable
+ * @h: the hash value of the entry
+ * @cmp: the comparison function
+ * @ptr: the pointer to hand to the comparison function.
+ *
+ * Convenient inline wrapper for htable_firstval/htable_nextval loop.
+ */
+static inline void *htable_get(const struct htable *ht,
+ size_t h,
+ bool (*cmp)(const void *candidate, void *ptr),
+ const void *ptr)
+{
+ struct htable_iter i;
+ void *c;
+
+ for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
+ if (cmp(c, (void *)ptr))
+ return c;
+ }
+ return NULL;
+}
+
+/**
+ * htable_first - find an entry in the hash table
+ * @ht: the hashtable
+ * @i: the struct htable_iter to initialize
+ *
+ * Get an entry in the hashtable; NULL if empty.
+ */
+#define htable_first(htable, i) \
+ htable_first_(htable_debug(htable, HTABLE_LOC), i)
+void *htable_first_(const struct htable *htable, struct htable_iter *i);
+
+/**
+ * htable_next - find another entry in the hash table
+ * @ht: the hashtable
+ * @i: the struct htable_iter to use
+ *
+ * Get another entry in the hashtable; NULL if all done.
+ * This is usually used after htable_first or prior non-NULL htable_next.
+ */
+#define htable_next(htable, i) \
+ htable_next_(htable_debug(htable, HTABLE_LOC), i)
+void *htable_next_(const struct htable *htable, struct htable_iter *i);
+
+/**
+ * htable_prev - find the previous entry in the hash table
+ * @ht: the hashtable
+ * @i: the struct htable_iter to use
+ *
+ * Get previous entry in the hashtable; NULL if all done.
+ *
+ * "previous" here only means the item that would have been returned by
+ * htable_next() before the item it returned most recently.
+ *
+ * This is usually used in the middle of (or after) a htable_next iteration and
+ * to "unwind" actions taken.
+ */
+#define htable_prev(htable, i) \
+ htable_prev_(htable_debug(htable, HTABLE_LOC), i)
+void *htable_prev_(const struct htable *htable, struct htable_iter *i);
+
+/**
+ * htable_delval - remove an iterated pointer from a hash table
+ * @ht: the htable
+ * @i: the htable_iter
+ *
+ * Usually used to delete a hash entry after it has been found with
+ * htable_firstval etc.
+ */
+#define htable_delval(htable, i) \
+ htable_delval_(htable_debug(htable, HTABLE_LOC), i)
+void htable_delval_(struct htable *ht, struct htable_iter *i);
+
+/**
+ * htable_pick - set iterator to a random valid entry.
+ * @ht: the htable
+ * @seed: a random number to use.
+ * @i: the htable_iter which is output (or NULL).
+ *
+ * Usually used with htable_delval to delete a random entry. Returns
+ * NULL iff the table is empty, otherwise a random entry.
+ */
+#define htable_pick(htable, seed, i) \
+ htable_pick_(htable_debug(htable, HTABLE_LOC), seed, i)
+void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i);
+
+/**
+ * htable_set_allocator - set calloc/free functions.
+ * @alloc: allocator to use, must zero memory!
+ * @free: unallocator to use (@p is NULL or a return from @alloc)
+ */
+void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
+ void (*free)(struct htable *, void *p));
+#endif /* CCAN_HTABLE_H */
diff --git a/ccan/ccan/htable/htable_type.h b/ccan/ccan/htable/htable_type.h
new file mode 100644
index 0000000..0aacb7f
--- /dev/null
+++ b/ccan/ccan/htable/htable_type.h
@@ -0,0 +1,188 @@
+/* Licensed under LGPLv2+ - see LICENSE file for details */
+#ifndef CCAN_HTABLE_TYPE_H
+#define CCAN_HTABLE_TYPE_H
+#include <ccan/htable/htable.h>
+#include <ccan/compiler/compiler.h>
+#include "config.h"
+
+/**
+ * HTABLE_DEFINE_TYPE - create a set of htable ops for a type
+ * @type: a type whose pointers will be values in the hash.
+ * @keyof: a function/macro to extract a key: <keytype> @keyof(const type *elem)
+ * @hashfn: a hash function for a @key: size_t @hashfn(const <keytype> *)
+ * @eqfn: an equality function keys: bool @eqfn(const type *, const <keytype> *)
+ * @prefix: a prefix for all the functions to define (of form <name>_*)
+ *
+ * NULL values may not be placed into the hash table.
+ *
+ * This defines the type hashtable type and an iterator type:
+ * struct <name>;
+ * struct <name>_iter;
+ *
+ * It also defines initialization and freeing functions:
+ * void <name>_init(struct <name> *);
+ * bool <name>_init_sized(struct <name> *, size_t);
+ * void <name>_clear(struct <name> *);
+ * bool <name>_copy(struct <name> *dst, const struct <name> *src);
+ *
+ * Count entries:
+ * size_t <name>_count(const struct <name> *ht);
+ *
+ * Add function only fails if we run out of memory:
+ * bool <name>_add(struct <name> *ht, const <type> *e);
+ *
+ * Delete and delete-by key return true if it was in the set:
+ * bool <name>_del(struct <name> *ht, const <type> *e);
+ * bool <name>_delkey(struct <name> *ht, const <keytype> *k);
+ *
+ * Delete by iterator:
+ * bool <name>_delval(struct <name> *ht, struct <name>_iter *i);
+ *
+ * Find and return the (first) matching element, or NULL:
+ * type *<name>_get(const struct @name *ht, const <keytype> *k);
+ *
+ * Find and return all matching elements, or NULL:
+ * type *<name>_getfirst(const struct @name *ht, const <keytype> *k,
+ * struct <name>_iter *i);
+ * type *<name>_getnext(const struct @name *ht, const <keytype> *k,
+ * struct <name>_iter *i);
+ *
+ * Iteration over hashtable is also supported:
+ * type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
+ * type *<name>_next(const struct <name> *ht, struct <name>_iter *i);
+ * type *<name>_prev(const struct <name> *ht, struct <name>_iter *i);
+ * type *<name>_pick(const struct <name> *ht, size_t seed,
+ * struct <name>_iter *i);
+ * It's currently safe to iterate over a changing hashtable, but you might
+ * miss an element. Iteration isn't very efficient, either.
+ *
+ * You can use HTABLE_INITIALIZER like so:
+ * struct <name> ht = { HTABLE_INITIALIZER(ht.raw, <name>_hash, NULL) };
+ */
+#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \
+ struct name { struct htable raw; }; \
+ struct name##_iter { struct htable_iter i; }; \
+ static inline size_t name##_hash(const void *elem, void *priv) \
+ { \
+ (void)priv; \
+ return hashfn(keyof((const type *)elem)); \
+ } \
+ static inline UNNEEDED void name##_init(struct name *ht) \
+ { \
+ htable_init(&ht->raw, name##_hash, NULL); \
+ } \
+ static inline UNNEEDED bool name##_init_sized(struct name *ht, \
+ size_t s) \
+ { \
+ return htable_init_sized(&ht->raw, name##_hash, NULL, s); \
+ } \
+ static inline UNNEEDED size_t name##_count(const struct name *ht) \
+ { \
+ return htable_count(&ht->raw); \
+ } \
+ static inline UNNEEDED void name##_clear(struct name *ht) \
+ { \
+ htable_clear(&ht->raw); \
+ } \
+ static inline UNNEEDED bool name##_copy(struct name *dst, \
+ const struct name *src) \
+ { \
+ return htable_copy(&dst->raw, &src->raw); \
+ } \
+ static inline bool name##_add(struct name *ht, const type *elem) \
+ { \
+ return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \
+ } \
+ static inline UNNEEDED bool name##_del(struct name *ht, \
+ const type *elem) \
+ { \
+ return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \
+ } \
+ static inline UNNEEDED type *name##_get(const struct name *ht, \
+ const HTABLE_KTYPE(keyof, type) k) \
+ { \
+ struct htable_iter i; \
+ size_t h = hashfn(k); \
+ void *c; \
+ \
+ for (c = htable_firstval(&ht->raw,&i,h); \
+ c; \
+ c = htable_nextval(&ht->raw,&i,h)) { \
+ if (eqfn(c, k)) \
+ return c; \
+ } \
+ return NULL; \
+ } \
+ static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \
+ const HTABLE_KTYPE(keyof, type) k, \
+ size_t h, \
+ type *v, \
+ struct name##_iter *iter) \
+ { \
+ while (v) { \
+ if (eqfn(v, k)) \
+ break; \
+ v = htable_nextval(&ht->raw, &iter->i, h); \
+ } \
+ return v; \
+ } \
+ static inline UNNEEDED type *name##_getfirst(const struct name *ht, \
+ const HTABLE_KTYPE(keyof, type) k, \
+ struct name##_iter *iter) \
+ { \
+ size_t h = hashfn(k); \
+ type *v = htable_firstval(&ht->raw, &iter->i, h); \
+ return name##_getmatch_(ht, k, h, v, iter); \
+ } \
+ static inline UNNEEDED type *name##_getnext(const struct name *ht, \
+ const HTABLE_KTYPE(keyof, type) k, \
+ struct name##_iter *iter) \
+ { \
+ size_t h = hashfn(k); \
+ type *v = htable_nextval(&ht->raw, &iter->i, h); \
+ return name##_getmatch_(ht, k, h, v, iter); \
+ } \
+ static inline UNNEEDED bool name##_delkey(struct name *ht, \
+ const HTABLE_KTYPE(keyof, type) k) \
+ { \
+ type *elem = name##_get(ht, k); \
+ if (elem) \
+ return name##_del(ht, elem); \
+ return false; \
+ } \
+ static inline UNNEEDED void name##_delval(struct name *ht, \
+ struct name##_iter *iter) \
+ { \
+ htable_delval(&ht->raw, &iter->i); \
+ } \
+ static inline UNNEEDED type *name##_pick(const struct name *ht, \
+ size_t seed, \
+ struct name##_iter *iter) \
+ { \
+ return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \
+ } \
+ static inline UNNEEDED type *name##_first(const struct name *ht, \
+ struct name##_iter *iter) \
+ { \
+ return htable_first(&ht->raw, &iter->i); \
+ } \
+ static inline UNNEEDED type *name##_next(const struct name *ht, \
+ struct name##_iter *iter) \
+ { \
+ return htable_next(&ht->raw, &iter->i); \
+ } \
+ static inline UNNEEDED type *name##_prev(const struct name *ht, \
+ struct name##_iter *iter) \
+ { \
+ return htable_prev(&ht->raw, &iter->i); \
+ }
+
+#if HAVE_TYPEOF
+#define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL))
+#else
+/* Assumes keys are a pointer: if not, override. */
+#ifndef HTABLE_KTYPE
+#define HTABLE_KTYPE(keyof, type) void *
+#endif
+#endif
+#endif /* CCAN_HTABLE_TYPE_H */
diff --git a/ccan/ccan/ilog/LICENSE b/ccan/ccan/ilog/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/ilog/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/ilog/ilog.c b/ccan/ccan/ilog/ilog.c
new file mode 100644
index 0000000..5f5122d
--- /dev/null
+++ b/ccan/ccan/ilog/ilog.c
@@ -0,0 +1,141 @@
+/*(C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain).
+ * See LICENSE file for details. */
+#include "ilog.h"
+#include <limits.h>
+
+/*The fastest fallback strategy for platforms with fast multiplication appears
+ to be based on de Bruijn sequences~\cite{LP98}.
+ Tests confirmed this to be true even on an ARM11, where it is actually faster
+ than using the native clz instruction.
+ Define ILOG_NODEBRUIJN to use a simpler fallback on platforms where
+ multiplication or table lookups are too expensive.
+
+ @UNPUBLISHED{LP98,
+ author="Charles E. Leiserson and Harald Prokop",
+ title="Using de {Bruijn} Sequences to Index a 1 in a Computer Word",
+ month=Jun,
+ year=1998,
+ note="\url{http://supertech.csail.mit.edu/papers/debruijn.pdf}"
+ }*/
+static UNNEEDED const unsigned char DEBRUIJN_IDX32[32]={
+ 0, 1,28, 2,29,14,24, 3,30,22,20,15,25,17, 4, 8,
+ 31,27,13,23,21,19,16, 7,26,12,18, 6,11, 5,10, 9
+};
+
+/* We always compile these in, in case someone takes address of function. */
+#undef ilog32_nz
+#undef ilog32
+#undef ilog64_nz
+#undef ilog64
+
+int ilog32(uint32_t _v){
+/*On a Pentium M, this branchless version tested as the fastest version without
+ multiplications on 1,000,000,000 random 32-bit integers, edging out a
+ similar version with branches, and a 256-entry LUT version.*/
+# if defined(ILOG_NODEBRUIJN)
+ int ret;
+ int m;
+ ret=_v>0;
+ m=(_v>0xFFFFU)<<4;
+ _v>>=m;
+ ret|=m;
+ m=(_v>0xFFU)<<3;
+ _v>>=m;
+ ret|=m;
+ m=(_v>0xFU)<<2;
+ _v>>=m;
+ ret|=m;
+ m=(_v>3)<<1;
+ _v>>=m;
+ ret|=m;
+ ret+=_v>1;
+ return ret;
+/*This de Bruijn sequence version is faster if you have a fast multiplier.*/
+# else
+ int ret;
+ ret=_v>0;
+ _v|=_v>>1;
+ _v|=_v>>2;
+ _v|=_v>>4;
+ _v|=_v>>8;
+ _v|=_v>>16;
+ _v=(_v>>1)+1;
+ ret+=DEBRUIJN_IDX32[_v*0x77CB531U>>27&0x1F];
+ return ret;
+# endif
+}
+
+int ilog32_nz(uint32_t _v)
+{
+ return ilog32(_v);
+}
+
+int ilog64(uint64_t _v){
+# if defined(ILOG_NODEBRUIJN)
+ uint32_t v;
+ int ret;
+ int m;
+ ret=_v>0;
+ m=(_v>0xFFFFFFFFU)<<5;
+ v=(uint32_t)(_v>>m);
+ ret|=m;
+ m=(v>0xFFFFU)<<4;
+ v>>=m;
+ ret|=m;
+ m=(v>0xFFU)<<3;
+ v>>=m;
+ ret|=m;
+ m=(v>0xFU)<<2;
+ v>>=m;
+ ret|=m;
+ m=(v>3)<<1;
+ v>>=m;
+ ret|=m;
+ ret+=v>1;
+ return ret;
+# else
+/*If we don't have a 64-bit word, split it into two 32-bit halves.*/
+# if LONG_MAX<9223372036854775807LL
+ uint32_t v;
+ int ret;
+ int m;
+ ret=_v>0;
+ m=(_v>0xFFFFFFFFU)<<5;
+ v=(uint32_t)(_v>>m);
+ ret|=m;
+ v|=v>>1;
+ v|=v>>2;
+ v|=v>>4;
+ v|=v>>8;
+ v|=v>>16;
+ v=(v>>1)+1;
+ ret+=DEBRUIJN_IDX32[v*0x77CB531U>>27&0x1F];
+ return ret;
+/*Otherwise do it in one 64-bit operation.*/
+# else
+ static const unsigned char DEBRUIJN_IDX64[64]={
+ 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
+ 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
+ 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
+ 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
+ };
+ int ret;
+ ret=_v>0;
+ _v|=_v>>1;
+ _v|=_v>>2;
+ _v|=_v>>4;
+ _v|=_v>>8;
+ _v|=_v>>16;
+ _v|=_v>>32;
+ _v=(_v>>1)+1;
+ ret+=DEBRUIJN_IDX64[_v*0x218A392CD3D5DBF>>58&0x3F];
+ return ret;
+# endif
+# endif
+}
+
+int ilog64_nz(uint64_t _v)
+{
+ return ilog64(_v);
+}
+
diff --git a/ccan/ccan/ilog/ilog.h b/ccan/ccan/ilog/ilog.h
new file mode 100644
index 0000000..32702b1
--- /dev/null
+++ b/ccan/ccan/ilog/ilog.h
@@ -0,0 +1,154 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#if !defined(_ilog_H)
+# define _ilog_H (1)
+# include "config.h"
+# include <stdint.h>
+# include <limits.h>
+# include <ccan/compiler/compiler.h>
+
+/**
+ * ilog32 - Integer binary logarithm of a 32-bit value.
+ * @_v: A 32-bit value.
+ * Returns floor(log2(_v))+1, or 0 if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * Note that many uses will resolve to the fast macro version instead.
+ *
+ * See Also:
+ * ilog32_nz(), ilog64()
+ *
+ * Example:
+ * // Rounds up to next power of 2 (if not a power of 2).
+ * static uint32_t round_up32(uint32_t i)
+ * {
+ * assert(i != 0);
+ * return 1U << ilog32(i-1);
+ * }
+ */
+int ilog32(uint32_t _v) CONST_FUNCTION;
+
+/**
+ * ilog32_nz - Integer binary logarithm of a non-zero 32-bit value.
+ * @_v: A 32-bit value.
+ * Returns floor(log2(_v))+1, or undefined if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * Note that many uses will resolve to the fast macro version instead.
+ * See Also:
+ * ilog32(), ilog64_nz()
+ * Example:
+ * // Find Last Set (ie. highest bit set, 0 to 31).
+ * static uint32_t fls32(uint32_t i)
+ * {
+ * assert(i != 0);
+ * return ilog32_nz(i) - 1;
+ * }
+ */
+int ilog32_nz(uint32_t _v) CONST_FUNCTION;
+
+/**
+ * ilog64 - Integer binary logarithm of a 64-bit value.
+ * @_v: A 64-bit value.
+ * Returns floor(log2(_v))+1, or 0 if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * Note that many uses will resolve to the fast macro version instead.
+ * See Also:
+ * ilog64_nz(), ilog32()
+ */
+int ilog64(uint64_t _v) CONST_FUNCTION;
+
+/**
+ * ilog64_nz - Integer binary logarithm of a non-zero 64-bit value.
+ * @_v: A 64-bit value.
+ * Returns floor(log2(_v))+1, or undefined if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * Note that many uses will resolve to the fast macro version instead.
+ * See Also:
+ * ilog64(), ilog32_nz()
+ */
+int ilog64_nz(uint64_t _v) CONST_FUNCTION;
+
+/**
+ * STATIC_ILOG_32 - The integer logarithm of an (unsigned, 32-bit) constant.
+ * @_v: A non-negative 32-bit constant.
+ * Returns floor(log2(_v))+1, or 0 if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * This macro should only be used when you need a compile-time constant,
+ * otherwise ilog32 or ilog32_nz are just as fast and more flexible.
+ *
+ * Example:
+ * #define MY_PAGE_SIZE 4096
+ * #define MY_PAGE_BITS (STATIC_ILOG_32(PAGE_SIZE) - 1)
+ */
+#define STATIC_ILOG_32(_v) (STATIC_ILOG5((uint32_t)(_v)))
+
+/**
+ * STATIC_ILOG_64 - The integer logarithm of an (unsigned, 64-bit) constant.
+ * @_v: A non-negative 64-bit constant.
+ * Returns floor(log2(_v))+1, or 0 if _v==0.
+ * This is the number of bits that would be required to represent _v in two's
+ * complement notation with all of the leading zeros stripped.
+ * This macro should only be used when you need a compile-time constant,
+ * otherwise ilog64 or ilog64_nz are just as fast and more flexible.
+ */
+#define STATIC_ILOG_64(_v) (STATIC_ILOG6((uint64_t)(_v)))
+
+/* Private implementation details */
+
+/*Note the casts to (int) below: this prevents "upgrading"
+ the type of an entire expression to an (unsigned) size_t.*/
+#if INT_MAX>=2147483647 && HAVE_BUILTIN_CLZ
+#define builtin_ilog32_nz(v) \
+ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v))
+#elif LONG_MAX>=2147483647L && HAVE_BUILTIN_CLZL
+#define builtin_ilog32_nz(v) \
+ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clzl(v))
+#endif
+
+#if INT_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZ
+#define builtin_ilog64_nz(v) \
+ (((int)sizeof(unsigned)*CHAR_BIT) - __builtin_clz(v))
+#elif LONG_MAX>=9223372036854775807LL && HAVE_BUILTIN_CLZL
+#define builtin_ilog64_nz(v) \
+ (((int)sizeof(unsigned long)*CHAR_BIT) - __builtin_clzl(v))
+#elif HAVE_BUILTIN_CLZLL
+#define builtin_ilog64_nz(v) \
+ (((int)sizeof(unsigned long long)*CHAR_BIT) - __builtin_clzll(v))
+#endif
+
+#ifdef builtin_ilog32_nz
+/* This used to be builtin_ilog32_nz(_v)&-!!(_v), which means it zeroes out
+ * the undefined builtin_ilog32_nz(0) return. But clang UndefinedBehaviorSantizer
+ * complains, so do the branch: */
+#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0)
+#define ilog32_nz(_v) builtin_ilog32_nz(_v)
+#else
+#define ilog32_nz(_v) ilog32(_v)
+#define ilog32(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_32(_v) : ilog32(_v))
+#endif /* builtin_ilog32_nz */
+
+#ifdef builtin_ilog64_nz
+#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0)
+#define ilog64_nz(_v) builtin_ilog64_nz(_v)
+#else
+#define ilog64_nz(_v) ilog64(_v)
+#define ilog64(_v) (IS_COMPILE_CONSTANT(_v) ? STATIC_ILOG_64(_v) : ilog64(_v))
+#endif /* builtin_ilog64_nz */
+
+/* Macros for evaluating compile-time constant ilog. */
+# define STATIC_ILOG0(_v) (!!(_v))
+# define STATIC_ILOG1(_v) (((_v)&0x2)?2:STATIC_ILOG0(_v))
+# define STATIC_ILOG2(_v) (((_v)&0xC)?2+STATIC_ILOG1((_v)>>2):STATIC_ILOG1(_v))
+# define STATIC_ILOG3(_v) \
+ (((_v)&0xF0)?4+STATIC_ILOG2((_v)>>4):STATIC_ILOG2(_v))
+# define STATIC_ILOG4(_v) \
+ (((_v)&0xFF00)?8+STATIC_ILOG3((_v)>>8):STATIC_ILOG3(_v))
+# define STATIC_ILOG5(_v) \
+ (((_v)&0xFFFF0000)?16+STATIC_ILOG4((_v)>>16):STATIC_ILOG4(_v))
+# define STATIC_ILOG6(_v) \
+ (((_v)&0xFFFFFFFF00000000ULL)?32+STATIC_ILOG5((_v)>>32):STATIC_ILOG5(_v))
+
+#endif /* _ilog_H */
diff --git a/ccan/ccan/likely/LICENSE b/ccan/ccan/likely/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/likely/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/likely/likely.c b/ccan/ccan/likely/likely.c
new file mode 100644
index 0000000..83e8d6f
--- /dev/null
+++ b/ccan/ccan/likely/likely.c
@@ -0,0 +1,136 @@
+/* CC0 (Public domain) - see LICENSE file for details. */
+#ifdef CCAN_LIKELY_DEBUG
+#include <ccan/likely/likely.h>
+#include <ccan/hash/hash.h>
+#include <ccan/htable/htable_type.h>
+#include <stdlib.h>
+#include <stdio.h>
+struct trace {
+ const char *condstr;
+ const char *file;
+ unsigned int line;
+ bool expect;
+ unsigned long count, right;
+};
+
+static size_t hash_trace(const struct trace *trace)
+{
+ return hash(trace->condstr, strlen(trace->condstr),
+ hash(trace->file, strlen(trace->file),
+ trace->line + trace->expect));
+}
+
+static bool trace_eq(const struct trace *t1, const struct trace *t2)
+{
+ return t1->condstr == t2->condstr
+ && t1->file == t2->file
+ && t1->line == t2->line
+ && t1->expect == t2->expect;
+}
+
+/* struct thash */
+HTABLE_DEFINE_TYPE(struct trace, (const struct trace *), hash_trace, trace_eq,
+ thash);
+
+static struct thash htable
+= { HTABLE_INITIALIZER(htable.raw, thash_hash, NULL) };
+
+static void init_trace(struct trace *trace,
+ const char *condstr, const char *file, unsigned int line,
+ bool expect)
+{
+ trace->condstr = condstr;
+ trace->file = file;
+ trace->line = line;
+ trace->expect = expect;
+ trace->count = trace->right = 0;
+}
+
+static struct trace *add_trace(const struct trace *t)
+{
+ struct trace *trace = malloc(sizeof(*trace));
+ *trace = *t;
+ thash_add(&htable, trace);
+ return trace;
+}
+
+long _likely_trace(bool cond, bool expect,
+ const char *condstr,
+ const char *file, unsigned int line)
+{
+ struct trace *p, trace;
+
+ init_trace(&trace, condstr, file, line, expect);
+ p = thash_get(&htable, &trace);
+ if (!p)
+ p = add_trace(&trace);
+
+ p->count++;
+ if (cond == expect)
+ p->right++;
+
+ return cond;
+}
+
+static double right_ratio(const struct trace *t)
+{
+ return (double)t->right / t->count;
+}
+
+char *likely_stats(unsigned int min_hits, unsigned int percent)
+{
+ struct trace *worst;
+ double worst_ratio;
+ struct thash_iter i;
+ char *ret;
+ struct trace *t;
+
+ worst = NULL;
+ worst_ratio = 2;
+
+ /* This is O(n), but it's not likely called that often. */
+ for (t = thash_first(&htable, &i); t; t = thash_next(&htable, &i)) {
+ if (t->count >= min_hits) {
+ if (right_ratio(t) < worst_ratio) {
+ worst = t;
+ worst_ratio = right_ratio(t);
+ }
+ }
+ }
+
+ if (worst_ratio * 100 > percent)
+ return NULL;
+
+ ret = malloc(strlen(worst->condstr) +
+ strlen(worst->file) +
+ sizeof(long int) * 8 +
+ sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)"));
+ sprintf(ret, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)",
+ worst->file, worst->line,
+ worst->expect ? "" : "un", worst->condstr,
+ (unsigned)(worst_ratio * 100),
+ worst->right, worst->count);
+
+ thash_del(&htable, worst);
+ free(worst);
+
+ return ret;
+}
+
+void likely_stats_reset(void)
+{
+ struct thash_iter i;
+ struct trace *t;
+
+ /* This is a bit better than O(n^2), but we have to loop since
+ * first/next during delete is unreliable. */
+ while ((t = thash_first(&htable, &i)) != NULL) {
+ for (; t; t = thash_next(&htable, &i)) {
+ thash_del(&htable, t);
+ free(t);
+ }
+ }
+
+ thash_clear(&htable);
+}
+#endif /*CCAN_LIKELY_DEBUG*/
diff --git a/ccan/ccan/likely/likely.h b/ccan/ccan/likely/likely.h
new file mode 100644
index 0000000..a8f003d
--- /dev/null
+++ b/ccan/ccan/likely/likely.h
@@ -0,0 +1,111 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_LIKELY_H
+#define CCAN_LIKELY_H
+#include "config.h"
+#include <stdbool.h>
+
+#ifndef CCAN_LIKELY_DEBUG
+#if HAVE_BUILTIN_EXPECT
+/**
+ * likely - indicate that a condition is likely to be true.
+ * @cond: the condition
+ *
+ * This uses a compiler extension where available to indicate a likely
+ * code path and optimize appropriately; it's also useful for readers
+ * to quickly identify exceptional paths through functions. The
+ * threshold for "likely" is usually considered to be between 90 and
+ * 99%; marginal cases should not be marked either way.
+ *
+ * See Also:
+ * unlikely(), likely_stats()
+ *
+ * Example:
+ * // Returns false if we overflow.
+ * static inline bool inc_int(unsigned int *val)
+ * {
+ * (*val)++;
+ * if (likely(*val))
+ * return true;
+ * return false;
+ * }
+ */
+#define likely(cond) __builtin_expect(!!(cond), 1)
+
+/**
+ * unlikely - indicate that a condition is unlikely to be true.
+ * @cond: the condition
+ *
+ * This uses a compiler extension where available to indicate an unlikely
+ * code path and optimize appropriately; see likely() above.
+ *
+ * See Also:
+ * likely(), likely_stats(), COLD (compiler.h)
+ *
+ * Example:
+ * // Prints a warning if we overflow.
+ * static inline void inc_int(unsigned int *val)
+ * {
+ * (*val)++;
+ * if (unlikely(*val == 0))
+ * fprintf(stderr, "Overflow!");
+ * }
+ */
+#define unlikely(cond) __builtin_expect(!!(cond), 0)
+#else
+#define likely(cond) (!!(cond))
+#define unlikely(cond) (!!(cond))
+#endif
+#else /* CCAN_LIKELY_DEBUG versions */
+#include <ccan/str/str.h>
+
+#define likely(cond) \
+ (_likely_trace(!!(cond), 1, stringify(cond), __FILE__, __LINE__))
+#define unlikely(cond) \
+ (_likely_trace(!!(cond), 0, stringify(cond), __FILE__, __LINE__))
+
+long _likely_trace(bool cond, bool expect,
+ const char *condstr,
+ const char *file, unsigned int line);
+/**
+ * likely_stats - return description of abused likely()/unlikely()
+ * @min_hits: minimum number of hits
+ * @percent: maximum percentage correct
+ *
+ * When CCAN_LIKELY_DEBUG is defined, likely() and unlikely() trace their
+ * results: this causes a significant slowdown, but allows analysis of
+ * whether the branches are labelled correctly.
+ *
+ * This function returns a malloc'ed description of the least-correct
+ * usage of likely() or unlikely(). It ignores places which have been
+ * called less than @min_hits times, and those which were predicted
+ * correctly more than @percent of the time. It returns NULL when
+ * nothing meets those criteria.
+ *
+ * Note that this call is destructive; the returned offender is
+ * removed from the trace so that the next call to likely_stats() will
+ * return the next-worst likely()/unlikely() usage.
+ *
+ * Example:
+ * // Print every place hit more than twice which was wrong > 5%.
+ * static void report_stats(void)
+ * {
+ * #ifdef CCAN_LIKELY_DEBUG
+ * const char *bad;
+ *
+ * while ((bad = likely_stats(2, 95)) != NULL) {
+ * printf("Suspicious likely: %s", bad);
+ * free(bad);
+ * }
+ * #endif
+ * }
+ */
+char *likely_stats(unsigned int min_hits, unsigned int percent);
+
+/**
+ * likely_stats_reset - free up memory of likely()/unlikely() branches.
+ *
+ * This can also plug memory leaks.
+ */
+void likely_stats_reset(void);
+#endif /* CCAN_LIKELY_DEBUG */
+#endif /* CCAN_LIKELY_H */
diff --git a/ccan/ccan/list/LICENSE b/ccan/ccan/list/LICENSE
new file mode 120000
index 0000000..2354d12
--- /dev/null
+++ b/ccan/ccan/list/LICENSE
@@ -0,0 +1 @@
+../../licenses/BSD-MIT \ No newline at end of file
diff --git a/ccan/ccan/list/list.c b/ccan/ccan/list/list.c
new file mode 100644
index 0000000..2717fa3
--- /dev/null
+++ b/ccan/ccan/list/list.c
@@ -0,0 +1,43 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#include <stdio.h>
+#include <stdlib.h>
+#include "list.h"
+
+static void *corrupt(const char *abortstr,
+ const struct list_node *head,
+ const struct list_node *node,
+ unsigned int count)
+{
+ if (abortstr) {
+ fprintf(stderr,
+ "%s: prev corrupt in node %p (%u) of %p\n",
+ abortstr, node, count, head);
+ abort();
+ }
+ return NULL;
+}
+
+struct list_node *list_check_node(const struct list_node *node,
+ const char *abortstr)
+{
+ const struct list_node *p, *n;
+ int count = 0;
+
+ for (p = node, n = node->next; n != node; p = n, n = n->next) {
+ count++;
+ if (n->prev != p)
+ return corrupt(abortstr, node, n, count);
+ }
+ /* Check prev on head node. */
+ if (node->prev != p)
+ return corrupt(abortstr, node, node, 0);
+
+ return (struct list_node *)node;
+}
+
+struct list_head *list_check(const struct list_head *h, const char *abortstr)
+{
+ if (!list_check_node(&h->n, abortstr))
+ return NULL;
+ return (struct list_head *)h;
+}
diff --git a/ccan/ccan/list/list.h b/ccan/ccan/list/list.h
new file mode 100644
index 0000000..a15321c
--- /dev/null
+++ b/ccan/ccan/list/list.h
@@ -0,0 +1,842 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_LIST_H
+#define CCAN_LIST_H
+//#define CCAN_LIST_DEBUG 1
+#include <stdbool.h>
+#include <assert.h>
+#include <ccan/str/str.h>
+#include <ccan/container_of/container_of.h>
+#include <ccan/check_type/check_type.h>
+
+/**
+ * struct list_node - an entry in a doubly-linked list
+ * @next: next entry (self if empty)
+ * @prev: previous entry (self if empty)
+ *
+ * This is used as an entry in a linked list.
+ * Example:
+ * struct child {
+ * const char *name;
+ * // Linked list of all us children.
+ * struct list_node list;
+ * };
+ */
+struct list_node
+{
+ struct list_node *next, *prev;
+};
+
+/**
+ * struct list_head - the head of a doubly-linked list
+ * @h: the list_head (containing next and prev pointers)
+ *
+ * This is used as the head of a linked list.
+ * Example:
+ * struct parent {
+ * const char *name;
+ * struct list_head children;
+ * unsigned int num_children;
+ * };
+ */
+struct list_head
+{
+ struct list_node n;
+};
+
+/**
+ * list_check - check head of a list for consistency
+ * @h: the list_head
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Because list_nodes have redundant information, consistency checking between
+ * the back and forward links can be done. This is useful as a debugging check.
+ * If @abortstr is non-NULL, that will be printed in a diagnostic if the list
+ * is inconsistent, and the function will abort.
+ *
+ * Returns the list head if the list is consistent, NULL if not (it
+ * can never return NULL if @abortstr is set).
+ *
+ * See also: list_check_node()
+ *
+ * Example:
+ * static void dump_parent(struct parent *p)
+ * {
+ * struct child *c;
+ *
+ * printf("%s (%u children):\n", p->name, p->num_children);
+ * list_check(&p->children, "bad child list");
+ * list_for_each(&p->children, c, list)
+ * printf(" -> %s\n", c->name);
+ * }
+ */
+struct list_head *list_check(const struct list_head *h, const char *abortstr);
+
+/**
+ * list_check_node - check node of a list for consistency
+ * @n: the list_node
+ * @abortstr: the location to print on aborting, or NULL.
+ *
+ * Check consistency of the list node is in (it must be in one).
+ *
+ * See also: list_check()
+ *
+ * Example:
+ * static void dump_child(const struct child *c)
+ * {
+ * list_check_node(&c->list, "bad child list");
+ * printf("%s\n", c->name);
+ * }
+ */
+struct list_node *list_check_node(const struct list_node *n,
+ const char *abortstr);
+
+#define LIST_LOC __FILE__ ":" stringify(__LINE__)
+#ifdef CCAN_LIST_DEBUG
+#define list_debug(h, loc) list_check((h), loc)
+#define list_debug_node(n, loc) list_check_node((n), loc)
+#else
+#define list_debug(h, loc) ((void)loc, h)
+#define list_debug_node(n, loc) ((void)loc, n)
+#endif
+
+/**
+ * LIST_HEAD_INIT - initializer for an empty list_head
+ * @name: the name of the list.
+ *
+ * Explicit initializer for an empty list.
+ *
+ * See also:
+ * LIST_HEAD, list_head_init()
+ *
+ * Example:
+ * static struct list_head my_list = LIST_HEAD_INIT(my_list);
+ */
+#define LIST_HEAD_INIT(name) { { &(name).n, &(name).n } }
+
+/**
+ * LIST_HEAD - define and initialize an empty list_head
+ * @name: the name of the list.
+ *
+ * The LIST_HEAD macro defines a list_head and initializes it to an empty
+ * list. It can be prepended by "static" to define a static list_head.
+ *
+ * See also:
+ * LIST_HEAD_INIT, list_head_init()
+ *
+ * Example:
+ * static LIST_HEAD(my_global_list);
+ */
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_head_init - initialize a list_head
+ * @h: the list_head to set to the empty list
+ *
+ * Example:
+ * ...
+ * struct parent *parent = malloc(sizeof(*parent));
+ *
+ * list_head_init(&parent->children);
+ * parent->num_children = 0;
+ */
+static inline void list_head_init(struct list_head *h)
+{
+ h->n.next = h->n.prev = &h->n;
+}
+
+/**
+ * list_node_init - initialize a list_node
+ * @n: the list_node to link to itself.
+ *
+ * You don't need to use this normally! But it lets you list_del(@n)
+ * safely.
+ */
+static inline void list_node_init(struct list_node *n)
+{
+ n->next = n->prev = n;
+}
+
+/**
+ * list_add_after - add an entry after an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node after
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ * struct child c1, c2, c3;
+ * LIST_HEAD(h);
+ *
+ * list_add_tail(&h, &c1.list);
+ * list_add_tail(&h, &c3.list);
+ * list_add_after(&h, &c1.list, &c2.list);
+ */
+#define list_add_after(h, p, n) list_add_after_(h, p, n, LIST_LOC)
+static inline void list_add_after_(struct list_head *h,
+ struct list_node *p,
+ struct list_node *n,
+ const char *abortstr)
+{
+ n->next = p->next;
+ n->prev = p;
+ p->next->prev = n;
+ p->next = n;
+ (void)list_debug(h, abortstr);
+}
+
+/**
+ * list_add - add an entry at the start of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * struct child *child = malloc(sizeof(*child));
+ *
+ * child->name = "marvin";
+ * list_add(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+#define list_add(h, n) list_add_(h, n, LIST_LOC)
+static inline void list_add_(struct list_head *h,
+ struct list_node *n,
+ const char *abortstr)
+{
+ list_add_after_(h, &h->n, n, abortstr);
+}
+
+/**
+ * list_add_before - add an entry before an existing node in a linked list
+ * @h: the list_head to add the node to (for debugging)
+ * @p: the existing list_node to add the node before
+ * @n: the new list_node to add to the list.
+ *
+ * The existing list_node must already be a member of the list.
+ * The new list_node does not need to be initialized; it will be overwritten.
+ *
+ * Example:
+ * list_head_init(&h);
+ * list_add_tail(&h, &c1.list);
+ * list_add_tail(&h, &c3.list);
+ * list_add_before(&h, &c3.list, &c2.list);
+ */
+#define list_add_before(h, p, n) list_add_before_(h, p, n, LIST_LOC)
+static inline void list_add_before_(struct list_head *h,
+ struct list_node *p,
+ struct list_node *n,
+ const char *abortstr)
+{
+ n->next = p;
+ n->prev = p->prev;
+ p->prev->next = n;
+ p->prev = n;
+ (void)list_debug(h, abortstr);
+}
+
+/**
+ * list_add_tail - add an entry at the end of a linked list.
+ * @h: the list_head to add the node to
+ * @n: the list_node to add to the list.
+ *
+ * The list_node does not need to be initialized; it will be overwritten.
+ * Example:
+ * list_add_tail(&parent->children, &child->list);
+ * parent->num_children++;
+ */
+#define list_add_tail(h, n) list_add_tail_(h, n, LIST_LOC)
+static inline void list_add_tail_(struct list_head *h,
+ struct list_node *n,
+ const char *abortstr)
+{
+ list_add_before_(h, &h->n, n, abortstr);
+}
+
+/**
+ * list_empty - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ *
+ * Example:
+ * assert(list_empty(&parent->children) == (parent->num_children == 0));
+ */
+#define list_empty(h) list_empty_(h, LIST_LOC)
+static inline bool list_empty_(const struct list_head *h, const char* abortstr)
+{
+ (void)list_debug(h, abortstr);
+ return h->n.next == &h->n;
+}
+
+/**
+ * list_empty_nodebug - is a list empty (and don't perform debug checks)?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true.
+ * This differs from list_empty() in that if CCAN_LIST_DEBUG is set it
+ * will NOT perform debug checks. Only use this function if you REALLY
+ * know what you're doing.
+ *
+ * Example:
+ * assert(list_empty_nodebug(&parent->children) == (parent->num_children == 0));
+ */
+#ifndef CCAN_LIST_DEBUG
+#define list_empty_nodebug(h) list_empty(h)
+#else
+static inline bool list_empty_nodebug(const struct list_head *h)
+{
+ return h->n.next == &h->n;
+}
+#endif
+
+/**
+ * list_empty_nocheck - is a list empty?
+ * @h: the list_head
+ *
+ * If the list is empty, returns true. This doesn't perform any
+ * debug check for list consistency, so it can be called without
+ * locks, racing with the list being modified. This is ok for
+ * checks where an incorrect result is not an issue (optimized
+ * bail out path for example).
+ */
+static inline bool list_empty_nocheck(const struct list_head *h)
+{
+ return h->n.next == &h->n;
+}
+
+/**
+ * list_del - delete an entry from an (unknown) linked list.
+ * @n: the list_node to delete from the list.
+ *
+ * Note that this leaves @n in an undefined state; it can be added to
+ * another list, but not deleted again.
+ *
+ * See also:
+ * list_del_from(), list_del_init()
+ *
+ * Example:
+ * list_del(&child->list);
+ * parent->num_children--;
+ */
+#define list_del(n) list_del_(n, LIST_LOC)
+static inline void list_del_(struct list_node *n, const char* abortstr)
+{
+ (void)list_debug_node(n, abortstr);
+ n->next->prev = n->prev;
+ n->prev->next = n->next;
+#ifdef CCAN_LIST_DEBUG
+ /* Catch use-after-del. */
+ n->next = n->prev = NULL;
+#endif
+}
+
+/**
+ * list_del_init - delete a node, and reset it so it can be deleted again.
+ * @n: the list_node to be deleted.
+ *
+ * list_del(@n) or list_del_init() again after this will be safe,
+ * which can be useful in some cases.
+ *
+ * See also:
+ * list_del_from(), list_del()
+ *
+ * Example:
+ * list_del_init(&child->list);
+ * parent->num_children--;
+ */
+#define list_del_init(n) list_del_init_(n, LIST_LOC)
+static inline void list_del_init_(struct list_node *n, const char *abortstr)
+{
+ list_del_(n, abortstr);
+ list_node_init(n);
+}
+
+/**
+ * list_del_from - delete an entry from a known linked list.
+ * @h: the list_head the node is in.
+ * @n: the list_node to delete from the list.
+ *
+ * This explicitly indicates which list a node is expected to be in,
+ * which is better documentation and can catch more bugs.
+ *
+ * See also: list_del()
+ *
+ * Example:
+ * list_del_from(&parent->children, &child->list);
+ * parent->num_children--;
+ */
+static inline void list_del_from(struct list_head *h, struct list_node *n)
+{
+#ifdef CCAN_LIST_DEBUG
+ {
+ /* Thorough check: make sure it was in list! */
+ struct list_node *i;
+ for (i = h->n.next; i != n; i = i->next)
+ assert(i != &h->n);
+ }
+#endif /* CCAN_LIST_DEBUG */
+
+ /* Quick test that catches a surprising number of bugs. */
+ assert(!list_empty(h));
+ list_del(n);
+}
+
+/**
+ * list_swap - swap out an entry from an (unknown) linked list for a new one.
+ * @o: the list_node to replace from the list.
+ * @n: the list_node to insert in place of the old one.
+ *
+ * Note that this leaves @o in an undefined state; it can be added to
+ * another list, but not deleted/swapped again.
+ *
+ * See also:
+ * list_del()
+ *
+ * Example:
+ * struct child x1, x2;
+ * LIST_HEAD(xh);
+ *
+ * list_add(&xh, &x1.list);
+ * list_swap(&x1.list, &x2.list);
+ */
+#define list_swap(o, n) list_swap_(o, n, LIST_LOC)
+static inline void list_swap_(struct list_node *o,
+ struct list_node *n,
+ const char* abortstr)
+{
+ (void)list_debug_node(o, abortstr);
+ *n = *o;
+ n->next->prev = n;
+ n->prev->next = n;
+#ifdef CCAN_LIST_DEBUG
+ /* Catch use-after-del. */
+ o->next = o->prev = NULL;
+#endif
+}
+
+/**
+ * list_entry - convert a list_node back into the structure containing it.
+ * @n: the list_node
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * Example:
+ * // First list entry is children.next; convert back to child.
+ * child = list_entry(parent->children.n.next, struct child, list);
+ *
+ * See Also:
+ * list_top(), list_for_each()
+ */
+#define list_entry(n, type, member) container_of(n, type, member)
+
+/**
+ * list_top - get the first entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *first;
+ * first = list_top(&parent->children, struct child, list);
+ * if (!first)
+ * printf("Empty list!\n");
+ */
+#define list_top(h, type, member) \
+ ((type *)list_top_((h), list_off_(type, member)))
+
+static inline const void *list_top_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.next - off;
+}
+
+/**
+ * list_pop - remove the first entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *one;
+ * one = list_pop(&parent->children, struct child, list);
+ * if (!one)
+ * printf("Empty list!\n");
+ */
+#define list_pop(h, type, member) \
+ ((type *)list_pop_((h), list_off_(type, member)))
+
+static inline const void *list_pop_(const struct list_head *h, size_t off)
+{
+ struct list_node *n;
+
+ if (list_empty(h))
+ return NULL;
+ n = h->n.next;
+ list_del(n);
+ return (const char *)n - off;
+}
+
+/**
+ * list_tail - get the last entry in a list
+ * @h: the list_head
+ * @type: the type of the entry
+ * @member: the list_node member of the type
+ *
+ * If the list is empty, returns NULL.
+ *
+ * Example:
+ * struct child *last;
+ * last = list_tail(&parent->children, struct child, list);
+ * if (!last)
+ * printf("Empty list!\n");
+ */
+#define list_tail(h, type, member) \
+ ((type *)list_tail_((h), list_off_(type, member)))
+
+static inline const void *list_tail_(const struct list_head *h, size_t off)
+{
+ if (list_empty(h))
+ return NULL;
+ return (const char *)h->n.prev - off;
+}
+
+/**
+ * list_for_each - iterate through a list.
+ * @h: the list_head (warning: evaluated multiple times!)
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * list_for_each(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each(h, i, member) \
+ list_for_each_off(h, i, list_off_var_(i, member))
+
+/**
+ * list_for_each_rev - iterate through a list backwards.
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal.
+ *
+ * Example:
+ * list_for_each_rev(&parent->children, child, list)
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev(h, i, member) \
+ list_for_each_rev_off(h, i, list_off_var_(i, member))
+
+/**
+ * list_for_each_rev_safe - iterate through a list backwards,
+ * maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list backwards.
+ * It's a for loop, so you can break and continue as normal. The extra
+ * variable * @nxt is used to hold the next element, so you can delete @i
+ * from the list.
+ *
+ * Example:
+ * struct child *next;
+ * list_for_each_rev_safe(&parent->children, child, next, list) {
+ * printf("Name: %s\n", child->name);
+ * }
+ */
+#define list_for_each_rev_safe(h, i, nxt, member) \
+ list_for_each_rev_safe_off(h, i, nxt, list_off_var_(i, member))
+
+/**
+ * list_for_each_safe - iterate through a list, maybe during deletion
+ * @h: the list_head
+ * @i: the structure containing the list_node
+ * @nxt: the structure containing the list_node
+ * @member: the list_node member of the structure
+ *
+ * This is a convenient wrapper to iterate @i over the entire list. It's
+ * a for loop, so you can break and continue as normal. The extra variable
+ * @nxt is used to hold the next element, so you can delete @i from the list.
+ *
+ * Example:
+ * list_for_each_safe(&parent->children, child, next, list) {
+ * list_del(&child->list);
+ * parent->num_children--;
+ * }
+ */
+#define list_for_each_safe(h, i, nxt, member) \
+ list_for_each_safe_off(h, i, nxt, list_off_var_(i, member))
+
+/**
+ * list_next - get the next entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the last entry in the list, returns NULL.
+ *
+ * Example:
+ * struct child *second;
+ * second = list_next(&parent->children, first, list);
+ * if (!second)
+ * printf("No second child!\n");
+ */
+#define list_next(h, i, member) \
+ ((list_typeof(i))list_entry_or_null(list_debug(h, \
+ __FILE__ ":" stringify(__LINE__)), \
+ (i)->member.next, \
+ list_off_var_((i), member)))
+
+/**
+ * list_prev - get the previous entry in a list
+ * @h: the list_head
+ * @i: a pointer to an entry in the list.
+ * @member: the list_node member of the structure
+ *
+ * If @i was the first entry in the list, returns NULL.
+ *
+ * Example:
+ * first = list_prev(&parent->children, second, list);
+ * if (!first)
+ * printf("Can't go back to first child?!\n");
+ */
+#define list_prev(h, i, member) \
+ ((list_typeof(i))list_entry_or_null(list_debug(h, \
+ __FILE__ ":" stringify(__LINE__)), \
+ (i)->member.prev, \
+ list_off_var_((i), member)))
+
+/**
+ * list_append_list - empty one list onto the end of another.
+ * @to: the list to append into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the end of
+ * @to. After this @from will be empty.
+ *
+ * Example:
+ * struct list_head adopter;
+ *
+ * list_append_list(&adopter, &parent->children);
+ * assert(list_empty(&parent->children));
+ * parent->num_children = 0;
+ */
+#define list_append_list(t, f) list_append_list_(t, f, \
+ __FILE__ ":" stringify(__LINE__))
+static inline void list_append_list_(struct list_head *to,
+ struct list_head *from,
+ const char *abortstr)
+{
+ struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+ struct list_node *to_tail = list_debug(to, abortstr)->n.prev;
+
+ /* Sew in head and entire list. */
+ to->n.prev = from_tail;
+ from_tail->next = &to->n;
+ to_tail->next = &from->n;
+ from->n.prev = to_tail;
+
+ /* Now remove head. */
+ list_del(&from->n);
+ list_head_init(from);
+}
+
+/**
+ * list_prepend_list - empty one list into the start of another.
+ * @to: the list to prepend into
+ * @from: the list to empty.
+ *
+ * This takes the entire contents of @from and moves it to the start
+ * of @to. After this @from will be empty.
+ *
+ * Example:
+ * list_prepend_list(&adopter, &parent->children);
+ * assert(list_empty(&parent->children));
+ * parent->num_children = 0;
+ */
+#define list_prepend_list(t, f) list_prepend_list_(t, f, LIST_LOC)
+static inline void list_prepend_list_(struct list_head *to,
+ struct list_head *from,
+ const char *abortstr)
+{
+ struct list_node *from_tail = list_debug(from, abortstr)->n.prev;
+ struct list_node *to_head = list_debug(to, abortstr)->n.next;
+
+ /* Sew in head and entire list. */
+ to->n.next = &from->n;
+ from->n.prev = &to->n;
+ to_head->prev = from_tail;
+ from_tail->next = to_head;
+
+ /* Now remove head. */
+ list_del(&from->n);
+ list_head_init(from);
+}
+
+/* internal macros, do not use directly */
+#define list_for_each_off_dir_(h, i, off, dir) \
+ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
+ (off)); \
+ list_node_from_off_((void *)i, (off)) != &(h)->n; \
+ i = list_node_to_off_(list_node_from_off_((void *)i, (off))->dir, \
+ (off)))
+
+#define list_for_each_safe_off_dir_(h, i, nxt, off, dir) \
+ for (i = list_node_to_off_(list_debug(h, LIST_LOC)->n.dir, \
+ (off)), \
+ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
+ (off)); \
+ list_node_from_off_(i, (off)) != &(h)->n; \
+ i = nxt, \
+ nxt = list_node_to_off_(list_node_from_off_(i, (off))->dir, \
+ (off)))
+
+/**
+ * list_for_each_off - iterate through a list of memory regions.
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * This is a low-level wrapper to iterate @i over the entire list, used to
+ * implement all oher, more high-level, for-each constructs. It's a for loop,
+ * so you can break and continue as normal.
+ *
+ * WARNING! Being the low-level macro that it is, this wrapper doesn't know
+ * nor care about the type of @i. The only assumption made is that @i points
+ * to a chunk of memory that at some @offset, relative to @i, contains a
+ * properly filled `struct list_node' which in turn contains pointers to
+ * memory chunks and it's turtles all the way down. With all that in mind
+ * remember that given the wrong pointer/offset couple this macro will
+ * happily churn all you memory until SEGFAULT stops it, in other words
+ * caveat emptor.
+ *
+ * It is worth mentioning that one of legitimate use-cases for that wrapper
+ * is operation on opaque types with known offset for `struct list_node'
+ * member(preferably 0), because it allows you not to disclose the type of
+ * @i.
+ *
+ * Example:
+ * list_for_each_off(&parent->children, child,
+ * offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_off(h, i, off) \
+ list_for_each_off_dir_((h),(i),(off),next)
+
+/**
+ * list_for_each_rev_off - iterate through a list of memory regions backwards
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * See list_for_each_off for details
+ */
+#define list_for_each_rev_off(h, i, off) \
+ list_for_each_off_dir_((h),(i),(off),prev)
+
+/**
+ * list_for_each_safe_off - iterate through a list of memory regions, maybe
+ * during deletion
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @nxt: the structure containing the list_node
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * For details see `list_for_each_off' and `list_for_each_safe'
+ * descriptions.
+ *
+ * Example:
+ * list_for_each_safe_off(&parent->children, child,
+ * next, offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_safe_off(h, i, nxt, off) \
+ list_for_each_safe_off_dir_((h),(i),(nxt),(off),next)
+
+/**
+ * list_for_each_rev_safe_off - iterate backwards through a list of
+ * memory regions, maybe during deletion
+ * @h: the list_head
+ * @i: the pointer to a memory region which contains list node data.
+ * @nxt: the structure containing the list_node
+ * @off: offset(relative to @i) at which list node data resides.
+ *
+ * For details see `list_for_each_rev_off' and `list_for_each_rev_safe'
+ * descriptions.
+ *
+ * Example:
+ * list_for_each_rev_safe_off(&parent->children, child,
+ * next, offsetof(struct child, list))
+ * printf("Name: %s\n", child->name);
+ */
+#define list_for_each_rev_safe_off(h, i, nxt, off) \
+ list_for_each_safe_off_dir_((h),(i),(nxt),(off),prev)
+
+/* Other -off variants. */
+#define list_entry_off(n, type, off) \
+ ((type *)list_node_from_off_((n), (off)))
+
+#define list_head_off(h, type, off) \
+ ((type *)list_head_off((h), (off)))
+
+#define list_tail_off(h, type, off) \
+ ((type *)list_tail_((h), (off)))
+
+#define list_add_off(h, n, off) \
+ list_add((h), list_node_from_off_((n), (off)))
+
+#define list_del_off(n, off) \
+ list_del(list_node_from_off_((n), (off)))
+
+#define list_del_from_off(h, n, off) \
+ list_del_from(h, list_node_from_off_((n), (off)))
+
+/* Offset helper functions so we only single-evaluate. */
+static inline void *list_node_to_off_(struct list_node *node, size_t off)
+{
+ return (void *)((char *)node - off);
+}
+static inline struct list_node *list_node_from_off_(void *ptr, size_t off)
+{
+ return (struct list_node *)((char *)ptr + off);
+}
+
+/* Get the offset of the member, but make sure it's a list_node. */
+#define list_off_(type, member) \
+ (container_off(type, member) + \
+ check_type(((type *)0)->member, struct list_node))
+
+#define list_off_var_(var, member) \
+ (container_off_var(var, member) + \
+ check_type(var->member, struct list_node))
+
+#if HAVE_TYPEOF
+#define list_typeof(var) typeof(var)
+#else
+#define list_typeof(var) void *
+#endif
+
+/* Returns member, or NULL if at end of list. */
+static inline void *list_entry_or_null(const struct list_head *h,
+ const struct list_node *n,
+ size_t off)
+{
+ if (n == &h->n)
+ return NULL;
+ return (char *)n - off;
+}
+#endif /* CCAN_LIST_H */
diff --git a/ccan/ccan/short_types/LICENSE b/ccan/ccan/short_types/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/short_types/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/short_types/short_types.h b/ccan/ccan/short_types/short_types.h
new file mode 100644
index 0000000..175377e
--- /dev/null
+++ b/ccan/ccan/short_types/short_types.h
@@ -0,0 +1,35 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_SHORT_TYPES_H
+#define CCAN_SHORT_TYPES_H
+#include <stdint.h>
+
+/**
+ * u64/s64/u32/s32/u16/s16/u8/s8 - short names for explicitly-sized types.
+ */
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint16_t u16;
+typedef int16_t s16;
+typedef uint8_t u8;
+typedef int8_t s8;
+
+/* Whichever they include first, they get these definitions. */
+#ifdef CCAN_ENDIAN_H
+/**
+ * be64/be32/be16 - 64/32/16 bit big-endian representation.
+ */
+typedef beint64_t be64;
+typedef beint32_t be32;
+typedef beint16_t be16;
+
+/**
+ * le64/le32/le16 - 64/32/16 bit little-endian representation.
+ */
+typedef leint64_t le64;
+typedef leint32_t le32;
+typedef leint16_t le16;
+#endif
+
+#endif /* CCAN_SHORT_TYPES_H */
diff --git a/ccan/ccan/str/LICENSE b/ccan/ccan/str/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/str/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/str/debug.c b/ccan/ccan/str/debug.c
new file mode 100644
index 0000000..8c51944
--- /dev/null
+++ b/ccan/ccan/str/debug.c
@@ -0,0 +1,108 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#include "config.h"
+#include <ccan/str/str_debug.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef CCAN_STR_DEBUG
+/* Because we mug the real ones with macros, we need our own wrappers. */
+int str_isalnum(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isalnum(i);
+}
+
+int str_isalpha(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isalpha(i);
+}
+
+int str_isascii(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isascii(i);
+}
+
+#if HAVE_ISBLANK
+int str_isblank(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isblank(i);
+}
+#endif
+
+int str_iscntrl(int i)
+{
+ assert(i >= -1 && i < 256);
+ return iscntrl(i);
+}
+
+int str_isdigit(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isdigit(i);
+}
+
+int str_isgraph(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isgraph(i);
+}
+
+int str_islower(int i)
+{
+ assert(i >= -1 && i < 256);
+ return islower(i);
+}
+
+int str_isprint(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isprint(i);
+}
+
+int str_ispunct(int i)
+{
+ assert(i >= -1 && i < 256);
+ return ispunct(i);
+}
+
+int str_isspace(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isspace(i);
+}
+
+int str_isupper(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isupper(i);
+}
+
+int str_isxdigit(int i)
+{
+ assert(i >= -1 && i < 256);
+ return isxdigit(i);
+}
+
+#undef strstr
+#undef strchr
+#undef strrchr
+
+char *str_strstr(const char *haystack, const char *needle)
+{
+ return strstr(haystack, needle);
+}
+
+char *str_strchr(const char *haystack, int c)
+{
+ return strchr(haystack, c);
+}
+
+char *str_strrchr(const char *haystack, int c)
+{
+ return strrchr(haystack, c);
+}
+#endif
diff --git a/ccan/ccan/str/str.c b/ccan/ccan/str/str.c
new file mode 100644
index 0000000..a9245c1
--- /dev/null
+++ b/ccan/ccan/str/str.c
@@ -0,0 +1,13 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#include <ccan/str/str.h>
+
+size_t strcount(const char *haystack, const char *needle)
+{
+ size_t i = 0, nlen = strlen(needle);
+
+ while ((haystack = strstr(haystack, needle)) != NULL) {
+ i++;
+ haystack += nlen;
+ }
+ return i;
+}
diff --git a/ccan/ccan/str/str.h b/ccan/ccan/str/str.h
new file mode 100644
index 0000000..d919b84
--- /dev/null
+++ b/ccan/ccan/str/str.h
@@ -0,0 +1,228 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_H
+#define CCAN_STR_H
+#include "config.h"
+#include <string.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <ctype.h>
+
+/**
+ * streq - Are two strings equal?
+ * @a: first string
+ * @b: first string
+ *
+ * This macro is arguably more readable than "!strcmp(a, b)".
+ *
+ * Example:
+ * if (streq(somestring, ""))
+ * printf("String is empty!\n");
+ */
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+/**
+ * strstarts - Does this string start with this prefix?
+ * @str: string to test
+ * @prefix: prefix to look for at start of str
+ *
+ * Example:
+ * if (strstarts(somestring, "foo"))
+ * printf("String %s begins with 'foo'!\n", somestring);
+ */
+#define strstarts(str,prefix) (strncmp((str),(prefix),strlen(prefix)) == 0)
+
+/**
+ * strends - Does this string end with this postfix?
+ * @str: string to test
+ * @postfix: postfix to look for at end of str
+ *
+ * Example:
+ * if (strends(somestring, "foo"))
+ * printf("String %s end with 'foo'!\n", somestring);
+ */
+static inline bool strends(const char *str, const char *postfix)
+{
+ if (strlen(str) < strlen(postfix))
+ return false;
+
+ return streq(str + strlen(str) - strlen(postfix), postfix);
+}
+
+/**
+ * stringify - Turn expression into a string literal
+ * @expr: any C expression
+ *
+ * Example:
+ * #define PRINT_COND_IF_FALSE(cond) \
+ * ((cond) || printf("%s is false!", stringify(cond)))
+ */
+#define stringify(expr) stringify_1(expr)
+/* Double-indirection required to stringify expansions */
+#define stringify_1(expr) #expr
+
+/**
+ * strcount - Count number of (non-overlapping) occurrences of a substring.
+ * @haystack: a C string
+ * @needle: a substring
+ *
+ * Example:
+ * assert(strcount("aaa aaa", "a") == 6);
+ * assert(strcount("aaa aaa", "ab") == 0);
+ * assert(strcount("aaa aaa", "aa") == 2);
+ */
+size_t strcount(const char *haystack, const char *needle);
+
+/**
+ * STR_MAX_CHARS - Maximum possible size of numeric string for this type.
+ * @type_or_expr: a pointer or integer type or expression.
+ *
+ * This provides enough space for a nul-terminated string which represents the
+ * largest possible value for the type or expression.
+ *
+ * Note: The implementation adds extra space so hex values or negative
+ * values will fit (eg. sprintf(... "%p"). )
+ *
+ * Example:
+ * char str[STR_MAX_CHARS(int)];
+ *
+ * sprintf(str, "%i", 7);
+ */
+#define STR_MAX_CHARS(type_or_expr) \
+ ((sizeof(type_or_expr) * CHAR_BIT + 8) / 9 * 3 + 2 \
+ + STR_MAX_CHARS_TCHECK_(type_or_expr))
+
+#if HAVE_TYPEOF
+/* Only a simple type can have 0 assigned, so test that. */
+#define STR_MAX_CHARS_TCHECK_(type_or_expr) \
+ (sizeof(({ typeof(type_or_expr) x = 0; x; }))*0)
+#else
+#define STR_MAX_CHARS_TCHECK_(type_or_expr) 0
+#endif
+
+/**
+ * cisalnum - isalnum() which takes a char (and doesn't accept EOF)
+ * @c: a character
+ *
+ * Surprisingly, the standard ctype.h isalnum() takes an int, which
+ * must have the value of EOF (-1) or an unsigned char. This variant
+ * takes a real char, and doesn't accept EOF.
+ */
+static inline bool cisalnum(char c)
+{
+ return isalnum((unsigned char)c);
+}
+static inline bool cisalpha(char c)
+{
+ return isalpha((unsigned char)c);
+}
+static inline bool cisascii(char c)
+{
+ return isascii((unsigned char)c);
+}
+#if HAVE_ISBLANK
+static inline bool cisblank(char c)
+{
+ return isblank((unsigned char)c);
+}
+#endif
+static inline bool ciscntrl(char c)
+{
+ return iscntrl((unsigned char)c);
+}
+static inline bool cisdigit(char c)
+{
+ return isdigit((unsigned char)c);
+}
+static inline bool cisgraph(char c)
+{
+ return isgraph((unsigned char)c);
+}
+static inline bool cislower(char c)
+{
+ return islower((unsigned char)c);
+}
+static inline bool cisprint(char c)
+{
+ return isprint((unsigned char)c);
+}
+static inline bool cispunct(char c)
+{
+ return ispunct((unsigned char)c);
+}
+static inline bool cisspace(char c)
+{
+ return isspace((unsigned char)c);
+}
+static inline bool cisupper(char c)
+{
+ return isupper((unsigned char)c);
+}
+static inline bool cisxdigit(char c)
+{
+ return isxdigit((unsigned char)c);
+}
+
+#include <ccan/str/str_debug.h>
+
+/* These checks force things out of line, hence they are under DEBUG. */
+#ifdef CCAN_STR_DEBUG
+#include <ccan/build_assert/build_assert.h>
+
+/* These are commonly misused: they take -1 or an *unsigned* char value. */
+#undef isalnum
+#undef isalpha
+#undef isascii
+#undef isblank
+#undef iscntrl
+#undef isdigit
+#undef isgraph
+#undef islower
+#undef isprint
+#undef ispunct
+#undef isspace
+#undef isupper
+#undef isxdigit
+
+/* You can use a char if char is unsigned. */
+#if HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
+#define str_check_arg_(i) \
+ ((i) + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(i), \
+ char) \
+ || (char)255 > 0))
+#else
+#define str_check_arg_(i) (i)
+#endif
+
+#define isalnum(i) str_isalnum(str_check_arg_(i))
+#define isalpha(i) str_isalpha(str_check_arg_(i))
+#define isascii(i) str_isascii(str_check_arg_(i))
+#if HAVE_ISBLANK
+#define isblank(i) str_isblank(str_check_arg_(i))
+#endif
+#define iscntrl(i) str_iscntrl(str_check_arg_(i))
+#define isdigit(i) str_isdigit(str_check_arg_(i))
+#define isgraph(i) str_isgraph(str_check_arg_(i))
+#define islower(i) str_islower(str_check_arg_(i))
+#define isprint(i) str_isprint(str_check_arg_(i))
+#define ispunct(i) str_ispunct(str_check_arg_(i))
+#define isspace(i) str_isspace(str_check_arg_(i))
+#define isupper(i) str_isupper(str_check_arg_(i))
+#define isxdigit(i) str_isxdigit(str_check_arg_(i))
+
+#if HAVE_TYPEOF
+/* With GNU magic, we can make const-respecting standard string functions. */
+#undef strstr
+#undef strchr
+#undef strrchr
+
+/* + 0 is needed to decay array into pointer. */
+#define strstr(haystack, needle) \
+ ((typeof((haystack) + 0))str_strstr((haystack), (needle)))
+#define strchr(haystack, c) \
+ ((typeof((haystack) + 0))str_strchr((haystack), (c)))
+#define strrchr(haystack, c) \
+ ((typeof((haystack) + 0))str_strrchr((haystack), (c)))
+#endif
+#endif /* CCAN_STR_DEBUG */
+
+#endif /* CCAN_STR_H */
diff --git a/ccan/ccan/str/str_debug.h b/ccan/ccan/str/str_debug.h
new file mode 100644
index 0000000..92c10c4
--- /dev/null
+++ b/ccan/ccan/str/str_debug.h
@@ -0,0 +1,30 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_STR_DEBUG_H
+#define CCAN_STR_DEBUG_H
+
+/* #define CCAN_STR_DEBUG 1 */
+
+#ifdef CCAN_STR_DEBUG
+/* Because we mug the real ones with macros, we need our own wrappers. */
+int str_isalnum(int i);
+int str_isalpha(int i);
+int str_isascii(int i);
+#if HAVE_ISBLANK
+int str_isblank(int i);
+#endif
+int str_iscntrl(int i);
+int str_isdigit(int i);
+int str_isgraph(int i);
+int str_islower(int i);
+int str_isprint(int i);
+int str_ispunct(int i);
+int str_isspace(int i);
+int str_isupper(int i);
+int str_isxdigit(int i);
+
+char *str_strstr(const char *haystack, const char *needle);
+char *str_strchr(const char *s, int c);
+char *str_strrchr(const char *s, int c);
+#endif /* CCAN_STR_DEBUG */
+
+#endif /* CCAN_STR_DEBUG_H */
diff --git a/ccan/ccan/strset/strset.c b/ccan/ccan/strset/strset.c
new file mode 100644
index 0000000..06b0d7a
--- /dev/null
+++ b/ccan/ccan/strset/strset.c
@@ -0,0 +1,309 @@
+/* This code is based on the public domain code at
+ * http://github.com/agl/critbit writtem by Adam Langley
+ * <agl@imperialviolet.org>.
+ *
+ * Here are the main implementation differences:
+ * (1) We don't strdup the string on insert; we use the pointer we're given.
+ * (2) We use a straight bit number rather than a mask; it's simpler.
+ * (3) We don't use the bottom bit of the pointer, but instead use a leading
+ * zero to distinguish nodes from strings.
+ * (4) The empty string (which would look like a node) is handled
+ * using a special "empty node".
+ * (5) Delete returns the string, so you can free it if you want to.
+ * (6) Unions instead of void *, bool instead of int.
+ */
+#include <ccan/strset/strset.h>
+#include <ccan/short_types/short_types.h>
+#include <ccan/likely/likely.h>
+#include <ccan/str/str.h>
+#include <ccan/ilog/ilog.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <errno.h>
+
+struct node {
+ /* To differentiate us from strings. */
+ char nul_byte;
+ /* The bit where these children differ. */
+ u8 bit_num;
+ /* The byte number where first bit differs (-1 == empty string node). */
+ size_t byte_num;
+ /* These point to strings or nodes. */
+ struct strset child[2];
+};
+
+/* Closest member to this in a non-empty set. */
+static const char *closest(struct strset n, const char *member)
+{
+ size_t len = strlen(member);
+ const u8 *bytes = (const u8 *)member;
+
+ /* Anything with first byte 0 is a node. */
+ while (!n.u.s[0]) {
+ u8 direction = 0;
+
+ /* Special node which represents the empty string. */
+ if (unlikely(n.u.n->byte_num == (size_t)-1)) {
+ n = n.u.n->child[0];
+ break;
+ }
+
+ if (n.u.n->byte_num < len) {
+ u8 c = bytes[n.u.n->byte_num];
+ direction = (c >> n.u.n->bit_num) & 1;
+ }
+ n = n.u.n->child[direction];
+ }
+ return n.u.s;
+}
+
+char *strset_get(const struct strset *set, const char *member)
+{
+ const char *str;
+
+ /* Non-empty set? */
+ if (set->u.n) {
+ str = closest(*set, member);
+ if (streq(member, str))
+ return (char *)str;
+ }
+ errno = ENOENT;
+ return NULL;
+}
+
+static bool set_string(struct strset *set,
+ struct strset *n, const char *member)
+{
+ /* Substitute magic empty node if this is the empty string */
+ if (unlikely(!member[0])) {
+ n->u.n = malloc(sizeof(*n->u.n));
+ if (unlikely(!n->u.n)) {
+ errno = ENOMEM;
+ return false;
+ }
+ n->u.n->nul_byte = '\0';
+ n->u.n->byte_num = (size_t)-1;
+ /* Attach the string to child[0] */
+ n = &n->u.n->child[0];
+ }
+ n->u.s = member;
+ return true;
+}
+
+bool strset_add(struct strset *set, const char *member)
+{
+ size_t len = strlen(member);
+ const u8 *bytes = (const u8 *)member;
+ struct strset *np;
+ const char *str;
+ struct node *newn;
+ size_t byte_num;
+ u8 bit_num, new_dir;
+
+ /* Empty set? */
+ if (!set->u.n) {
+ return set_string(set, set, member);
+ }
+
+ /* Find closest existing member. */
+ str = closest(*set, member);
+
+ /* Find where they differ. */
+ for (byte_num = 0; str[byte_num] == member[byte_num]; byte_num++) {
+ if (member[byte_num] == '\0') {
+ /* All identical! */
+ errno = EEXIST;
+ return false;
+ }
+ }
+
+ /* Find which bit differs (if we had ilog8, we'd use it) */
+ bit_num = ilog32_nz((u8)str[byte_num] ^ bytes[byte_num]) - 1;
+ assert(bit_num < CHAR_BIT);
+
+ /* Which direction do we go at this bit? */
+ new_dir = ((bytes[byte_num]) >> bit_num) & 1;
+
+ /* Allocate new node. */
+ newn = malloc(sizeof(*newn));
+ if (!newn) {
+ errno = ENOMEM;
+ return false;
+ }
+ newn->nul_byte = '\0';
+ newn->byte_num = byte_num;
+ newn->bit_num = bit_num;
+ if (unlikely(!set_string(set, &newn->child[new_dir], member))) {
+ free(newn);
+ return false;
+ }
+
+ /* Find where to insert: not closest, but first which differs! */
+ np = set;
+ while (!np->u.s[0]) {
+ u8 direction = 0;
+
+ /* Special node which represents the empty string will
+ * break here too! */
+ if (np->u.n->byte_num > byte_num)
+ break;
+ /* Subtle: bit numbers are "backwards" for comparison */
+ if (np->u.n->byte_num == byte_num && np->u.n->bit_num < bit_num)
+ break;
+
+ if (np->u.n->byte_num < len) {
+ u8 c = bytes[np->u.n->byte_num];
+ direction = (c >> np->u.n->bit_num) & 1;
+ }
+ np = &np->u.n->child[direction];
+ }
+
+ newn->child[!new_dir]= *np;
+ np->u.n = newn;
+ return true;
+}
+
+char *strset_del(struct strset *set, const char *member)
+{
+ size_t len = strlen(member);
+ const u8 *bytes = (const u8 *)member;
+ struct strset *parent = NULL, *n;
+ const char *ret = NULL;
+ u8 direction = 0; /* prevent bogus gcc warning. */
+
+ /* Empty set? */
+ if (!set->u.n) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* Find closest, but keep track of parent. */
+ n = set;
+ /* Anything with first byte 0 is a node. */
+ while (!n->u.s[0]) {
+ u8 c = 0;
+
+ /* Special node which represents the empty string. */
+ if (unlikely(n->u.n->byte_num == (size_t)-1)) {
+ const char *empty_str = n->u.n->child[0].u.s;
+
+ if (member[0]) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ /* Sew empty string back so remaining logic works */
+ free(n->u.n);
+ n->u.s = empty_str;
+ break;
+ }
+
+ parent = n;
+ if (n->u.n->byte_num < len) {
+ c = bytes[n->u.n->byte_num];
+ direction = (c >> n->u.n->bit_num) & 1;
+ } else
+ direction = 0;
+ n = &n->u.n->child[direction];
+ }
+
+ /* Did we find it? */
+ if (!streq(member, n->u.s)) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ ret = n->u.s;
+
+ if (!parent) {
+ /* We deleted last node. */
+ set->u.n = NULL;
+ } else {
+ struct node *old = parent->u.n;
+ /* Raise other node to parent. */
+ *parent = old->child[!direction];
+ free(old);
+ }
+
+ return (char *)ret;
+}
+
+static bool iterate(struct strset n,
+ bool (*handle)(const char *, void *), const void *data)
+{
+ if (n.u.s[0])
+ return handle(n.u.s, (void *)data);
+ if (unlikely(n.u.n->byte_num == (size_t)-1))
+ return handle(n.u.n->child[0].u.s, (void *)data);
+
+ return iterate(n.u.n->child[0], handle, data)
+ && iterate(n.u.n->child[1], handle, data);
+}
+
+void strset_iterate_(const struct strset *set,
+ bool (*handle)(const char *, void *), const void *data)
+{
+ /* Empty set? */
+ if (!set->u.n)
+ return;
+
+ iterate(*set, handle, data);
+}
+
+const struct strset *strset_prefix(const struct strset *set, const char *prefix)
+{
+ const struct strset *n, *top;
+ size_t len = strlen(prefix);
+ const u8 *bytes = (const u8 *)prefix;
+
+ /* Empty set -> return empty set. */
+ if (!set->u.n)
+ return set;
+
+ top = n = set;
+
+ /* We walk to find the top, but keep going to check prefix matches. */
+ while (!n->u.s[0]) {
+ u8 c = 0, direction;
+
+ /* Special node which represents the empty string. */
+ if (unlikely(n->u.n->byte_num == (size_t)-1)) {
+ n = &n->u.n->child[0];
+ break;
+ }
+
+ if (n->u.n->byte_num < len)
+ c = bytes[n->u.n->byte_num];
+
+ direction = (c >> n->u.n->bit_num) & 1;
+ n = &n->u.n->child[direction];
+ if (c)
+ top = n;
+ }
+
+ if (!strstarts(n->u.s, prefix)) {
+ /* Convenient return for prefixes which do not appear in set. */
+ static const struct strset empty_set;
+ return &empty_set;
+ }
+
+ return top;
+}
+
+static void clear(struct strset n)
+{
+ if (!n.u.s[0]) {
+ if (likely(n.u.n->byte_num != (size_t)-1)) {
+ clear(n.u.n->child[0]);
+ clear(n.u.n->child[1]);
+ }
+ free(n.u.n);
+ }
+}
+
+void strset_clear(struct strset *set)
+{
+ if (set->u.n)
+ clear(*set);
+ set->u.n = NULL;
+}
diff --git a/ccan/ccan/strset/strset.h b/ccan/ccan/strset/strset.h
new file mode 100644
index 0000000..9d6f1ae
--- /dev/null
+++ b/ccan/ccan/strset/strset.h
@@ -0,0 +1,167 @@
+#ifndef CCAN_STRSET_H
+#define CCAN_STRSET_H
+#include "config.h"
+#include <ccan/typesafe_cb/typesafe_cb.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+/**
+ * struct strset - representation of a string set
+ *
+ * It's exposed here to allow you to embed it and so we can inline the
+ * trivial functions.
+ */
+struct strset {
+ union {
+ struct node *n;
+ const char *s;
+ } u;
+};
+
+/**
+ * strset_init - initialize a string set (empty)
+ *
+ * For completeness; if you've arranged for it to be NULL already you don't
+ * need this.
+ *
+ * Example:
+ * struct strset set;
+ *
+ * strset_init(&set);
+ */
+static inline void strset_init(struct strset *set)
+{
+ set->u.n = NULL;
+}
+
+/**
+ * strset_empty - is this string set empty?
+ * @set: the set.
+ *
+ * Example:
+ * if (!strset_empty(&set))
+ * abort();
+ */
+static inline bool strset_empty(const struct strset *set)
+{
+ return set->u.n == NULL;
+}
+
+/**
+ * strset_get - is this a member of this string set?
+ * @set: the set.
+ * @member: the string to search for.
+ *
+ * Returns the member, or NULL if it isn't in the set (and sets errno
+ * = ENOENT).
+ *
+ * Example:
+ * if (strset_get(&set, "hello"))
+ * printf("hello is in the set\n");
+ */
+char *strset_get(const struct strset *set, const char *member);
+
+/**
+ * strset_add - place a member in the string set.
+ * @set: the set.
+ * @member: the string to place in the set.
+ *
+ * This returns false if we run out of memory (errno = ENOMEM), or
+ * (more normally) if that string already appears in the set (EEXIST).
+ *
+ * Note that the pointer is placed in the set, the string is not copied. If
+ * you want a copy in the set, use strdup().
+ *
+ * Example:
+ * if (!strset_add(&set, "goodbye"))
+ * printf("goodbye was already in the set\n");
+ */
+bool strset_add(struct strset *set, const char *member);
+
+/**
+ * strset_del - remove a member from the string set.
+ * @set: the set.
+ * @member: the string to remove from the set.
+ *
+ * This returns the string which was passed to strset_add(), or NULL if
+ * the string was not in the map (in which case it sets errno = ENOENT).
+ *
+ * This means that if you allocated a string (eg. using strdup()), you can
+ * free it here.
+ *
+ * Example:
+ * if (!strset_del(&set, "goodbye"))
+ * printf("goodbye was not in the set?\n");
+ */
+char *strset_del(struct strset *set, const char *member);
+
+/**
+ * strset_clear - remove every member from the set.
+ * @set: the set.
+ *
+ * The set will be empty after this.
+ *
+ * Example:
+ * strset_clear(&set);
+ */
+void strset_clear(struct strset *set);
+
+/**
+ * strset_iterate - ordered iteration over a set
+ * @set: the set.
+ * @handle: the function to call.
+ * @arg: the argument for the function (types should match).
+ *
+ * You should not alter the set within the @handle function! If it returns
+ * false, the iteration will stop.
+ *
+ * Example:
+ * static bool dump_some(const char *member, int *num)
+ * {
+ * // Only dump out num nodes.
+ * if (*(num--) == 0)
+ * return false;
+ * printf("%s\n", member);
+ * return true;
+ * }
+ *
+ * static void dump_set(const struct strset *set)
+ * {
+ * int max = 100;
+ * strset_iterate(set, dump_some, &max);
+ * if (max < 0)
+ * printf("... (truncated to 100 entries)\n");
+ * }
+ */
+#define strset_iterate(set, handle, arg) \
+ strset_iterate_((set), typesafe_cb_preargs(bool, void *, \
+ (handle), (arg), \
+ const char *), \
+ (arg))
+void strset_iterate_(const struct strset *set,
+ bool (*handle)(const char *, void *), const void *data);
+
+
+/**
+ * strset_prefix - return a subset matching a prefix
+ * @set: the set.
+ * @prefix: the prefix.
+ *
+ * This returns a pointer into @set, so don't alter @set while using
+ * the return value. You can use strset_iterate(), strset_test() or
+ * strset_empty() on the returned pointer.
+ *
+ * Example:
+ * static void dump_prefix(const struct strset *set, const char *prefix)
+ * {
+ * int max = 100;
+ * printf("Nodes with prefix %s:\n", prefix);
+ * strset_iterate(strset_prefix(set, prefix), dump_some, &max);
+ * if (max < 0)
+ * printf("... (truncated to 100 entries)\n");
+ * }
+ */
+const struct strset *strset_prefix(const struct strset *set,
+ const char *prefix);
+
+#endif /* CCAN_STRSET_H */
diff --git a/ccan/ccan/typesafe_cb/LICENSE b/ccan/ccan/typesafe_cb/LICENSE
new file mode 120000
index 0000000..b7951da
--- /dev/null
+++ b/ccan/ccan/typesafe_cb/LICENSE
@@ -0,0 +1 @@
+../../licenses/CC0 \ No newline at end of file
diff --git a/ccan/ccan/typesafe_cb/typesafe_cb.h b/ccan/ccan/typesafe_cb/typesafe_cb.h
new file mode 100644
index 0000000..126d325
--- /dev/null
+++ b/ccan/ccan/typesafe_cb/typesafe_cb.h
@@ -0,0 +1,134 @@
+/* CC0 (Public domain) - see LICENSE file for details */
+#ifndef CCAN_TYPESAFE_CB_H
+#define CCAN_TYPESAFE_CB_H
+#include "config.h"
+
+#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
+/**
+ * typesafe_cb_cast - only cast an expression if it matches a given type
+ * @desttype: the type to cast to
+ * @oktype: the type we allow
+ * @expr: the expression to cast
+ *
+ * This macro is used to create functions which allow multiple types.
+ * The result of this macro is used somewhere that a @desttype type is
+ * expected: if @expr is exactly of type @oktype, then it will be
+ * cast to @desttype type, otherwise left alone.
+ *
+ * This macro can be used in static initializers.
+ *
+ * This is merely useful for warnings: if the compiler does not
+ * support the primitives required for typesafe_cb_cast(), it becomes an
+ * unconditional cast, and the @oktype argument is not used. In
+ * particular, this means that @oktype can be a type which uses the
+ * "typeof": it will not be evaluated if typeof is not supported.
+ *
+ * Example:
+ * // We can take either an unsigned long or a void *.
+ * void _set_some_value(void *val);
+ * #define set_some_value(e) \
+ * _set_some_value(typesafe_cb_cast(void *, unsigned long, (e)))
+ */
+#define typesafe_cb_cast(desttype, oktype, expr) \
+ __builtin_choose_expr( \
+ __builtin_types_compatible_p(__typeof__(0?(expr):(expr)), \
+ oktype), \
+ (desttype)(expr), (expr))
+#else
+#define typesafe_cb_cast(desttype, oktype, expr) ((desttype)(expr))
+#endif
+
+/**
+ * typesafe_cb_cast3 - only cast an expression if it matches given types
+ * @desttype: the type to cast to
+ * @ok1: the first type we allow
+ * @ok2: the second type we allow
+ * @ok3: the third type we allow
+ * @expr: the expression to cast
+ *
+ * This is a convenient wrapper for multiple typesafe_cb_cast() calls.
+ * You can chain them inside each other (ie. use typesafe_cb_cast()
+ * for expr) if you need more than 3 arguments.
+ *
+ * Example:
+ * // We can take either a long, unsigned long, void * or a const void *.
+ * void _set_some_value(void *val);
+ * #define set_some_value(expr) \
+ * _set_some_value(typesafe_cb_cast3(void *,, \
+ * long, unsigned long, const void *,\
+ * (expr)))
+ */
+#define typesafe_cb_cast3(desttype, ok1, ok2, ok3, expr) \
+ typesafe_cb_cast(desttype, ok1, \
+ typesafe_cb_cast(desttype, ok2, \
+ typesafe_cb_cast(desttype, ok3, \
+ (expr))))
+
+/**
+ * typesafe_cb - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * If a callback function takes a single argument, this macro does
+ * appropriate casts to a function which takes a single atype argument if the
+ * callback provided matches the @arg.
+ *
+ * It is assumed that @arg is of pointer type: usually @arg is passed
+ * or assigned to a void * elsewhere anyway.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb(void, (fn), void*, (arg)), (arg))
+ */
+#define typesafe_cb(rtype, atype, fn, arg) \
+ typesafe_cb_cast(rtype (*)(atype), \
+ rtype (*)(__typeof__(arg)), \
+ (fn))
+
+/**
+ * typesafe_cb_preargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * before the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(int, void *arg), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_preargs(void, void *, \
+ * (fn), (arg), int), \
+ * (arg))
+ */
+#define typesafe_cb_preargs(rtype, atype, fn, arg, ...) \
+ typesafe_cb_cast(rtype (*)(__VA_ARGS__, atype), \
+ rtype (*)(__VA_ARGS__, __typeof__(arg)), \
+ (fn))
+
+/**
+ * typesafe_cb_postargs - cast a callback function if it matches the arg
+ * @rtype: the return type of the callback function
+ * @atype: the (pointer) type which the callback function expects.
+ * @fn: the callback function to cast
+ * @arg: the (pointer) argument to hand to the callback function.
+ *
+ * This is a version of typesafe_cb() for callbacks that take other arguments
+ * after the @arg.
+ *
+ * Example:
+ * void _register_callback(void (*fn)(void *arg, int), void *arg);
+ * #define register_callback(fn, arg) \
+ * _register_callback(typesafe_cb_postargs(void, (fn), void *, \
+ * (arg), int), \
+ * (arg))
+ */
+#define typesafe_cb_postargs(rtype, atype, fn, arg, ...) \
+ typesafe_cb_cast(rtype (*)(atype, __VA_ARGS__), \
+ rtype (*)(__typeof__(arg), __VA_ARGS__), \
+ (fn))
+#endif /* CCAN_CAST_IF_TYPE_H */
diff --git a/ccan/licenses/BSD-MIT b/ccan/licenses/BSD-MIT
new file mode 100644
index 0000000..89de354
--- /dev/null
+++ b/ccan/licenses/BSD-MIT
@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/ccan/licenses/CC0 b/ccan/licenses/CC0
new file mode 100644
index 0000000..feb9b11
--- /dev/null
+++ b/ccan/licenses/CC0
@@ -0,0 +1,28 @@
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following:
+
+ the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work;
+ moral rights retained by the original author(s) and/or performer(s);
+ publicity and privacy rights pertaining to a person's image or likeness depicted in a Work;
+ rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below;
+ rights protecting the extraction, dissemination, use and reuse of data in a Work;
+ database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and
+ other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document.
+ Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law.
+ Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work.
+ Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work.
diff --git a/ccan/licenses/LGPL-2.1 b/ccan/licenses/LGPL-2.1
new file mode 100644
index 0000000..2d2d780
--- /dev/null
+++ b/ccan/licenses/LGPL-2.1
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/ccan/meson.build b/ccan/meson.build
new file mode 100644
index 0000000..35d2b88
--- /dev/null
+++ b/ccan/meson.build
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+sources += files([
+ 'ccan/hash/hash.c',
+ 'ccan/htable/htable.c',
+ 'ccan/ilog/ilog.c',
+ 'ccan/likely/likely.c',
+ 'ccan/list/list.c',
+ 'ccan/str/debug.c',
+ 'ccan/str/str.c',
+ 'ccan/strset/strset.c',
+])
+
+if get_option('buildtype') == 'debug'
+ add_project_arguments('-DCCAN_LIST_DEBUG=1', language : ['c'])
+ add_project_arguments('-DCCAN_STR_DEBUG=1', language : ['c'])
+endif
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 0000000..50d9e55
--- /dev/null
+++ b/cmd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _CMD_H
+#define _CMD_H
+
+#undef PLUGIN
+#define PLUGIN(n, c)
+
+#undef COMMAND_LIST
+#define COMMAND_LIST(args...)
+
+#endif
diff --git a/cmd_handler.h b/cmd_handler.h
new file mode 100644
index 0000000..c4b26f4
--- /dev/null
+++ b/cmd_handler.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Stage 1
+ *
+ * Define function prototypes.
+ */
+
+#undef NAME
+#define NAME(n, d, v)
+
+#undef ENTRY
+#define ENTRY(n, h, f, ...) \
+static int f(int argc, char **argv, struct command *command, struct plugin *plugin);
+
+#undef COMMAND_LIST
+#define COMMAND_LIST(args...) args
+
+#undef PLUGIN
+#define PLUGIN(name, cmds) cmds
+
+#include CMD_INCLUDE(CMD_INC_FILE)
+
+/*
+ * Stage 2
+ *
+ * Define command structures.
+ */
+
+#undef NAME
+#define NAME(n, d, v)
+
+#undef ENTRY_W_ALIAS
+#define ENTRY_W_ALIAS(n, h, f, a) \
+static struct command f ## _cmd = { \
+ .name = n, \
+ .help = h, \
+ .fn = f, \
+ .alias = a, \
+};
+
+#undef ENTRY_WO_ALIAS
+#define ENTRY_WO_ALIAS(n, h, f) \
+ ENTRY_W_ALIAS(n, h, f, NULL)
+
+#undef ENTRY_SEL
+#define ENTRY_SEL(n, h, f, a, CMD, ...) CMD
+
+#undef ENTRY
+#define ENTRY(...) \
+ ENTRY_SEL(__VA_ARGS__, ENTRY_W_ALIAS, ENTRY_WO_ALIAS)(__VA_ARGS__)
+
+#undef COMMAND_LIST
+#define COMMAND_LIST(args...) args
+
+#undef PLUGIN
+#define PLUGIN(name, cmds) cmds
+
+#include CMD_INCLUDE(CMD_INC_FILE)
+
+/*
+ * Stage 3
+ *
+ * Generate list of commands for the plugin.
+ */
+
+#undef NAME
+#define NAME(n, d, v)
+
+#undef ENTRY
+#define ENTRY(n, h, f, ...) &f ## _cmd,
+
+#undef COMMAND_LIST
+#define COMMAND_LIST(args...) \
+static struct command *commands[] = { \
+ args \
+ NULL, \
+};
+
+#undef PLUGIN
+#define PLUGIN(name, cmds) cmds
+
+#include CMD_INCLUDE(CMD_INC_FILE)
+
+/*
+ * Stage 4
+ *
+ * Define and register plugin
+ */
+
+#undef NAME
+#define NAME(n, d, v) .name = n, .desc = d, .version = v,
+
+#undef COMMAND_LIST
+#define COMMAND_LIST(args...)
+
+#undef PLUGIN
+#define PLUGIN(name, cmds) \
+static struct plugin plugin = { \
+ name \
+ .commands = commands \
+}; \
+ \
+static void init(void) __attribute__((constructor)); \
+static void init(void) \
+{ \
+ register_extension(&plugin); \
+}
+
+#include CMD_INCLUDE(CMD_INC_FILE)
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000..b63481a
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,6 @@
+---
+ignore:
+ - 'subprojects'
+ - 'ccan'
+ - 'tests'
+ - 'unit'
diff --git a/common.h b/common.h
new file mode 100644
index 0000000..b5594e9
--- /dev/null
+++ b/common.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#include <string.h>
+
+#include "ccan/endian/endian.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+#define min(x, y) ((x) > (y) ? (y) : (x))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+#ifdef __packed
+#else /* __packed */
+#define __packed __attribute__((__packed__))
+#endif /* __packed */
+
+static inline uint32_t mmio_read32(void *addr)
+{
+ leint32_t *p = addr;
+
+ return le32_to_cpu(*p);
+}
+
+/* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */
+static inline uint64_t mmio_read64(void *addr)
+{
+ const volatile uint32_t *p = addr;
+ uint32_t low, high;
+
+ low = le32_to_cpu(*p);
+ high = le32_to_cpu(*(p + 1));
+
+ return ((uint64_t) high << 32) | low;
+}
+
+#endif
diff --git a/completions/README b/completions/README
new file mode 100644
index 0000000..ba1032a
--- /dev/null
+++ b/completions/README
@@ -0,0 +1,120 @@
+Kelly Kaoudis, kelly.n.kaoudis at intel.com, June 2015
+
+Setting Up NVMe Tab Autocompletion for bash or zsh
+==================================================
+
+If your working shell is bash...
+--------------------------------
+the following gets bash autocompletion to behave properly
+#echo "bind 'set show-all-if-ambiguous on'" >> ~/.bashrc
+#echo "bind 'set show-all-if-unmodified on'" >> ~/.bashrc
+#echo "bind 'set completion-ignore-case on'" >> ~/.bashrc
+#echo "bind 'set completion-map-case on'" >> ~/.bashrc
+
+add NVMe autocompletion script to your autocompletes directory
+#cp `pwd`/bash-nvme-completion.sh /etc/bash_completion.d/nvme
+
+make sure this bash knows where everything is
+#source /etc/bash_completion.d/nvme && source ~/.bashrc
+
+you should be able to autocomplete with the nvme utility now
+(double TABs still apply)! If autocompleting has disappeared,
+just re-source nvme and .bashrc. To see a full list of auto-completable
+NVMe commands, type "nvme help " and hit TAB.
+
+You may also need to uncomment the "enable bash completion in interactive
+shells" part of /etc/bash.bashrc, which hopefully looks something like:
+
+if [ -f /usr/share/bash-completion/bash_completion ]; then
+ . /usr/share/bash-completion/bash_completion
+elif [ -f /etc/bash_completion ]; then
+ . /etc/bash_completion
+fi
+
+(don't bother with the shopt part, your Bash version might not support shopt).
+
+Bash footnote: for bash vers >= 4.2, it appears to be the case that
+menu-complete **no longer works.** If the bash dev folks ever re-patch this,
+try binding TAB to menu-complete to cycle through the NVMe subcommand matches
+on whatever you typed.
+
+if your working shell is zsh...
+-------------------------------
+create the zsh completions directory if you don't have it
+#if [ ! -e "~/.zsh" ]; then
+# mkdir ~/.zsh
+# mkdir ~/.zsh/completion
+#fi
+
+#cp `pwd`/_nvme ~/.zsh/completion/_nvme
+
+add compinit if you don't have it in your .zshrc
+#echo "autoload -Uz compinit && compinit" >> ~/.zshrc
+
+add nvme autocompletions to your .zshrc
+#echo "# source for tab autocompletions" >> ~/.zshrc
+#echo "fpath=(~/.zsh/completion $fpath)" >> ~/.zshrc
+#echo "source ~/.zsh/completion/_nvme" >> ~/.zshrc
+
+make sure this zsh knows where everything is
+#source ~/.zsh/completion/_nvme && source ~/.zshrc
+
+You should be able to autocomplete with the nvme utility now (single TAB press
+should get you a completion with descriptions -- sadly, bash doesn't support
+descriptions within completions). If autocompletes disappear, just re-source
+_nvme and .zshrc. Also, make sure your .zshrc is ordered correctly: we want to
+source _nvme before updating our fpath. Both of these should occur before
+compinit is loaded.
+
+Updating NVMe Tab Autocompletions
+=================================
+
+zsh
+---
+
+Add your new command to the _cmds array in the following format:
+
+'command:short-form description'
+
+Add a case to the zsh case statement for autocompletion of subopts
+in the following format (as seen in _nvme):
+
+(bar)
+ local _list_of_subopts
+ _list_of_subopts=(
+ /dev/nvme':supply a device to use (required)'
+ --foo':do something cool'
+ -f':alias of --foo'
+ )
+
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme bar options" _list_of_subopts
+ ;;
+
+All zsh autocompletion built-ins start with _, and so should anything
+internal to your autocompletes. _arguments and _describe are built-ins.
+The '*:: :->subcmds' bit describes the format in which we want our
+options to be displayed (don't change this, unless you like pain.)
+_describe -t adds our list of options to the data structure associated with
+our command `bar'.
+
+Add the name of your command to the (help) case as well.
+
+Update your ~/.zsh/completion/_nvme with your new changes and re-source as needed.
+
+bash
+----
+
+Add the name of your command to _cmds in bash_nvme_completion.sh. Add a case to
+_nvme_list_opts in the following format:
+
+"bar")
+opts+="--foo= -f --baz= -b"
+;;
+
+Update your /etc/bash_completion.d/nvme version, and re-source things as needed.
+
+TO DO
+-----
+Automatically generate man pages and autocompletions for new NVMe commands, possibly
+with kerneldoc.
diff --git a/completions/_nvme b/completions/_nvme
new file mode 100644
index 0000000..e90fc42
--- /dev/null
+++ b/completions/_nvme
@@ -0,0 +1,2316 @@
+#compdef _nvme nvme
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# zsh completions for the nvme command-line interface,
+# very loosely based on git and adb command completion
+# Kelly Kaoudis kelly.n.kaoudis at intel.com, June 2015
+
+_nvme () {
+ local -a _cmds
+ _cmds=(
+ 'list:identify basic information for all NVMe namespaces'
+ 'list-subsys:identify information for subsystems'
+ 'id-ctrl:display information about the controller'
+ 'id-ns:display information about the namespace'
+ 'id-ns-granularity:display namespace granularity list'
+ 'id-ns-lba-format:display information about the namespace capability fields for specific LBA format'
+ 'list-ns:identify all namespace(s) attached'
+ 'cmdset-ind-id-ns:display I/O Command Set Independent information about the namespace'
+ 'id-iocs:display information about I/O command sets'
+ 'id-domain:display information about domain list'
+ 'create-ns:create a new namespace before attachment'
+ 'delete-ns:delete a detached namespace'
+ 'attach-ns:attach namespace to controller'
+ 'detach-ns:detach namespace from controller'
+ 'list-ctrl:identify all controller(s) attached'
+ 'nvm-id-ctrl:display information about the nvm command set'
+ 'nvm-id-ns:display information about the namespace of nvm command set'
+ 'nvm-id-ns-lba-format:display information about the namespace of nvm command set capability fields for specific LBA format'
+ 'primary-ctrl-caps:display primary controller capabilities'
+ 'list-secondary:identify secondary controller list associated with the primary controller'
+ 'ns-descs:display namespace identification descriptors'
+ 'id-nvmset:display entries for NVM Set identifiers'
+ 'id-uuid:display list of supported Vendor Specific UUIDs'
+ 'list-endgrp:display information about nvme endurance group list'
+ 'get-ns-id:get namespace id of opened block device'
+ 'get-log:retrieve any log in raw format'
+ 'predictable-lat-log:retrieve predictable latency per nvmset log'
+ 'pred-lat-event-agg-log:retrieve predictable latency event aggregate log'
+ 'persistent-event-log:retrieve persistent event log'
+ 'telemetry-log:retrieve telemetry log'
+ 'fw-log:retrieve fw log'
+ 'changed-ns-list-log:retrieve changed namespaces log'
+ 'smart-log:retrieve SMART log'
+ 'smart-log-add:retrieve additional SMART log'
+ 'ana-log:retrieve ANA log'
+ 'error-log:retrieve error log'
+ 'effects-log:retrieve command effects log page and print the table'
+ 'endurance-log:retrieves endurance groups log page and prints the 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'
+ 'device-self-test:implementing the device self-test feature'
+ 'self-test-log:retrieve the self-test log'
+ 'set-feature:set a controller feature and show results'
+ 'set-property:writes and shows the defined NVMe controller property for NVMe over Fabric'
+ 'get-property:Reads and shows the defined NVMe controller property for NVMe over Fabric'
+ 'format:apply new block format to namespace'
+ 'fw-activate:activate a firmware on the device'
+ 'fw-download:download a firmware to the device'
+ 'admin-passthru:submit a passthrough admin command IOCTL'
+ 'io-passthru:submit a passthrough io command IOCTL'
+ 'security-send:send security/secure data to controller'
+ 'security-recv:ask for security/secure data from controller'
+ 'get-lba-status:display information about potentially unrecoverable LBAs'
+ 'resv-acquire:acquire reservation on a namespace'
+ 'resv-register:register reservation on a namespace'
+ 'resv-release:release reservation on a namespace'
+ 'resv-report:report reservation on a namespace'
+ 'dsm:submit a Data Set Management command'
+ 'copy:submit a simple copy command'
+ 'flush:submit a flush'
+ 'compare:compare data on device to data elsewhere'
+ 'read:submit a read command'
+ 'write:submit a write command'
+ 'capacity-mgmt:submit capacity management command'
+ 'write-zeroes:submit an NVMe write zeroes command'
+ 'write-uncor:submit an NVMe write uncorrectable command'
+ 'verify:submit an NVMe Verify command'
+ 'sanitize:submit a sanitize command'
+ 'sanitize-log:retrieve sanitize log and show it'
+ 'reset:reset the NVMe controller'
+ 'subsystem-reset:reset the NVMe subsystem'
+ 'ns-rescan:rescan the NVMe namespaces'
+ 'show-regs:show the controller registers; require admin character device'
+ 'boot-part-log:retrieve boot partition log'
+ 'fid-support-effects-log:retrieve fid support and effects log'
+ 'supported-log-pages:retrieve support log pages details'
+ 'lockdown:submit a lockdown command'
+ 'media-unit-stat-log:retrieve media unit status log pages details'
+ 'supported-cap-config-log:retrieve the list of Supported Capacity Configuration Descriptors'
+ 'discover:send Get Log Page request to Discovery Controller'
+ 'connect-all:discover NVMeoF subsystems and connect to them'
+ 'connect:connect to NVMeoF subsystem'
+ 'dim:send Discovery Information Management command to a Discovery Controller (DC)'
+ 'disconnect:disconnect from NVMeoF subsystem'
+ 'disconnect-all:disconnect from all connected NVMeoF subsystems'
+ 'gen-hostnqn:generate a host NVMe Qualified Name'
+ 'show-hostnqn:show the host NQN configured for the system'
+ 'dir-receive:read directive parameters of the specified directive type'
+ 'dir-send:set directive parameters of the specified directive type'
+ 'virt-mgmt:submit a Virtualization Management command'
+ 'rpmb:submit an NVMe RPMB command'
+ 'show-topology:show subsystem topology'
+ 'nvme-mi-recv:send a NVMe-MI receive command'
+ 'nvme-mi-send:send a NVMe-MI send command'
+ 'version:show the program version'
+ 'ocp:OCP cloud SSD extensions'
+ 'solidigm:Solidigm plug-in extensions'
+ 'help:print brief descriptions of all nvme commands'
+ 'json:dump output in json format'
+ )
+
+ local expl
+
+ _arguments '*:: :->subcmds' && return 0
+
+ if (( CURRENT == 1 )); then
+ _describe -t commands "nvme subcommands" _cmds
+ return
+ elif (( CURRENT > 2 )); then
+ case ${words[1]} in
+ (ocp)
+ case ${words[2]} in
+ (smart-add-log)
+ local _smart_add_log
+ _smart_add_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp smart-add-log options" _smart_add_log
+ ;;
+ (latency-monitor-log)
+ local _latency_monitor_log
+ _latency_monitor_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp latency-monitor-log options" _latency_monitor_log
+ ;;
+ (set-latency-monitor-feature)
+ local _set_latency_monitor_feature
+ _set_latency_monitor_feature=(
+ /dev/nvme':supply a device to use (required)'
+ --active_bucket_timer_threshold=':Active Bucket Timer Threshold'
+ -t':alias for --active_bucket_timer_threshold'
+ --active_threshold_a=':Active Threshold A'
+ -a':alias for --active_threshold_a'
+ --active_threshold_a=':Active Threshold B'
+ -b':alias for --active_threshold_b'
+ --active_threshold_c=':Active Threshold C'
+ -c':alias for --active_threshold_c'
+ --active_threshold_d=':Active Threshold D'
+ -d':alias for --active_threshold_d'
+ --active_latency_config=':Active Latency Configuration'
+ -f':alias for --active_latency_config'
+ --active_latency_minimum_window=':Active Latency Minimum Window'
+ -w':alias for --active_latency_minimum_window'
+ --debug_log_trigger_enable='Debug Log Trigger Enable'
+ -r':alias for --debug_log_trigger_enable'
+ --discard_debug_log='Discard Debug Log'
+ -l':alias for --discard_debug_log'
+ --latency_monitor_feature_enable='Latency Monitor Feature Enable'
+ -e':alias for --latency_monitor_feature_enable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp set-latency-monitor-feature options" _set_latency_monitor_feature
+ ;;
+ (internal-log)
+ local _internal_log
+ _internal_log=(
+ /dev/nvme':supply a device to use (required)'
+ --telemetry_type=':Telemetry Type; host (Create bit) or controller'
+ -t':alias for --telemetry_type'
+ --telemetry_data_area=':Telemetry Data Area; 1 or 3'
+ -a':alias for --telemetry_data_area'
+ --output-file=':Output file name with path'
+ -o':alias for --output-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp internal-log options" _internal_log
+ ;;
+ (clear-fw-activate-history)
+ local _clear_fw_activate_history
+ _clear_fw_activate_history=(
+ /dev/nvme':supply a device to use (required)'
+ --no-uuid':Skip UUID index search'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp clear-fw-activate-history options" _clear_fw_activate_history
+ ;;
+ (eol-plp-failure-mode)
+ local _eol_plp_failure_mode
+ _eol_plp_failure_mode=(
+ /dev/nvme':supply a device to use (required)'
+ --mode=':0-3: default/rom/wtm/normal'
+ -m':alias for --mode'
+ --save':Specifies that the controller shall save the attribute'
+ -s':alias for --save'
+ --sel=':0-3,8: current/default/saved/supported/changed:'
+ -S':alias for --sel'
+ --no-uuid':Skip UUID index search'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp eol-plp-failure-mode options" _eol_plp_failure_mode
+ ;;
+ (clear-pcie-correctable-error-counters)
+ local _clear_pcie_correctable_error_counters
+ _clear_pcie_correctable_error_counters=(
+ /dev/nvme':supply a device to use (required)'
+ --no-uuid':Skip UUID index search'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp clear-pcie-correctable-error-counters options" _clear_pcie_correctable_error_counters
+ ;;
+ (fw-activate-history)
+ local _fw_activate_history
+ _fw_activate_history=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp fw-activate-history options" _fw_activate_history
+ ;;
+ (device-capability-log)
+ local _device_capability_log
+ _device_capability_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp device-capability-log options" _device_capability_log
+ ;;
+ (set-dssd-power-state-feature)
+ local _set_dssd_power_state_feature
+ _set_dssd_power_state_feature=(
+ /dev/nvme':supply a device to use (required)'
+ --power-state=':DSSD Power State to set in watts'
+ -p':alias for --power-state'
+ --save':Specifies that the controller shall save the attribute'
+ -s':alias for --save'
+ --no-uuid':Skip UUID index search'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp set-dssd-power-state-feature options" _set_dssd_power_state_feature
+ ;;
+ (telemetry-string-log)
+ local _telemetry_string_log
+ _telemetry_string_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-file=':Output file name with path'
+ -o':alias for --output-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp telemetry-string-log options" _telemetry_string_log
+ ;;
+ (*)
+ _files
+ ;;
+ esac
+ ;;
+ (solidigm)
+ case ${words[2]} in
+ (id-ctrl)
+ local _id_ctrl
+ _id_ctrl=(
+ --verbose':Increase output verbosity'
+ -v':alias for --verbose'
+ --output-format':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --vendor-specific':dump binary vendor field'
+ -V':alias for --vendor-specific'
+ --raw-binary':show identify in binary format'
+ -b':alias for --raw-binary'
+ --human-readable':show identify in readable format'
+ -H':alias for --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm id-ctrl options" _id_ctrl
+ ;;
+ (smart-log-add)
+ local _smart_log_add
+ _smart_log_add=(
+ --namespace-id':(optional) desired namespace'
+ -n':alias for --namespace-id'
+ --output-format':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm smart-log-add options" _smart_log_add
+ ;;
+ (vs-smart-add-log)
+ local _vs_smart_add_log
+ _vs_smart_add_log=(
+ --output-format':output Format: normal|json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm vs-smart-add-log options" _vs_smart_add_log
+ ;;
+ (vs-internal-log)
+ local _vs_internal_log
+ _vs_internal_log=(
+ --type':Log type: ALL,
+ CONTROLLERINITTELEMETRY,
+ HOSTINITTELEMETRY,
+ HOSTINITTELEMETRYNOGEN, NLOG,
+ ASSERT, EVENT. Defaults to ALL.'
+ -t':alias for --type'
+ --namespace-id':Namespace to get logs from.'
+ -n':alias for --namespace-id'
+ --dir-prefix':Output dir prefix; defaults to device serial number.'
+ -p':alias for --dir-prefix'
+ --verbose':To print out verbose info.'
+ -v':alias for --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm vs-internal-log" _vs_internal_log
+ ;;
+ (garbage-collect-log)
+ local _garbage_collect_log
+ _garbage_collect_log=(
+ --output-format':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm garbage-collect-log" _garbage_collect_log
+ ;;
+ (market-log)
+ local _market_log
+ _market_log=(
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm market-log" _market_log
+ ;;
+ (latency-tracking-log)
+ local _latency_tracking_log
+ _latency_tracking_log=(
+ --enable':Enable Latency Tracking'
+ -e':alias for --enable'
+ --disable':Disable Latency Tracking'
+ -d':alias for --disable'
+ --read':Get read statistics'
+ -r':alias for --read'
+ --write':Get write statistics'
+ -w':alias for --write'
+ --type':Log type to get'
+ -t':alias for --type'
+ --output-format':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm latency-tracking-log" _latency_tracking_log
+ ;;
+ (parse-telemetry-log)
+ local _parse_telemetry_log
+ _parse_telemetry_log=(
+ --host-generate':Controls when to generate new
+ host initiated report. Default
+ value '1' generates new host
+ initiated report, value '0'
+ causes retrieval of existing
+ log.'
+ -g':alias for --host-generate'
+ --controller-init':Gather report generated by the controller.'
+ -c':alias for --controller-init'
+ --data-area':Pick which telemetry data area to
+ report. Default is 3 to fetch
+ areas 1-3. Valid options are 1,
+ 2, 3, 4.'
+ -d':alias for --data-area'
+ --config-file':JSON configuration file'
+ -j':alias for --config-file'
+ --source-file':data source <device> is binary
+ file containing log dump instead
+ of block or character device'
+ -s':alias for --source-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm parse-telemetry-log" _parse_telemetry_log
+ ;;
+ (clear-pcie-correctable-errors)
+ local _clear_pcie_correctable_errors
+ _clear_pcie_correctable_errors=(
+ --no-uuid':Skip UUID index search (UUID index not required for OCP 1.0)'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm clear-pcie-correctable-errors" _clear_pcie_correctable_errors
+ ;;
+ (clear-fw-activate-history)
+ local _clear_fw_activate_history
+ _clear_fw_activate_history=(
+ --no-uuid':Skip UUID index search (UUID index not required for OCP 1.0)'
+ -n':alias for --no-uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm clear-fw-activate-history" _clear_fw_activate_history
+ ;;
+ (vs-fw-activate-history)
+ local _vs_fw_activate_history
+ _vs_fw_activate_history=(
+ --output-format':output format : normal | json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm vs-fw-activate-history" _vs_fw_activate_history
+ ;;
+ (log-page-directory)
+ local _log_page_directory
+ _log_page_directory=(
+ --output-format':output format : normal | json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm log-page-directory" _log_page_directory
+ ;;
+ (temp-stats)
+ local _temp_stats
+ _temp_stats=(
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm temp-stats" _temp_stats
+ ;;
+ (vs-drive-info)
+ local _vs_drive_info
+ _vs_drive_info=(
+ --output-format':output format : normal | json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm vs-drive-info" _vs_drive_info
+ ;;
+ (*)
+ _files
+ ;;
+ esac
+ ;;
+ (sanitize)
+ case ${words[CURRENT-1]} in
+ (--sanact=|-a)
+ _values '' 'exit-failure' 'start-block-erase' 'start-overwrite' 'start-crypto-erase'
+ ;;
+ (*)
+ _files
+ ;;
+ esac
+ ;;
+ (*)
+ _files
+ ;;
+ esac
+ return
+ else
+ case ${words[CURRENT-1]} in
+ (list)
+ local _list
+ _list=(
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list options" _list
+ ;;
+ (list-subsys)
+ local _listsubsys
+ _listsubsys=(
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-subsys options" _listsubsys
+ ;;
+ (id-ctrl)
+ local _idctrl
+ _idctrl=(
+ /dev/nvme':supply a device to use (required)'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ --vendor-specific':also dump binary vendor infos'
+ -V':alias of --vendor-specific'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-ctrl options" _idctrl
+ ;;
+ (id-ns)
+ local _idns
+ _idns=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ --vendor-specific':also dump binary vendor infos'
+ -V':alias of --vendor-specific'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-ns options" _idns
+ ;;
+ (id-ns-granularity)
+ local _idns_granularity
+ _idns_granularity=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-ns-granularity options" _idns_granularity
+ ;;
+ (id-ns-lba-format)
+ local _idns_lba_format
+ _idns_lba_format=(
+ /dev/nvme':supply a device to use (required)'
+ --lba-format-index=':show infos for lba format index <lba-format-index>'
+ -i':alias of --lba-format-index'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-ns-lba-format options" _idns_lba_format
+ ;;
+ (list-ns)
+ local _listns
+ _listns=(
+ /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'
+ --all':show all namespaces in the subsystem, whether attached or inactive'
+ -a':alias of --all'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-ns options" _listns
+ ;;
+ (cmdset-ind-id-ns)
+ local _cmdset_ind_idns
+ _cmdset_ind_idns=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme cmdset-ind-id-ns options" _cmdset_ind_idns
+ ;;
+ (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
+ ;;
+ (id-domain)
+ local _iddomain
+ _iddomain=(
+ /dev/nvme':supply a device to use (required)'
+ --dom-id=':show infos for domain id <cntid>'
+ -d':alias of --dom-id'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-domain options" _iddomain
+ ;;
+ (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
+ ;;
+ (nvm-id-ns)
+ local _nvmidns
+ _nvmidns=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme nvm-id-ns options" _nvmidns
+ ;;
+ (nvm-id-ns-lba-format)
+ local _nvm_idns_lba_format
+ _nvm_idns_lba_format=(
+ /dev/nvme':supply a device to use (required)'
+ --lba-format-index=':show infos for lba format index <lba-format-index>'
+ -i':alias of --lba-format-index'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme nvm-id-ns-lba-format options" _nvm_idns_lba_format
+ ;;
+ (primary-ctrl-caps)
+ local _primary_ctrl_caps
+ _primary_ctrl_caps=(
+ /dev/nvme':supply a device to use (required)'
+ --cntlid=':show infos for controller <cntid>'
+ -c':alias of --cntlid'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme primary-ctrl-caps options" _primary_ctrl_caps
+ ;;
+ (list-secondary)
+ local _listsecondary
+ _listsecondary=(
+ /dev/nvme':supply a device to use (required)'
+ --cntid=':show infos for lowest controller <cntid>'
+ -c':alias of --cntid'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --num-entries=':number of entries to retrieve'
+ -e':alias of --num-entries'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-secondary options" _listsecondary
+ ;;
+ (ns-descs)
+ local _ns_descs
+ _ns_descs=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ns-descs options" _ns_descs
+ ;;
+ (id-nvmset)
+ local _id_nvmset
+ _id_nvmset=(
+ /dev/nvme':supply a device to use (required)'
+ --nvmset_id=':NVM Set Identify value'
+ -i':alias of --nvmset_id'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-nvmset options" _id_nvmset
+ ;;
+ (id-uuid)
+ local _id_uuid
+ _id_uuid=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme id-uuid options" _id_uuid
+ ;;
+ (list-endgrp)
+ local _listendgrp
+ _listendgrp=(
+ /dev/nvme':supply a device to use (required)'
+ --endgrp-id=':endurance group id'
+ -i':alias of --endgrp-id'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-endgrp options" _listendgrp
+ ;;
+ (create-ns)
+ local _createns
+ _createns=(
+ /dev/nvme':supply a device to use (required)'
+ --nsze=':namespace size to create'
+ -s':alias of --nsze'
+ --ncap=':namespace capacity'
+ -c':alias of --ncap'
+ --flbas=':FLBA size'
+ -f':alias of --flbas'
+ --dps=':data protection?'
+ -d':alias of --dps'
+ --nmic=':multipath and sharing'
+ -m':alias of --nmic'
+ --anagrp-id=':ANA Group Identifier'
+ -a':alias of --anagrp-id'
+ --nvmset-id=':NVM Set Identifier'
+ -i':alias of --nvmset-id'
+ --endg-id=':Endurance Group Identifier'
+ -e':alias of --endg-id'
+ --block-size=':target block size'
+ -b':alias of --block-size'
+ --timeout=':value for timeout'
+ -t':alias of --timeout'
+ --csi=':command set identifier'
+ -y':alias of --csi'
+ --lbstm=':logical block storage tag mask'
+ -l':alias of --lbstm'
+ --nsze-si=':size of ns (NSZE) in standard SI units'
+ -S':alias of --nsze-si'
+ --ncap-si=':capacity of ns (NCAP) in standard SI units'
+ -C':alias of --ncap-si'
+ --azr=':Allocate ZRWA Resources (AZR) for Zoned Namespace Command Set'
+ -z':alias of --azr'
+ --rar=':Requested Active Resources (RAR) for Zoned Namespace Command Set'
+ -r':alias of --rar'
+ --ror=':Requested Open Resources (ROR) for Zoned Namespace Command Set'
+ -O':alias of --ror'
+ --rnumzrwa=':Requested Number of ZRWA Resources (RNUMZRWA) for Zoned Namespace Command Set'
+ -u':alias of --rnumzrwa'
+ --phndls=':Comma separated list of Placement Handle Associated RUH'
+ -p':alias of --phndls'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme create-ns options" _createns
+ ;;
+ (delete-ns)
+ local _deletens
+ _deletens=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':namespace to delete'
+ -n':alias of --namespace-id'
+ --timeout=':value for timeout'
+ -t':alias of --timeout'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme delete-ns options" _deletens
+ ;;
+ (attach-ns)
+ local _attachns
+ _attachns=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':namespace to attach to the controller'
+ -n':alias of --namespace-id'
+ --controllers=':if a device is not provided, supply a comma-sep list of controllers'
+ -c':alias of --controllers'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme attach-ns options" _attachns
+ ;;
+ (detach-ns)
+ local _detachns
+ _detachns=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':namespace to detach from controller'
+ -n':alias of --namespace-id'
+ --controllers=':if a device is not provided, supply a comma-sep list of controllers'
+ -c':alias of --controllers'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme detach-ns options" _detachns
+ ;;
+ (list-ctrl)
+ local _listctrl
+ _listctrl=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show controllers attached to this namespace'
+ -n':alias of --namespace-id'
+ --cntid=':start the list with this controller'
+ -c':alias of --cntid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-ctrl options" _listctrl
+ ;;
+ (get-ns-id)
+ local _getnsid
+ _getnsid=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme get-ns-id options" _getnsid
+ ;;
+ (get-log)
+ local _getlog
+ _getlog=(
+ /dev/nvme':supply a device to use (required)'
+ --log-id=':requested log number'
+ -i':alias of --log-id'
+ --log-len=':number of bytes to show for requested log'
+ -l':alias of --log-len'
+ --namespace-id=':get log specific to <nsid> if namespace logs are supported'
+ -n':alias of --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ --aen=':result of the aen, use to override log id'
+ -a':alias of --aen'
+ --lpo=':log page offset specifies the location within a log page from where to start returning data'
+ -L':alias of --lpo'
+ --lsi=':log specific identifier specifies an identifier that is required for a particular log page'
+ -S':alias of --lsi'
+ --rae':Retain an Asynchronous Event'
+ -r':alias of --rae'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ --csi=':command set identifier'
+ -y':alias of --csi'
+ --ot':offset type'
+ -O':alias of --ot'
+ --xfer-len=':read chunk size (default 4k)'
+ -x':alias of --xfer-len'
+ )
+ _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 "nvme persistent-event-log options" _persistenteventlog
+ ;;
+ (telemetry-log)
+ local _telemetry_log
+ _telemetry_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-file=':telemetry data output write'
+ -O':alias for --output-file'
+ --host-generate=':Have the host tell the controller to generate the report'
+ -g':alias to --host-generate'
+ --controller-init':Gather report generated by the controller'
+ -c':alias of --controller-init'
+ --data-area':Pick which telemetry data area to report'
+ -d':alias of --data-area'
+ --data-area':Pick which telemetry data area to report'
+ -d':alias of --data-area'
+ --rae':Retain an Asynchronous Event'
+ -r':alias to --rae'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme telemetry-log options" _telemetry_log
+ ;;
+ (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
+ ;;
+ (predictable-lat-log)
+ 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=(
+ /dev/nvme':supply a device to use (required)'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme fw-log options" _fwlog
+ ;;
+ (changed-ns-list-log)
+ local _changed_ns_list_log
+ _changed_ns_list_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme changed-ns-list-log options" _changed_ns_list_log
+ ;;
+ (smart-log)
+ local _smartlog
+ _smartlog=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':get SMART log specific to <nsid> if namespace logs are supported'
+ -n':alias to --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias to --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme smart-log options" _smartlog
+ ;;
+ (smart-log-add)
+ local _add
+ _add=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':get additional SMART log specific to <nsid> if namespace logs supported'
+ -n':alias to --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias to --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme smart-log-add options" _add
+ ;;
+ (ana-log)
+ local _ana_log
+ _ana_log=(
+ /dev/nvme':supply a device to use (required)'
+ --groups':Return ANA groups only'
+ -g':alias to --groups'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ana-log options" _ana_log
+ ;;
+ (error-log)
+ local _errlog
+ _errlog=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':get log specific to <nsid> if namespace logs are supported'
+ -n':alias to --namespace-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias to --raw-binary'
+ --log-entries=':request n >= 1 log entries'
+ -e':alias to --log-entries'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme error-log options" _errlog
+ ;;
+ (effects-log)
+ local _effects_log
+ _effects_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ --raw-binary':dump infos in binary format'
+ -b':alias to --raw-binary'
+ --csi=':command set identifier'
+ -c':alias of --csi'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme effects-log options" _effects_log
+ ;;
+ (endurance-log)
+ local _endurance_log
+ _endurance_log=(
+ /dev/nvme':supply a device to use (required)'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --group-id=':The endurance group identifier'
+ -g':alias of --group-id'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme endurance-log options" _endurance_log
+ ;;
+ (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
+ ;;
+ (boot-part-log)
+ local _bootpartlog
+ _bootpartlog=(
+ /dev/nvme':supply a device to use (required)'
+ --lsp=':log specific field'
+ -s':alias to --lsp'
+ --output-file=':boot partition data output write'
+ -f':alias for --output-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme boot-part-log options" _bootpartlog
+ ;;
+ (get-feature)
+ local _getf
+ _getf=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':get feature specific to <nsid>'
+ -n':alias to --namespace-id'
+ --feature-id=':hexadecimal name of feature to examine (required)'
+ -f':alias to --feature-id'
+ --sel=':select from 0 - current, 1 - default, 2 - saved, 3 - supported'
+ -s':alias to --sel'
+ --data-len=':buffer len for returned LBA Type Range or host identifier data'
+ -l':alias for --data-len'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ --cdw11=':dword 11 value, used for interrupt vector configuration only'
+ --raw-binary':dump infos in binary format'
+ -b':alias to --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme get-feature options" _getf
+ ;;
+ (device-self-test)
+ local _device_self_test
+ _device_self_test=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':Indicate the namespace in which the device self-test has to be carried out'
+ -n':alias to --namespace-id'
+ --self-test-code=':This field specifies the action taken by the device self-test command'
+ -s':alias for --self-test-code'
+ --wait':Wait for the test to finish'
+ -w':alias to --wait'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme device-self-test options" _device_self_test
+ ;;
+ (self-test-log)
+ local _self_test_log
+ _self_test_log=(
+ /dev/nvme':supply a device to use (required)'
+ --dst-entries=':Indicate how many DST log entries to be retrieved'
+ -e':alias to --dst-entries'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme self-test-log options" _self_test_log
+ ;;
+ (lockdown)
+ local _lockdown
+ _lockdown=(
+ /dev/nvme':supply a device to use (required)'
+ --ofi=':Opcode or Feature Identifier(OFI) (required)'
+ -O':alias of --ofi'
+ --ifc=':Interface (INF) field Information (required)'
+ -f':alias of --ifc'
+ --prhbt=':Prohibit(PRHBT) bit field (required)'
+ -p':alias of --prhbt'
+ --scp=':Scope(SCP) field for identifying opcode or feature id (required)'
+ -s':alias of --scp'
+ --uuid=':UUID Index field required aligned with Scope'
+ -U':alias of --uuid'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme lockdown options" _lockdown
+ ;;
+ (set-feature)
+ local _setf
+ _setf=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':feature is specific to <nsid>'
+ -n':alias to --namespace-id'
+ --feature-id=':hexadecimal name of feature to set (required)'
+ -f':alias to --feature-id'
+ --data-len=':buffer length, only used for LBA Type Range or host identifier data'
+ -l':alias for --data-len'
+ --data=':data file for LBA Type Range or host identifier buffer (defaults to stdin)'
+ -d':alias to --data'
+ --value=':new value of feature (required)'
+ -V'alias to --value'
+ --uuid-index=':uuid index'
+ -U':alias for --uuid-index'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme set-feature options" _setf
+ ;;
+ (set-property)
+ local _set_property
+ _set_property=(
+ /dev/nvme':supply a device to use (required)'
+ --offset=':the offset of the property'
+ -O':alias to --offset'
+ --value=':the value of the property to be set'
+ -V':alias to --value'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme set-property options" _set_property
+ ;;
+ (get-property)
+ local _get_property
+ _get_property=(
+ /dev/nvme':supply a device to use (required)'
+ --offset=':the offset of the property'
+ -O':alias to --offset'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme get-property options" _get_property
+ ;;
+ (format)
+ local _format
+ _format=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':<nsid> of namespace to format (required)'
+ -n':alias of --namespace-id'
+ --timeout=':value for timeout'
+ -t':alias of --timeout'
+ --lbaf=':LBA format to apply to namespace (required)'
+ -l':alias of --lbaf'
+ --ses=':secure erase? 0 - no-op (default), 1 - user-data erase, 2 - cryptographic erase'
+ -s':alias of --ses'
+ --pil=':location of protection information? 0 - end, 1 - start'
+ -p':alias of --pil'
+ --pi=':protection information? 0 - off, 1 - Type 1 on, 2 - Type 2 on, 3 - Type 3 on'
+ -i':alias of --pi'
+ --ms=':extended format? 0 - off (metadata in separate buffer), 1 - on (extended LBA used)'
+ -m':alias of --ms'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme format options" _format
+ ;;
+ (fw-activate)
+ local _fwact
+ _fwact=(
+ /dev/nvme':supply a device to use (required)'
+ --action=':activation action (required)? 0 - replace fw without activating, 1 - replace with activation, 2 - replace with activation at next reset'
+ -a':alias of --action'
+ --slot=':firmware slot to activate'
+ -s':alias of --slot'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme fw-activate options" _fwact
+ ;;
+ (fw-download)
+ local _fwd
+ _fwd=(
+ /dev/nvme':supply a device to use (required)'
+ --fw=':firmware file to download (required)'
+ -f':alias of --fw'
+ --xfer=':limit on chunk-size of transfer (if device has download size limit)'
+ -x':alias of --xfer'
+ --offset=':starting offset, in dwords (defaults to 0, only useful if download is split across multiple files)'
+ -O':alias of --offset'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme fw-download options" _fwd
+ ;;
+ (capacity-mgmt)
+ local _fwd
+ _fwd=(
+ /dev/nvme':supply a device to use (required)'
+ --operation=':Operation to be performed by the controller'
+ -O':alias of --operation'
+ --element-id=':specific to the value of the Operation field'
+ -i':alias of --element-id'
+ --cap-lower=':Least significant 32 bits of the capacity in bytes'
+ -l':alias of --cap-lower'
+ --cap-upper=':Most significant 32 bits of the capacity in bytes'
+ -u':alias of --cap-upper'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme capacity-mgmt options" _fwd
+ ;;
+ (write-zeroes)
+ local _write_zeroes
+ _write_zeroes=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --start-block=':64-bit address of the first logical block to be written'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to write'
+ -c':alias of --block-count'
+ --dir-type=':directive type'
+ -T':alias of --dir-type'
+ --deac':Set DEAC bit, requesting controller to deallocate specified logical blocks'
+ -d':alias of --deac'
+ --limited-retry':if included, controller should try less hard to send data to media (if not included, all available data-recovery means used)'
+ -l':alias of --limited-retry'
+ --force-unit-access':data shall be written to nonvolatile media before command completion is indicated'
+ -f':alias of --force-unit-access'
+ --prinfo=':protection information and check field'
+ -p':alias of --prinfo'
+ --ref-tag=':reference tag (for end to end PI)'
+ -r':alias of --ref-tag'
+ --app-tag-mask=':application tag mask (for end to end PI)'
+ -m':alias of --app-tag-mask'
+ --app-tag=':application tag (for end to end PI)'
+ -a':alias of --app-tag'
+ --storage-tag=':storage tag for end-to-end PI'
+ -S':alias of --storage-tag'
+ --storage-tag-check':Storage Tag field shall be checked as part of end-to-end data protection processing'
+ -C':alias of --storage-tag-check'
+ --dir-spec=':directive specific'
+ -D':alias of --dir-spec'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme write-zeroes options" _write_zeroes
+ ;;
+ (write-uncor)
+ local _write_uncor
+ _write_uncor=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --start-block=':64-bit address of the first logical block to be written'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to write'
+ -c':alias of --block-count'
+ --dir-type=':directive type'
+ -T':alias of --dir-type'
+ --dir-spec':directive specific'
+ -S':alias of --dir-spec'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme write-uncor options" _write_uncor
+ ;;
+ (verify)
+ local _verify
+ _verify=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --start-block=':64-bit address of the first logical block to be verified'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to verify'
+ -c':alias of --block-count'
+ --limited-retry':if included, controller should try less hard to send data to media (if not included, all available data-recovery means used)'
+ -l':alias of --limited-retry'
+ --force-unit-access':data shall be verified from nonvolatile media before command completion is indicated'
+ -f':alias of --force-unit-access'
+ --prinfo=':protection information and check field'
+ -p':alias of --prinfo'
+ --ref-tag=':reference tag (for end to end PI)'
+ -r':alias of --ref-tag'
+ --app-tag=':application tag (for end to end PI)'
+ -a':alias of --app-tag'
+ --app-tag-mask=':application tag mask (for end to end PI)'
+ -m':alias of --app-tag-mask'
+ --storage-tag=':storage tag for end-to-end PI'
+ -S':alias of --storage-tag'
+ --storage-tag-check':Storage Tag field shall be checked as part of end-to-end data protection processing'
+ -C':alias of --storage-tag-check'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme verify options" _verify
+ ;;
+ (sanitize)
+ local _sanitize
+ _sanitize=(
+ /dev/nvme':supply a device to use (required)'
+ --no-dealloc':No deallocate after sanitize'
+ -d':alias of --no-dealloc'
+ --oipbp':Overwrite invert pattern between passes'
+ -i':alias of --oipbp'
+ --owpass=':Overwrite pass count'
+ -n':alias of --owpass'
+ --ause':Allow unrestricted sanitize exit'
+ -u':alias of --ause'
+ --sanact=':Sanitize action: 1 = Exit failure mode, 2 = Start block erase, 3 = Start overwrite, 4 = Start crypto erase'
+ -a':alias of --sanact'
+ --ovrpat=':Overwrite pattern'
+ -p':alias of --ovrpat'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme sanitize options" _sanitize
+ ;;
+ (sanitize-log)
+ local _sanitize_log
+ _sanitize_log=(
+ /dev/nvme':supply a device to use (required)'
+ --rae':Retain an Asynchronous Event'
+ -r':alias of --rae'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme sanitize-log options" _sanitize_log
+ ;;
+ (reset)
+ local _reset
+ _reset=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme reset options" _reset
+ ;;
+ (subsystem-reset)
+ local _subsystem_reset
+ _subsystem_reset=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme subsystem-reset options" _subsystem_reset
+ ;;
+ (ns-rescan)
+ local _ns_rescan
+ _ns_rescan=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ns-rescan options" _ns_rescan
+ ;;
+ (supported-log-pages)
+ local _support
+ _support=(
+ /dev/nvme':supply a device to use (required)'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme supported-log-pages options" _support
+ ;;
+ (media-unit-stat-log)
+ local _medialog
+ _medialog=(
+ /dev/nvme':supply a device to use (required)'
+ --dom-id=':show infos for domain id'
+ -d':alias of --dom-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme media-unit-stat-log" _medialog
+ ;;
+ (supported-cap-config-log)
+ local _caplog
+ _caplog=(
+ /dev/nvme':supply a device to use (required)'
+ --dom-id=':show infos for domain id'
+ -d':alias of --dom-id'
+ --raw-binary':dump infos in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme supported-cap-config-log" _caplog
+ ;;
+ (admin-passthru)
+ local _admin
+ _admin=(
+ /dev/nvme':supply a device to use (required)'
+ --opcode=':hexadecimal opcode to send (required)'
+ -O':alias of --opcode'
+ --flags=':command flags'
+ -f':alias of --flags'
+ --rsvd=':value for reserved field'
+ -R':alias of --rsvd'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --metadata-len=':length for metadata buffer'
+ -m':alias of --metadata-len'
+ --timeout=':value for timeout'
+ -t':alias of --timeout'
+ --cdw2=':value for command dword 2'
+ -2':alias for --cdw2'
+ --cdw3=':value for command dword 3'
+ -3':alias for --cdw3'
+ --cdw10=':value for command dword 10'
+ -4':alias for --cdw10'
+ --cdw11=':value for command dword 11'
+ -5':alias for --cdw11'
+ --cdw12=':value for command dword 12'
+ -6':alias for --cdw12'
+ --cdw13=':value for command dword 13'
+ -7':alias for --cdw13'
+ --cdw14=':value for command dword 14'
+ -8':alias for command dword 14'
+ --cdw15=':value for command dword 15'
+ -9':alias for command dword 15'
+ --input-file=':defaults to stdin; input for write (send direction)'
+ -i':alias for --input-file'
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ --show-command':simply print command instead of sending it to <device>'
+ -s':alias for --show-command'
+ --dry-run':alias for --show-command'
+ -d':alias for --show-command'
+ --read':set dataflow direction to receive'
+ -r':alias for --read'
+ --write':set dataflow direction to send'
+ -w':alias for --write'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme admin-passthru options" _admin
+ ;;
+ (io-passthru)
+ local _io
+ _io=(
+ /dev/nvme':supply a device to use (required)'
+ --opcode=':hexadecimal opcode to send (required)'
+ -O':alias of --opcode'
+ --flags=':command flags'
+ -f':alias of --flags'
+ --rsvd=':value for reserved field'
+ -R':alias of --rsvd'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --metadata-len=':length for metadata buffer'
+ -m':alias of --metadata-len'
+ --timeout=':value for timeout'
+ -t':alias of --timeout'
+ --cdw2=':value for command dword 2'
+ -2':alias for --cdw2'
+ --cdw3=':value for command dword 3'
+ -3':alias for --cdw3'
+ --cdw10=':value for command dword 10'
+ -4':alias for --cdw10'
+ --cdw11=':value for command dword 11'
+ -5':alias for --cdw11'
+ --cdw12=':value for command dword 12'
+ -6':alias for --cdw12'
+ --cdw13=':value for command dword 13'
+ -7':alias for --cdw13'
+ --cdw14=':value for command dword 14'
+ -8':alias for command dword 14'
+ --cdw15=':value for command dword 15'
+ -9':alias for command dword 15'
+ --input-file=':defaults to stdin; input for write (send direction)'
+ -i':alias for --input-file'
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ --show-command':simply print command instead of sending it to <device>'
+ -s':alias for --show-command'
+ --dry-run':alias for --show-command'
+ -d':alias for --show-command'
+ --read':set dataflow direction to receive'
+ -r':alias for --read'
+ --write':set dataflow direction to send'
+ -w':alias for --write'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme io-passthru options" _io
+ ;;
+ (security-send)
+ local _ssend
+ _ssend=(
+ /dev/nvme':supply a device to use (required)'
+ --file=':payload'
+ -f':alias for --file'
+ --secp=':security protocol as defined in SPC-4'
+ -p':alias for --secp'
+ --spsp=':send security-protocol-specific data as defined in SPC-4'
+ -s':alias for --spsp'
+ --tl=':transfer length as defined in SPC-4'
+ -t':alias for --tl'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme security-send options" _ssend
+ ;;
+ (security-recv)
+ local _srecv
+ _srecv=(
+ /dev/nvme':supply a device to use (required)'
+ --secp=':security protocol as defined in SPC-4'
+ -p':alias for --secp'
+ --spsp=':send security-protocol-specific data as defined in SPC-4'
+ -s':alias for --spsp'
+ --size=':size of buffer (prints to stdout on successful recv)'
+ -x':alias for --size'
+ --al=':allocation length as defined in SPC-4'
+ -a':alias for --al'
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme security-recv options" _srecv
+ ;;
+ (get-lba-status)
+ local _get_lba_status
+ _get_lba_status=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':show infos for namespace <nsid>'
+ -n':alias of --namespace-id'
+ --start-lba=':Starting LBA(SLBA) in 64-bit address of the first logical block'
+ -s':alias for --start-lba'
+ --max-dw=':Maximum Number of Dwords(MNDW) specifies maximum number of dwords to return'
+ -m':alias for --max-dw'
+ --action=':Action Type(ATYPE) specifies the mechanism'
+ -a':alias for --action'
+ --range-len=':Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA'
+ -l':alias for --range-len'
+ --timeout':value for timeout'
+ -t':alias for --timeout'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme get-lba-status options" _get_lba_status
+ ;;
+ (resv-acquire)
+ local _acq
+ _acq=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':<nsid> of namespace to try to reserve (required)'
+ -n':alias for --namespace-id'
+ --prkey=':pre-empt reservation key'
+ -p':alias for --prkey'
+ --rtype=':hexadecimal reservation type'
+ -t':alias for --rtype'
+ --racqa=':reservation acquire action'
+ -a':alias for --racqa'
+ --iekey=':ignore existing reservation key'
+ -i':alias for --iekey'
+ --crkey':current reservation key'
+ -c':alias for --crkey'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-acquire options" _acq
+ ;;
+ (resv-release)
+ local _rel
+ _rel=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':nsid'
+ -n':alias of --namespace-id'
+ --rtype=':hexadecimal reservation type'
+ -t':alias of --rtype'
+ --rrela=':reservation release action'
+ -a':alias of --rrela'
+ --iekey':ignore existing reservation key'
+ -i':alias of --iekey'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-release options" _rel
+ ;;
+ (resv-report)
+ local _rep
+ _rep=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':nsid'
+ -n':alias of --namespace-id'
+ --numd=':number of dwords of reservation status to xfer'
+ -d':alias of --numd'
+ --eds':request extended data structure'
+ -e':alias of --eds'
+ --raw-binary':dump output in binary format'
+ -b':alias of --raw-binary'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-report options" _rep
+ ;;
+ (resv-register)
+ local _reg
+ _reg=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':nsid'
+ -n':alias of --namespace-id'
+ --crkey=':current reservation key'
+ -c'alias of --crkey'
+ --nrkey=':new reservation key'
+ -k':alias of --nrkey'
+ --cptpl=':change persistence through power loss setting'
+ -p':alias for --cptpl'
+ --rrega=':reservation registration action to perform'
+ -r':alias for --rrega'
+ --iekey':ignore existing reservation key'
+ -i':alias for --iekey'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-register options" _reg
+ ;;
+ (dsm)
+ local _dsm
+ _dsm=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --ctx-attrs=':Comma separated list of the context attributes in each range'
+ -a':alias of --ctx-attrs'
+ --blocks':Comma separated list of the number of blocks in each range'
+ -b':alias of --blocks'
+ --slbs':Comma separated list of the starting block in each range'
+ -s':alias of --slbs'
+ --ad':Attribute Deallocate'
+ -d':alias of --ad'
+ --idw':Attribute Integral Dataset for Write'
+ -w':alias of --idw'
+ --idr':Attribute Integral Dataset for Read'
+ -r':alias of --idr'
+ --cdw11=':value for command dword 11'
+ -c':alias for --cdw11'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme dsm options" _dsm
+ ;;
+ (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=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':nsid'
+ -n':alias of --namespace-id'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme flush options" _flush
+ ;;
+ (compare)
+ local _comp
+ _comp=(
+ /dev/nvme':supply a device to use (required)'
+ --start-block=':begin compare at this 64-bit LBA on device'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to compare to local data'
+ -c':alias of --block-count'
+ --metadata-size=':number of bytes of metadata to compare'
+ -y':alias of --metadata-size'
+ --data-size=':size of local data buffer in bytes'
+ -z':alias of --data-size'
+ --data=':local data file to compare to blocks on device'
+ -d':alias of --data'
+ --prinfo=':protection information action and check field'
+ -p':alias of --prinfo'
+ --app-tag-mask=':application tag mask (for end to end PI)'
+ -m':alias of --app-tag-mask'
+ --app-tag=':application tag (for end to end PI)'
+ -a':alias of --app-tag'
+ --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'
+ --show-command':show command instead of sending to device'
+ -V':alias of --show-command'
+ --dry-run':show command instead of sending to device'
+ -w':alias of --show-command'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme compare options" _comp
+ ;;
+ (read)
+ local _read
+ _read=(
+ /dev/nvme':supply a device to use (required)'
+ --start-block=':64-bit address of the first logical block to be read'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to read'
+ -c':alias of --block-count'
+ --data-size=':size of data to be read'
+ -z':alias of --data-size'
+ --metadata-size=':size of metadata to be read'
+ -y':alias of --metadata-size'
+ --ref-tag=':reference tag (for end to end PI)'
+ -r':alias of --ref-tag'
+ --data=':file into which data should be read (defaults to stdout)'
+ -d':alias of --data'
+ --prinfo=':protection information and check field'
+ -p':alias of --prinfo'
+ --app-tag-mask=':application tag mask (for end to end PI)'
+ -m':alias of --app-tag-mask'
+ --app-tag=':application tag (for end to end PI)'
+ -a':alias of --app-tag'
+ --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'
+ --latency':latency statistics will be output following read'
+ -t':alias of --latency'
+ --force-unit-access':data read shall be returned from nonvolatile media before command completion is indicated'
+ -f':alias of --force-unit-access'
+ --show-command':show command instead of sending to device'
+ -V':alias of --show-command'
+ --dry-run':show command instead of sending to device'
+ -w':alias of --show-command'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme read options" _read
+ ;;
+ (write)
+ local _wr
+ _wr=(
+ /dev/nvme':supply a device to use (required)'
+ --start-block=':64-bit address of the first logical block to be written'
+ -s':alias of --start-block'
+ --block-count=':number of logical blocks on device to write'
+ -c':alias of --block-count'
+ --data-size=':size of data to be written'
+ -z':alias of --data-size'
+ --metadata-size=':size of metadata to be written'
+ -y':alias of --metadata-size'
+ --ref-tag=':reference tag (for end to end PI)'
+ -r':alias of --ref-tag'
+ --data=':file from which data should be written to device (defaults to stdin)'
+ -d':alias of --data'
+ --prinfo=':protection information and check field'
+ -p':alias of --prinfo'
+ --app-tag-mask=':application tag mask (for end to end PI)'
+ -m':alias of --app-tag-mask'
+ --app-tag=':application tag (for end to end PI)'
+ -a':alias of --app-tag'
+ --limited-retry':if included, controller should try less hard to send data to media (if not included, all available data-recovery means used)'
+ -l':alias of --limited-retry'
+ --latency':latency statistics will be output following write'
+ -t':alias of --latency'
+ --force-unit-access':data shall be written to nonvolatile media before command completion is indicated'
+ -f':alias of --force-unit-access'
+ --show-command':show command instead of sending to device'
+ -V':alias of --show-command'
+ --dry-run':show command instead of sending to device'
+ -w':alias of --show-command'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme write options" _wr
+ ;;
+ (show-regs)
+ local _shor
+ _shor=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme show-regs options" _shor
+ ;;
+ (fid-support-effects-log)
+ local _fidsupporteffectslog
+ _fidsupporteffectslog=(
+ /dev/nvme':supply a device to use (required)'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme fid-support-effects-log options" _fidsupporteffectslog
+ ;;
+ (discover)
+ local _discover
+ _discover=(
+ --device=':use existing discovery controller device'
+ -d':alias for --device'
+ --transport=':transport type'
+ -t':alias for --transport'
+ --nqn=':subsystem nqn'
+ -n':alias for --nqn'
+ --traddr=':transport address'
+ -a':alias for --traddr'
+ --trsvcid=':transport service id (e.g. IP port)'
+ -s':alias for --trsvcid'
+ --host-traddr=':host traddr (e.g. FC WWN's)'
+ -w':alias for --host-traddr'
+ --host-iface=':host interface (for tcp transport)'
+ -f':alias for --host-iface'
+ --hostnqn=':user-defined hostnqn'
+ -q':alias for --hostnqn'
+ --hostid=':user-defined hostid (if default not used)'
+ -I':alias for --hostid'
+ --dhchap-secret=':user-defined dhchap key (if default not used)'
+ -S':alias for --dhchap-secret'
+ --nr-io-queues=':number of io queues to use (default is core count)'
+ -i':alias for --nr-io-queues'
+ --nr-write-queues=':number of write queues to use (default 0)'
+ -W':alias for --nr-write-queues'
+ --nr-poll-queues=':number of poll queues to use (default 0)'
+ -P':alias for --nr-poll-queues'
+ --queue-size=':number of io queue elements to use (default 128)'
+ -Q':alias for --queue-size'
+ --keep-alive-tmo=':keep alive timeout period in seconds'
+ -k':alias for --keep-alive-tmo'
+ --reconnect-delay=':reconnect timeout period in seconds'
+ -c':alias for --reconnect-delay'
+ --ctrl-loss-tmo=':controller loss timeout period in seconds'
+ -l':alias for --ctrl-loss-tmo'
+ --tos=':type of service'
+ -T':alias for --tos'
+ --keyring=':Keyring for TLS key lookup'
+ --tls_key=':TLS key to use'
+ --duplicate-connect':allow duplicate connections between same transport host and subsystem port'
+ -D':alias for --duplicate-connect'
+ --disable-sqflow':disable controller sq flow control (default false)'
+ -d':alias for --disable-sqflow'
+ --hdr-digest':enable transport protocol header digest (TCP transport)'
+ -g':alias for --hdr-digest'
+ --data-digest':enable transport protocol data digest (TCP transport)'
+ -G':alias for --data-digest'
+ --tls':enable TLS'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --raw':save raw output to file'
+ -r':alias of --raw'
+ --persistent':'
+ -p':alias for --'
+ --quiet':'
+ -S':alias for --'
+ --config=':Use specified JSON configuration file or none to disable'
+ -J':alias for --config'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ --dump-config':Dump configuration file to stdout'
+ -O':alias for --dump-config'
+ --force':Force persistent discovery controller creation'
+ --nbft':Only look at NBFT tables'
+ --no-nbft':Do not look at NBFT tables'
+ --nbft-patch=':user-defined path for NBFT tables'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme discover options" _discover
+ ;;
+ (connect-all)
+ local _connect_all
+ _connect_all=(
+ --device=':use existing discovery controller device'
+ -d':alias for --device'
+ --transport=':transport type'
+ -t':alias for --transport'
+ --nqn=':subsystem nqn'
+ -n':alias for --nqn'
+ --traddr=':transport address'
+ -a':alias for --traddr'
+ --trsvcid=':transport service id (e.g. IP port)'
+ -s':alias for --trsvcid'
+ --host-traddr=':host traddr (e.g. FC WWN's)'
+ -w':alias for --host-traddr'
+ --host-iface=':host interface (for tcp transport)'
+ -f':alias for --host-iface'
+ --hostnqn=':user-defined hostnqn'
+ -q':alias for --hostnqn'
+ --hostid=':user-defined hostid (if default not used)'
+ -I':alias for --hostid'
+ --dhchap-secret=':user-defined dhchap key (if default not used)'
+ -S':alias for --dhchap-secret'
+ --nr-io-queues=':number of io queues to use (default is core count)'
+ -i':alias for --nr-io-queues'
+ --nr-write-queues=':number of write queues to use (default 0)'
+ -W':alias for --nr-write-queues'
+ --nr-poll-queues=':number of poll queues to use (default 0)'
+ -P':alias for --nr-poll-queues'
+ --queue-size=':number of io queue elements to use (default 128)'
+ -Q':alias for --queue-size'
+ --keep-alive-tmo=':keep alive timeout period in seconds'
+ -k':alias for --keep-alive-tmo'
+ --reconnect-delay=':reconnect timeout period in seconds'
+ -c':alias for --reconnect-delay'
+ --ctrl-loss-tmo=':controller loss timeout period in seconds'
+ -l':alias for --ctrl-loss-tmo'
+ --tos=':type of service'
+ -T':alias for --tos'
+ --keyring=':Keyring for TLS key lookup'
+ --tls_key=':TLS key to use'
+ --duplicate-connect':allow duplicate connections between same transport host and subsystem port'
+ -D':alias for --duplicate-connect'
+ --disable-sqflow':disable controller sq flow control (default false)'
+ -d':alias for --disable-sqflow'
+ --hdr-digest':enable transport protocol header digest (TCP transport)'
+ -g':alias for --hdr-digest'
+ --data-digest':enable transport protocol data digest (TCP transport)'
+ -G':alias for --data-digest'
+ --tls':enable TLS'
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --raw':save raw output to file'
+ -r':alias of --raw'
+ --persistent':'
+ -p':alias for --'
+ --quiet':'
+ -S':alias for --'
+ --config=':Use specified JSON configuration file or none to disable'
+ -J':alias for --config'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ --dump-config':Dump configuration file to stdout'
+ -O':alias for --dump-config'
+ --force':Force persistent discovery controller creation'
+ --nbft':Only look at NBFT tables'
+ --no-nbft':Do not look at NBFT tables'
+ --nbft-patch=':user-defined path for NBFT tables'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme connect-all options" _connect_all
+ ;;
+ (connect)
+ local _connect
+ _connect=(
+ --transport=':transport type'
+ -t':alias for --transport'
+ --nqn=':subsystem nqn'
+ -n':alias for --nqn'
+ --traddr=':transport address'
+ -a':alias for --traddr'
+ --trsvcid=':transport service id (e.g. IP port)'
+ -s':alias for --trsvcid'
+ --host-traddr=':host transport address'
+ -w':alias for --host-traddr'
+ --host-iface=':host interface (for tcp transport)'
+ -f':alias for --host-iface'
+ --hostnqn=':user-defined hostnqn'
+ -q':alias for --hostnqn'
+ --hostid=':user-defined hostid (if default not used)'
+ -I':alias for --hostid'
+ --dhchap-secret=':user-defined dhchap key (if default not used)'
+ -S':alias for --dhchap-secret'
+ --nr-io-queues=':number of io queues to use (default is core count)'
+ -i':alias for --nr-io-queues'
+ --nr-write-queues=':number of write queues to use (default 0)'
+ -W':alias for --nr-write-queues'
+ --nr-poll-queues=':number of poll queues to use (default 0)'
+ -P':alias for --nr-poll-queues'
+ --queue-size=':number of io queue elements to use (default 128)'
+ -Q':alias for --queue-size'
+ --keep-alive-tmo=':keep alive timeout period in seconds'
+ -k':alias for --keep-alive-tmo'
+ --reconnect-delay=':reconnect timeout period in seconds'
+ -c':alias for --reconnect-delay'
+ --ctrl-loss-tmo=':controller loss timeout period in seconds'
+ -l':alias for --ctrl-loss-tmo'
+ --tos=':type of service'
+ -T':alias for --tos'
+ --keyring=':Keyring for TLS key lookup'
+ --tls_key=':TLS key to use'
+ --duplicate-connect':allow duplicate connections between same transport host and subsystem port'
+ -D':alias for --duplicate-connect'
+ --disable-sqflow':disable controller sq flow control (default false)'
+ -d':alias for --disable-sqflow'
+ --hdr-digest':enable transport protocol header digest (TCP transport)'
+ -g':alias for --hdr-digest'
+ --data-digest':enable transport protocol data digest (TCP transport)'
+ -G':alias for --data-digest'
+ --tls':enable TLS'
+ --dhchap-ctrl-secret=':user-defined dhchap controller key (for bi-directional authentication)'
+ -C':alias for --dhchap-ctrl-secret'
+ --config=':Use specified JSON configuration file or none to disable'
+ -J':alias for --config'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ --dump-config':Dump configuration file to stdout'
+ -O':alias for --dump-config'
+ --output-format=':Output format: normal|json'
+ -o':alias for --output-format'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme connect options" _connect
+ ;;
+ (dim)
+ local _dim
+ _dim=(
+ --nqn=':Comma-separated list of DC nqn'
+ -n':alias for --nqn'
+ --device=':Comma-separated list of DC nvme device handle'
+ -d':alias for --device'
+ --task=':The task to perform: register|deregister'
+ -t':alias for --task'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme dim options" _dim
+ ;;
+ (disconnect)
+ local _disconnect
+ _disconnect=(
+ --nqn=':subsystem nqn'
+ -n':alias for --nqn'
+ --device=':nvme device handle'
+ -d':alias for --device'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme disconnect options" _disconnect
+ ;;
+ (disconnect-all)
+ local _disconnect_all
+ _disconnect_all=(
+ --transport=':transport type'
+ -r':alias for --transport'
+ --verbose':Increase logging verbosity'
+ -v':alias for --verbose'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme disconnect-all options" _disconnect_all
+ ;;
+ (gen-hostnqn)
+ local _gen_hostnqn
+ _gen_hostnqn=(
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme gen-hostnqn options" _gen_hostnqn
+ ;;
+ (show-hostnqn)
+ local _show_hostnqn
+ _show_hostnqn=(
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme show-hostnqn options" _show_hostnqn
+ ;;
+ (dir-receive)
+ local _dir_receive
+ _dir_receive=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ --dir-type=':directive type'
+ -D':alias of --dir-type'
+ --dir-spec=':directive specific'
+ -S':alias of --dir-spec'
+ --dir-oper=':directive operation'
+ -O':alias of --dir-oper'
+ --req-resource=':namespace stream requested'
+ -r':alias of --req-resource'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme dir-receive options" _dir_receive
+ ;;
+ (dir-send)
+ local _dir_send
+ _dir_send=(
+ /dev/nvme':supply a device to use (required)'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --dir-type=':directive type'
+ -D':alias of --dir-type'
+ --target-dir=':target directive type to be enabled/disabled'
+ -T':alias of --target-dir'
+ --dir-spec=':directive specific'
+ -S':alias of --dir-spec'
+ --dir-oper=':directive operation'
+ -O':alias of --dir-oper'
+ --endir=':directive enable'
+ -e':alias of --endir'
+ --human-readable':show infos in readable format'
+ -H':alias of --human-readable'
+ --raw-binary':dump output in binary format'
+ -b':alias for --raw-binary'
+ --input-file=':write/send file (default stdin)'
+ -i':alias of --input-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme dir-send options" _dir_send
+ ;;
+ (virt-mgmt)
+ local _virt_mgmt
+ _virt_mgmt=(
+ /dev/nvme':supply a device to use (required)'
+ --cntlid=':Controller Identifier(CNTLID)'
+ -c':alias of --cntlid'
+ --rt=':Resource Type(RT): 0|1'
+ -r':alias of --rt'
+ --act=':Action(ACT): 1|7|8|9'
+ -a':alias of --act'
+ --nr=':Number of Controller Resources(NR)'
+ -n':alias of --nr'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme virt-mgmt options" _virt_mgmt
+ ;;
+ (rpmb)
+ local _rpmb
+ _rpmb=(
+ /dev/nvme':supply a device to use (required)'
+ --cmd=':RPMB action: info|program-key|read-counter|write-data|read-data|write-config|read-config'
+ -c':alias of --cmd'
+ --msgfile=':data file for read/write-data, read/write-config options'
+ -f':alias of --msgfile'
+ --keyfile=':key file that has authentication key to be used'
+ -g':alias of --keyfile'
+ --key=':key to be used for authentication'
+ -k':alias of --key'
+ --msg=':data to be written on write-data or write-config commands'
+ -d':alias of --msg'
+ --address=':Sector offset to read from or write to for an RPMB target, default 0'
+ -o':alias of --address'
+ --blocks=':Number of 512 blocks to read or write'
+ -b':alias of --blocks'
+ --target=':RPMB target - numerical value of 0 to 6, default 0'
+ -t':alias of --target'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme rpmb options" _rpmb
+ ;;
+ (show-topology)
+ local _showtopology
+ _showtopology=(
+ --output-format=':Output format: normal|json|binary'
+ -o':alias for --output-format'
+ --verbose':show infos verbosely'
+ -v':alias of --verbose'
+ --ranking=':Ranking order: namespace|ctrl'
+ -r':alias for --ranking'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme show-topology options" _showtopology
+ ;;
+ (nvme-mi-recv)
+ local _nvme_mi_recv
+ _nvme_mi_recv=(
+ --opcode=':NVMe-MI opcode to send'
+ -O':alias of --opcode'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --nmimt':value for NVMe-MI message type'
+ -m':alias of --nmimt'
+ --nmd0':value for NVMe management request dword 0'
+ -0':alias of --nmd0'
+ --nmd1':value for NVMe management request dword 1'
+ -1':alias of --nmd1'
+ --input-file=':defaults to stdin; input for write (send direction)'
+ -i':alias for --input-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme nvme-mi-recv options" _nvme_mi_recv
+ ;;
+ (nvme-mi-send)
+ local _nvme_mi_send
+ _nvme_mi_send=(
+ --opcode=':NVMe-MI opcode to send'
+ -O':alias of --opcode'
+ --namespace-id=':value for nsid'
+ -n':alias of --namespace-id'
+ --data-len=':length for data buffer'
+ -l':alias of --data-len'
+ --nmimt':value for NVMe-MI message type'
+ -m':alias of --nmimt'
+ --nmd0':value for NVMe management request dword 0'
+ -0':alias of --nmd0'
+ --nmd1':value for NVMe management request dword 1'
+ -1':alias of --nmd1'
+ --input-file=':defaults to stdin; input for write (send direction)'
+ -i':alias for --input-file'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme nvme-mi-send options" _nvme_mi_send
+ ;;
+ (version)
+ local _version
+ _version=(
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme version options" _version
+ ;;
+ (ocp)
+ local _ocp
+ _ocp=(
+ smart-add-log':Retrieve extended SMART Information'
+ latency-monitor-log':Get Latency Monitor Log Page'
+ set-latency-monitor-feature':Set Latency Monitor feature'
+ internal-log':Retrieve and save internal device telemetry log'
+ clear-fw-activate-history':Clear firmware update history log"'
+ eol-plp-failure-mode':Define EOL or PLP circuitry failure mode'
+ clear-pcie-correctable-error-counters':Clear PCIe correctable error counters'
+ vs-fw-activate-history':Get firmware activation history log'
+ device-capability-log':Get Device capability log'
+ set-dssd-power-state-feature':Set DSSD Power State'
+ telemetry-string-log':Retrieve Telemetry string Log Page'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme ocp options" _ocp
+ ;;
+ (solidigm)
+ local _solidigm
+ _solidigm=(
+ id-ctrl':Send NVMe Identify Controller'
+ smart-log-add':Retrieve Solidigm SMART Log'
+ vs-smart-add-log':Get SMART / health extended log (redirects to ocp plug-in)'
+ vs-internal-log':Retrieve Debug log binaries'
+ garbage-collect-log':Retrieve Garbage Collection Log'
+ market-log':Retrieve Market Log'
+ latency-tracking-log':Enable/Retrieve Latency tracking Log'
+ parse-telemetry-log':Parse Telemetry Log binary'
+ clear-pcie-correctable-errors':Clear PCIe Correctable Error Counters (redirects to ocp plug-in)'
+ clear-fw-activate-history':Clear firmware update history log (redirects to ocp plug-in)'
+ vs-fw-activate-history':Get firmware activation history log (redirects to ocp plug-in)'
+ log-page-directory':Retrieve log page directory'
+ temp-stats':Retrieve Temperature Statistics log'
+ vs-drive-info':Retrieve drive information'
+ cloud-SSDplugin-version':Prints plug-in OCP version'
+ version':Shows the program version'
+ help':Display this help'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme solidigm options" _solidigm
+ ;;
+ (help)
+ local _h
+ _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 copy show-regs persistent-event-log
+ pred-lat-event-agg-log nvm-id-ctrl endurance-event-agg-log lba-status-log
+ resv-notif-log capacity-mgmt id-domain boot-part-log fid-support-effects-log
+ supported-log-pages lockdown media-unit-stat-log id-ns-lba-format nvm-id-ns
+ nvm-id-ns-lba-format supported-cap-config-log show-topology
+ list list-subsys id-ns-granularity primary-ctrl-caps list-secondary ns-descs
+ id-nvmset id-uuid list-endgrp telemetry-log changed-ns-list-log ana-log
+ effects-log endurance-log device-self-test self-test-log set-property
+ get-property write-zeroes write-uncor verify sanitize sanitize-log reset
+ subsystem-reset ns-rescan get-lba-status dsm discover connect-all connect
+ dim disconnect disconnect-all gen-hostnqn show-hostnqn dir-receive dir-send
+ virt-mgmt rpmb version ocp solidigm
+ )
+ _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
+ ;;
+ (*)
+ _files
+ ;;
+ esac
+ return
+ fi
+
+ _files
+}
diff --git a/completions/bash-nvme-completion.sh b/completions/bash-nvme-completion.sh
new file mode 100644
index 0000000..d862aab
--- /dev/null
+++ b/completions/bash-nvme-completion.sh
@@ -0,0 +1,1604 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# bash tab completion for the nvme command line utility
+# (unfortunately, bash won't let me add descriptions to cmds)
+# Kelly Kaoudis kelly.n.kaoudis at intel.com, Aug. 2015
+
+nvme_list_opts () {
+ local opts=""
+ local compargs=""
+ local vals=""
+ local opt=""
+ local val=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 2 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+ vals+=" "
+
+ if [[ $cur != -* ]] && [[ $cur != "" ]] && [[ $prev == "=" ]] && [[ ${words[$cword-2]} == --* ]]; then
+ opt+="${words[$cword-2]}"
+ val+="$cur"
+ elif [[ $cur == "" ]] && [[ $prev != "=" ]] || [[ $cur == "=" ]] && [[ $prev == --* ]]; then
+ opt+="$prev"
+ elif [[ $cur != "=" ]] && [[ $prev != --* ]] && [[ $prev != "=" ]]; then
+ opt+="$prev"
+ val+="$cur"
+ else
+ opt+="$cur"
+ fi
+
+ # Listed here in the same order as in nvme-builtin.h
+ case "$1" in
+ "list")
+ opts+=$NO_OPTS
+ ;;
+ "list-subsys")
+ opts=+=" --output-format= -o --verbose -v"
+ ;;
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -V --output-format= -o"
+ ;;
+ "id-ns")
+ opts+=" --namespace-id= -n --raw-binary -b \
+ --human-readable -H --vendor-specific -V \
+ --force -f --output-format= -o"
+ ;;
+ "id-ns-granularity")
+ opts+=" --output-format= -o"
+ ;;
+ "id-ns-lba-format")
+ opts+=" --lba-format-index= -i --uuid-index= -U \
+ --verbose -v --output-format= -o"
+ ;;
+ "list-ns")
+ opts+=" --namespace-id= -n --al -a --csi= -y \
+ --outputformat= -o"
+ ;;
+ "list-ctrl")
+ opts+=" --namespace-id= -n --cntid= -c \
+ --output-format= -o"
+ ;;
+ "cmdset-ind-id-ns")
+ opts+=" --namespace-id= -n --raw-binary -b \
+ --human-readable -H --output-format= -o"
+ ;;
+ "nvm-id-ctrl")
+ opts+=" --output-format= -o"
+ ;;
+ "nvm-id-ns")
+ opts+=" --namespace-id= -n --uuid-index= -U\
+ --verbose -v --output-format= -o"
+ ;;
+ "nvm-id-ns-lba-format")
+ opts+=" --lba-format-index= -i --uuid-index= -U \
+ --verbose -v --output-format= -o"
+ ;;
+ "primary-ctrl-caps")
+ opts+=" --output-format= -o --human-readable -H"
+ ;;
+ "list-secondary")
+ opts+=" --cntid= -c --namespace-id= n --num-entries -e \
+ --output-format= -o"
+ ;;
+ "ns-descs")
+ opts+=" --namespace-id= -n --output-format -o --raw-binary -b"
+ ;;
+ "id-nvmset")
+ opts+=" --nvmeset-id= -i --output-format= -o"
+ ;;
+ "id-uuid")
+ opts+=" --output-format= -o --raw-binary -b --human-readable -H"
+ ;;
+ "list-endgrp")
+ opts+=" --endgrp-id= -i --output-format= -o"
+ ;;
+ "id-iocs")
+ opts+=" --controller-id= -c"
+ ;;
+ "id-domain")
+ opts+=" --domain-id= -c --output-format= -o"
+ ;;
+ "create-ns")
+ opts+=" --nsze= -s --ncap= -c --flbas= -f \
+ --dps= -d --nmic= -m --anagrp-id= -a --nvmset-id= -i \
+ --block-size= -b --timeout= -t --csi= -y --lbstm= -l \
+ --nphndls= -n --nsze-si= -S --ncap-si= -C --azr -z --rar= -r \
+ --ror= -O --rnumzrwa= -u --phndls= -p --endg-id= -e"
+ ;;
+ "delete-ns")
+ opts+=" -namespace-id= -n --timeout= -t"
+ ;;
+ "attach-ns")
+ opts+=" --namespace-id= -n --controllers= -c"
+ ;;
+ "detach-ns")
+ opts+=" --namespace-id= -n --controllers= -c"
+ ;;
+ "get-ns-id")
+ opts+=$NO_OPTS
+ ;;
+ "get-log")
+ opts+=" --log-id= -i --log-len= -l --namespace-id= -n \
+ --aen= -a --lpo= -O --lsp= -s --lsi= -S \
+ --rae -r --uuid-index= -U --csi= -y --ot -O \
+ --raw-binary -b"
+ ;;
+ "supported-log-pages")
+ opts+=" --output-format= -o --human-readable -H"
+ ;;
+ "telemetry-log")
+ opts+=" --output-file= -O --host-generate= -g \
+ --controller-init -c --data-area= -d"
+ ;;
+ "fw-log")
+ opts+=" --raw-binary -b --output-format= -o"
+ ;;
+ "changed-ns-list-log")
+ opts+=" --output-format= -o --raw-binary -b"
+ ;;
+ "smart-log")
+ opts+=" --namespace-id= -n --raw-binary -b \
+ --output-format= -o"
+ ;;
+ "ana-log")
+ opts+=" --output-format -o"
+ ;;
+ "fid-support-effects-log")
+ opts+=" --output-format -o"
+ ;;
+ "error-log")
+ opts+=" --raw-binary -b --log-entries= -e \
+ --output-format= -o"
+ ;;
+ "effects-log")
+ opts+=" --output-format= -o --human-readable -H \
+ --raw-binary -b"
+ ;;
+ "endurance-log")
+ opts+=" --output-format= -o --group-id -g"
+ ;;
+ "predictable-lat-log")
+ opts+=" --nvmset-id= -i --raw-binary -b \
+ --output-format= -o"
+ ;;
+ "pred-lat-event-agg-log")
+ opts+=" --log-entries= -e --rae -r \
+ --raw-binary -b --output-format= -o"
+ ;;
+ "persistent-event-log")
+ opts+=" --action= -a --log-len= -l \
+ --raw-binary -b --output-format= -o"
+ ;;
+ "endurance-event-agg-log")
+ opts+=" --log-entries= -e --rae -r \
+ --raw-binary -b --output-format= -o"
+ ;;
+ "lba-status-log")
+ opts+=" --rae -r --output-format= -o"
+ ;;
+ "resv-notif-log")
+ opts+=" --output-format= -o"
+ ;;
+ "boot-part-log")
+ opts+=" --lsp -s --output-file= -f \
+ --output-format= -o"
+ ;;
+ "media-unit-stat-log")
+ opts+=" --dom-id= -d --output-format= -o \
+ --raw-binary -b"
+ ;;
+ "supported-cap-config-log")
+ opts+=" --dom-id= -d --output-format= -o \
+ --raw-binary -b"
+ ;;
+ "get-feature")
+ opts+=" --namespace-id= -n --feature-id= -f --sel= -s \
+ --data-len= -l --cdw11= --c -uuid-index= -U --raw-binary -b \
+ --human-readable -H"
+ ;;
+ "device-self-test")
+ opts+=" --namespace-id= -n --self-test-code= -s"
+ ;;
+ "self-test-log")
+ opts+=" --dst-entries= -e --output-format= -o \
+ --verbose -v"
+ ;;
+ "set-feature")
+ opts+=" --namespace-id= -n --feature-id= -f --value= -v \
+ --data-len= -l -data= -d --value= -v --save -s --uuid-index= -U \
+ --cdw12= -c"
+ ;;
+ "set-property")
+ opts+=" --offset= -O --value= -V"
+ ;;
+ "get-property")
+ opts=+" --offset= -O --human-readable -H"
+ ;;
+ "format")
+ opts+=" --namespace-id= -n --timeout= -t --lbaf= -l \
+ --ses= -s --pil= -p -pi= -i --ms= -m --reset -r"
+ ;;
+ "fw-commit")
+ opts+=" --slot= -s --action= -a --bpid= -b"
+ ;;
+ "fw-download")
+ opts+=" --fw= -f --xfer= -x --offset= -O"
+ ;;
+ "capacity-mgmt")
+ opts+=" --operation= -O --element-id= -i --cap-lower= -l \
+ --cap-upper= -u"
+ ;;
+ "lockdown")
+ opts+=" --ofi= -O --ifc= -f --prhbt= -p --scp= -s --uuid -U"
+ ;;
+ "admin-passthru")
+ opts+=" --opcode= -O --flags= -f --prefil= -p --rsvd= -R \
+ --namespace-id= -n --data-len= -l --metadata-len= -m \
+ --timeout= -t --cdw2= -2 --cdw3= -3 --cdw10= -4 \
+ --cdw11= -5 --cdw12= -6 --cdw13= -7 --cdw14= -8 \
+ --cdw15= -9 --input-file= -i --raw-binary -b \
+ --show-command -s --dry-run -d --read -r --write -w \
+ --latency -T"
+ ;;
+ "io-passthru")
+ opts+=" --opcode= -O --flags= -f --prefill= -p --rsvd= -R \
+ --namespace-id= -n --data-len= -l --metadata-len= -m \
+ --timeout= -t --cdw2= -2 --cdw3= -3 --cdw10= -4 \
+ --cdw11= -5 --cdw12= -6 --cdw13= -7 --cdw14= -8 \
+ --cdw15= -9 --input-file= -i --raw-binary -b \
+ --show-command -s --dry-run -d --read -r --write -w \
+ --latency -T"
+ ;;
+ "security-send")
+ opts+=" --namespace-id= -n --file= -f --nssf= -N --secp= -p \
+ --spsp= -s --tl= -t"
+ ;;
+ "security-recv")
+ opts+=" --namespace-id= -n --size= -x --secp= -p --spsp= -s \
+ --al= -t --raw-binary -b"
+ ;;
+ "get-lba-status")
+ opts+=" --namespace-id= -n --start-lba= -s --max-dw= -m \
+ --action= -a --range-len= -l --timeout= -t \
+ --output-format= -o"
+ ;;
+ "resv-acquire")
+ opts+=" --namespace-id= -n --crkey= -c --prkey= -p \
+ --rtype= -t --racqa= -a --iekey= -i"
+ ;;
+ "resv-register")
+ opts+=" --namespace-id= -n --crkey= -c --nrkey= -k \
+ --rrega= -r --cptpl= -p --iekey -i"
+ ;;
+ "resv-release")
+ opts+=" --namespace-id= -n --crkey -c --rtype= -t \
+ --rrela= -a --iekey -i"
+ ;;
+ "resv-report")
+ opts+=" --namespace-id= -n --numd= -d --eds -e \
+ --raw-binary= -b --output-format= -o"
+ ;;
+ "dsm")
+ opts+=" --namespace-id= -n --ctx-attrs= -a --blocks= -b\
+ --slbs= -s --ad -d --idw -w --idr -r --cdw11= -c"
+ ;;
+ "copy")
+ opts+=" --namespace-id= -n --sdlba= -d --blocks= -b --slbs= -s \
+ --limited-retry -l --force-unit-access -f \
+ --prinfow= -p --prinfor= -P \
+ --ref-tag= -r --expected-ref-tag= -R \
+ --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"
+ ;;
+ "compare")
+ opts+=" --start-block= -s --block-count= -c --data-size= -z \
+ --metadata-size= -y --ref-tag= -r --data= -d \
+ --metadata= -M --prinfo= -p --app-tag-mask= -m \
+ --app-tag= -a --limited-retry -l \
+ --force-unit-access -f --storage-tag-check -C \
+ --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \
+ --dry-run -w --latency -t"
+ ;;
+ "read")
+ opts+=" --start-block= -s --block-count= -c --data-size= -z \
+ --metadata-size= -y --ref-tag= -r --data= -d \
+ --metadata= -M --prinfo= -p --app-tag-mask= -m \
+ --app-tag= -a --limited-retry -l \
+ --force-unit-access -f --storage-tag-check -C \
+ --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \
+ --dry-run -w --latency -t"
+ ;;
+ "write")
+ opts+=" --start-block= -s --block-count= -c --data-size= -z \
+ --metadata-size= -y --ref-tag= -r --data= -d \
+ --metadata= -M --prinfo= -p --app-tag-mask= -m \
+ --app-tag= -a --limited-retry -l \
+ --force-unit-access -f --storage-tag-check -C \
+ --dir-type= -T --dir-spec= -S --dsm= -D --show-command -V \
+ --dry-run -w --latency -t"
+ ;;
+ "write-zeroes")
+ opts+=" --namespace-id= -n --start-block= -s \
+ --block-count= -c --deac -d --limited-retry -l \
+ --force-unit-access -f --prinfo= -p --ref-tag= -r \
+ --app-tag-mask= -m --app-tag= -a \
+ --storage-tag= -S --storage-tag-check -C \
+ --dir-type= -T --dir-spec= -S"
+ ;;
+ "write-uncor")
+ opts+=" --namespace-id= -n --start-block= -s \
+ --block-count= -c --dir-type= -T --dir-spec= -S"
+ ;;
+ "verify")
+ opts+=" --namespace-id= -n --start-block= -s \
+ --block-count= -c --limited-retry -l \
+ --force-unit-access -f --prinfo= -p --ref-tag= -r \
+ --app-tag= -a --app-tag-mask= -m \
+ --storage-tag= -S --storage-tag-check -C"
+ ;;
+ "sanitize")
+ opts+=" --no-dealloc -d --oipbp -i --owpass= -n \
+ --ause -u --sanact= -a --ovrpat= -p"
+ case $opt in
+ --sanact|-a)
+ vals+=" exit-failure start-block-erase start-overwrite start-crypto-erase"
+ ;;
+ esac
+ ;;
+ "sanitize-log")
+ opts+=" --rae -r --output-format= -o --human-readable -H \
+ --raw-binary -b"
+ ;;
+ "reset")
+ opts+=$NO_OPTS
+ ;;
+ "subsystem-reset")
+ opts+=$NO_OPTS
+ ;;
+ "ns-rescan")
+ opts+=$NO_OPTS
+ ;;
+ "show-regs")
+ opts+=" --output-format= -o --human-readable -H"
+ ;;
+ "discover")
+ opts+=" --transport= -t -traddr= -a -trsvcid= -s \
+ --host-traddr= -w --host-iface= -f \
+ --hostnqn= -q --hostid -I --raw= -r \
+ --raw= -r --device= -d --keep-alive-tmo= -k \
+ --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \
+ --tos= -T --hdr-digest= -g --data-digest -G \
+ --nr-io-queues= -i --nr-write-queues= -W \
+ --nr-poll-queues= -P --queue-size= -Q \
+ --persistent -p --quiet -S \
+ --output-format= -o"
+ ;;
+ "connect-all")
+ opts+=" --transport= -t -traddr= -a -trsvcid= -s \
+ --host-traddr= -w --host-iface= -f \
+ --hostnqn= -q --hostid -I --raw= -r \
+ --raw= -r --device= -d --keep-alive-tmo= -k \
+ --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \
+ --tos= -T --hdr-digest= -g --data-digest -G \
+ --nr-io-queues= -i --nr-write-queues= -W \
+ --nr-poll-queues= -P --queue-size= -Q \
+ --persistent -p --quiet -S \
+ --output-format= -o"
+ ;;
+ "connect")
+ opts+=" --transport= -t --nqn= -n --traddr= -a --trsvcid -s \
+ --hostnqn= -q --host-id= -I --nr-io-queues= -i \
+ --nr-poll-queues= -P --queue-size= -Q \
+ --keep-alive-tmo= -k --reconnect-delay= -r \
+ --ctrl-loss-tmo= -l --fast-io-fail-tmo= -f \
+ --tos= -T --duplicate-connect -D --disable-sqflow -d\
+ --hdr-digest -g --data-digest -G --output-format= -o"
+ ;;
+ "dim")
+ opts+=" --task -t --nqn -n --device -d"
+ ;;
+ "disconnect")
+ opts+=" --nqn -n --device -d"
+ ;;
+ "disconnect-all")
+ opts+=$NO_OPTS
+ ;;
+ "gen-hostnqn")
+ opts+=$NO_OPTS
+ ;;
+ "show-hostnqn")
+ opts+=$NO_OPTS
+ ;;
+ "dir-receive")
+ opts+=" --namespace-id= -n --data-len= -l --raw-binary -b \
+ --dir-type= -D --dir-spec= -S --dir-oper= -O \
+ --req-resource= -r --human-readable -H"
+ ;;
+ "dir-send")
+ opts+=" --namespace-id= -n --data-len= -l --dir-type= -D \
+ --target-dir= -T --dir-spec= -S --dir-oper= -O \
+ --endir= -e --human-readable -H --raw-binary -b"
+ ;;
+ "virt-mgmt")
+ opts+=" --cntlid= -c --rt= -r --act= -a --nr= -n"
+ ;;
+ "rpmb")
+ opts+=" --cmd= -c --msgfile= -f --keyfile= -g \
+ --key= -k --msg= -d --address= -o --blocks= -b \
+ --target= -t"
+ ;;
+ "show-topology")
+ opts+=" --output-format= -o --verbose -v --ranking= -r"
+ ;;
+ "nvme-mi-recv")
+ opts+=" --opcode= -O --namespace-id= -n --data-len= -l \
+ --nmimt= -m --nmd0= -0 --nmd1= -1 --input-file= -i"
+ ;;
+ "nvme-mi-send")
+ opts+=" --opcode= -O --namespace-id= -n --data-len= -l \
+ --nmimt= -m --nmd0= -0 --nmd1= -1 --input-file= -i"
+ ;;
+ "version")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts=$_cmds
+ ;;
+ esac
+
+ opts+=" -h --help -j --json"
+
+ if [[ $vals == " " ]]; then
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+ else
+ COMPREPLY+=( $( compgen $compargs -W "$vals" -- $val ) )
+ fi
+
+ return 0
+}
+
+plugin_intel_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "internal-log")
+ opts+=" --log= -l --region= -r --nlognum= -m \
+ --namespace-id= -n --output-file= -o \
+ --verbose-nlog -v"
+ ;;
+ "lat-stats")
+ opts+=" --write -w --raw-binary -b --json -j"
+ ;;
+ "set-bucket-thresholds")
+ opts+=" --write -w --bucket-thresholds= -t"
+ ;;
+ "lat-stats-tracking")
+ opts+=" --enable -e --disable -d"
+ ;;
+ "market-name")
+ opts+=" --raw-binary -b"
+ ;;
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b \
+ --json -j"
+ ;;
+ "temp-stats")
+ opts+=" --raw-binary -b"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_amzn_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_memblaze_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b"
+ ;;
+ "get-pm-status")
+ opts+=$NO_OPTS
+ ;;
+ "set-pm-status")
+ opts+=" --value= -v --save -s"
+ ;;
+ "select-download")
+ opts+=" --fw= -f --select= -s"
+ ;;
+ "lat-stats")
+ opts+=" --enable -e --disable -d"
+ ;;
+ "lat-stats-print")
+ opts+=" --write -w"
+ ;;
+ "lat-log")
+ opts+=" --param= -p"
+ ;;
+ "lat-log-print")
+ opts+=$NO_OPTS
+ ;;
+ "clear-error-log")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_wdc_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "cap-diag")
+ opts+=" --output-file= -o --transfer-size= -s"
+ ;;
+ "drive-log")
+ opts+=" --output-file= -o"
+ ;;
+ "get-crash-dump")
+ opts+=" --output-file= -o"
+ ;;
+ "get-pfail-dump")
+ opts+=" --output-file= -o"
+ ;;
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "purge")
+ opts+=$NO_OPTS
+ ;;
+ "purge-monitor")
+ opts+=$NO_OPTS
+ ;;
+ "vs-internal-log")
+ opts+=" --output-file= -o --transfer-size= -s --data-area= -d \
+ --file-size= -f --offset= -e --type= -t --verbose -v"
+ ;;
+ "vs-nand-stats")
+ opts+=" --output-format= -o"
+ ;;
+ "vs-smart-add-log")
+ opts+=" --interval= -i --output-format= -o --log-page-version= -l \
+ --log-page-mask= -p"
+ ;;
+ "clear-pcie-correctable-errors")
+ opts+=$NO_OPTS
+ ;;
+ "drive-essentials")
+ opts+=" --dir-name= -d"
+ ;;
+ "get-drive-status")
+ opts+=$NO_OPTS
+ ;;
+ "clear-assert-dump")
+ opts+=$NO_OPTS
+ ;;
+ "drive-resize")
+ opts+=" --size= -s"
+ ;;
+ "vs-fw-activate-history")
+ opts+=" --output-format= -o"
+ ;;
+ "clear-fw-activate-history")
+ opts+=$NO_OPTS
+ ;;
+ "enc-get-log")
+ opts+=" --output-file= -o --transfer-size= -s --log-id= -l"
+ ;;
+ "vs-telemetry-controller-option")
+ opts+=" --disable -d --enable -e --status -s"
+ ;;
+ "vs-error-reason-identifier")
+ opts+=" --log-id= -i --file= -o"
+ ;;
+ "log-page-directory")
+ opts+=" --output-format= -o"
+ ;;
+ "namespace-resize")
+ opts+=" --namespace-id= -n --op-option= -o"
+ ;;
+ "vs-drive-info")
+ opts+=" --output-format= -o"
+ ;;
+ "vs-temperature-stats")
+ opts+=" --output-format= -o"
+ ;;
+ "capabilities")
+ opts+=$NO_OPTS
+ ;;
+ "cloud-SSD-plugin-version")
+ opts+=$NO_OPTS
+ ;;
+ "vs-pcie-stats")
+ opts+=" --output-format= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_huawei_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "list")
+ opts+=" --output-format= -o"
+ ;;
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_toshiba_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "vs-smart-add-log")
+ opts+=" --namespace-id= -n --output-file= -o --log= -l"
+ ;;
+ "vs-internal-log")
+ opts+=" --output-file= -o --prev-log -p"
+ ;;
+ "clear-pcie-correctable-errors")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_micron_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "select-download")
+ opts+=" --fw= -f --select= -s"
+ ;;
+ "vs-temperature-stats")
+ opts+=" --format= -f"
+ ;;
+ "vs-pcie-stats")
+ opts+=" --format= -f"
+ ;;
+ "clear-pcie-correctable-errors")
+ opts+=$NO_OPTS
+ ;;
+ "vs-internal-log")
+ opts+=" --type= -t --package= -p --data_area= -d"
+ ;;
+ "vs-telemetry-controller-option")
+ opts+=" --option= -o --select= -s"
+ ;;
+ "vs-nand-stats")
+ opts+=" --format= -f"
+ ;;
+ "vs-drive-info")
+ opts+=" --format= -f"
+ ;;
+ "plugin-version")
+ opts+=$NO_OPTS
+ ;;
+ "cloud-SSD-plugin-version")
+ opts+=$NO_OPTS
+ ;;
+ "log-page-directory")
+ opts+=$NO_OPTS
+ ;;
+ "vs-fw-activate-history")
+ opts+=" --format= -f"
+ ;;
+ "vs-error-reason-identifier")
+ opts+=" --format= -f"
+ ;;
+ "vs-smart-add-log")
+ opts+=" --format= -f"
+ ;;
+ "clear-fw-activate-history")
+ opts+=$NO_OPTS
+ ;;
+ "vs-smbus-option")
+ opts+=" --option= -o --value= -v --save= -s"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_seagate_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "vs-temperature-stats")
+ opts+=" --output-format= -o"
+ ;;
+ "vs-log-page-sup")
+ opts+=" --output-format= -o"
+ ;;
+ "vs-smart-add-log")
+ opts+=" --output-format= -o"
+ ;;
+ "vs-pcie-stats")
+ opts+=" --output-format= -o"
+ ;;
+ "clear-pcie-correctable-errors")
+ opts+=" --save -s"
+ ;;
+ "get-host-tele")
+ opts+=" --namespace-id= -n --log-specific= -i --raw-binary -b"
+ ;;
+ "get-ctrl-tele")
+ opts+=" --namespace-id= -n --raw-binary -b"
+ ;;
+ "vs-internal-log")
+ opts+=" --namespace-id= -n --dump-file= -f"
+ ;;
+ "plugin-version")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=""
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_virtium_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "save-smart-to-vtview-log")
+ opts+=" --run-time= -r --freq= -f --output-file= -o --test-name= -n"
+ ;;
+ "show-identify")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_shannon_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b"
+ ;;
+ "get-feature-add")
+ opts+=" --namespace-id= -n --feature-id -f --sel= -s \
+ --data-len= -l --raw-binary -b --cdw11= -c --human-readable -H"
+ ;;
+ "set-feature-add")
+ opts+=" --namespace-id= -n --feature-id= -f --value= -V \
+ --data-len= -l --data= -d --save -s"
+ ;;
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_dera_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-log-add")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_sfx_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b --json -j"
+ ;;
+ "lat-stats")
+ opts+=" --write -w --raw-binary -b"
+ ;;
+ "get-bad-block")
+ opts+=$NO_OPTS
+ ;;
+ "query-cap")
+ opts+=" --raw-binary --json"
+ ;;
+ "change-cap")
+ opts+=" --cap= -c --cap-byte= -z --force -f --raw-binary -b --json -j"
+ ;;
+ "set-feature")
+ opts+=" --namespace-id= -n --feature-id= -f --value= -v --force -s"
+ ;;
+ "get-feature")
+ opts+=" --namespace-id= -n --feature-id -f"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_solidigm_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o \
+ --verbose -v "
+ ;;
+ "vs-smart-add-log")
+ opts+="--output-format= -o"
+ ;;
+ "garbage-collect-log")
+ opts+="--output-format= -o"
+ ;;
+ "vs-internal-log")
+ opts+=" --type= -t --namespace-id= -n \
+ --file-prefix= -p --verbose -v"
+ ;;
+ "latency-tracking-log")
+ opts+=" --enable -e --disable -d \
+ --read -r --write -w \
+ --type -t --output-format -o"
+ ;;
+ "clear-pcie-correctable-errors")
+ opts+=" --no-uuid -n"
+ ;;
+ "parse-telemetry-log")
+ opts+=" --host-generate -g --controller-init -c \
+ --data-area -d --config-file -j \
+ --source-file -s"
+ ;;
+ "clear-fw-activate-history")
+ opts+=" --no-uuid -n"
+ ;;
+ "vs-fw-activate-history")
+ opts+=" --output-format -o"
+ ;;
+ "log-page-directory")
+ opts+=" --output-format -o"
+ ;;
+ "vs-drive-info")
+ opts+=" "
+ ;;
+ "cloud-SSDplugin-version")
+ opts+=$NO_OPTS
+ ;;
+ "market-log")
+ opts+=" --raw-binary -b"
+ ;;
+ "smart-log-add")
+ opts+=" --namespace-id= -n --output-format -o"
+ ;;
+ "temp-stats")
+ opts+=" --raw-binary -b"
+ ;;
+ "version")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_transcend_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "healthvalue")
+ opts+=$NO_OPTS
+ ;;
+ "badblock")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_zns_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "id-ns")
+ opts+=" --namespace-id= -n --vendor-specific -v \
+ --output-format= -o --human-readable -H"
+ ;;
+ "zone-mgmt-recv")
+ opts+=" --output-format= -o --namespace-id= -n \
+ --start-lba= -s --zra= -z --zrasf= -S --partial -p \
+ --data-len= -l"
+ ;;
+ "zone-mgmt-send")
+ opts+=" --namespace-id= -n --start-lba= -s --zsaso -o \
+ --select-all -a --zsa= -z --data-len= -l \
+ --data= -d --timeout= -t"
+ ;;
+ "report-zones")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --descs= -d --state= -S --output-format= -o \
+ --human-readable -H --extended -e --partial -p"
+ ;;
+ "close-zone")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --select-all -a --timeout= -t"
+ ;;
+ "finish-zone")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --select-all -a --timeout= -t"
+ ;;
+ "open-zone")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --select-all -a --timeout= -t --zrwa -r"
+ ;;
+ "reset-zone")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --select-all -a --timeout= -t"
+ ;;
+ "offline-zone")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --select-all -a --timeout= -t"
+ ;;
+ "set-zone-desc")
+ opts+=" --namespace-id= -n --start-lba= -s \
+ --data= -d --timeout= -t --zrwa -r"
+ ;;
+ "flush-zone")
+ opts+=" --namespace-id= -n --last-lba= -l --timeout= -t"
+ ;;
+ "zone-append")
+ opts+=" --namespace-id= -n --zslba= -s --data-size= -z \
+ --metadata-size= -y --data= -d --metadata= -M \
+ --limited-retry -l --force-unit-access -f --ref-tag= -r
+ --app-tag-mask= -m --app-tag= -a --prinfo= -p \
+ --piremap -P --latency -t"
+ ;;
+ "changed-zone-list")
+ opts+=" --namespace-id= -n --output-format= -o --rae -r"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_nvidia_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "id-ctrl")
+ opts+=" --raw-binary -b --human-readable -H \
+ --vendor-specific -v --output-format= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_ymtc_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_inspur_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "nvme-vendor-log")
+ opts+=$NO_OPTS
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+plugin_ocp_opts () {
+ local opts=""
+ local compargs=""
+
+ local nonopt_args=0
+ for (( i=0; i < ${#words[@]}-1; i++ )); do
+ if [[ ${words[i]} != -* ]]; then
+ let nonopt_args+=1
+ fi
+ done
+
+ if [ $nonopt_args -eq 3 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "smart-add-log")
+ opts+=" --output-format= -o"
+ ;;
+ "latency-monitor-log")
+ opts+=" --output-format= -o"
+ ;;
+ "set-latency-monitor-feature")
+ opts+=" --active_bucket_timer_threshold= -t \
+ --active_threshold_a= -a --active_threshold_b= -b \
+ --active_threshold_c= -c --active_threshold_d= -d \
+ --active_latency_config= -f \
+ --active_latency_minimum_window= -w \
+ --debug_log_trigger_enable -r --discard_debug_log= -l \
+ --latency_monitor_feature_enable= -e"
+ ;;
+ "internal-log")
+ opts+=" --telemetry_type= -t --telemetry_data_area= -a \
+ --output-file= -o"
+ ;;
+ "clear-fw-activate-history")
+ opts+=" --no-uuid -n"
+ ;;
+ "eol-plp-failure-mode")
+ opts+=" --mode= -m --save -s --sel= -S --no-uuid -n"
+ ;;
+ "clear-pcie-correctable-error-counters")
+ opts+=" --no-uuid -n"
+ ;;
+ "fw-activate-history")
+ opts+=" --output-format= -o"
+ ;;
+ "device-capability-log")
+ opts+=" --output-format= -o"
+ ;;
+ "set-dssd-power-state-feature")
+ opts+=" --power-state= -p --no-uuid -n --save -s"
+ ;;
+ "telemetry-string-log")
+ opts+=" --output-file= -o"
+ ;;
+ "help")
+ opts+=$NO_OPTS
+ ;;
+ esac
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+_nvme_subcmds () {
+ local cur prev words cword
+ _init_completion || return
+
+ # Constant to indicate command has no options
+ NO_OPTS=""
+
+ # Associative array of plugins and associated subcommands
+ # Order here is same as PLUGIN_OBJS in Makefile
+ typeset -Ar _plugin_subcmds=(
+ [intel]="id-ctrl internal-log lat-stats \
+ set-bucket-thresholds lat-stats-tracking \
+ market-name smart-log-add temp-stats"
+ [amzn]="id-ctrl"
+ [memblaze]="smart-log-add get-pm-status set-pm-status \
+ select-download lat-stats lat-stats-print lat-log \
+ lat-log-print clear-error-log"
+ [wdc]="cap-diag drive-log get-crash-dump get-pfail-dump \
+ id-ctrl purge purge-monitor vs-internal-log \
+ vs-nand-stats vs-smart-add-log clear-pcie-correctable-errors \
+ drive-essentials get-drive-status clear-assert-dump \
+ drive-resize vs-fw-activate-history clear-fw-activate-history \
+ enc-get-log vs-telemetry-controller-option \
+ vs-error-reason-identifier log-page-directory \
+ namespace-resize vs-drive-info vs-temperature-stats \
+ capabilities cloud-SSD-plugin-version vs-pcie-stats"
+ [huawei]="list id-ctrl"
+ [netapp]="smdevices ontapdevices"
+ [toshiba]="vs-smart-add-log vs-internal-log \
+ clear-pcie-correctable-errors"
+ [micron]="select-download vs-temperature-stats vs-pcie-stats \
+ clear-pcie-correctable-errors vs-internal-log \
+ vs-telemetry-controller-option vs-nand-stats \
+ vs-drive-info plugin-version cloud-SSD-plugin-version \
+ log-page-directory vs-fw-activate-history \
+ vs-error-reason-identifier vs-smart-add-log \
+ clear-fw-activate-history vs-smbus-option"
+ [seagate]="vs-temperature-stats vs-log-page-sup \
+ vs-smart-add-log vs-pcie-stats clear-pcie-correctable-errors \
+ get-host-tele get-ctrl-tele vs-internal-log \
+ plugin-version"
+ [virtium]="save-smart-to-vtview-log show-identify"
+ [shannon]="smart-log-add get-feature-add set-feature-add id-ctrl"
+ [dera]="smart-log-add"
+ [sfx]="smart-log-add lat-stats get-bad-block query-cap \
+ change-cap set-feature get-feature"
+ [solidigm]="id-ctrl vs-smart-add-log garbage-collect-log \
+ vs-internal-log latency-tracking-log \
+ clear-pcie-correctable-errors parse-telemetry-log \
+ clear-fw-activate-history vs-fw-activate-history log-page-directory \
+ vs-drive-info cloud-SSDplugin-version market-log \
+ smart-log-add temp-stats version help"
+ [transcend]="healthvalue badblock"
+ [zns]="id-ctrl id-ns zone-mgmt-recv \
+ zone-mgmt-send report-zones close-zone \
+ finish-zone open-zone reset-zone offline-zone \
+ set-zone-desc zone-append changed-zone-list"
+ [nvidia]="id-ctrl"
+ [ymtc]="smart-log-add"
+ [inspur]="nvme-vendor-log"
+ [ocp]="smart-add-log latency-monitor-log \
+ set-latency-monitor-feature internal-log \
+ clear-fw-activate-history eol-plp-failure-mode \
+ clear-pcie-correctable-error-counters \
+ vs-fw-activate-history device-capability-log \
+ set-dssd-power-state-feature telemetry-string-log"
+ )
+
+ # Associative array mapping plugins to corresponding option completions
+ typeset -Ar _plugin_funcs=(
+ [intel]="plugin_intel_opts"
+ [amzn]="plugin_amzn_opts"
+ [memblaze]="plugin_memblaze_opts"
+ [wdc]="plugin_wdc_opts"
+ [huawei]="plugin_huawei_opts"
+ [toshiba]="plugin_toshiba_opts"
+ [micron]="plugin_micron_opts"
+ [seagate]="plugin_seagate_opts"
+ [virtium]="plugin_virtium_opts"
+ [shannon]="plugin_shannon_opts"
+ [dera]="plugin_dera_opts"
+ [sfx]="plugin_sfx_opts"
+ [solidigm]="plugin_solidigm_opts"
+ [transcend]="plugin_transcend_opts"
+ [zns]="plugin_zns_opts"
+ [nvidia]="plugin_nvidia_opts"
+ [ymtc]="plugin_ymtc_opts"
+ [inspur]="plugin_inspur_opts"
+ [ocp]="plugin_ocp_opts"
+ )
+
+ # Top level commands
+ _cmds="list list-subsys id-ctrl id-ns \
+ id-ns-granularity list-ns list-ctrl \
+ id-ns-lba-format nvm-id-ns nvm-id-ns-lba-format \
+ nvm-id-ctrl primary-ctrl-caps list-secondary \
+ ns-descs id-nvmset id-uuid id-iocs id-domain create-ns \
+ delete-ns get-ns-id get-log telemetry-log \
+ fw-log changed-ns-list-log smart-log ana-log \
+ error-log effects-log endurance-log \
+ predictable-lat-log pred-lat-event-agg-log \
+ persistent-event-log endurance-agg-log \
+ lba-status-log resv-notif-log get-feature \
+ device-self-test self-test-log set-feature \
+ set-property get-property format fw-commit \
+ fw-download admin-passthru io-passthru \
+ security-send security-recv get-lba-status \
+ resv-acquire resv-register resv-release \
+ resv-report dsm copy flush compare read \
+ write write-zeros write-uncor verify \
+ sanitize sanitize-log reset subsystem-reset \
+ ns-rescan show-regs discover connect-all \
+ connect disconnect disconnect-all gen-hostnqn \
+ show-hostnqn dir-receive dir-send virt-mgmt \
+ rpmb boot-part-log fid-support-effects-log \
+ supported-log-pages lockdown media-unit-stat-log \
+ supported-cap-config-log dim show-topology list-endgrp \
+ nvme-mi-recv nvme-mi-send"
+
+ # Add plugins:
+ for plugin in "${!_plugin_subcmds[@]}"; do
+ _cmds+=" $plugin"
+ done
+
+ _cmds+=" version help"
+
+ if [[ ${#words[*]} -lt 3 ]]; then
+ COMPREPLY+=( $(compgen -W "$_cmds" -- $cur ) )
+ else
+ for subcmd in "${!_plugin_subcmds[@]}"; do
+ if [[ ${words[1]} == $subcmd ]]; then
+ if [[ ${#words[*]} -lt 4 ]]; then
+ COMPREPLY+=( $(compgen -W "${_plugin_subcmds[$subcmd]}" -- $cur ) )
+ else
+ func=${_plugin_funcs[$subcmd]}
+ $func ${words[2]} $prev
+ fi
+ return 0
+ fi
+ done
+
+ nvme_list_opts ${words[1]} $prev
+ fi
+
+ return 0
+}
+
+complete -o default -F _nvme_subcmds nvme
diff --git a/define_cmd.h b/define_cmd.h
new file mode 100644
index 0000000..af31992
--- /dev/null
+++ b/define_cmd.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifdef CREATE_CMD
+#undef CREATE_CMD
+
+
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+#define __CMD_INCLUDE(cmd) __stringify(cmd.h)
+#define CMD_INCLUDE(cmd) __CMD_INCLUDE(cmd)
+
+#define CMD_HEADER_MULTI_READ
+
+#include CMD_INCLUDE(CMD_INC_FILE)
+
+#include "cmd_handler.h"
+
+#undef CMD_HEADER_MULTI_READ
+
+#define CREATE_CMD
+#endif
diff --git a/etc/discovery.conf.in b/etc/discovery.conf.in
new file mode 100644
index 0000000..cfdac1e
--- /dev/null
+++ b/etc/discovery.conf.in
@@ -0,0 +1,4 @@
+# Used for extracting default parameters for discovery
+#
+# Example:
+# --transport=<trtype> --traddr=<traddr> --trsvcid=<trsvcid> --host-traddr=<host-traddr> --host-iface=<host-iface>
diff --git a/fabrics.c b/fabrics.c
new file mode 100644
index 0000000..1a53b23
--- /dev/null
+++ b/fabrics.c
@@ -0,0 +1,1448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
+ * Copyright (c) 2016 HGST, a Western Digital Company.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * 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 the discovery controller feature of NVMe over
+ * Fabrics specification standard.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <stddef.h>
+#include <syslog.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <linux/types.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "nbft.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "fabrics.h"
+
+#define PATH_NVMF_DISC SYSCONFDIR "/nvme/discovery.conf"
+#define PATH_NVMF_CONFIG SYSCONFDIR "/nvme/config.json"
+#define PATH_NVMF_RUNDIR RUNDIR "/nvme"
+#define MAX_DISC_ARGS 32
+#define MAX_DISC_RETRIES 10
+
+#define NVMF_DEF_DISC_TMO 30
+
+/* Name of file to output log pages in their raw format */
+static char *raw;
+static bool persistent;
+static bool quiet;
+static bool dump_config;
+
+static const char *nvmf_tport = "transport type";
+static const char *nvmf_traddr = "transport address";
+static const char *nvmf_nqn = "subsystem nqn";
+static const char *nvmf_trsvcid = "transport service id (e.g. IP port)";
+static const char *nvmf_htraddr = "host traddr (e.g. FC WWN's)";
+static const char *nvmf_hiface = "host interface (for tcp transport)";
+static const char *nvmf_hostnqn = "user-defined hostnqn";
+static const char *nvmf_hostid = "user-defined hostid (if default not used)";
+static const char *nvmf_hostkey = "user-defined dhchap key (if default not used)";
+static const char *nvmf_ctrlkey = "user-defined dhchap controller key (for bi-directional authentication)";
+static const char *nvmf_nr_io_queues = "number of io queues to use (default is core count)";
+static const char *nvmf_nr_write_queues = "number of write queues to use (default 0)";
+static const char *nvmf_nr_poll_queues = "number of poll queues to use (default 0)";
+static const char *nvmf_queue_size = "number of io queue elements to use (default 128)";
+static const char *nvmf_keep_alive_tmo = "keep alive timeout period in seconds";
+static const char *nvmf_reconnect_delay = "reconnect timeout period in seconds";
+static const char *nvmf_ctrl_loss_tmo = "controller loss timeout period in seconds";
+static const char *nvmf_tos = "type of service";
+static const char *nvmf_keyring = "Keyring for TLS key lookup";
+static const char *nvmf_tls_key = "TLS key to use";
+static const char *nvmf_dup_connect = "allow duplicate connections between same transport host and subsystem port";
+static const char *nvmf_disable_sqflow = "disable controller sq flow control (default false)";
+static const char *nvmf_hdr_digest = "enable transport protocol header digest (TCP transport)";
+static const char *nvmf_data_digest = "enable transport protocol data digest (TCP transport)";
+static const char *nvmf_tls = "enable TLS";
+static const char *nvmf_concat = "enable secure concatenation";
+static const char *nvmf_config_file = "Use specified JSON configuration file or 'none' to disable";
+static const char *nvmf_context = "execution context identification string";
+
+#define NVMF_ARGS(n, c, ...) \
+ struct argconfig_commandline_options n[] = { \
+ OPT_STRING("transport", 't', "STR", &transport, nvmf_tport), \
+ OPT_STRING("nqn", 'n', "STR", &subsysnqn, nvmf_nqn), \
+ OPT_STRING("traddr", 'a', "STR", &traddr, nvmf_traddr), \
+ OPT_STRING("trsvcid", 's', "STR", &trsvcid, nvmf_trsvcid), \
+ OPT_STRING("host-traddr", 'w', "STR", &c.host_traddr, nvmf_htraddr), \
+ OPT_STRING("host-iface", 'f', "STR", &c.host_iface, nvmf_hiface), \
+ OPT_STRING("hostnqn", 'q', "STR", &hostnqn, nvmf_hostnqn), \
+ OPT_STRING("hostid", 'I', "STR", &hostid, nvmf_hostid), \
+ OPT_STRING("dhchap-secret", 'S', "STR", &hostkey, nvmf_hostkey), \
+ OPT_INT("nr-io-queues", 'i', &c.nr_io_queues, nvmf_nr_io_queues), \
+ OPT_INT("nr-write-queues", 'W', &c.nr_write_queues, nvmf_nr_write_queues), \
+ OPT_INT("nr-poll-queues", 'P', &c.nr_poll_queues, nvmf_nr_poll_queues), \
+ OPT_INT("queue-size", 'Q', &c.queue_size, nvmf_queue_size), \
+ OPT_INT("keep-alive-tmo", 'k', &c.keep_alive_tmo, nvmf_keep_alive_tmo), \
+ OPT_INT("reconnect-delay", 'c', &c.reconnect_delay, nvmf_reconnect_delay), \
+ OPT_INT("ctrl-loss-tmo", 'l', &c.ctrl_loss_tmo, nvmf_ctrl_loss_tmo), \
+ OPT_INT("tos", 'T', &c.tos, nvmf_tos), \
+ OPT_INT("keyring", 0, &c.keyring, nvmf_keyring), \
+ OPT_INT("tls_key", 0, &c.tls_key, nvmf_tls_key), \
+ OPT_FLAG("duplicate-connect", 'D', &c.duplicate_connect, nvmf_dup_connect), \
+ OPT_FLAG("disable-sqflow", 'd', &c.disable_sqflow, nvmf_disable_sqflow), \
+ OPT_FLAG("hdr-digest", 'g', &c.hdr_digest, nvmf_hdr_digest), \
+ OPT_FLAG("data-digest", 'G', &c.data_digest, nvmf_data_digest), \
+ OPT_FLAG("tls", 0, &c.tls, nvmf_tls), \
+ OPT_FLAG("concat", 0, &c.concat, nvmf_concat), \
+ __VA_ARGS__, \
+ OPT_END() \
+ }
+
+static bool is_persistent_discovery_ctrl(nvme_host_t h, nvme_ctrl_t c)
+{
+ if (nvme_host_is_pdc_enabled(h, DEFAULT_PDC_ENABLED))
+ return nvme_ctrl_is_unique_discovery_ctrl(c);
+
+ return false;
+}
+
+nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg)
+{
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+
+ nvme_for_each_subsystem(h, s) {
+ c = nvme_ctrl_find(s,
+ trcfg->transport,
+ trcfg->traddr,
+ trcfg->trsvcid,
+ trcfg->subsysnqn,
+ trcfg->host_traddr,
+ trcfg->host_iface);
+ if (c)
+ return c;
+ }
+
+ return NULL;
+}
+
+static int set_discovery_kato(struct nvme_fabrics_config *cfg)
+{
+ int tmo = cfg->keep_alive_tmo;
+
+ /* Set kato to NVMF_DEF_DISC_TMO for persistent controllers */
+ if (persistent && !cfg->keep_alive_tmo)
+ cfg->keep_alive_tmo = NVMF_DEF_DISC_TMO;
+ /* Set kato to zero for non-persistent controllers */
+ else if (!persistent && (cfg->keep_alive_tmo > 0))
+ cfg->keep_alive_tmo = 0;
+
+ return tmo;
+}
+
+static nvme_ctrl_t __create_discover_ctrl(nvme_root_t r, nvme_host_t h,
+ struct nvme_fabrics_config *cfg,
+ struct tr_config *trcfg)
+{
+ nvme_ctrl_t c;
+ int tmo, ret;
+
+ c = nvme_create_ctrl(r, trcfg->subsysnqn, trcfg->transport,
+ trcfg->traddr, trcfg->host_traddr,
+ trcfg->host_iface, trcfg->trsvcid);
+ if (!c)
+ return NULL;
+
+ nvme_ctrl_set_discovery_ctrl(c, true);
+ nvme_ctrl_set_unique_discovery_ctrl(c,
+ strcmp(trcfg->subsysnqn, NVME_DISC_SUBSYS_NAME));
+ tmo = set_discovery_kato(cfg);
+
+ errno = 0;
+ ret = nvmf_add_ctrl(h, c, cfg);
+
+ cfg->keep_alive_tmo = tmo;
+ if (ret) {
+ nvme_free_ctrl(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+static nvme_ctrl_t create_discover_ctrl(nvme_root_t r, nvme_host_t h,
+ struct nvme_fabrics_config *cfg,
+ struct tr_config *trcfg)
+{
+ nvme_ctrl_t c;
+
+ c = __create_discover_ctrl(r, h, cfg, trcfg);
+ if (!c)
+ return NULL;
+
+ if (nvme_ctrl_is_unique_discovery_ctrl(c))
+ return c;
+
+ /* Find out the name of discovery controller */
+ struct nvme_id_ctrl id = { 0 };
+
+ if (nvme_ctrl_identify(c, &id)) {
+ fprintf(stderr, "failed to identify controller, error %s\n",
+ nvme_strerror(errno));
+ nvme_disconnect_ctrl(c);
+ nvme_free_ctrl(c);
+ return NULL;
+ }
+
+ if (!strcmp(id.subnqn, NVME_DISC_SUBSYS_NAME))
+ return c;
+
+ /*
+ * The subsysnqn is not the well-known name. Prefer the unique
+ * subsysnqn over the well-known one.
+ */
+ nvme_disconnect_ctrl(c);
+ nvme_free_ctrl(c);
+
+ trcfg->subsysnqn = id.subnqn;
+ return __create_discover_ctrl(r, h, cfg, trcfg);
+}
+
+static void save_discovery_log(char *raw, struct nvmf_discovery_log *log)
+{
+ uint64_t numrec = le64_to_cpu(log->numrec);
+ int fd, len, ret;
+
+ fd = open(raw, O_CREAT | O_RDWR | O_TRUNC, 0600);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open %s: %s\n", raw, strerror(errno));
+ return;
+ }
+
+ len = sizeof(struct nvmf_discovery_log) + numrec * sizeof(struct nvmf_disc_log_entry);
+
+ ret = write(fd, log, len);
+ if (ret < 0)
+ fprintf(stderr, "failed to write to %s: %s\n",
+ raw, strerror(errno));
+ else
+ printf("Discovery log is saved to %s\n", raw);
+
+ close(fd);
+}
+
+static int __discover(nvme_ctrl_t c, struct nvme_fabrics_config *defcfg,
+ char *raw, bool connect, bool persistent,
+ enum nvme_print_flags flags)
+{
+ struct nvmf_discovery_log *log = NULL;
+ nvme_subsystem_t s = nvme_ctrl_get_subsystem(c);
+ nvme_host_t h = nvme_subsystem_get_host(s);
+ uint64_t numrec;
+
+ struct nvme_get_discovery_args args = {
+ .c = c,
+ .args_size = sizeof(args),
+ .max_retries = MAX_DISC_RETRIES,
+ .result = 0,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lsp = 0,
+ };
+
+ log = nvmf_get_discovery_wargs(&args);
+ if (!log) {
+ fprintf(stderr, "failed to get discovery log: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+
+ numrec = le64_to_cpu(log->numrec);
+ if (raw)
+ save_discovery_log(raw, log);
+ else if (!connect) {
+ nvme_show_discovery_log(log, numrec, flags);
+ } else if (connect) {
+ int i;
+
+ for (i = 0; i < numrec; i++) {
+ struct nvmf_disc_log_entry *e = &log->entries[i];
+ nvme_ctrl_t cl;
+ bool discover = false;
+ bool disconnect;
+ nvme_ctrl_t child;
+ int tmo = defcfg->keep_alive_tmo;
+
+ struct tr_config trcfg = {
+ .subsysnqn = e->subnqn,
+ .transport = nvmf_trtype_str(e->trtype),
+ .traddr = e->traddr,
+ .host_traddr = defcfg->host_traddr,
+ .host_iface = defcfg->host_iface,
+ .trsvcid = e->trsvcid,
+ };
+
+ /* Already connected ? */
+ cl = lookup_ctrl(h, &trcfg);
+ if (cl && nvme_ctrl_get_name(cl))
+ continue;
+
+ /* Skip connect if the transport types don't match */
+ if (strcmp(nvme_ctrl_get_transport(c),
+ nvmf_trtype_str(e->trtype)))
+ continue;
+
+ if (e->subtype == NVME_NQN_DISC ||
+ e->subtype == NVME_NQN_CURR) {
+ __u16 eflags = le16_to_cpu(e->eflags);
+ /*
+ * Does this discovery controller return the
+ * same information?
+ */
+ if (eflags & NVMF_DISC_EFLAGS_DUPRETINFO)
+ continue;
+
+ /* Are we supposed to keep the discovery controller around? */
+ disconnect = !persistent;
+
+ if (strcmp(e->subnqn, NVME_DISC_SUBSYS_NAME)) {
+ /*
+ * Does this discovery controller doesn't
+ * support explicit persistent connection?
+ */
+ if (!(eflags & NVMF_DISC_EFLAGS_EPCSD))
+ disconnect = true;
+ else
+ disconnect = false;
+ }
+
+ set_discovery_kato(defcfg);
+ } else {
+ /* NVME_NQN_NVME */
+ disconnect = false;
+ }
+
+ errno = 0;
+ child = nvmf_connect_disc_entry(h, e, defcfg,
+ &discover);
+
+ defcfg->keep_alive_tmo = tmo;
+
+ if (child) {
+ if (discover)
+ __discover(child, defcfg, raw,
+ true, persistent, flags);
+
+ if (disconnect) {
+ nvme_disconnect_ctrl(child);
+ nvme_free_ctrl(child);
+ }
+ } else if (errno == ENVME_CONNECT_ALREADY && !quiet) {
+ char *traddr = log->entries[i].traddr;
+
+ fprintf(stderr,
+ "traddr=%s is already connected\n",
+ traddr);
+ }
+ }
+ }
+
+ free(log);
+ return 0;
+}
+
+static char *get_default_trsvcid(const char *transport,
+ bool discovery_ctrl)
+{
+ if (!transport)
+ return NULL;
+ if (!strcmp(transport, "tcp")) {
+ if (discovery_ctrl)
+ /* Default port for NVMe/TCP discovery controllers */
+ return stringify(NVME_DISC_IP_PORT);
+ /* Default port for NVMe/TCP io controllers */
+ return stringify(NVME_RDMA_IP_PORT);
+ } else if (!strcmp(transport, "rdma")) {
+ /* Default port for NVMe/RDMA controllers */
+ return stringify(NVME_RDMA_IP_PORT);
+ }
+
+ return NULL;
+}
+
+static int discover_from_conf_file(nvme_root_t r, nvme_host_t h,
+ const char *desc, bool connect,
+ const struct nvme_fabrics_config *defcfg)
+{
+ char *transport = NULL, *traddr = NULL, *trsvcid = NULL;
+ char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL;
+ char *subsysnqn = NULL;
+ char *ptr, **argv, *p, line[4096];
+ int argc, ret = 0;
+ unsigned int verbose = 0;
+ FILE *f;
+ enum nvme_print_flags flags;
+ char *format = "normal";
+ struct nvme_fabrics_config cfg;
+ bool force = false;
+
+ NVMF_ARGS(opts, cfg,
+ OPT_FMT("output-format", 'o', &format, output_format),
+ OPT_FILE("raw", 'r', &raw, "save raw output to file"),
+ OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"),
+ OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"),
+ OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"),
+ OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"));
+
+ nvmf_default_config(&cfg);
+
+ ret = validate_output_format(format, &flags);
+ if (ret < 0) {
+ nvme_show_error("Invalid output format");
+ return ret;
+ }
+
+ f = fopen(PATH_NVMF_DISC, "r");
+ if (f == NULL) {
+ fprintf(stderr, "No params given and no %s\n", PATH_NVMF_DISC);
+ errno = ENOENT;
+ return -1;
+ }
+
+ argv = calloc(MAX_DISC_ARGS, sizeof(char *));
+ if (!argv) {
+ ret = -1;
+ goto out;
+ }
+
+ argv[0] = "discover";
+ memset(line, 0, sizeof(line));
+ while (fgets(line, sizeof(line), f) != NULL) {
+ nvme_ctrl_t c;
+
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ argc = 1;
+ p = line;
+ while ((ptr = strsep(&p, " =\n")) != NULL)
+ argv[argc++] = ptr;
+ argv[argc] = NULL;
+
+ memcpy(&cfg, defcfg, sizeof(cfg));
+ subsysnqn = NVME_DISC_SUBSYS_NAME;
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ goto next;
+ if (!transport && !traddr)
+ goto next;
+
+ if (!trsvcid)
+ trsvcid = get_default_trsvcid(transport, true);
+
+ struct tr_config trcfg = {
+ .subsysnqn = subsysnqn,
+ .transport = transport,
+ .traddr = traddr,
+ .host_traddr = cfg.host_traddr,
+ .host_iface = cfg.host_iface,
+ .trsvcid = trsvcid,
+ };
+
+ if (!force) {
+ c = lookup_ctrl(h, &trcfg);
+ if (c) {
+ __discover(c, &cfg, raw, connect,
+ true, flags);
+ goto next;
+ }
+ }
+
+ c = create_discover_ctrl(r, h, &cfg, &trcfg);
+ if (!c)
+ goto next;
+
+ __discover(c, &cfg, raw, connect, persistent, flags);
+ if (!(persistent || is_persistent_discovery_ctrl(h, c)))
+ ret = nvme_disconnect_ctrl(c);
+ nvme_free_ctrl(c);
+
+next:
+ memset(&cfg, 0, sizeof(cfg));
+ }
+ free(argv);
+out:
+ fclose(f);
+ return ret;
+}
+
+static int discover_from_json_config_file(nvme_root_t r, nvme_host_t h,
+ const char *desc, bool connect,
+ const struct nvme_fabrics_config *defcfg,
+ enum nvme_print_flags flags,
+ bool force)
+{
+ const char *transport, *traddr, *host_traddr, *host_iface, *trsvcid, *subsysnqn;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c, cn;
+ struct nvme_fabrics_config cfg;
+ int ret = 0;
+
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ transport = nvme_ctrl_get_transport(c);
+ traddr = nvme_ctrl_get_traddr(c);
+ host_traddr = nvme_ctrl_get_host_traddr(c);
+ host_iface = nvme_ctrl_get_host_iface(c);
+
+ if (!transport && !traddr)
+ continue;
+
+ /* ignore none fabric transports */
+ if (strcmp(transport, "tcp") &&
+ strcmp(transport, "rdma") &&
+ strcmp(transport, "fc"))
+ continue;
+
+ /* ignore if no host_traddr for fc */
+ if (!strcmp(transport, "fc")) {
+ if (!host_traddr) {
+ fprintf(stderr, "host_traddr required for fc\n");
+ continue;
+ }
+ }
+
+ /* ignore if host_iface set for any transport other than tcp */
+ if (!strcmp(transport, "rdma") || !strcmp(transport, "fc")) {
+ if (host_iface) {
+ fprintf(stderr, "host_iface not permitted for rdma or fc\n");
+ continue;
+ }
+ }
+
+ trsvcid = nvme_ctrl_get_trsvcid(c);
+ if (!trsvcid || !strcmp(trsvcid, ""))
+ trsvcid = get_default_trsvcid(transport, true);
+
+ if (force)
+ subsysnqn = nvme_ctrl_get_subsysnqn(c);
+ else
+ subsysnqn = NVME_DISC_SUBSYS_NAME;
+
+ if (nvme_ctrl_is_persistent(c))
+ persistent = true;
+
+ memcpy(&cfg, defcfg, sizeof(cfg));
+
+ struct tr_config trcfg = {
+ .subsysnqn = subsysnqn,
+ .transport = transport,
+ .traddr = traddr,
+ .host_traddr = host_traddr,
+ .host_iface = host_iface,
+ .trsvcid = trsvcid,
+ };
+
+ if (!force) {
+ cn = lookup_ctrl(h, &trcfg);
+ if (cn) {
+ __discover(cn, &cfg, raw, connect,
+ true, flags);
+ continue;
+ }
+ }
+
+ cn = create_discover_ctrl(r, h, &cfg, &trcfg);
+ if (!cn)
+ continue;
+
+ __discover(cn, &cfg, raw, connect, persistent, flags);
+ if (!(persistent || is_persistent_discovery_ctrl(h, cn)))
+ ret = nvme_disconnect_ctrl(cn);
+ nvme_free_ctrl(cn);
+ }
+ }
+
+ return ret;
+}
+
+static int nvme_read_volatile_config(nvme_root_t r)
+{
+ char *filename, *ext;
+ struct dirent *dir;
+ DIR *d;
+ int ret = -ENOENT;
+
+ d = opendir(PATH_NVMF_RUNDIR);
+ if (!d)
+ return -ENOTDIR;
+
+ while ((dir = readdir(d))) {
+ if (dir->d_type != DT_REG)
+ continue;
+
+ ext = strchr(dir->d_name, '.');
+ if (!ext || strcmp("json", ext + 1))
+ continue;
+
+ if (asprintf(&filename, "%s/%s", PATH_NVMF_RUNDIR, dir->d_name) < 0) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ if (nvme_read_config(r, filename))
+ ret = 0;
+
+ free(filename);
+ }
+ closedir(d);
+
+ return ret;
+}
+
+char *nvmf_hostid_from_hostnqn(const char *hostnqn)
+{
+ const char *uuid;
+
+ if (!hostnqn)
+ return NULL;
+
+ uuid = strstr(hostnqn, "uuid:");
+ if (!uuid)
+ return NULL;
+
+ return strdup(uuid + strlen("uuid:"));
+}
+
+void nvmf_check_hostid_and_hostnqn(const char *hostid, const char *hostnqn, unsigned int verbose)
+{
+ char *hostid_from_file, *hostid_from_hostnqn;
+
+ if (!hostid)
+ return;
+
+ hostid_from_file = nvmf_hostid_from_file();
+ if (hostid_from_file && strcmp(hostid_from_file, hostid)) {
+ if (verbose)
+ fprintf(stderr,
+ "warning: use generated hostid instead of hostid file\n");
+ free(hostid_from_file);
+ }
+
+ if (!hostnqn)
+ return;
+
+ hostid_from_hostnqn = nvmf_hostid_from_hostnqn(hostnqn);
+ if (hostid_from_hostnqn && strcmp(hostid_from_hostnqn, hostid)) {
+ if (verbose)
+ fprintf(stderr,
+ "warning: use hostid which does not match uuid in hostnqn\n");
+ free(hostid_from_hostnqn);
+ }
+}
+
+int nvmf_discover(const char *desc, int argc, char **argv, bool connect)
+{
+ char *subsysnqn = NVME_DISC_SUBSYS_NAME;
+ char *hostnqn = NULL, *hostid = NULL, *hostkey = NULL;
+ char *hostnqn_arg, *hostid_arg;
+ char *transport = NULL, *traddr = NULL, *trsvcid = NULL;
+ char *config_file = PATH_NVMF_CONFIG;
+ char *hnqn = NULL, *hid = NULL;
+ char *context = NULL;
+ enum nvme_print_flags flags;
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t c = NULL;
+ unsigned int verbose = 0;
+ int ret;
+ char *format = "normal";
+ struct nvme_fabrics_config cfg;
+ char *device = NULL;
+ bool force = false;
+ bool json_config = false;
+ bool nbft = false, nonbft = false;
+ char *nbft_path = NBFT_SYSFS_PATH;
+
+ NVMF_ARGS(opts, cfg,
+ OPT_STRING("device", 'd', "DEV", &device, "use existing discovery controller device"),
+ OPT_FMT("output-format", 'o', &format, output_format),
+ OPT_FILE("raw", 'r', &raw, "save raw output to file"),
+ OPT_FLAG("persistent", 'p', &persistent, "persistent discovery connection"),
+ OPT_FLAG("quiet", 'S', &quiet, "suppress already connected errors"),
+ OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file),
+ OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"),
+ OPT_FLAG("dump-config", 'O', &dump_config, "Dump configuration file to stdout"),
+ OPT_FLAG("force", 0, &force, "Force persistent discovery controller creation"),
+ OPT_FLAG("nbft", 0, &nbft, "Only look at NBFT tables"),
+ OPT_FLAG("no-nbft", 0, &nonbft, "Do not look at NBFT tables"),
+ OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"),
+ OPT_STRING("context", 0, "STR", &context, nvmf_context));
+
+ nvmf_default_config(&cfg);
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(format, &flags);
+ if (ret < 0) {
+ nvme_show_error("Invalid output format");
+ return ret;
+ }
+
+ if (!strcmp(config_file, "none"))
+ config_file = NULL;
+
+ r = nvme_create_root(stderr, map_log_level(verbose, quiet));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ if (context)
+ nvme_root_set_application(r, context);
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+
+ if (!nvme_read_config(r, config_file))
+ json_config = true;
+ if (!nvme_read_volatile_config(r))
+ json_config = true;
+
+ hostnqn_arg = hostnqn;
+ hostid_arg = hostid;
+ if (!hostnqn)
+ hostnqn = hnqn = nvmf_hostnqn_from_file();
+ if (!hostnqn) {
+ hostnqn = hnqn = nvmf_hostnqn_generate();
+ hostid = hid = nvmf_hostid_from_hostnqn(hostnqn);
+ }
+ if (!hostid)
+ hostid = hid = nvmf_hostid_from_file();
+ if (!hostid && hostnqn)
+ hostid = hid = nvmf_hostid_from_hostnqn(hostnqn);
+ nvmf_check_hostid_and_hostnqn(hostid, hostnqn, verbose);
+ h = nvme_lookup_host(r, hostnqn, hostid);
+ if (!h) {
+ ret = ENOMEM;
+ goto out_free;
+ }
+ if (device) {
+ if (!strcmp(device, "none"))
+ device = NULL;
+ else if (!strncmp(device, "/dev/", 5))
+ device += 5;
+ }
+ if (hostkey)
+ nvme_host_set_dhchap_key(h, hostkey);
+
+ if (!device && !transport && !traddr) {
+ if (!nonbft)
+ discover_from_nbft(r, hostnqn_arg, hostid_arg,
+ hostnqn, hostid, desc, connect,
+ &cfg, nbft_path, flags, verbose);
+
+ if (nbft)
+ goto out_free;
+
+ if (json_config)
+ ret = discover_from_json_config_file(r, h, desc,
+ connect, &cfg,
+ flags, force);
+ if (ret || access(PATH_NVMF_DISC, F_OK))
+ goto out_free;
+
+ ret = discover_from_conf_file(r, h, desc, connect, &cfg);
+ goto out_free;
+ }
+
+ if (!trsvcid)
+ trsvcid = get_default_trsvcid(transport, true);
+
+ struct tr_config trcfg = {
+ .subsysnqn = subsysnqn,
+ .transport = transport,
+ .traddr = traddr,
+ .host_traddr = cfg.host_traddr,
+ .host_iface = cfg.host_iface,
+ .trsvcid = trsvcid,
+ };
+
+ if (device && !force) {
+ c = nvme_scan_ctrl(r, device);
+ if (c) {
+ /* Check if device matches command-line options */
+ if (!nvme_ctrl_config_match(c, transport, traddr, trsvcid, subsysnqn,
+ cfg.host_traddr, cfg.host_iface)) {
+ fprintf(stderr,
+ "ctrl device %s found, ignoring non matching command-line options\n",
+ device);
+ }
+
+ if (!nvme_ctrl_is_discovery_ctrl(c)) {
+ fprintf(stderr,
+ "ctrl device %s found, ignoring non discovery controller\n",
+ device);
+
+ nvme_free_ctrl(c);
+ c = NULL;
+ persistent = false;
+ } else {
+ /*
+ * If the controller device is found it must
+ * be persistent, and shouldn't be disconnected
+ * on exit.
+ */
+ persistent = true;
+ /*
+ * When --host-traddr/--host-iface are not specified on the
+ * command line, use the discovery controller's (c) host-
+ * traddr/host-iface for the connections to controllers
+ * returned in the Discovery Log Pages. This is essential
+ * when invoking "connect-all" with --device to reuse an
+ * existing persistent discovery controller (as is done
+ * for the udev rules). This ensures that host-traddr/
+ * host-iface are consistent with the discovery controller (c).
+ */
+ if (!cfg.host_traddr)
+ cfg.host_traddr = (char *)nvme_ctrl_get_host_traddr(c);
+ if (!cfg.host_iface)
+ cfg.host_iface = (char *)nvme_ctrl_get_host_iface(c);
+ }
+ } else {
+ /*
+ * No controller found, fall back to create one.
+ * But that controller cannot be persistent.
+ */
+ fprintf(stderr,
+ "ctrl device %s not found%s\n", device,
+ persistent ? ", ignoring --persistent" : "");
+ persistent = false;
+ }
+ }
+ if (!c && !force) {
+ c = lookup_ctrl(h, &trcfg);
+ if (c)
+ persistent = true;
+ }
+ if (!c) {
+ /* No device or non-matching device, create a new controller */
+ c = create_discover_ctrl(r, h, &cfg, &trcfg);
+ if (!c) {
+ if (errno != ENVME_CONNECT_IGNORED)
+ fprintf(stderr,
+ "failed to add controller, error %s\n",
+ nvme_strerror(errno));
+ ret = errno;
+ goto out_free;
+ }
+ }
+
+ ret = __discover(c, &cfg, raw, connect, persistent, flags);
+ if (!(persistent || is_persistent_discovery_ctrl(h, c)))
+ nvme_disconnect_ctrl(c);
+ nvme_free_ctrl(c);
+
+out_free:
+ free(hnqn);
+ free(hid);
+ if (dump_config)
+ nvme_dump_config(r);
+ nvme_free_tree(r);
+
+ return ret;
+}
+
+int nvmf_connect(const char *desc, int argc, char **argv)
+{
+ char *subsysnqn = NULL;
+ char *transport = NULL, *traddr = NULL;
+ char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL;
+ char *hostkey = NULL, *ctrlkey = NULL;
+ char *hnqn = NULL, *hid = NULL;
+ char *config_file = PATH_NVMF_CONFIG;
+ char *context = NULL;
+ unsigned int verbose = 0;
+ nvme_root_t r;
+ nvme_host_t h;
+ nvme_ctrl_t c;
+ int ret;
+ enum nvme_print_flags flags;
+ struct nvme_fabrics_config cfg = { 0 };
+ char *format = "normal";
+
+
+ NVMF_ARGS(opts, cfg,
+ OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey),
+ OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file),
+ OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"),
+ OPT_FLAG("dump-config", 'O', &dump_config, "Dump JSON configuration to stdout"),
+ OPT_FMT("output-format", 'o', &format, "Output format: normal|json"),
+ OPT_STRING("context", 0, "STR", &context, nvmf_context));
+
+ nvmf_default_config(&cfg);
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(format, &flags);
+ if (ret < 0) {
+ nvme_show_error("Invalid output format");
+ return ret;
+ }
+
+ if (!subsysnqn) {
+ fprintf(stderr,
+ "required argument [--nqn | -n] not specified\n");
+ return -EINVAL;
+ }
+
+ if (!transport) {
+ fprintf(stderr,
+ "required argument [--transport | -t] not specified\n");
+ return -EINVAL;
+ }
+
+ if (strcmp(transport, "loop")) {
+ if (!traddr) {
+ fprintf(stderr,
+ "required argument [--traddr | -a] not specified for transport %s\n",
+ transport);
+ return -EINVAL;
+ }
+ }
+
+ if (!strcmp(config_file, "none"))
+ config_file = NULL;
+
+ r = nvme_create_root(stderr, map_log_level(verbose, quiet));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ if (context)
+ nvme_root_set_application(r, context);
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+ nvme_read_config(r, config_file);
+ nvme_read_volatile_config(r);
+
+ if (!hostnqn)
+ hostnqn = hnqn = nvmf_hostnqn_from_file();
+ if (!hostnqn) {
+ hostnqn = hnqn = nvmf_hostnqn_generate();
+ hostid = hid = nvmf_hostid_from_hostnqn(hostnqn);
+ }
+ if (!hostid)
+ hostid = hid = nvmf_hostid_from_file();
+ if (!hostid && hostnqn)
+ hostid = hid = nvmf_hostid_from_hostnqn(hostnqn);
+ nvmf_check_hostid_and_hostnqn(hostid, hostnqn, verbose);
+ h = nvme_lookup_host(r, hostnqn, hostid);
+ if (!h) {
+ errno = ENOMEM;
+ goto out_free;
+ }
+ if (hostkey)
+ nvme_host_set_dhchap_key(h, hostkey);
+ if (!trsvcid)
+ trsvcid = get_default_trsvcid(transport, false);
+
+ struct tr_config trcfg = {
+ .subsysnqn = subsysnqn,
+ .transport = transport,
+ .traddr = traddr,
+ .host_traddr = cfg.host_traddr,
+ .host_iface = cfg.host_iface,
+ .trsvcid = trsvcid,
+ };
+
+ c = lookup_ctrl(h, &trcfg);
+ if (c && nvme_ctrl_get_name(c)) {
+ fprintf(stderr, "already connected\n");
+ errno = EALREADY;
+ goto out_free;
+ }
+
+ c = nvme_create_ctrl(r, subsysnqn, transport, traddr,
+ cfg.host_traddr, cfg.host_iface, trsvcid);
+ if (!c) {
+ errno = ENOMEM;
+ goto out_free;
+ }
+ if (ctrlkey)
+ nvme_ctrl_set_dhchap_key(c, ctrlkey);
+
+ errno = 0;
+ ret = nvmf_add_ctrl(h, c, &cfg);
+ if (ret)
+ fprintf(stderr, "could not add new controller: %s\n",
+ nvme_strerror(errno));
+ else {
+ errno = 0;
+ if (flags != -EINVAL)
+ nvme_show_connect_msg(c, flags);
+ }
+
+out_free:
+ free(hnqn);
+ free(hid);
+ if (dump_config)
+ nvme_dump_config(r);
+ nvme_free_tree(r);
+ return -errno;
+}
+
+static nvme_ctrl_t lookup_nvme_ctrl(nvme_root_t r, const char *name)
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ if (!strcmp(nvme_ctrl_get_name(c), name))
+ return c;
+ }
+ }
+ }
+ return NULL;
+}
+
+static void nvmf_disconnect_nqn(nvme_root_t r, char *nqn)
+{
+ int i = 0;
+ char *n = nqn;
+ char *p;
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+
+ while ((p = strsep(&n, ",")) != NULL) {
+ if (!strlen(p))
+ continue;
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ if (strcmp(nvme_subsystem_get_nqn(s), p))
+ continue;
+ nvme_subsystem_for_each_ctrl(s, c) {
+ if (!nvme_disconnect_ctrl(c))
+ i++;
+ }
+ }
+ }
+ }
+ printf("NQN:%s disconnected %d controller(s)\n", nqn, i);
+}
+
+int nvmf_disconnect(const char *desc, int argc, char **argv)
+{
+ const char *device = "nvme device handle";
+ nvme_root_t r;
+ nvme_ctrl_t c;
+ char *p;
+ int ret;
+
+ struct config {
+ char *nqn;
+ char *device;
+ unsigned int verbose;
+ };
+
+ struct config cfg = { 0 };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("nqn", 'n', "NAME", &cfg.nqn, nvmf_nqn),
+ OPT_STRING("device", 'd', "DEV", &cfg.device, device),
+ OPT_INCR("verbose", 'v', &cfg.verbose, "Increase logging verbosity"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ if (!cfg.nqn && !cfg.device) {
+ fprintf(stderr,
+ "Neither device name [--device | -d] nor NQN [--nqn | -n] provided\n");
+ return -EINVAL;
+ }
+
+ r = nvme_create_root(stderr, map_log_level(cfg.verbose, false));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+
+ if (cfg.nqn)
+ nvmf_disconnect_nqn(r, cfg.nqn);
+
+ if (cfg.device) {
+ char *d;
+
+ d = cfg.device;
+ while ((p = strsep(&d, ",")) != NULL) {
+ if (!strncmp(p, "/dev/", 5))
+ p += 5;
+ c = lookup_nvme_ctrl(r, p);
+ if (!c) {
+ fprintf(stderr,
+ "Did not find device %s\n", p);
+ nvme_free_tree(r);
+ return -errno;
+ }
+ ret = nvme_disconnect_ctrl(c);
+ if (ret)
+ fprintf(stderr,
+ "Failed to disconnect %s: %s\n",
+ p, nvme_strerror(errno));
+ }
+ }
+ nvme_free_tree(r);
+
+ return 0;
+}
+
+int nvmf_disconnect_all(const char *desc, int argc, char **argv)
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_root_t r;
+ nvme_ctrl_t c;
+ int ret;
+
+ struct config {
+ char *transport;
+ unsigned int verbose;
+ };
+
+ struct config cfg = { 0 };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("transport", 'r', "STR", (char *)&cfg.transport, nvmf_tport),
+ OPT_INCR("verbose", 'v', &cfg.verbose, "Increase logging verbosity"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_create_root(stderr, map_log_level(cfg.verbose, false));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ if (cfg.transport &&
+ strcmp(cfg.transport,
+ nvme_ctrl_get_transport(c)))
+ continue;
+ else if (!strcmp(nvme_ctrl_get_transport(c),
+ "pcie"))
+ continue;
+ if (nvme_disconnect_ctrl(c))
+ fprintf(stderr,
+ "failed to disconnect %s\n",
+ nvme_ctrl_get_name(c));
+ }
+ }
+ }
+ nvme_free_tree(r);
+
+ return 0;
+}
+
+int nvmf_config(const char *desc, int argc, char **argv)
+{
+ char *subsysnqn = NULL;
+ char *transport = NULL, *traddr = NULL;
+ char *trsvcid = NULL, *hostnqn = NULL, *hostid = NULL;
+ char *hnqn = NULL, *hid = NULL;
+ char *hostkey = NULL, *ctrlkey = NULL;
+ char *config_file = PATH_NVMF_CONFIG;
+ unsigned int verbose = 0;
+ nvme_root_t r;
+ int ret;
+ struct nvme_fabrics_config cfg;
+ bool scan_tree = false, modify_config = false, update_config = false;
+
+ NVMF_ARGS(opts, cfg,
+ OPT_STRING("dhchap-ctrl-secret", 'C', "STR", &ctrlkey, nvmf_ctrlkey),
+ OPT_STRING("config", 'J', "FILE", &config_file, nvmf_config_file),
+ OPT_INCR("verbose", 'v', &verbose, "Increase logging verbosity"),
+ OPT_FLAG("scan", 'R', &scan_tree, "Scan current NVMeoF topology"),
+ OPT_FLAG("modify", 'M', &modify_config, "Modify JSON configuration file"),
+ OPT_FLAG("dump", 'O', &dump_config, "Dump JSON configuration to stdout"),
+ OPT_FLAG("update", 'U', &update_config, "Update JSON configuration file"));
+
+ nvmf_default_config(&cfg);
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ if (!strcmp(config_file, "none"))
+ config_file = NULL;
+
+ r = nvme_create_root(stderr, map_log_level(verbose, quiet));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ if (scan_tree) {
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+ }
+ nvme_read_config(r, config_file);
+
+ if (modify_config) {
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+
+ if (!subsysnqn) {
+ fprintf(stderr,
+ "required argument [--nqn | -n] needed with --modify\n");
+ return -EINVAL;
+ }
+
+ if (!transport) {
+ fprintf(stderr,
+ "required argument [--transport | -t] needed with --modify\n");
+ return -EINVAL;
+ }
+
+ if (!hostnqn)
+ hostnqn = hnqn = nvmf_hostnqn_from_file();
+ if (!hostid && hnqn)
+ hostid = hid = nvmf_hostid_from_file();
+ h = nvme_lookup_host(r, hostnqn, hostid);
+ if (!h) {
+ fprintf(stderr, "Failed to lookup host '%s': %s\n",
+ hostnqn, nvme_strerror(errno));
+ goto out;
+ }
+ if (hostkey)
+ nvme_host_set_dhchap_key(h, hostkey);
+ s = nvme_lookup_subsystem(h, NULL, subsysnqn);
+ if (!s) {
+ fprintf(stderr, "Failed to lookup subsystem '%s': %s\n",
+ subsysnqn, nvme_strerror(errno));
+ goto out;
+ }
+ c = nvme_lookup_ctrl(s, transport, traddr,
+ cfg.host_traddr, cfg.host_iface,
+ trsvcid, NULL);
+ if (!c) {
+ fprintf(stderr, "Failed to lookup controller: %s\n",
+ nvme_strerror(errno));
+ goto out;
+ }
+ nvmf_update_config(c, &cfg);
+ if (ctrlkey)
+ nvme_ctrl_set_dhchap_key(c, ctrlkey);
+ }
+
+ if (update_config)
+ nvme_update_config(r);
+
+ if (dump_config)
+ nvme_dump_config(r);
+
+out:
+ if (hid)
+ free(hid);
+ if (hnqn)
+ free(hnqn);
+ nvme_free_tree(r);
+ return -errno;
+}
+
+static void dim_operation(nvme_ctrl_t c, enum nvmf_dim_tas tas, const char *name)
+{
+ static const char * const task[] = {
+ [NVMF_DIM_TAS_REGISTER] = "register",
+ [NVMF_DIM_TAS_DEREGISTER] = "deregister",
+ };
+ const char *t;
+ int status;
+ __u32 result;
+
+ t = (tas > NVMF_DIM_TAS_DEREGISTER || !task[tas]) ? "reserved" : task[tas];
+ status = nvmf_register_ctrl(c, tas, &result);
+ if (status == NVME_SC_SUCCESS) {
+ printf("%s DIM %s command success\n", name, t);
+ } else if (status < NVME_SC_SUCCESS) {
+ fprintf(stderr, "%s DIM %s command error. Status:0x%04x - %s\n",
+ name, t, status, nvme_status_to_string(status, false));
+ } else {
+ fprintf(stderr, "%s DIM %s command error. Result:0x%04x, Status:0x%04x - %s\n",
+ name, t, result, status, nvme_status_to_string(status, false));
+ }
+}
+
+int nvmf_dim(const char *desc, int argc, char **argv)
+{
+ enum nvmf_dim_tas tas;
+ nvme_root_t r;
+ nvme_ctrl_t c;
+ char *p;
+ int ret;
+
+ struct {
+ char *nqn;
+ char *device;
+ char *tas;
+ unsigned int verbose;
+ } cfg = { 0 };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("nqn", 'n', "NAME", &cfg.nqn, "Comma-separated list of DC nqn"),
+ OPT_STRING("device", 'd', "DEV", &cfg.device, "Comma-separated list of DC nvme device handle."),
+ OPT_STRING("task", 't', "TASK", &cfg.tas, "[register|deregister]"),
+ OPT_INCR("verbose", 'v', &cfg.verbose, "Increase logging verbosity"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ if (!cfg.nqn && !cfg.device) {
+ fprintf(stderr,
+ "Neither device name [--device | -d] nor NQN [--nqn | -n] provided\n");
+ return -EINVAL;
+ }
+
+ if (!cfg.tas) {
+ fprintf(stderr,
+ "Task [--task | -t] must be specified\n");
+ return -EINVAL;
+ }
+
+ /* Allow partial name (e.g. "reg" for "register" */
+ if (strstarts("register", cfg.tas)) {
+ tas = NVMF_DIM_TAS_REGISTER;
+ } else if (strstarts("deregister", cfg.tas)) {
+ tas = NVMF_DIM_TAS_DEREGISTER;
+ } else {
+ fprintf(stderr, "Invalid --task: %s\n", cfg.tas);
+ return -EINVAL;
+ }
+
+ r = nvme_create_root(stderr, map_log_level(cfg.verbose, false));
+ if (!r) {
+ fprintf(stderr, "Failed to create topology root: %s\n",
+ nvme_strerror(errno));
+ return -errno;
+ }
+ ret = nvme_scan_topology(r, NULL, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to scan topology: %s\n",
+ nvme_strerror(errno));
+ nvme_free_tree(r);
+ return ret;
+ }
+
+ if (cfg.nqn) {
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ char *n = cfg.nqn;
+
+ while ((p = strsep(&n, ",")) != NULL) {
+ if (!strlen(p))
+ continue;
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ if (strcmp(nvme_subsystem_get_nqn(s), p))
+ continue;
+ nvme_subsystem_for_each_ctrl(s, c) {
+ dim_operation(c, tas, p);
+ }
+ }
+ }
+ }
+ }
+
+ if (cfg.device) {
+ char *d = cfg.device;
+
+ while ((p = strsep(&d, ",")) != NULL) {
+ if (!strncmp(p, "/dev/", 5))
+ p += 5;
+ c = nvme_scan_ctrl(r, p);
+ if (!c) {
+ fprintf(stderr,
+ "Did not find device %s: %s\n",
+ p, nvme_strerror(errno));
+ nvme_free_tree(r);
+ return -errno;
+ }
+ dim_operation(c, tas, p);
+ }
+ }
+
+ nvme_free_tree(r);
+
+ return 0;
+}
diff --git a/fabrics.h b/fabrics.h
new file mode 100644
index 0000000..c16df60
--- /dev/null
+++ b/fabrics.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _FABRICS_H
+#define _FABRICS_H
+
+struct tr_config {
+ const char *subsysnqn;
+ const char *transport;
+ const char *traddr;
+ const char *host_traddr;
+ const char *host_iface;
+ const char *trsvcid;
+};
+
+extern nvme_ctrl_t lookup_ctrl(nvme_host_t h, struct tr_config *trcfg);
+extern int nvmf_discover(const char *desc, int argc, char **argv, bool connect);
+extern int nvmf_connect(const char *desc, int argc, char **argv);
+extern int nvmf_disconnect(const char *desc, int argc, char **argv);
+extern int nvmf_disconnect_all(const char *desc, int argc, char **argv);
+extern int nvmf_config(const char *desc, int argc, char **argv);
+extern int nvmf_dim(const char *desc, int argc, char **argv);
+
+#endif
diff --git a/libnvme-wrap.c b/libnvme-wrap.c
new file mode 100644
index 0000000..b5b4838
--- /dev/null
+++ b/libnvme-wrap.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * This file is part of nvme-cli
+ *
+ * Copyright (c) 2022 Daniel Wagner, SUSE
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <libnvme.h>
+#include "nvme-print.h"
+
+#define PROTO(args...) args
+#define ARGS(args...) args
+
+#define VOID_FN(name, proto, args) \
+void __attribute__((weak)) name(proto) \
+{ \
+ void (*fn)(proto); \
+ fn = dlsym(RTLD_NEXT, #name); \
+ if (!fn) { \
+ nvme_show_error("libnvme function " #name " not found");\
+ exit(EXIT_FAILURE); \
+ } \
+ fn(args); \
+}
+
+#define FN(name, rtype, proto, args, defret) \
+rtype __attribute__((weak)) name(proto) \
+{ \
+ rtype (*fn)(proto); \
+ fn = dlsym(RTLD_NEXT, #name); \
+ if (fn) \
+ return fn(args); \
+ return defret; \
+}
+
+FN(nvme_get_version,
+ const char *, PROTO(enum nvme_version type),
+ ARGS(type), "n/a")
+
+VOID_FN(nvme_init_copy_range_f1,
+ PROTO(struct nvme_copy_range_f1 *copy, __u16 *nlbs,
+ __u64 *slbas, __u64 *eilbrts, __u32 *elbatms,
+ __u32 *elbats, __u16 nr),
+ ARGS(copy, nlbs, slbas, eilbrts, elbatms, elbats, nr))
+
+VOID_FN(nvme_init_copy_range_f2,
+ PROTO(struct nvme_copy_range_f2 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u32 *eilbrts,
+ __u32 *elbatms, __u32 *elbats, __u16 nr),
+ ARGS(copy, snsids, nlbs, slbas, sopts, eilbrts, elbatms, elbats, nr))
+
+VOID_FN(nvme_init_copy_range_f3,
+ PROTO(struct nvme_copy_range_f3 *copy, __u32 *snsids,
+ __u16 *nlbs, __u64 *slbas, __u16 *sopts, __u64 *eilbrts,
+ __u32 *elbatms, __u32 *elbats, __u16 nr),
+ ARGS(copy, snsids, nlbs, slbas, sopts, eilbrts, elbatms, elbats, nr))
+
+FN(nvme_get_feature_length2,
+ int,
+ PROTO(int fid, __u32 cdw11, enum nvme_data_tfr dir,
+ __u32 *len),
+ ARGS(fid, cdw11, dir, len),
+ -EEXIST)
+
+FN(nvme_ctrl_is_persistent,
+ bool,
+ PROTO(nvme_ctrl_t c),
+ ARGS(c),
+ false)
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..1b31603
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,358 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+################################################################################
+project(
+ 'nvme-cli', ['c'],
+ meson_version: '>= 0.50.0',
+ license: 'GPL-2.0-only',
+ version: '2.8',
+ default_options: [
+ 'c_std=gnu99',
+ 'buildtype=debug',
+ 'prefix=/usr/local',
+ 'warning_level=1',
+ 'sysconfdir=etc',
+ 'wrap_mode=nofallback',
+ ]
+)
+
+################################################################################
+cc = meson.get_compiler('c')
+
+prefixdir = get_option('prefix')
+datadir = join_paths(prefixdir, get_option('datadir'))
+mandir = join_paths(prefixdir, get_option('mandir'))
+sbindir = join_paths(prefixdir, get_option('sbindir'))
+sysconfdir = join_paths(prefixdir, get_option('sysconfdir'))
+
+udevrulesdir = join_paths(prefixdir, get_option('udevrulesdir'))
+dracutrulesdir = join_paths(prefixdir, get_option('dracutrulesdir'))
+systemddir = join_paths(prefixdir, get_option('systemddir'))
+rundir = join_paths(prefixdir, get_option('rundir'))
+
+###############################################################################
+conf = configuration_data()
+requires = ''
+
+version_tag = get_option('version-tag')
+if version_tag != ''
+ conf.set('GIT_VERSION', '"@0@"'.format(version_tag))
+else
+ r = run_command('scripts/meson-vcs-tag.sh',
+ meson.current_source_dir(),
+ meson.project_version(),
+ check: true)
+ conf.set('GIT_VERSION', '"@0@"'.format(r.stdout().strip()))
+endif
+
+conf.set('SYSCONFDIR', '"@0@"'.format(sysconfdir))
+conf.set('RUNDIR', '"@0@"'.format(rundir))
+
+# Check for libnvme availability
+libnvme_dep = dependency('libnvme', version: '>=1.8', required: true,
+ fallback : ['libnvme', 'libnvme_dep'])
+libnvme_mi_dep = dependency('libnvme-mi', required: true,
+ fallback : ['libnvme', 'libnvme_mi_dep'])
+
+# Check for libjson-c availability
+if get_option('json-c').disabled()
+ json_c_dep = dependency('', required: false)
+else
+ json_c_dep = dependency('json-c', required: get_option('json-c'), version: '>=0.13',
+ fallback : ['json-c', 'json_c_dep'])
+ if json_c_dep.version().version_compare('>=0.14')
+ conf.set('CONFIG_JSONC_14', true, description: 'Is json-c at least 0.14?')
+ requires = 'Requires: json-c >= 0.14'
+ else
+ requires = 'Requires: json-c >= 0.13'
+ endif
+endif
+conf.set('CONFIG_JSONC', json_c_dep.found(), description: 'Is json-c available?')
+
+# Set the nvme-cli version
+conf.set('NVME_VERSION', '"' + meson.project_version() + '"')
+
+conf.set10('DEFAULT_PDC_ENABLED', get_option('pdc-enabled'))
+
+# local (cross-compilable) implementations of ccan configure steps
+conf.set10(
+ 'HAVE_BUILTIN_TYPES_COMPATIBLE_P',
+ cc.compiles(
+ '''int main(void) {
+ return __builtin_types_compatible_p(int, long);
+ }
+ ''',
+ name: '__builtin_type_compatible_p'
+ ),
+ description: 'Is __builtin_types_compatible_p available?'
+)
+conf.set10(
+ 'HAVE_TYPEOF',
+ cc.compiles(
+ '''int main(void) {
+ int a = 1;
+ typeof(a) b;
+ b = a;
+ }
+ ''',
+ name: 'typeof'
+ ),
+ description: 'Is typeof available?'
+)
+conf.set10(
+ 'HAVE_BYTESWAP_H',
+ cc.compiles(
+ '''#include <byteswap.h>''',
+ name: 'byteswap.h'
+ ),
+ description: 'Is byteswap.h include-able?'
+)
+conf.set10(
+ 'HAVE_BSWAP_64',
+ cc.links(
+ '''#include <byteswap.h>
+ int main(void) {
+ return bswap_64(0);
+ }
+ ''',
+ name: 'bswap64'
+ ),
+ description: 'Is bswap_64 available?'
+)
+conf.set10(
+ 'HAVE_LITTLE_ENDIAN',
+ host_machine.endian() == 'little',
+ description: 'Building for little-endian'
+)
+conf.set10(
+ 'HAVE_BIG_ENDIAN',
+ host_machine.endian() == 'big',
+ description: 'Building for big-endian'
+)
+conf.set10(
+ 'HAVE_ISBLANK',
+ cc.links(
+ '''#include <ctype.h>
+ int main(int argc, char **argv) {
+ return isblank(argv[0][0]);
+ }
+ ''',
+ name: 'isblank'
+ ),
+ description: 'Is isblank() available?'
+)
+conf.set10(
+ 'HAVE_SYS_RANDOM',
+ cc.compiles(
+ '''#include <sys/random.h>''',
+ name: 'sys/random.h'
+ ),
+ description: 'Is sys/random.h(getrandom) include-able?'
+)
+conf.set10(
+ 'HAVE_ATTRIBUTE_UNUSED',
+ cc.get_id() == 'clang',
+ description: 'Is compiler warning about unused static line function?'
+)
+conf.set10(
+ 'HAVE_SED_OPAL',
+ cc.compiles(
+ '''#include <linux/sed-opal.h>''',
+ name: 'linux/sed-opal.h'
+
+ ),
+ description: 'Is linux/sed-opa.h include-able?'
+)
+conf.set10(
+ 'HAVE_KEY_TYPE',
+ cc.compiles(
+ '''
+ #include <linux/sed-opal.h>
+ int main(void) {
+ struct opal_key key;
+ key.key_type = OPAL_INCLUDED;
+ }
+ ''',
+ name: 'key_type'
+ ),
+ description: 'Does struct opal_key have a key_type field?'
+)
+
+if cc.has_function_attribute('fallthrough')
+ conf.set('fallthrough', '__attribute__((__fallthrough__))')
+else
+ conf.set('fallthrough', 'do {} while (0) /* fallthrough */')
+endif
+
+configure_file(
+ output: 'config.h',
+ configuration: conf
+)
+
+################################################################################
+libtype = get_option('default_library')
+if libtype == 'static'
+ requires = ''
+endif
+
+substs = configuration_data()
+substs.set('NAME', meson.project_name())
+substs.set('VERSION', meson.project_version())
+substs.set('LICENSE', meson.project_license()[0])
+substs.set('UDEVRULESDIR', udevrulesdir)
+substs.set('DRACUTRILESDIR', dracutrulesdir)
+substs.set('REQUIRES', requires)
+substs.set('DATADIR', datadir)
+substs.set('MANDIR', mandir)
+substs.set('RUNDIR', rundir)
+substs.set('SBINDIR', sbindir)
+substs.set('SYSCONFDIR', sysconfdir)
+substs.set('SYSTEMDDIR', systemddir)
+substs.set('SYSTEMCTL', get_option('systemctl'))
+
+configure_file(
+ input: 'nvme.spec.in',
+ output: 'nvme.spec',
+ configuration: substs,
+)
+
+disc = configure_file(
+ input: 'etc/discovery.conf.in',
+ output: 'discovery.conf',
+ configuration: substs,
+)
+
+dracut_files = [
+ '70-nvmf-autoconnect.conf',
+]
+
+foreach file : dracut_files
+ configure_file(
+ input: 'nvmf-autoconnect/dracut-conf/' + file + '.in',
+ output: file,
+ configuration: substs,
+ )
+endforeach
+
+systemd_files = [
+ 'nvmefc-boot-connections.service',
+ 'nvmf-autoconnect.service',
+ 'nvmf-connect-nbft.service',
+ 'nvmf-connect.target',
+ 'nvmf-connect@.service',
+]
+
+foreach file : systemd_files
+ configure_file(
+ input: 'nvmf-autoconnect/systemd/' + file + '.in',
+ output: file,
+ configuration: substs,
+ )
+endforeach
+
+udev_files = [
+ '65-persistent-net-nbft.rules',
+ '70-nvmf-autoconnect.rules',
+ '71-nvmf-netapp.rules',
+]
+
+foreach file : udev_files
+ configure_file(
+ input: 'nvmf-autoconnect/udev-rules/' + file + '.in',
+ output: file,
+ configuration: substs,
+ )
+endforeach
+
+################################################################################
+add_project_arguments(['-fomit-frame-pointer', '-D_GNU_SOURCE',
+ '-include', 'config.h'], language : 'c')
+incdir = include_directories(['ccan'])
+
+################################################################################
+sources = [
+ 'nbft.c',
+ 'fabrics.c',
+ 'nvme.c',
+ 'nvme-models.c',
+ 'nvme-print.c',
+ 'nvme-print-stdout.c',
+ 'nvme-print-binary.c',
+ 'nvme-rpmb.c',
+ 'nvme-wrap.c',
+ 'plugin.c',
+ 'libnvme-wrap.c',
+]
+if json_c_dep.found()
+ sources += [
+ 'nvme-print-json.c',
+ ]
+endif
+
+subdir('ccan')
+subdir('plugins')
+subdir('unit')
+if get_option('nvme-tests')
+ subdir('tests')
+endif
+subdir('util')
+subdir('Documentation')
+
+executable(
+ 'nvme',
+ sources,
+ dependencies: [ libnvme_dep, libnvme_mi_dep, json_c_dep ],
+ link_args: '-ldl',
+ include_directories: incdir,
+ install: true,
+ install_dir: sbindir
+)
+
+################################################################################
+install_data('completions/bash-nvme-completion.sh',
+ rename: 'nvme',
+ install_dir: datadir + '/bash-completion/completions')
+install_data('completions/_nvme',
+ install_dir: datadir + '/zsh/site-functions')
+
+foreach file : dracut_files
+ install_data(meson.current_build_dir() + '/' + file,
+ install_dir: dracutrulesdir)
+endforeach
+
+foreach file : systemd_files
+ install_data(meson.current_build_dir() + '/' + file,
+ install_dir: systemddir)
+endforeach
+
+foreach file : udev_files
+ install_data(meson.current_build_dir() + '/' + file,
+ install_dir: udevrulesdir)
+endforeach
+
+install_data(disc,
+ install_dir: join_paths(sysconfdir, 'nvme'))
+
+################################################################################
+if meson.version().version_compare('>=0.53.0')
+ path_dict = {
+ 'prefixdir': prefixdir,
+ 'sysconfdir': sysconfdir,
+ 'sbindir': sbindir,
+ 'datadir': datadir,
+ 'mandir': mandir,
+ 'udevrulesdir': udevrulesdir,
+ 'dracutrulesdir': dracutrulesdir,
+ 'rundir': rundir,
+ 'systemddir': systemddir,
+ 'build location': meson.current_build_dir(),
+ }
+ summary(path_dict, section: 'Paths')
+ dep_dict = {
+ 'json-c': json_c_dep.found(),
+ }
+ summary(dep_dict, section: 'Dependencies')
+ conf_dict = {
+ 'pdc enabled': get_option('pdc-enabled')
+ }
+ summary(conf_dict, section: 'Configuration')
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..c61dae0
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+option(
+ 'docs',
+ type : 'combo',
+ choices : ['false', 'html', 'man', 'all'],
+ description : 'install documentation'
+)
+option(
+ 'docs-build',
+ type : 'boolean',
+ value : false,
+ description : 'build documentation'
+)
+option(
+ 'dracutrulesdir',
+ type : 'string',
+ value : 'lib/dracut/dracut.conf.d/',
+ description : 'directory for dracut rules files'
+)
+option(
+ 'htmldir',
+ type : 'string',
+ value : '',
+ description : 'directory for HTML documentation'
+)
+option(
+ 'json-c',
+ type: 'feature',
+ value: 'auto',
+ description: 'JSON suppport'
+)
+option(
+ 'nvme-tests',
+ type : 'boolean',
+ value : false,
+ description: 'Run tests against real hardware'
+)
+option(
+ 'pdc-enabled',
+ type: 'boolean',
+ value : false,
+ description : 'set default Persistent Discovery Controllers behavior'
+)
+option(
+ 'rundir',
+ type: 'string',
+ value: 'run',
+ description: 'directory for volatile configuration files',
+)
+option(
+ 'systemctl',
+ type : 'string',
+ value : '/usr/bin/systemctl',
+ description : 'path to systemctl binary'
+)
+option(
+ 'systemddir',
+ type : 'string',
+ value : 'lib/systemd/system',
+ description : 'directory for systemd files'
+)
+option(
+ 'udevrulesdir',
+ type : 'string',
+ value : 'lib/udev/rules.d',
+ description : 'directory for udev rules files'
+)
+option(
+ 'version-tag',
+ type : 'string',
+ description : 'override the git version string'
+)
diff --git a/nbft.c b/nbft.c
new file mode 100644
index 0000000..ff36119
--- /dev/null
+++ b/nbft.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <errno.h>
+#include <stdio.h>
+#include <fnmatch.h>
+#include <stdlib.h>
+
+#include <libnvme.h>
+
+#include "nvme.h"
+#include "nbft.h"
+#include "fabrics.h"
+#include "nvme-print.h"
+
+#include "util/types.h"
+
+#define NBFT_SYSFS_FILENAME "NBFT*"
+
+static void print_connect_msg(nvme_ctrl_t c)
+{
+ printf("device: %s\n", nvme_ctrl_get_name(c));
+}
+
+static void json_connect_msg(nvme_ctrl_t c)
+{
+#ifdef CONFIG_JSONC
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_string(root, "device", nvme_ctrl_get_name(c));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+#endif
+}
+
+int nbft_filter(const struct dirent *dent)
+{
+ return !fnmatch(NBFT_SYSFS_FILENAME, dent->d_name, FNM_PATHNAME);
+}
+
+int read_nbft_files(struct list_head *nbft_list, char *path)
+{
+ struct dirent **dent;
+ char filename[PATH_MAX];
+ int i, count, ret;
+ struct nbft_file_entry *entry;
+ struct nbft_info *nbft;
+
+ count = scandir(path, &dent, nbft_filter, NULL);
+ if (count < 0)
+ return -errno;
+
+ for (i = 0; i < count; i++) {
+ snprintf(filename, sizeof(filename), "%s/%s", path, dent[i]->d_name);
+ ret = nvme_nbft_read(&nbft, filename);
+ if (!ret) {
+ entry = calloc(1, sizeof(*entry));
+ entry->nbft = nbft;
+ list_add_tail(nbft_list, &entry->node);
+ }
+ free(dent[i]);
+ }
+ free(dent);
+ return 0;
+}
+
+void free_nbfts(struct list_head *nbft_list)
+{
+ struct nbft_file_entry *entry;
+
+ while ((entry = list_pop(nbft_list, struct nbft_file_entry, node))) {
+ nvme_nbft_free(entry->nbft);
+ free(entry);
+ }
+}
+
+int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg,
+ char *hostnqn_sys, char *hostid_sys,
+ const char *desc, bool connect,
+ const struct nvme_fabrics_config *cfg, char *nbft_path,
+ enum nvme_print_flags flags, bool verbose)
+{
+ char *hostnqn = NULL, *hostid = NULL, *host_traddr = NULL;
+ nvme_host_t h;
+ nvme_ctrl_t c;
+ int ret, i;
+ struct list_head nbft_list;
+ struct nbft_file_entry *entry;
+ struct nbft_info_subsystem_ns **ss;
+ struct nbft_info_hfi *hfi;
+
+ if (!connect)
+ /* to do: print discovery-type info from NBFT tables */
+ return 0;
+
+ list_head_init(&nbft_list);
+ ret = read_nbft_files(&nbft_list, nbft_path);
+ if (ret) {
+ if (ret != ENOENT)
+ nvme_show_perror("Failed to access ACPI tables directory");
+ goto out_free_2;
+ }
+
+ list_for_each(&nbft_list, entry, node)
+ for (ss = entry->nbft->subsystem_ns_list; ss && *ss; ss++)
+ for (i = 0; i < (*ss)->num_hfis; i++) {
+ nvme_ctrl_t cl;
+
+ hfi = (*ss)->hfis[i];
+ if (hostnqn_arg)
+ hostnqn = hostnqn_arg;
+ else {
+ hostnqn = entry->nbft->host.nqn;
+ if (!hostnqn)
+ hostnqn = hostnqn_sys;
+ }
+
+ if (hostid_arg)
+ hostid = hostid_arg;
+ else if (*entry->nbft->host.id) {
+ hostid = (char *)util_uuid_to_string(entry->nbft->host.id);
+ if (!hostid)
+ hostid = hostid_sys;
+ }
+
+ h = nvme_lookup_host(r, hostnqn, hostid);
+ if (!h) {
+ errno = ENOMEM;
+ goto out_free;
+ }
+
+ if (!cfg->host_traddr) {
+ host_traddr = NULL;
+ if (!strncmp((*ss)->transport, "tcp", 3))
+ host_traddr = hfi->tcp_info.ipaddr;
+ }
+
+ struct tr_config trcfg = {
+ .subsysnqn = (*ss)->subsys_nqn,
+ .transport = (*ss)->transport,
+ .traddr = (*ss)->traddr,
+ .host_traddr = host_traddr,
+ .host_iface = NULL,
+ .trsvcid = (*ss)->trsvcid,
+ };
+
+ /* Already connected ? */
+ cl = lookup_ctrl(h, &trcfg);
+ if (cl && nvme_ctrl_get_name(cl))
+ continue;
+
+ c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport,
+ (*ss)->traddr, host_traddr, NULL,
+ (*ss)->trsvcid);
+ if (!c) {
+ errno = ENOMEM;
+ goto out_free;
+ }
+
+ errno = 0;
+ ret = nvmf_add_ctrl(h, c, cfg);
+
+ /*
+ * With TCP/DHCP, it can happen that the OS
+ * obtains a different local IP address than the
+ * firmware had. Retry without host_traddr.
+ */
+ if (ret == -1 && errno == ENVME_CONNECT_ADDRNOTAVAIL &&
+ !strcmp((*ss)->transport, "tcp") &&
+ strlen(hfi->tcp_info.dhcp_server_ipaddr) > 0) {
+ nvme_free_ctrl(c);
+
+ trcfg.host_traddr = NULL;
+ cl = lookup_ctrl(h, &trcfg);
+ if (cl && nvme_ctrl_get_name(cl))
+ continue;
+
+ c = nvme_create_ctrl(r, (*ss)->subsys_nqn, (*ss)->transport,
+ (*ss)->traddr,
+ NULL, NULL, (*ss)->trsvcid);
+ if (!c) {
+ errno = ENOMEM;
+ goto out_free;
+ }
+ errno = 0;
+ ret = nvmf_add_ctrl(h, c, cfg);
+ if (ret == 0 && verbose >= 1)
+ fprintf(stderr,
+ "connect with host_traddr=\"%s\" failed, success after omitting host_traddr\n",
+ host_traddr);
+ }
+
+ if (ret)
+ fprintf(stderr, "no controller found\n");
+ else {
+ if (flags == NORMAL)
+ print_connect_msg(c);
+ else if (flags == JSON)
+ json_connect_msg(c);
+ }
+out_free:
+ if (errno == ENOMEM)
+ goto out_free_2;
+ }
+out_free_2:
+ free_nbfts(&nbft_list);
+ return errno;
+}
diff --git a/nbft.h b/nbft.h
new file mode 100644
index 0000000..0e09733
--- /dev/null
+++ b/nbft.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <ccan/list/list.h>
+
+#define NBFT_SYSFS_PATH "/sys/firmware/acpi/tables"
+
+struct nbft_file_entry {
+ struct list_node node;
+ struct nbft_info *nbft;
+};
+
+int read_nbft_files(struct list_head *nbft_list, char *path);
+void free_nbfts(struct list_head *nbft_list);
+
+extern int discover_from_nbft(nvme_root_t r, char *hostnqn_arg, char *hostid_arg,
+ char *hostnqn_sys, char *hostid_sys,
+ const char *desc, bool connect,
+ const struct nvme_fabrics_config *cfg, char *nbft_path,
+ enum nvme_print_flags flags, bool verbose);
diff --git a/nvme-builtin.h b/nvme-builtin.h
new file mode 100644
index 0000000..2d2bead
--- /dev/null
+++ b/nvme-builtin.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE nvme-builtin
+
+#if !defined(NVME_BUILTIN) || defined(CMD_HEADER_MULTI_READ)
+#define NVME_BUILTIN
+
+#include "cmd.h"
+
+COMMAND_LIST(
+ ENTRY("list", "List all NVMe devices and namespaces on machine", list)
+ ENTRY("list-subsys", "List nvme subsystems", list_subsys)
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ ENTRY("id-ns", "Send NVMe Identify Namespace, display structure", id_ns)
+ ENTRY("id-ns-granularity", "Send NVMe Identify Namespace Granularity List, display structure", id_ns_granularity)
+ ENTRY("id-ns-lba-format", "Send NVMe Identify Namespace for the specified LBA Format index, display structure", id_ns_lba_format)
+ ENTRY("list-ns", "Send NVMe Identify List, display structure", list_ns)
+ ENTRY("list-ctrl", "Send NVMe Identify Controller List, display structure", list_ctrl)
+ ENTRY("nvm-id-ctrl", "Send NVMe Identify Controller NVM Command Set, display structure", nvm_id_ctrl)
+ ENTRY("nvm-id-ns", "Send NVMe Identify Namespace NVM Command Set, display structure", nvm_id_ns)
+ ENTRY("nvm-id-ns-lba-format", "Send NVMe Identify Namespace NVM Command Set for the specified LBA Format index, display structure", nvm_id_ns_lba_format)
+ ENTRY("primary-ctrl-caps", "Send NVMe Identify Primary Controller Capabilities", primary_ctrl_caps)
+ ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl)
+ ENTRY("cmdset-ind-id-ns", "I/O Command Set Independent Identify Namespace", cmd_set_independent_id_ns)
+ 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("id-domain", "Send NVMe Identify Domain List, display structure", id_domain)
+ ENTRY("list-endgrp", "Send NVMe Identify Endurance Group List, display structure", id_endurance_grp_list)
+ 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)
+ ENTRY("detach-ns", "Detaches a namespace from requested controller(s)", detach_ns)
+ ENTRY("get-ns-id", "Retrieve the namespace ID of opened block device", get_ns_id)
+ ENTRY("get-log", "Generic NVMe get log, returns log in raw format", get_log)
+ ENTRY("telemetry-log", "Retrieve FW Telemetry log write to file", get_telemetry_log)
+ ENTRY("fw-log", "Retrieve FW Log, show it", get_fw_log)
+ ENTRY("changed-ns-list-log", "Retrieve Changed Namespace List, show it", get_changed_ns_list_log)
+ ENTRY("smart-log", "Retrieve SMART Log, show it", get_smart_log)
+ ENTRY("ana-log", "Retrieve ANA Log, show it", get_ana_log)
+ 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 Persistent 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("boot-part-log", "Retrieve Boot Partition Log, show it", get_boot_part_log)
+ ENTRY("phy-rx-eom-log", "Retrieve Physical Interface Receiver Eye Opening Measurement, show it", get_phy_rx_eom_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)
+ ENTRY("supported-log-pages", "Retrieve the Supported Log pages details, show it", get_supported_log_pages)
+ ENTRY("fid-support-effects-log", "Retrieve FID Support and Effects log and show it", get_fid_support_effects_log)
+ ENTRY("mi-cmd-support-effects-log", "Retrieve MI Command Support and Effects log and show it", get_mi_cmd_support_effects_log)
+ ENTRY("media-unit-stat-log", "Retrieve the configuration and wear of media units, show it", get_media_unit_stat_log)
+ ENTRY("supported-cap-config-log", "Retrieve the list of Supported Capacity Configuration Descriptors", get_supp_cap_config_log)
+ ENTRY("set-feature", "Set a feature and show the resulting value", set_feature)
+ ENTRY("set-property", "Set a property and show the resulting value", set_property)
+ ENTRY("get-property", "Get a property and show the resulting value", get_property)
+ ENTRY("format", "Format namespace with new block format", format_cmd)
+ ENTRY("fw-commit", "Verify and commit firmware to a specific slot (fw-activate in old version < 1.2)", fw_commit, "fw-activate")
+ ENTRY("fw-download", "Download new firmware", fw_download)
+ ENTRY("admin-passthru", "Submit an arbitrary admin command, return results", admin_passthru)
+ ENTRY("io-passthru", "Submit an arbitrary IO command, return results", io_passthru)
+ ENTRY("security-send", "Submit a Security Send command, return results", sec_send)
+ ENTRY("security-recv", "Submit a Security Receive command, return results", sec_recv)
+ ENTRY("get-lba-status", "Submit a Get LBA Status command, return results", get_lba_status)
+ ENTRY("capacity-mgmt", "Submit Capacity Management Command, return results", capacity_mgmt)
+ ENTRY("resv-acquire", "Submit a Reservation Acquire, return results", resv_acquire)
+ ENTRY("resv-register", "Submit a Reservation Register, return results", resv_register)
+ ENTRY("resv-release", "Submit a Reservation Release, return results", resv_release)
+ 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_cmd)
+ ENTRY("flush", "Submit a Flush command, return results", flush_cmd)
+ ENTRY("compare", "Submit a Compare command, return results", compare)
+ ENTRY("read", "Submit a read command, return results", read_cmd)
+ ENTRY("write", "Submit a write command, return results", write_cmd)
+ ENTRY("write-zeroes", "Submit a write zeroes command, return results", write_zeroes)
+ ENTRY("write-uncor", "Submit a write uncorrectable command, return results", write_uncor)
+ ENTRY("verify", "Submit a verify command, return results", verify_cmd)
+ ENTRY("sanitize", "Submit a sanitize command", sanitize_cmd)
+ ENTRY("sanitize-log", "Retrieve sanitize log, show it", sanitize_log)
+ ENTRY("reset", "Resets the controller", reset)
+ ENTRY("subsystem-reset", "Resets the subsystem", subsystem_reset)
+ ENTRY("ns-rescan", "Rescans the NVME namespaces", ns_rescan)
+ ENTRY("show-regs", "Shows the controller registers or properties. Requires character device", show_registers)
+ ENTRY("discover", "Discover NVMeoF subsystems", discover_cmd)
+ ENTRY("connect-all", "Discover and Connect to NVMeoF subsystems", connect_all_cmd)
+ ENTRY("connect", "Connect to NVMeoF subsystem", connect_cmd)
+ ENTRY("disconnect", "Disconnect from NVMeoF subsystem", disconnect_cmd)
+ ENTRY("disconnect-all", "Disconnect from all connected NVMeoF subsystems", disconnect_all_cmd)
+ ENTRY("config", "Configuration of NVMeoF subsystems", config_cmd)
+ ENTRY("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd)
+ ENTRY("show-hostnqn", "Show NVMeoF host NQN", show_hostnqn_cmd)
+ ENTRY("gen-dhchap-key", "Generate NVMeoF DH-HMAC-CHAP host key", gen_dhchap_key)
+ ENTRY("check-dhchap-key", "Validate NVMeoF DH-HMAC-CHAP host key", check_dhchap_key)
+ ENTRY("gen-tls-key", "Generate NVMeoF TLS PSK", gen_tls_key)
+ ENTRY("check-tls-key", "Validate NVMeoF TLS PSK", check_tls_key)
+ 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)
+ ENTRY("lockdown", "Submit a Lockdown command,return result", lockdown_cmd)
+ ENTRY("dim", "Send Discovery Information Management command to a Discovery Controller", dim_cmd) \
+ ENTRY("show-topology", "Show the topology", show_topology_cmd) \
+ ENTRY("io-mgmt-recv", "I/O Management Receive", io_mgmt_recv)
+ ENTRY("io-mgmt-send", "I/O Management Send", io_mgmt_send)
+ ENTRY("nvme-mi-recv", "Submit a NVMe-MI Receive command, return results", nmi_recv)
+ ENTRY("nvme-mi-send", "Submit a NVMe-MI Send command, return results", nmi_send)
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/nvme-models.c b/nvme-models.c
new file mode 100644
index 0000000..f638e4d
--- /dev/null
+++ b/nvme-models.c
@@ -0,0 +1,357 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "nvme-models.h"
+
+static char *_fmt1 = "/sys/class/nvme/nvme%d/device/subsystem_vendor";
+static char *_fmt2 = "/sys/class/nvme/nvme%d/device/subsystem_device";
+static char *_fmt3 = "/sys/class/nvme/nvme%d/device/vendor";
+static char *_fmt4 = "/sys/class/nvme/nvme%d/device/device";
+static char *_fmt5 = "/sys/class/nvme/nvme%d/device/class";
+
+static char fmt1[78];
+static char fmt2[78];
+static char fmt3[78];
+static char fmt4[78];
+static char fmt5[78];
+
+static char *device_top;
+static char *device_mid;
+static char *device_final;
+static char *class_top;
+static char *class_mid;
+static char *class_final;
+
+
+
+static void free_all(void)
+{
+ free(device_top);
+ device_top = NULL;
+ free(device_mid);
+ device_mid = NULL;
+ free(device_final);
+ device_final = NULL;
+ free(class_top);
+ class_top = NULL;
+ free(class_mid);
+ class_mid = NULL;
+ free(class_final);
+ class_final = NULL;
+}
+
+static char *find_data(char *data)
+{
+ while (*data != '\0') {
+ if (*data >= '0' && *data <= '9')
+ return data;
+ data++;
+ }
+ return NULL;
+}
+
+static char *locate_info(char *data, bool is_inner, bool is_class)
+{
+ char *orig = data;
+ char *locate;
+ if (!data)
+ return orig;
+
+ locate = find_data(data);
+ if (!locate)
+ return orig;
+ if (is_class)
+ return locate + 4;
+ if (!is_inner)
+ /* 4 to get over the number, 2 for spaces */
+ return locate + 4 + 2;
+
+ /* Inner data, has "sub_ven(space)sub_dev(space)(space)string */
+ return locate + 4 + 1 + 4 + 2;
+}
+
+static void format_and_print(char *save)
+{
+
+ if (!class_mid) {
+ if (device_final)
+ snprintf(save, 1024, "%s %s %s",
+ locate_info(device_top, false, false),
+ locate_info(device_mid, false, false),
+ locate_info(device_final, true, false));
+ else
+ snprintf(save, 1024, "%s %s",
+ locate_info(device_top, false, false),
+ locate_info(device_mid, false, false));
+ } else {
+ if (device_final)
+ snprintf(save, 1024, "%s: %s %s %s",
+ locate_info(class_mid, false, true),
+ locate_info(device_top, false, false),
+ locate_info(device_mid, false, false),
+ locate_info(device_final, true, false));
+ else
+ snprintf(save, 1024, "%s: %s %s",
+ locate_info(class_mid, false, true),
+ locate_info(device_top, false, false),
+ locate_info(device_mid, false, false));
+ }
+}
+
+static void format_all(char *save, char *vendor, char *device)
+{
+ if (device_top && device_mid)
+ format_and_print(save);
+
+ else if (device_top && !device_mid && class_mid)
+ snprintf(save, 1024, "%s: %s Device %s",
+ locate_info(class_mid, false, true),
+ locate_info(device_top, false, false),
+ device);
+
+ else if (!device_top && class_mid)
+ snprintf(save, 1024, "%s: Vendor %s Device %s",
+ locate_info(class_mid, false, true),
+ vendor,
+ device);
+ else
+ snprintf(save, 1024, "Unknown device");
+}
+
+static int is_final_match(char *line, char *search)
+{
+ return !memcmp(&line[2], search, 2);
+}
+
+static int is_inner_sub_vendev(char *line, char *search, char *search2)
+{
+ char combine[10];
+ snprintf(combine, sizeof(combine), "%s %s", &search[2], &search2[2]);
+ if (line[0] != '\t' && line[1] != '\t')
+ return 0;
+
+ return !memcmp(combine, &line[2], 9);
+}
+
+static int is_mid_level_match(char *line, char *device, bool class)
+{
+ if (!class)
+ return !memcmp(&line[1], &device[2], 4);
+
+ return !memcmp(&line[1], device, 2);
+}
+
+static inline bool is_comment(char *line)
+{
+ return line[0] == '#';
+}
+
+static int is_top_level_match(char *line, const char* device, bool class)
+{
+ if (line[0] == '\t')
+ return false;
+ if (line[0] == '#')
+ return false;
+ if (!class)
+ return !memcmp(line, &device[2], 4);
+ if (line[0] != 'C')
+ return false;
+ /* Skipping C(SPACE) 0x */
+ return !memcmp(&line[2], &device[2], 2);
+}
+
+static inline int is_tab(char *line)
+{
+ return line[0] == '\t';
+}
+
+static inline int is_class_info(char *line)
+{
+ return !memcmp(line, "# C class", 9);
+}
+
+static void parse_vendor_device(char **line, FILE *file,
+ char *device, char *subdev,
+ char *subven)
+{
+ bool device_single_found = false;
+ size_t amnt = 1024;
+ size_t found = 0;
+ char *newline;
+
+ while ((found = getline(line, &amnt, file)) != -1) {
+ newline = *line;
+ if (is_comment(newline))
+ continue;
+ if (!is_tab(newline))
+ return;
+
+ newline[found - 1] = '\0';
+ if (!device_single_found && is_mid_level_match(newline, device, false)) {
+ device_single_found = true;
+ device_mid = strdup(newline);
+ continue;
+ }
+
+ if (device_single_found && is_inner_sub_vendev(newline, subven, subdev)) {
+ device_final = strdup(newline);
+ break;
+ }
+ }
+}
+
+static void pull_class_info(char **_newline, FILE *file, char *class)
+{
+ size_t amnt;
+ size_t size = 1024;
+ bool top_found = false;
+ bool mid_found = false;
+ char *newline;
+
+ while ((amnt = getline(_newline, &size, file)) != -1) {
+ newline = *_newline;
+ newline[amnt - 1] = '\0';
+ if (!top_found && is_top_level_match(newline, class, true)) {
+ class_top = strdup(newline);
+ top_found = true;
+ continue;
+ }
+ if (!mid_found && top_found &&
+ is_mid_level_match(newline, &class[4], true)) {
+ class_mid = strdup(newline);
+ mid_found = true;
+ continue;
+ }
+ if (top_found && mid_found &&
+ is_final_match(newline, &class[6])) {
+ class_final = strdup(newline);
+ break;
+ }
+ }
+}
+
+static int read_sys_node(char *where, char *save, size_t savesz)
+{
+ char *new;
+ int fd, ret = 0, len;
+ fd = open(where, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open %s with errno %s\n",
+ where, strerror(errno));
+ return 1;
+ }
+ /* -1 so we can safely use strstr below */
+ len = read(fd, save, savesz - 1);
+ if (!len)
+ ret = 1;
+ else {
+ save[len] = '\0';
+ new = strstr(save, "\n");
+ if (new)
+ new[0] = '\0';
+ }
+ close(fd);
+ return ret;
+}
+
+static FILE *open_pci_ids(void)
+{
+ int i;
+ char *pci_ids_path;
+ FILE *fp;
+
+ const char* pci_ids[] = {
+ "/usr/share/hwdata/pci.ids", /* RHEL */
+ "/usr/share/pci.ids", /* SLES */
+ "/usr/share/misc/pci.ids", /* Ubuntu */
+ NULL
+ };
+
+ /* First check if user gave pci ids in environment */
+ if ((pci_ids_path = getenv("PCI_IDS_PATH")) != NULL) {
+ if ((fp = fopen(pci_ids_path, "r")) != NULL) {
+ return fp;
+ } else {
+ /* fail if user provided environment variable but could not open */
+ perror(pci_ids_path);
+ return NULL;
+ }
+ }
+
+ /* NO environment, check in predefined places */
+ for (i = 0; pci_ids[i] != NULL; i++) {
+ if ((fp = fopen(pci_ids[i], "r")) != NULL)
+ return fp;
+ }
+
+ fprintf(stderr, "Could not find pci.ids file\n");
+ return NULL;
+}
+
+char *nvme_product_name(int id)
+{
+ char *line = NULL;
+ ssize_t amnt;
+ char vendor[7] = { 0 };
+ char device[7] = { 0 };
+ char sub_device[7] = { 0 };
+ char sub_vendor[7] = { 0 };
+ char class[13] = { 0 };
+ size_t size = 1024;
+ char ret;
+ FILE *file = open_pci_ids();
+
+ if (!file)
+ goto error1;
+
+ snprintf(fmt1, 78, _fmt1, id);
+ snprintf(fmt2, 78, _fmt2, id);
+ snprintf(fmt3, 78, _fmt3, id);
+ snprintf(fmt4, 78, _fmt4, id);
+ snprintf(fmt5, 78, _fmt5, id);
+
+ ret = read_sys_node(fmt1, sub_vendor, 7);
+ ret |= read_sys_node(fmt2, sub_device, 7);
+ ret |= read_sys_node(fmt3, vendor, 7);
+ ret |= read_sys_node(fmt4, device, 7);
+ ret |= read_sys_node(fmt5, class, 13);
+ if (ret)
+ goto error0;
+
+ line = malloc(1024);
+ if (!line) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ goto error0;
+ }
+
+ while ((amnt = getline(&line, &size, file)) != -1) {
+ if (is_comment(line) && !is_class_info(line))
+ continue;
+ if (is_top_level_match(line, vendor, false)) {
+ line[amnt - 1] = '\0';
+ free(device_top);
+ device_top = strdup(line);
+ parse_vendor_device(&line, file,
+ device,
+ sub_device,
+ sub_vendor);
+ }
+ if (is_class_info(line))
+ pull_class_info(&line, file, class);
+ }
+ fclose(file);
+ format_all(line, vendor, device);
+ free_all();
+ return line;
+error0:
+ fclose(file);
+error1:
+ return strdup("NULL");
+}
diff --git a/nvme-models.h b/nvme-models.h
new file mode 100644
index 0000000..2dcc164
--- /dev/null
+++ b/nvme-models.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef NVME_MODEL_H
+#define NVME_MODEL_H
+
+char *nvme_product_name(int id);
+
+#endif
diff --git a/nvme-print-binary.c b/nvme-print-binary.c
new file mode 100644
index 0000000..e9371e5
--- /dev/null
+++ b/nvme-print-binary.c
@@ -0,0 +1,386 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "nvme-print.h"
+
+static struct print_ops binary_print_ops;
+
+static void binary_predictable_latency_per_nvmset(
+ struct nvme_nvmset_predictable_lat_log *plpns_log,
+ __u16 nvmset_id, const char *devname)
+{
+ d_raw((unsigned char *)plpns_log, sizeof(*plpns_log));
+}
+
+static void binary_predictable_latency_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *pea_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ d_raw((unsigned char *)pea_log, size);
+}
+
+static void binary_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size, const char *devname)
+{
+ d_raw((unsigned char *)pevent_log_info, size);
+}
+
+static void binary_endurance_group_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ d_raw((unsigned char *)endurance_log, size);
+}
+
+static void binary_lba_status_log(void *lba_status, __u32 size,
+ const char *devname)
+{
+ d_raw((unsigned char *)lba_status, size);
+}
+
+static void binary_resv_notif_log(struct nvme_resv_notification_log *resv,
+ const char *devname)
+{
+ d_raw((unsigned char *)resv, sizeof(*resv));
+}
+
+static void binary_fid_support_effects_log(
+ struct nvme_fid_supported_effects_log *fid_log,
+ const char *devname)
+{
+ d_raw((unsigned char *)fid_log, sizeof(*fid_log));
+}
+
+static void binary_mi_cmd_support_effects_log(
+ struct nvme_mi_cmd_supported_effects_log *mi_cmd_log,
+ const char *devname)
+{
+ d_raw((unsigned char *)mi_cmd_log, sizeof(*mi_cmd_log));
+}
+
+static void binary_boot_part_log(void *bp_log, const char *devname,
+ __u32 size)
+{
+ d_raw((unsigned char *)bp_log, size);
+}
+
+static void binary_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log,
+ __u16 controller)
+{
+ size_t len;
+ if (log->eomip == NVME_PHY_RX_EOM_COMPLETED)
+ len = log->hsize + log->dsize * log->nd;
+ else
+ len = log->hsize;
+
+ d_raw((unsigned char *)log, len);
+}
+
+static void binary_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log)
+{
+ d_raw((unsigned char *)mus_log, sizeof(*mus_log));
+}
+
+static void binary_fdp_configs(struct nvme_fdp_config_log *log, size_t len)
+{
+ d_raw((unsigned char *)log, len);
+}
+
+static void binary_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len)
+{
+
+ d_raw((unsigned char *)log, len);
+}
+
+static void binary_fdp_stats(struct nvme_fdp_stats_log *log)
+{
+ d_raw((unsigned char*)log, sizeof(*log));
+}
+
+static void binary_fdp_events(struct nvme_fdp_events_log *log)
+{
+ d_raw((unsigned char*)log, sizeof(*log));
+}
+
+static void binary_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len)
+{
+ d_raw((unsigned char *)status, len);
+}
+
+static void binary_supported_cap_config_log(
+ struct nvme_supported_cap_config_list_log *cap)
+{
+ d_raw((unsigned char *)cap, sizeof(*cap));
+}
+
+static void binary_ctrl_registers(void *bar, bool fabrics)
+{
+ const unsigned int reg_size = 0x0e1c; /* 0x0000 to 0x0e1b */
+
+ d_raw((unsigned char *)bar, reg_size);
+}
+
+static void binary_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ unsigned int lba_index, bool cap_only)
+{
+ d_raw((unsigned char *)ns, sizeof(*ns));
+}
+
+
+static void binary_cmd_set_independent_id_ns(
+ struct nvme_id_independent_id_ns *ns, unsigned int nsid)
+{
+ d_raw((unsigned char *)ns, sizeof(*ns));
+}
+
+static void binary_id_ns_descs(void *data, unsigned nsid)
+{
+ d_raw((unsigned char *)data, 0x1000);
+}
+
+static void binary_id_ctrl(struct nvme_id_ctrl *ctrl,
+ void (*vendor_show)(__u8 *vs, struct json_object *root))
+{
+ d_raw((unsigned char *)ctrl, sizeof(*ctrl));
+}
+
+static void binary_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm)
+{
+ d_raw((unsigned char *)ctrl_nvm, sizeof(*ctrl_nvm));
+}
+
+static void binary_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid,
+ struct nvme_id_ns *ns, unsigned int lba_index,
+ bool cap_only)
+{
+ d_raw((unsigned char *)nvm_ns, sizeof(*nvm_ns));
+}
+
+static void binary_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl)
+{
+ d_raw((unsigned char *)ctrl, sizeof(*ctrl));
+}
+
+static void binary_zns_id_ns(struct nvme_zns_id_ns *ns, struct nvme_id_ns *id_ns)
+{
+ d_raw((unsigned char *)ns, sizeof(*ns));
+}
+
+static void binary_zns_changed(struct nvme_zns_changed_zone_log *log)
+{
+ d_raw((unsigned char *)log, sizeof(*log));
+}
+
+static void binary_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size,
+ struct json_object *zone_list)
+{
+ d_raw((unsigned char *)report, report_size);
+}
+
+static void binary_list_ctrl(struct nvme_ctrl_list *ctrl_list)
+{
+ d_raw((unsigned char *)ctrl_list, sizeof(*ctrl_list));
+}
+
+static void binary_id_nvmset(struct nvme_id_nvmset_list *nvmset, unsigned nvmset_id)
+{
+ d_raw((unsigned char *)nvmset, sizeof(*nvmset));
+}
+
+static void binary_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps)
+{
+ d_raw((unsigned char *)caps, sizeof(*caps));
+}
+
+static void binary_list_secondary_ctrl(
+ const struct nvme_secondary_ctrl_list *sc_list,
+ __u32 count)
+{
+ d_raw((unsigned char *)sc_list, sizeof(*sc_list));
+}
+
+static void binary_id_ns_granularity_list(
+ const struct nvme_id_ns_granularity_list *glist)
+{
+ d_raw((unsigned char *)glist, sizeof(*glist));
+}
+
+static void binary_id_uuid_list(const struct nvme_id_uuid_list *uuid_list)
+{
+ d_raw((unsigned char *)uuid_list, sizeof(*uuid_list));
+}
+
+static void binary_id_domain_list(struct nvme_id_domain_list *id_dom)
+{
+ d_raw((unsigned char *)id_dom, sizeof(*id_dom));
+}
+
+static void binary_error_log(struct nvme_error_log_page *err_log, int entries,
+ const char *devname)
+{
+ d_raw((unsigned char *)err_log, entries * sizeof(*err_log));
+}
+
+static void binary_resv_report(struct nvme_resv_status *status, int bytes,
+ bool eds)
+{
+ d_raw((unsigned char *)status, bytes);
+}
+
+static void binary_fw_log(struct nvme_firmware_slot *fw_log,
+ const char *devname)
+{
+ d_raw((unsigned char *)fw_log, sizeof(*fw_log));
+}
+
+static void binary_changed_ns_list_log(struct nvme_ns_list *log,
+ const char *devname)
+{
+ d_raw((unsigned char *)log, sizeof(*log));
+}
+
+
+static void binary_supported_log(struct nvme_supported_log_pages *support_log,
+ const char *devname)
+{
+ d_raw((unsigned char *)support_log, sizeof(*support_log));
+}
+
+static void binary_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id,
+ const char *devname)
+{
+ return d_raw((unsigned char *)endurance_log, sizeof(*endurance_log));
+}
+
+static void binary_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ const char *devname)
+{
+ d_raw((unsigned char *)smart, sizeof(*smart));
+}
+
+static void binary_ana_log(struct nvme_ana_log *ana_log, const char *devname,
+ size_t len)
+{
+ d_raw((unsigned char *)ana_log, len);
+}
+
+static void binary_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries,
+ __u32 size, const char *devname)
+{
+ d_raw((unsigned char *)self_test, size);
+}
+
+static void binary_sanitize_log(struct nvme_sanitize_log_page *sanitize,
+ const char *devname)
+{
+ d_raw((unsigned char *)sanitize, sizeof(*sanitize));
+}
+
+static void binary_directive(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len)
+{
+ if (!buf)
+ return;
+
+ d_raw(buf, len);
+}
+
+static void binary_lba_status(struct nvme_lba_status *list, unsigned long len)
+{
+ d_raw((unsigned char *)list, len);
+}
+
+static void binary_discovery_log(struct nvmf_discovery_log *log, int numrec)
+{
+ d_raw((unsigned char *)log,
+ sizeof(struct nvmf_discovery_log) +
+ numrec * sizeof(struct nvmf_disc_log_entry));
+}
+
+static struct print_ops binary_print_ops = {
+ /* libnvme types.h print functions */
+ .ana_log = binary_ana_log,
+ .boot_part_log = binary_boot_part_log,
+ .phy_rx_eom_log = binary_phy_rx_eom_log,
+ .ctrl_list = binary_list_ctrl,
+ .ctrl_registers = binary_ctrl_registers,
+ .directive = binary_directive,
+ .discovery_log = binary_discovery_log,
+ .effects_log_list = NULL,
+ .endurance_group_event_agg_log = binary_endurance_group_event_agg_log,
+ .endurance_group_list = NULL,
+ .endurance_log = binary_endurance_log,
+ .error_log = binary_error_log,
+ .fdp_config_log = binary_fdp_configs,
+ .fdp_event_log = binary_fdp_events,
+ .fdp_ruh_status = binary_fdp_ruh_status,
+ .fdp_stats_log = binary_fdp_stats,
+ .fdp_usage_log = binary_fdp_usage,
+ .fid_supported_effects_log = binary_fid_support_effects_log,
+ .fw_log = binary_fw_log,
+ .id_ctrl = binary_id_ctrl,
+ .id_ctrl_nvm = binary_id_ctrl_nvm,
+ .id_domain_list = binary_id_domain_list,
+ .id_independent_id_ns = binary_cmd_set_independent_id_ns,
+ .id_iocs = NULL,
+ .id_ns = binary_id_ns,
+ .id_ns_descs = binary_id_ns_descs,
+ .id_ns_granularity_list = binary_id_ns_granularity_list,
+ .id_nvmset_list = binary_id_nvmset,
+ .id_uuid_list = binary_id_uuid_list,
+ .lba_status = binary_lba_status,
+ .lba_status_log = binary_lba_status_log,
+ .media_unit_stat_log = binary_media_unit_stat_log,
+ .mi_cmd_support_effects_log = binary_mi_cmd_support_effects_log,
+ .ns_list = NULL,
+ .ns_list_log = binary_changed_ns_list_log,
+ .nvm_id_ns = binary_nvm_id_ns,
+ .persistent_event_log = binary_persistent_event_log,
+ .predictable_latency_event_agg_log = binary_predictable_latency_event_agg_log,
+ .predictable_latency_per_nvmset = binary_predictable_latency_per_nvmset,
+ .primary_ctrl_cap = binary_primary_ctrl_cap,
+ .resv_notification_log = binary_resv_notif_log,
+ .resv_report = binary_resv_report,
+ .sanitize_log_page = binary_sanitize_log,
+ .secondary_ctrl_list = binary_list_secondary_ctrl,
+ .select_result = NULL,
+ .self_test_log = binary_self_test_log,
+ .single_property = NULL,
+ .smart_log = binary_smart_log,
+ .supported_cap_config_list_log = binary_supported_cap_config_log,
+ .supported_log_pages = binary_supported_log,
+ .zns_start_zone_list = NULL,
+ .zns_changed_zone_log = binary_zns_changed,
+ .zns_finish_zone_list = NULL,
+ .zns_id_ctrl = binary_zns_id_ctrl,
+ .zns_id_ns = binary_zns_id_ns,
+ .zns_report_zones = binary_zns_report_zones,
+ .show_feature = NULL,
+ .show_feature_fields = NULL,
+ .id_ctrl_rpmbs = NULL,
+ .lba_range = NULL,
+ .lba_status_info = NULL,
+ .d = NULL,
+ .show_init = NULL,
+ .show_finish = NULL,
+
+ /* libnvme tree print functions */
+ .list_item = NULL,
+ .list_items = NULL,
+ .print_nvme_subsystem_list = NULL,
+ .topology_ctrl = NULL,
+ .topology_namespace = NULL,
+
+ /* status and error messages */
+ .connect_msg = NULL,
+ .show_message = NULL,
+ .show_perror = NULL,
+ .show_status = NULL,
+ .show_error_status = NULL,
+};
+
+struct print_ops *nvme_get_binary_print_ops(enum nvme_print_flags flags)
+{
+ binary_print_ops.flags = flags;
+ return &binary_print_ops;
+}
diff --git a/nvme-print-json.c b/nvme-print-json.c
new file mode 100644
index 0000000..27f5c7c
--- /dev/null
+++ b/nvme-print-json.c
@@ -0,0 +1,4514 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+
+#include "nvme-print.h"
+
+#include "util/json.h"
+#include "nvme.h"
+#include "common.h"
+
+#define ERROR_MSG_LEN 100
+#define STR_LEN 100
+#define NAME_LEN 128
+#define BUF_LEN 320
+#define VAL_LEN 4096
+#define BYTE_TO_BIT(byte) ((byte) * 8)
+#define POWER_OF_TWO(exponent) (1 << (exponent))
+#define MS_TO_SEC(time) ((time) / 1000)
+#define MS500_TO_MS(time) ((time) * 500)
+#define MS500_TO_SEC(time) (MS_TO_SEC(MS500_TO_MS(time)))
+
+#define array_add_obj json_array_add_value_object
+#define array_add_str json_array_add_value_string
+
+#define obj_add_array json_object_add_value_array
+#define obj_add_int json_object_add_value_int
+#define obj_add_obj json_object_add_value_object
+#define obj_add_str json_object_add_value_string
+#define obj_add_uint json_object_add_value_uint
+#define obj_add_uint128 json_object_add_value_uint128
+#define obj_add_uint64 json_object_add_value_uint64
+
+static const uint8_t zero_uuid[16] = { 0 };
+static struct print_ops json_print_ops;
+static struct json_object *json_r = NULL;
+
+static void d_json(unsigned char *buf, int len, int width, int group, struct json_object *array)
+{
+ int i;
+ char ascii[32 + 1] = { 0 };
+
+ assert(width < sizeof(ascii));
+
+ for (i = 0; i < len; i++) {
+ ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.';
+ if (!((i + 1) % width)) {
+ array_add_str(array, ascii);
+ memset(ascii, 0, sizeof(ascii));
+ }
+ }
+
+ if (strlen(ascii)) {
+ ascii[i % width + 1] = '\0';
+ array_add_str(array, ascii);
+ }
+}
+
+static void obj_add_uint_x(struct json_object *o, const char *k, __u32 v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "%x", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_uint_0x(struct json_object *o, const char *k, __u32 v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "0x%x", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_uint_02x(struct json_object *o, const char *k, __u32 v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "0x%02x", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_uint_nx(struct json_object *o, const char *k, __u32 v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "%#x", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_nprix64(struct json_object *o, const char *k, uint64_t v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "%#"PRIx64"", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_prix64(struct json_object *o, const char *k, uint64_t v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "%"PRIx64"", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_int_secs(struct json_object *o, const char *k, int v)
+{
+ char str[STR_LEN];
+
+ sprintf(str, "%d secs", v);
+ obj_add_str(o, k, str);
+}
+
+static void obj_add_result(struct json_object *o, const char *v, ...)
+{
+ va_list ap;
+ va_start(ap, v);
+ char *value;
+
+ if (vasprintf(&value, v, ap) < 0)
+ value = NULL;
+
+ if (value)
+ obj_add_str(o, "Result", value);
+ else
+ obj_add_str(o, "Result", "Could not allocate string");
+
+ free(value);
+}
+
+static void obj_add_key(struct json_object *o, const char *k, const char *v, ...)
+{
+ va_list ap;
+ va_start(ap, v);
+ char *value;
+
+ if (vasprintf(&value, v, ap) < 0)
+ value = NULL;
+
+ if (value)
+ obj_add_str(o, k, value);
+ else
+ obj_add_str(o, k, "Could not allocate string");
+
+ free(value);
+}
+
+static struct json_object *obj_create_array_obj(struct json_object *o, const char *k)
+{
+ struct json_object *array = json_create_array();
+ struct json_object *obj = json_create_object();
+
+ obj_add_array(o, k, array);
+ array_add_obj(array, obj);
+
+ return obj;
+}
+
+static struct json_object *obj_create(const char *k)
+{
+ struct json_object *array;
+ struct json_object *obj = json_create_object();
+
+ if (json_r) {
+ array = json_create_array();
+ obj_add_array(json_r, k, array);
+ array_add_obj(array, obj);
+ }
+
+ return obj;
+}
+
+static void json_print(struct json_object *r)
+{
+ json_print_object(r, NULL);
+ printf("\n");
+ json_free_object(r);
+}
+
+static bool human(void)
+{
+ return json_print_ops.flags & VERBOSE;
+}
+
+static void json_id_iocs(struct nvme_id_iocs *iocs)
+{
+ struct json_object *r = json_create_object();
+ char json_str[STR_LEN];
+ __u16 i;
+
+ for (i = 0; i < ARRAY_SIZE(iocs->iocsc); i++) {
+ if (iocs->iocsc[i]) {
+ sprintf(json_str, "I/O Command Set Combination[%u]", i);
+ obj_add_uint64(r, json_str, le64_to_cpu(iocs->iocsc[i]));
+ }
+ }
+
+ json_print(r);
+}
+
+static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ unsigned int lba_index, bool cap_only)
+{
+ 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 *r = json_create_object();
+ struct json_object *lbafs = json_create_array();
+ struct json_object *vs = json_create_array();
+ int i;
+ nvme_uint128_t nvmcap = le128_to_cpu(ns->nvmcap);
+
+ if (!cap_only) {
+ obj_add_uint64(r, "nsze", le64_to_cpu(ns->nsze));
+ obj_add_uint64(r, "ncap", le64_to_cpu(ns->ncap));
+ obj_add_uint64(r, "nuse", le64_to_cpu(ns->nuse));
+ obj_add_int(r, "nsfeat", ns->nsfeat);
+ }
+
+ obj_add_int(r, "nlbaf", ns->nlbaf);
+
+ if (!cap_only)
+ obj_add_int(r, "flbas", ns->flbas);
+
+ obj_add_int(r, "mc", ns->mc);
+ obj_add_int(r, "dpc", ns->dpc);
+
+ if (!cap_only) {
+ obj_add_int(r, "dps", ns->dps);
+ obj_add_int(r, "nmic", ns->nmic);
+ obj_add_int(r, "rescap", ns->rescap);
+ obj_add_int(r, "fpi", ns->fpi);
+ obj_add_int(r, "dlfeat", ns->dlfeat);
+ obj_add_int(r, "nawun", le16_to_cpu(ns->nawun));
+ obj_add_int(r, "nawupf", le16_to_cpu(ns->nawupf));
+ obj_add_int(r, "nacwu", le16_to_cpu(ns->nacwu));
+ obj_add_int(r, "nabsn", le16_to_cpu(ns->nabsn));
+ obj_add_int(r, "nabo", le16_to_cpu(ns->nabo));
+ obj_add_int(r, "nabspf", le16_to_cpu(ns->nabspf));
+ obj_add_int(r, "noiob", le16_to_cpu(ns->noiob));
+ obj_add_uint128(r, "nvmcap", nvmcap);
+ obj_add_int(r, "nsattr", ns->nsattr);
+ obj_add_int(r, "nvmsetid", le16_to_cpu(ns->nvmsetid));
+
+ if (ns->nsfeat & 0x10) {
+ obj_add_int(r, "npwg", le16_to_cpu(ns->npwg));
+ obj_add_int(r, "npwa", le16_to_cpu(ns->npwa));
+ obj_add_int(r, "npdg", le16_to_cpu(ns->npdg));
+ obj_add_int(r, "npda", le16_to_cpu(ns->npda));
+ obj_add_int(r, "nows", le16_to_cpu(ns->nows));
+ }
+
+ obj_add_int(r, "mssrl", le16_to_cpu(ns->mssrl));
+ obj_add_uint(r, "mcl", le32_to_cpu(ns->mcl));
+ obj_add_int(r, "msrc", ns->msrc);
+ }
+
+ obj_add_int(r, "nulbaf", ns->nulbaf);
+
+ if (!cap_only) {
+ obj_add_uint(r, "anagrpid", le32_to_cpu(ns->anagrpid));
+ obj_add_int(r, "endgid", le16_to_cpu(ns->endgid));
+
+ memset(eui64, 0, sizeof(eui64_buf));
+
+ for (i = 0; i < sizeof(ns->eui64); i++)
+ eui64 += sprintf(eui64, "%02x", ns->eui64[i]);
+
+ memset(nguid, 0, sizeof(nguid_buf));
+
+ for (i = 0; i < sizeof(ns->nguid); i++)
+ nguid += sprintf(nguid, "%02x", ns->nguid[i]);
+
+ obj_add_str(r, "eui64", eui64_buf);
+ obj_add_str(r, "nguid", nguid_buf);
+ }
+
+ obj_add_array(r, "lbafs", lbafs);
+
+ for (i = 0; i <= ns->nlbaf; i++) {
+ struct json_object *lbaf = json_create_object();
+
+ obj_add_int(lbaf, "ms", le16_to_cpu(ns->lbaf[i].ms));
+ obj_add_int(lbaf, "ds", ns->lbaf[i].ds);
+ obj_add_int(lbaf, "rp", ns->lbaf[i].rp);
+
+ array_add_obj(lbafs, lbaf);
+ }
+
+ d_json(ns->vs, strnlen((const char *)ns->vs, sizeof(ns->vs)), 16, 1, vs);
+ obj_add_array(r, "vs", vs);
+
+ json_print(r);
+}
+
+ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl,
+ void (*vs)(__u8 *vs, struct json_object *r))
+{
+ struct json_object *r = json_create_object();
+ struct json_object *psds = json_create_array();
+ nvme_uint128_t tnvmcap = le128_to_cpu(ctrl->tnvmcap);
+ nvme_uint128_t unvmcap = le128_to_cpu(ctrl->unvmcap);
+ nvme_uint128_t megcap = le128_to_cpu(ctrl->megcap);
+ nvme_uint128_t maxdna = le128_to_cpu(ctrl->maxdna);
+ char sn[sizeof(ctrl->sn) + 1], mn[sizeof(ctrl->mn) + 1],
+ fr[sizeof(ctrl->fr) + 1], subnqn[sizeof(ctrl->subnqn) + 1];
+ __u32 ieee = ctrl->ieee[2] << 16 | ctrl->ieee[1] << 8 | ctrl->ieee[0];
+ int i;
+
+ snprintf(sn, sizeof(sn), "%-.*s", (int)sizeof(ctrl->sn), ctrl->sn);
+ snprintf(mn, sizeof(mn), "%-.*s", (int)sizeof(ctrl->mn), ctrl->mn);
+ snprintf(fr, sizeof(fr), "%-.*s", (int)sizeof(ctrl->fr), ctrl->fr);
+ snprintf(subnqn, sizeof(subnqn), "%-.*s", (int)sizeof(ctrl->subnqn), ctrl->subnqn);
+
+ obj_add_int(r, "vid", le16_to_cpu(ctrl->vid));
+ obj_add_int(r, "ssvid", le16_to_cpu(ctrl->ssvid));
+ obj_add_str(r, "sn", sn);
+ obj_add_str(r, "mn", mn);
+ obj_add_str(r, "fr", fr);
+ obj_add_int(r, "rab", ctrl->rab);
+ obj_add_int(r, "ieee", ieee);
+ obj_add_int(r, "cmic", ctrl->cmic);
+ obj_add_int(r, "mdts", ctrl->mdts);
+ obj_add_int(r, "cntlid", le16_to_cpu(ctrl->cntlid));
+ obj_add_uint(r, "ver", le32_to_cpu(ctrl->ver));
+ obj_add_uint(r, "rtd3r", le32_to_cpu(ctrl->rtd3r));
+ obj_add_uint(r, "rtd3e", le32_to_cpu(ctrl->rtd3e));
+ obj_add_uint(r, "oaes", le32_to_cpu(ctrl->oaes));
+ obj_add_uint(r, "ctratt", le32_to_cpu(ctrl->ctratt));
+ obj_add_int(r, "rrls", le16_to_cpu(ctrl->rrls));
+ obj_add_int(r, "cntrltype", ctrl->cntrltype);
+ obj_add_str(r, "fguid", util_uuid_to_string(ctrl->fguid));
+ obj_add_int(r, "crdt1", le16_to_cpu(ctrl->crdt1));
+ obj_add_int(r, "crdt2", le16_to_cpu(ctrl->crdt2));
+ obj_add_int(r, "crdt3", le16_to_cpu(ctrl->crdt3));
+ obj_add_int(r, "nvmsr", ctrl->nvmsr);
+ obj_add_int(r, "vwci", ctrl->vwci);
+ obj_add_int(r, "mec", ctrl->mec);
+ obj_add_int(r, "oacs", le16_to_cpu(ctrl->oacs));
+ obj_add_int(r, "acl", ctrl->acl);
+ obj_add_int(r, "aerl", ctrl->aerl);
+ obj_add_int(r, "frmw", ctrl->frmw);
+ obj_add_int(r, "lpa", ctrl->lpa);
+ obj_add_int(r, "elpe", ctrl->elpe);
+ obj_add_int(r, "npss", ctrl->npss);
+ obj_add_int(r, "avscc", ctrl->avscc);
+ obj_add_int(r, "apsta", ctrl->apsta);
+ obj_add_int(r, "wctemp", le16_to_cpu(ctrl->wctemp));
+ obj_add_int(r, "cctemp", le16_to_cpu(ctrl->cctemp));
+ obj_add_int(r, "mtfa", le16_to_cpu(ctrl->mtfa));
+ obj_add_uint(r, "hmpre", le32_to_cpu(ctrl->hmpre));
+ obj_add_uint(r, "hmmin", le32_to_cpu(ctrl->hmmin));
+ obj_add_uint128(r, "tnvmcap", tnvmcap);
+ obj_add_uint128(r, "unvmcap", unvmcap);
+ obj_add_uint(r, "rpmbs", le32_to_cpu(ctrl->rpmbs));
+ obj_add_int(r, "edstt", le16_to_cpu(ctrl->edstt));
+ obj_add_int(r, "dsto", ctrl->dsto);
+ obj_add_int(r, "fwug", ctrl->fwug);
+ obj_add_int(r, "kas", le16_to_cpu(ctrl->kas));
+ obj_add_int(r, "hctma", le16_to_cpu(ctrl->hctma));
+ obj_add_int(r, "mntmt", le16_to_cpu(ctrl->mntmt));
+ obj_add_int(r, "mxtmt", le16_to_cpu(ctrl->mxtmt));
+ obj_add_uint(r, "sanicap", le32_to_cpu(ctrl->sanicap));
+ obj_add_uint(r, "hmminds", le32_to_cpu(ctrl->hmminds));
+ obj_add_int(r, "hmmaxd", le16_to_cpu(ctrl->hmmaxd));
+ obj_add_int(r, "nsetidmax", le16_to_cpu(ctrl->nsetidmax));
+ obj_add_int(r, "endgidmax", le16_to_cpu(ctrl->endgidmax));
+ obj_add_int(r, "anatt",ctrl->anatt);
+ obj_add_int(r, "anacap", ctrl->anacap);
+ obj_add_uint(r, "anagrpmax", le32_to_cpu(ctrl->anagrpmax));
+ obj_add_uint(r, "nanagrpid", le32_to_cpu(ctrl->nanagrpid));
+ obj_add_uint(r, "pels", le32_to_cpu(ctrl->pels));
+ obj_add_int(r, "domainid", le16_to_cpu(ctrl->domainid));
+ obj_add_uint128(r, "megcap", megcap);
+ obj_add_int(r, "sqes", ctrl->sqes);
+ obj_add_int(r, "cqes", ctrl->cqes);
+ obj_add_int(r, "maxcmd", le16_to_cpu(ctrl->maxcmd));
+ obj_add_uint(r, "nn", le32_to_cpu(ctrl->nn));
+ obj_add_int(r, "oncs", le16_to_cpu(ctrl->oncs));
+ obj_add_int(r, "fuses", le16_to_cpu(ctrl->fuses));
+ obj_add_int(r, "fna", ctrl->fna);
+ obj_add_int(r, "vwc", ctrl->vwc);
+ obj_add_int(r, "awun", le16_to_cpu(ctrl->awun));
+ obj_add_int(r, "awupf", le16_to_cpu(ctrl->awupf));
+ obj_add_int(r, "icsvscc", ctrl->icsvscc);
+ obj_add_int(r, "nwpc", ctrl->nwpc);
+ obj_add_int(r, "acwu", le16_to_cpu(ctrl->acwu));
+ obj_add_int(r, "ocfs", le16_to_cpu(ctrl->ocfs));
+ obj_add_uint(r, "sgls", le32_to_cpu(ctrl->sgls));
+ obj_add_uint(r, "mnan", le32_to_cpu(ctrl->mnan));
+ obj_add_uint128(r, "maxdna", maxdna);
+ obj_add_uint(r, "maxcna", le32_to_cpu(ctrl->maxcna));
+ obj_add_uint(r, "oaqd", le32_to_cpu(ctrl->oaqd));
+
+ if (strlen(subnqn))
+ obj_add_str(r, "subnqn", subnqn);
+
+ obj_add_uint(r, "ioccsz", le32_to_cpu(ctrl->ioccsz));
+ obj_add_uint(r, "iorcsz", le32_to_cpu(ctrl->iorcsz));
+ obj_add_int(r, "icdoff", le16_to_cpu(ctrl->icdoff));
+ obj_add_int(r, "fcatt", ctrl->fcatt);
+ obj_add_int(r, "msdbd", ctrl->msdbd);
+ obj_add_int(r, "ofcs", le16_to_cpu(ctrl->ofcs));
+
+ obj_add_array(r, "psds", psds);
+
+ for (i = 0; i <= ctrl->npss; i++) {
+ struct json_object *psd = json_create_object();
+
+ obj_add_int(psd, "max_power", le16_to_cpu(ctrl->psd[i].mp));
+ obj_add_int(psd, "max_power_scale", ctrl->psd[i].flags & 0x1);
+ obj_add_int(psd, "non-operational_state", (ctrl->psd[i].flags & 2) >> 1);
+ obj_add_uint(psd, "entry_lat", le32_to_cpu(ctrl->psd[i].enlat));
+ obj_add_uint(psd, "exit_lat", le32_to_cpu(ctrl->psd[i].exlat));
+ obj_add_int(psd, "read_tput", ctrl->psd[i].rrt);
+ obj_add_int(psd, "read_lat", ctrl->psd[i].rrl);
+ obj_add_int(psd, "write_tput", ctrl->psd[i].rwt);
+ obj_add_int(psd, "write_lat", ctrl->psd[i].rwl);
+ obj_add_int(psd, "idle_power", le16_to_cpu(ctrl->psd[i].idlp));
+ obj_add_int(psd, "idle_scale", nvme_psd_power_scale(ctrl->psd[i].ips));
+ obj_add_int(psd, "active_power", le16_to_cpu(ctrl->psd[i].actp));
+ obj_add_int(psd, "active_power_work", ctrl->psd[i].apws & 7);
+ obj_add_int(psd, "active_scale", nvme_psd_power_scale(ctrl->psd[i].apws));
+
+ array_add_obj(psds, psd);
+ }
+
+ if(vs)
+ vs(ctrl->vs, r);
+
+ json_print(r);
+}
+
+static void json_error_log(struct nvme_error_log_page *err_log, int entries,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *errors = json_create_array();
+ int i;
+
+ obj_add_array(r, "errors", errors);
+
+ for (i = 0; i < entries; i++) {
+ struct json_object *error = json_create_object();
+
+ obj_add_uint64(error, "error_count", le64_to_cpu(err_log[i].error_count));
+ obj_add_int(error, "sqid", le16_to_cpu(err_log[i].sqid));
+ obj_add_int(error, "cmdid", le16_to_cpu(err_log[i].cmdid));
+ obj_add_int(error, "status_field", le16_to_cpu(err_log[i].status_field >> 0x1));
+ obj_add_int(error, "phase_tag", le16_to_cpu(err_log[i].status_field & 0x1));
+ obj_add_int(error, "parm_error_location",
+ le16_to_cpu(err_log[i].parm_error_location));
+ obj_add_uint64(error, "lba", le64_to_cpu(err_log[i].lba));
+ obj_add_uint(error, "nsid", le32_to_cpu(err_log[i].nsid));
+ obj_add_int(error, "vs", err_log[i].vs);
+ obj_add_int(error, "trtype", err_log[i].trtype);
+ obj_add_uint64(error, "cs", le64_to_cpu(err_log[i].cs));
+ obj_add_int(error, "trtype_spec_info", le16_to_cpu(err_log[i].trtype_spec_info));
+
+ array_add_obj(errors, error);
+ }
+
+ json_print(r);
+}
+
+void json_nvme_resv_report(struct nvme_resv_status *status,
+ int bytes, bool eds)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *rcs = json_create_array();
+ int i, j, entries;
+ int regctl = status->regctl[0] | (status->regctl[1] << 8);
+
+ obj_add_uint(r, "gen", le32_to_cpu(status->gen));
+ obj_add_int(r, "rtype", status->rtype);
+ obj_add_int(r, "regctl", regctl);
+ obj_add_int(r, "ptpls", status->ptpls);
+
+ /* check Extended Data Structure bit */
+ if (!eds) {
+ /*
+ * if status buffer was too small, don't loop past the end of
+ * the buffer
+ */
+ entries = (bytes - 24) / 24;
+ if (entries < regctl)
+ regctl = entries;
+
+ obj_add_array(r, "regctls", rcs);
+ for (i = 0; i < regctl; i++) {
+ struct json_object *rc = json_create_object();
+
+ obj_add_int(rc, "cntlid", le16_to_cpu(status->regctl_ds[i].cntlid));
+ obj_add_int(rc, "rcsts", status->regctl_ds[i].rcsts);
+ obj_add_uint64(rc, "hostid", le64_to_cpu(status->regctl_ds[i].hostid));
+ obj_add_uint64(rc, "rkey", le64_to_cpu(status->regctl_ds[i].rkey));
+
+ array_add_obj(rcs, rc);
+ }
+ } else {
+ char hostid[33];
+
+ /* if status buffer was too small, don't loop past the end of the buffer */
+ entries = (bytes - 64) / 64;
+
+ if (entries < regctl)
+ regctl = entries;
+
+ obj_add_array(r, "regctlext", rcs);
+
+ for (i = 0; i < regctl; i++) {
+ struct json_object *rc = json_create_object();
+
+ obj_add_int(rc, "cntlid", le16_to_cpu(status->regctl_eds[i].cntlid));
+ obj_add_int(rc, "rcsts", status->regctl_eds[i].rcsts);
+ obj_add_uint64(rc, "rkey", le64_to_cpu(status->regctl_eds[i].rkey));
+
+ for (j = 0; j < 16; j++)
+ sprintf(hostid + j * 2, "%02x", status->regctl_eds[i].hostid[j]);
+
+ obj_add_str(rc, "hostid", hostid);
+ array_add_obj(rcs, rc);
+ }
+ }
+
+ json_print(r);
+}
+
+void json_fw_log(struct nvme_firmware_slot *fw_log, const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *fwsi = json_create_object();
+ char fmt[21];
+ char str[32];
+ int i;
+ __le64 *frs;
+
+ obj_add_int(fwsi, "Active Firmware Slot (afi)", fw_log->afi);
+
+ for (i = 0; i < 7; i++) {
+ if (fw_log->frs[i][0]) {
+ snprintf(fmt, sizeof(fmt), "Firmware Rev Slot %d",
+ i + 1);
+ frs = (__le64 *)&fw_log->frs[i];
+ snprintf(str, sizeof(str), "%"PRIu64" (%s)",
+ le64_to_cpu(*frs),
+ util_fw_to_string(fw_log->frs[i]));
+ obj_add_str(fwsi, fmt, str);
+ }
+ }
+
+ obj_add_obj(r, devname, fwsi);
+
+ json_print(r);
+}
+
+void json_changed_ns_list_log(struct nvme_ns_list *log,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *nsi = json_create_object();
+ char fmt[32];
+ char str[32];
+ __u32 nsid;
+ int i;
+
+ if (log->ns[0] == cpu_to_le32(0xffffffff))
+ return;
+
+ obj_add_str(r, "Changed Namespace List Log", devname);
+
+ for (i = 0; i < NVME_ID_NS_LIST_MAX; i++) {
+ nsid = le32_to_cpu(log->ns[i]);
+
+ if (nsid == 0)
+ break;
+
+ snprintf(fmt, sizeof(fmt), "[%4u]", i + 1);
+ snprintf(str, sizeof(str), "%#x", nsid);
+ obj_add_str(nsi, fmt, str);
+ }
+
+ obj_add_obj(r, devname, nsi);
+
+ json_print(r);
+}
+
+static void json_endurance_log(struct nvme_endurance_group_log *endurance_group, __u16 group_id,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ nvme_uint128_t endurance_estimate = le128_to_cpu(endurance_group->endurance_estimate);
+ nvme_uint128_t data_units_read = le128_to_cpu(endurance_group->data_units_read);
+ nvme_uint128_t data_units_written = le128_to_cpu(endurance_group->data_units_written);
+ nvme_uint128_t media_units_written = le128_to_cpu(endurance_group->media_units_written);
+ nvme_uint128_t host_read_cmds = le128_to_cpu(endurance_group->host_read_cmds);
+ nvme_uint128_t host_write_cmds = le128_to_cpu(endurance_group->host_write_cmds);
+ nvme_uint128_t media_data_integrity_err =
+ le128_to_cpu(endurance_group->media_data_integrity_err);
+ nvme_uint128_t num_err_info_log_entries =
+ le128_to_cpu(endurance_group->num_err_info_log_entries);
+ nvme_uint128_t total_end_grp_cap = le128_to_cpu(endurance_group->total_end_grp_cap);
+ nvme_uint128_t unalloc_end_grp_cap = le128_to_cpu(endurance_group->unalloc_end_grp_cap);
+
+ obj_add_int(r, "critical_warning", endurance_group->critical_warning);
+ obj_add_int(r, "endurance_group_features", endurance_group->endurance_group_features);
+ obj_add_int(r, "avl_spare", endurance_group->avl_spare);
+ obj_add_int(r, "avl_spare_threshold", endurance_group->avl_spare_threshold);
+ obj_add_int(r, "percent_used", endurance_group->percent_used);
+ obj_add_int(r, "domain_identifier", endurance_group->domain_identifier);
+ obj_add_uint128(r, "endurance_estimate", endurance_estimate);
+ obj_add_uint128(r, "data_units_read", data_units_read);
+ obj_add_uint128(r, "data_units_written", data_units_written);
+ obj_add_uint128(r, "media_units_written", media_units_written);
+ obj_add_uint128(r, "host_read_cmds", host_read_cmds);
+ obj_add_uint128(r, "host_write_cmds", host_write_cmds);
+ obj_add_uint128(r, "media_data_integrity_err", media_data_integrity_err);
+ obj_add_uint128(r, "num_err_info_log_entries", num_err_info_log_entries);
+ obj_add_uint128(r, "total_end_grp_cap", total_end_grp_cap);
+ obj_add_uint128(r, "unalloc_end_grp_cap", unalloc_end_grp_cap);
+
+ json_print(r);
+}
+
+static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ int c;
+ char key[21];
+ unsigned int temperature = ((smart->temperature[1] << 8) |
+ smart->temperature[0]);
+ nvme_uint128_t data_units_read = le128_to_cpu(smart->data_units_read);
+ nvme_uint128_t data_units_written = le128_to_cpu(smart->data_units_written);
+ nvme_uint128_t host_read_commands = le128_to_cpu(smart->host_reads);
+ nvme_uint128_t host_write_commands = le128_to_cpu(smart->host_writes);
+ nvme_uint128_t controller_busy_time = le128_to_cpu(smart->ctrl_busy_time);
+ nvme_uint128_t power_cycles = le128_to_cpu(smart->power_cycles);
+ nvme_uint128_t power_on_hours = le128_to_cpu(smart->power_on_hours);
+ nvme_uint128_t unsafe_shutdowns = le128_to_cpu(smart->unsafe_shutdowns);
+ nvme_uint128_t media_errors = le128_to_cpu(smart->media_errors);
+ nvme_uint128_t num_err_log_entries = le128_to_cpu(smart->num_err_log_entries);
+
+ if (human()) {
+ struct json_object *crt = json_create_object();
+
+ obj_add_int(crt, "value", smart->critical_warning);
+ obj_add_int(crt, "available_spare", smart->critical_warning & 1);
+ obj_add_int(crt, "temp_threshold", (smart->critical_warning & 2) >> 1);
+ obj_add_int(crt, "reliability_degraded", (smart->critical_warning & 4) >> 2);
+ obj_add_int(crt, "ro", (smart->critical_warning & 8) >> 3);
+ obj_add_int(crt, "vmbu_failed", (smart->critical_warning & 0x10) >> 4);
+ obj_add_int(crt, "pmr_ro", (smart->critical_warning & 0x20) >> 5);
+
+ obj_add_obj(r, "critical_warning", crt);
+ } else {
+ obj_add_int(r, "critical_warning", smart->critical_warning);
+ }
+
+ obj_add_int(r, "temperature", temperature);
+ obj_add_int(r, "avail_spare", smart->avail_spare);
+ obj_add_int(r, "spare_thresh", smart->spare_thresh);
+ obj_add_int(r, "percent_used", smart->percent_used);
+ obj_add_int(r, "endurance_grp_critical_warning_summary", smart->endu_grp_crit_warn_sumry);
+ obj_add_uint128(r, "data_units_read", data_units_read);
+ obj_add_uint128(r, "data_units_written", data_units_written);
+ obj_add_uint128(r, "host_read_commands", host_read_commands);
+ obj_add_uint128(r, "host_write_commands", host_write_commands);
+ obj_add_uint128(r, "controller_busy_time", controller_busy_time);
+ obj_add_uint128(r, "power_cycles", power_cycles);
+ obj_add_uint128(r, "power_on_hours", power_on_hours);
+ obj_add_uint128(r, "unsafe_shutdowns", unsafe_shutdowns);
+ obj_add_uint128(r, "media_errors", media_errors);
+ obj_add_uint128(r, "num_err_log_entries", num_err_log_entries);
+ obj_add_uint(r, "warning_temp_time", le32_to_cpu(smart->warning_temp_time));
+ obj_add_uint(r, "critical_comp_time", le32_to_cpu(smart->critical_comp_time));
+
+ for (c = 0; c < 8; c++) {
+ __s32 temp = le16_to_cpu(smart->temp_sensor[c]);
+
+ if (temp == 0)
+ continue;
+
+ sprintf(key, "temperature_sensor_%d",c+1);
+ obj_add_int(r, key, temp);
+ }
+
+ obj_add_uint(r, "thm_temp1_trans_count", le32_to_cpu(smart->thm_temp1_trans_count));
+ obj_add_uint(r, "thm_temp2_trans_count", le32_to_cpu(smart->thm_temp2_trans_count));
+ obj_add_uint(r, "thm_temp1_total_time", le32_to_cpu(smart->thm_temp1_total_time));
+ obj_add_uint(r, "thm_temp2_total_time", le32_to_cpu(smart->thm_temp2_total_time));
+
+ json_print(r);
+}
+
+static void json_ana_log(struct nvme_ana_log *ana_log, const char *devname,
+ size_t len)
+{
+ int offset = sizeof(struct nvme_ana_log);
+ struct nvme_ana_log *hdr = ana_log;
+ struct nvme_ana_group_desc *ana_desc;
+ struct json_object *desc_list = json_create_array();
+ struct json_object *ns_list;
+ struct json_object *desc;
+ struct json_object *nsid;
+ struct json_object *r = json_create_object();
+ size_t nsid_buf_size;
+ void *base = ana_log;
+ __u32 nr_nsids;
+ int i, j;
+
+ obj_add_str(r, "Asymmetric Namespace Access Log for NVMe device", devname);
+ obj_add_uint64(r, "chgcnt", le64_to_cpu(hdr->chgcnt));
+ obj_add_uint(r, "ngrps", le16_to_cpu(hdr->ngrps));
+
+ for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) {
+ desc = json_create_object();
+ ana_desc = base + offset;
+ nr_nsids = le32_to_cpu(ana_desc->nnsids);
+ nsid_buf_size = nr_nsids * sizeof(__le32);
+
+ offset += sizeof(*ana_desc);
+ obj_add_uint(desc, "grpid", le32_to_cpu(ana_desc->grpid));
+ obj_add_uint(desc, "nnsids", le32_to_cpu(ana_desc->nnsids));
+ obj_add_uint64(desc, "chgcnt", le64_to_cpu(ana_desc->chgcnt));
+ obj_add_str(desc, "state", nvme_ana_state_to_string(ana_desc->state));
+
+ ns_list = json_create_array();
+ for (j = 0; j < le32_to_cpu(ana_desc->nnsids); j++) {
+ nsid = json_create_object();
+ obj_add_uint(nsid, "nsid", le32_to_cpu(ana_desc->nsids[j]));
+ array_add_obj(ns_list, nsid);
+ }
+ obj_add_array(desc, "NSIDS", ns_list);
+ offset += nsid_buf_size;
+ array_add_obj(desc_list, desc);
+ }
+
+ obj_add_array(r, "ANA DESC LIST ", desc_list);
+
+ json_print(r);
+}
+
+static void json_select_result(enum nvme_features_id fid, __u32 result)
+{
+ struct json_object *r = json_r ? json_r : json_create_object();
+ char json_str[STR_LEN];
+ struct json_object *feature = json_create_array();
+
+ if (result & 0x1)
+ array_add_str(feature, "saveable");
+ if (result & 0x2)
+ array_add_str(feature, "per-namespace");
+ if (result & 0x4)
+ array_add_str(feature, "changeable");
+
+ sprintf(json_str, "Feature: %#0*x: select", fid ? 4 : 2, fid);
+ obj_add_array(r, json_str, feature);
+
+ json_print(r);
+}
+
+static void json_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entries,
+ __u32 size, const char *devname)
+{
+ struct json_object *valid_attrs;
+ struct json_object *r = json_create_object();
+ struct json_object *valid = json_create_array();
+ int i;
+ __u32 num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS);
+
+ obj_add_int(r, "Current Device Self-Test Operation", self_test->current_operation);
+ obj_add_int(r, "Current Device Self-Test Completion", self_test->completion);
+
+ for (i = 0; i < num_entries; i++) {
+ valid_attrs = json_create_object();
+ obj_add_int(valid_attrs, "Self test result", self_test->result[i].dsts & 0xf);
+
+ if ((self_test->result[i].dsts & 0xf) == 0xf)
+ goto add;
+
+ obj_add_int(valid_attrs, "Self test code",
+ self_test->result[i].dsts >> 4);
+ obj_add_int(valid_attrs, "Segment number",
+ self_test->result[i].seg);
+ obj_add_int(valid_attrs, "Valid Diagnostic Information",
+ self_test->result[i].vdi);
+ obj_add_uint64(valid_attrs, "Power on hours",
+ le64_to_cpu(self_test->result[i].poh));
+
+ if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_NSID)
+ obj_add_uint(valid_attrs, "Namespace Identifier",
+ le32_to_cpu(self_test->result[i].nsid));
+
+ if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_FLBA)
+ obj_add_uint64(valid_attrs, "Failing LBA",
+ le64_to_cpu(self_test->result[i].flba));
+
+ if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SCT)
+ obj_add_int(valid_attrs, "Status Code Type", self_test->result[i].sct);
+
+ if (self_test->result[i].vdi & NVME_ST_VALID_DIAG_INFO_SC)
+ obj_add_int(valid_attrs, "Status Code", self_test->result[i].sc);
+
+ obj_add_int(valid_attrs, "Vendor Specific",
+ self_test->result[i].vs[1] << 8 | self_test->result[i].vs[0]);
+
+add:
+ array_add_obj(valid, valid_attrs);
+ }
+
+ obj_add_array(r, "List of Valid Reports", valid);
+
+ json_print(r);
+}
+
+static void json_registers_cap(struct nvme_bar_cap *cap, struct json_object *r)
+{
+ char json_str[STR_LEN];
+ struct json_object *cssa = json_create_array();
+ struct json_object *csso = json_create_object();
+ struct json_object *amsa = json_create_array();
+ struct json_object *amso = json_create_object();
+
+ sprintf(json_str, "%"PRIx64"", *(uint64_t *)cap);
+ obj_add_str(r, "cap", json_str);
+
+ obj_add_str(r, "Controller Ready With Media Support (CRWMS)",
+ cap->crwms ? "Supported" : "Not supported");
+ obj_add_str(r, "Controller Ready Independent of Media Support (CRIMS)",
+ cap->crims ? "Supported" : "Not supported");
+ obj_add_str(r, "NVM Subsystem Shutdown Supported (NSSS)",
+ cap->nsss ? "Supported" : "Not supported");
+ obj_add_str(r, "Controller Memory Buffer Supported (CMBS):",
+ cap->cmbs ? "Supported" : "Not supported");
+ obj_add_str(r, "Persistent Memory Region Supported (PMRS)",
+ cap->pmrs ? "Supported" : "Not supported");
+
+ sprintf(json_str, "%u bytes", 1 << (12 + cap->mpsmax));
+ obj_add_str(r, "Memory Page Size Maximum (MPSMAX)", json_str);
+
+ sprintf(json_str, "%u bytes", 1 << (12 + cap->mpsmin));
+ obj_add_str(r, "Memory Page Size Minimum (MPSMIN)", json_str);
+
+ obj_add_str(r, "Controller Power Scope (CPS)", !cap->cps ? "Not Reported" : cap->cps == 1 ?
+ "Controller scope" : cap->cps == 2 ? "Domain scope" : "NVM subsystem scope");
+ obj_add_str(r, "Boot Partition Support (BPS)", cap->bps ? "Yes" : "No");
+
+ obj_add_array(r, "Command Sets Supported (CSS)", cssa);
+ obj_add_str(csso, "NVM command set", cap->css & 1 ? "Supported" : "Not supported");
+ obj_add_str(csso, "One or more I/O Command Sets",
+ cap->css & 0x40 ? "Supported" : "Not supported");
+ obj_add_str(csso, cap->css & 0x80 ? "Only Admin Command Set" : "I/O Command Set",
+ "Supported");
+ array_add_obj(cssa, csso);
+
+ obj_add_str(r, "NVM Subsystem Reset Supported (NSSRS)", cap->nssrs ? "Yes" : "No");
+
+ sprintf(json_str, "%u bytes", 1 << (2 + cap->dstrd));
+ obj_add_str(r, "Doorbell Stride (DSTRD)", json_str);
+
+ sprintf(json_str, "%u ms", MS500_TO_MS(cap->to));
+ obj_add_str(r, "Timeout (TO)", json_str);
+
+ obj_add_array(r, "Arbitration Mechanism Supported (AMS)", amsa);
+ obj_add_str(amso, "Weighted Round Robin with Urgent Priority Class",
+ cap->ams & 2 ? "Supported" : "Not supported");
+ array_add_obj(amsa, amso);
+
+ obj_add_str(r, "Contiguous Queues Required (CQR)", cap->cqr ? "Yes" : "No");
+ obj_add_uint(r, "Maximum Queue Entries Supported (MQES)", cap->mqes + 1);
+}
+
+static void json_registers_version(__u32 vs, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%x", vs);
+ obj_add_str(r, "Version", json_str);
+
+ sprintf(json_str, "%d.%d", (vs & 0xffff0000) >> 16, (vs & 0x0000ff00) >> 8);
+ obj_add_str(r, "NVMe specification", json_str);
+}
+
+static void json_registers_intms(__u32 intms, struct json_object *r)
+{
+ obj_add_uint_x(r, "intms", intms);
+
+ obj_add_uint_x(r, "Interrupt Vector Mask Set (IVMS)", intms);
+}
+
+static void json_registers_intmc(__u32 intmc, struct json_object *r)
+{
+ obj_add_uint_x(r, "intmc", intmc);
+
+ obj_add_uint_x(r, "Interrupt Vector Mask Set (IVMC)", intmc);
+}
+
+static void json_registers_cc_ams(__u8 ams, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ switch (ams) {
+ case 0:
+ sprintf(json_str, "Round Robin");
+ break;
+ case 1:
+ sprintf(json_str, "Weighted Round Robin with Urgent Priority Class");
+ break;
+ case 7:
+ sprintf(json_str, "Vendor Specific");
+ break;
+ default:
+ sprintf(json_str, "%s", "Reserved");
+ break;
+ }
+
+ obj_add_str(r, "Arbitration Mechanism Selected (AMS)", json_str);
+}
+
+static void json_registers_cc_shn(__u8 shn, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ switch (shn) {
+ case 0:
+ sprintf(json_str, "No notification; no effect");
+ break;
+ case 1:
+ sprintf(json_str, "Normal shutdown notification");
+ break;
+ case 2:
+ sprintf(json_str, "Abrupt shutdown notification");
+ break;
+ default:
+ sprintf(json_str, "%s", "Reserved");
+ break;
+ }
+
+ obj_add_str(r, "Shutdown Notification (SHN)", json_str);
+}
+
+static void json_registers_cc(__u32 cc, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%x", cc);
+ obj_add_str(r, "cc", json_str);
+
+ obj_add_str(r, "Controller Ready Independent of Media Enable (CRIME)",
+ NVME_CC_CRIME(cc) ? "Enabled" : "Disabled");
+
+ sprintf(json_str, "%u bytes", POWER_OF_TWO(NVME_GET(cc, CC_IOCQES)));
+ obj_add_str(r, "I/O Completion Queue Entry Size (IOCQES): ", json_str);
+
+ sprintf(json_str, "%u bytes", POWER_OF_TWO(NVME_GET(cc, CC_IOSQES)));
+ obj_add_str(r, "I/O Submission Queue Entry Size (IOSQES)", json_str);
+
+ json_registers_cc_shn((cc & 0xc000) >> NVME_CC_SHN_SHIFT, r);
+ json_registers_cc_ams((cc & 0x3800) >> NVME_CC_AMS_SHIFT, r);
+
+ sprintf(json_str, "%u bytes", POWER_OF_TWO(12 + NVME_GET(cc, CC_MPS)));
+ obj_add_str(r, "Memory Page Size (MPS)", json_str);
+
+ obj_add_str(r, "I/O Command Set Selected (CSS)", (cc & 0x70) == 0x00 ? "NVM Command Set" :
+ (cc & 0x70) == 0x60 ? "All supported I/O Command Sets" :
+ (cc & 0x70) == 0x70 ? "Admin Command Set only" : "Reserved");
+ obj_add_str(r, "Enable (EN)", cc & 1 ? "Yes" : "No");
+}
+
+static void json_registers_csts_shst(__u8 shst, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ switch (shst) {
+ case 0:
+ sprintf(json_str, "Normal operation (no shutdown has been requested)");
+ break;
+ case 1:
+ sprintf(json_str, "Shutdown processing occurring");
+ break;
+ case 2:
+ sprintf(json_str, "Shutdown processing complete");
+ break;
+ default:
+ sprintf(json_str, "%s", "Reserved");
+ break;
+ }
+
+ obj_add_str(r, "Shutdown Status (SHST)", json_str);
+}
+
+static void json_registers_csts(__u32 csts, struct json_object *r)
+{
+ obj_add_uint_x(r, "csts", csts);
+
+ obj_add_str(r, "Processing Paused (PP)", csts & 0x20 ? "Yes" : "No");
+ obj_add_str(r, "NVM Subsystem Reset Occurred (NSSRO)", csts & 0x10 ? "Yes" : "No");
+
+ json_registers_csts_shst((csts & 0xc) >> 2, r);
+
+ obj_add_str(r, "Controller Fatal Status (CFS)", csts & 2 ? "True" : "False");
+ obj_add_str(r, "Ready (RDY)", csts & 1 ? "Yes" : "No");
+}
+
+static void json_registers_nssr(__u32 nssr, struct json_object *r)
+{
+ obj_add_uint_x(r, "nssr", nssr);
+ obj_add_uint(r, "NVM Subsystem Reset Control (NSSRC)", nssr);
+}
+
+static void json_registers_crto(__u32 crto, struct json_object *r)
+{
+ obj_add_uint_x(r, "crto", crto);
+
+ obj_add_int_secs(r, "CRIMT", MS500_TO_SEC(NVME_CRTO_CRIMT(crto)));
+ obj_add_int_secs(r, "CRWMT", MS500_TO_SEC(NVME_CRTO_CRWMT(crto)));
+}
+
+static void json_registers_aqa(uint32_t aqa, struct json_object *r)
+{
+ obj_add_uint_x(r, "aqa", aqa);
+ obj_add_uint(r, "Admin Completion Queue Size (ACQS)", ((aqa & 0xfff0000) >> 16) + 1);
+ obj_add_uint(r, "Admin Submission Queue Size (ASQS)", (aqa & 0xfff) + 1);
+}
+
+static void json_registers_asq(uint64_t asq, struct json_object *r)
+{
+ obj_add_prix64(r, "asq", asq);
+ obj_add_prix64(r, "Admin Submission Queue Base (ASQB)", asq);
+}
+
+static void json_registers_acq(uint64_t acq, struct json_object *r)
+{
+ obj_add_prix64(r, "acq", acq);
+ obj_add_prix64(r, "Admin Completion Queue Base (ACQB)", acq);
+}
+
+static void json_registers_cmbloc(uint32_t cmbloc, void *bar, struct json_object *r)
+{
+ uint32_t cmbsz = mmio_read32(bar + NVME_REG_CMBSZ);
+
+ obj_add_uint_x(r, "cmbloc", cmbloc);
+
+ if (!cmbsz) {
+ obj_add_result(r, "Controller Memory Buffer feature is not supported");
+ return;
+ }
+
+ obj_add_uint_0x(r, "Offset (OFST) (See cmbsz.szu for granularity)",
+ (cmbloc & 0xfffff000) >> 12);
+ obj_add_int(r, "CMB Queue Dword Alignment (CQDA)", (cmbloc & 0x100) >> 8);
+ obj_add_str(r, "CMB Data Metadata Mixed Memory Support (CDMMMS)",
+ (cmbloc & 0x00000080) >> 7 ? "Not enforced" : "Enforced");
+ obj_add_str(r, "CMB Data Pointer and Command Independent Locations Support (CDPCILS)",
+ (cmbloc & 0x00000040) >> 6 ? "Not enforced" : "Enforced");
+ obj_add_str(r, "CMB Data Pointer Mixed Locations Support (CDPMLS)",
+ (cmbloc & 0x00000020) >> 5 ? "Not enforced" : "Enforced");
+ obj_add_str(r, "CMB Queue Physically Discontiguous Support (CQPDS)",
+ (cmbloc & 0x00000010) >> 4 ? "Not enforced" : "Enforced");
+ obj_add_str(r, "CMB Queue Mixed Memory Support (CQMMS)",
+ (cmbloc & 0x00000008) >> 3 ? "Not enforced" : "Enforced");
+ obj_add_uint_0x(r, "Base Indicator Register (BIR)", (cmbloc & 0x00000007));
+}
+
+static void json_registers_cmbsz(uint32_t cmbsz, struct json_object *r)
+{
+ obj_add_uint_x(r, "cmbsz", cmbsz);
+
+ if (!cmbsz) {
+ obj_add_result(r, "Controller Memory Buffer feature is not supported");
+ return;
+ }
+
+ obj_add_uint(r, "Size (SZ)", (cmbsz & 0xfffff000) >> 12);
+ obj_add_str(r, "Size Units (SZU)", nvme_register_szu_to_string((cmbsz & 0xf00) >> 8));
+ obj_add_str(r, "Write Data Support (WDS)", cmbsz & 0x10 ? "Supported" : "Not supported");
+ obj_add_str(r, "Read Data Support (RDS)", cmbsz & 8 ? "Supported" : "Not supported");
+ obj_add_str(r, "PRP SGL List Support (LISTS)", cmbsz & 4 ? "Supported" : "Not supported");
+ obj_add_str(r, "Completion Queue Support (CQS)", cmbsz & 2 ? "Supported" : "Not supported");
+ obj_add_str(r, "Submission Queue Support (SQS)", cmbsz & 1 ? "Supported" : "Not supported");
+}
+
+static void json_registers_bpinfo_brs(__u8 brs, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ switch (brs) {
+ case 0:
+ sprintf(json_str, "No Boot Partition read operation requested");
+ break;
+ case 1:
+ sprintf(json_str, "Boot Partition read in progress");
+ break;
+ case 2:
+ sprintf(json_str, "Boot Partition read completed successfully");
+ break;
+ case 3:
+ sprintf(json_str, "Error completing Boot Partition read");
+ break;
+ default:
+ sprintf(json_str, "%s", "Invalid");
+ break;
+ }
+
+ obj_add_str(r, "Boot Read Status (BRS)", json_str);
+}
+
+static void json_registers_bpinfo(uint32_t bpinfo, struct json_object *r)
+{
+ obj_add_uint_x(r, "bpinfo", bpinfo);
+
+ obj_add_uint(r, "Active Boot Partition ID (ABPID)", (bpinfo & 0x80000000) >> 31);
+ json_registers_bpinfo_brs((bpinfo & 0x3000000) >> 24, r);
+ obj_add_uint(r, "Boot Partition Size (BPSZ)", bpinfo & 0x7fff);
+}
+
+static void json_registers_bprsel(uint32_t bprsel, struct json_object *r)
+{
+ obj_add_uint_x(r, "bprsel", bprsel);
+
+ obj_add_uint(r, "Boot Partition Identifier (BPID)", (bprsel & 0x80000000) >> 31);
+ obj_add_uint_x(r, "Boot Partition Read Offset (BPROF)", (bprsel & 0x3ffffc00) >> 10);
+ obj_add_uint_x(r, "Boot Partition Read Size (BPRSZ)", bprsel & 0x3ff);
+}
+
+static void json_registers_bpmbl(uint64_t bpmbl, struct json_object *r)
+{
+ obj_add_prix64(r, "bpmbl", bpmbl);
+
+ obj_add_prix64(r, "Boot Partition Memory Buffer Base Address (BMBBA)", bpmbl);
+}
+
+static void json_registers_cmbmsc(uint64_t cmbmsc, struct json_object *r)
+{
+ obj_add_prix64(r, "cmbmsc", cmbmsc);
+
+ obj_add_prix64(r, "Controller Base Address (CBA)", (cmbmsc & 0xfffffffffffff000) >> 12);
+ obj_add_prix64(r, "Controller Memory Space Enable (CMSE)", (cmbmsc & 2) >> 1);
+ obj_add_str(r, "Capabilities Registers Enabled (CRE)",
+ cmbmsc & 1 ? "Enabled" : "Not enabled");
+}
+
+static void json_registers_cmbsts(uint32_t cmbsts , struct json_object *r)
+{
+ obj_add_uint_x(r, "cmbsts", cmbsts);
+
+ obj_add_uint_x(r, "Controller Base Address Invalid (CBAI)", cmbsts & 1);
+}
+
+static void json_registers_pmrcap(uint32_t pmrcap, struct json_object *r)
+{
+ obj_add_uint_x(r, "pmrcap", pmrcap);
+
+ obj_add_str(r, "Controller Memory Space Supported (CMSS)",
+ ((pmrcap & 0x01000000) >> 24) ? "Supported" : "Not supported");
+ obj_add_uint_x(r, "Persistent Memory Region Timeout (PMRTO)", (pmrcap & 0xff0000) >> 16);
+ obj_add_uint_x(r, "Persistent Memory Region Write Barrier Mechanisms (PMRWBM)",
+ (pmrcap & 0x3c00) >> 10);
+ obj_add_str(r, "Persistent Memory Region Time Units (PMRTU)",
+ (pmrcap & 0x300) >> 8 ? "minutes" : "500 milliseconds");
+ obj_add_uint_x(r, "Base Indicator Register (BIR)", (pmrcap & 0xe0) >> 5);
+ obj_add_str(r, "Write Data Support (WDS)", pmrcap & 0x10 ? "Supported" : "Not supported");
+ obj_add_str(r, "Read Data Support (RDS)", pmrcap & 8 ? "Supported" : "Not supported");
+}
+
+static void json_registers_pmrctl(uint32_t pmrctl, struct json_object *r)
+{
+ obj_add_uint_x(r, "pmrctl", pmrctl);
+
+ obj_add_str(r, "Enable (EN)", pmrctl & 1 ? "Ready" : "Disabled");
+}
+
+static void json_registers_pmrsts(uint32_t pmrsts, void *bar, struct json_object *r)
+{
+ uint32_t pmrctl = mmio_read32(bar + NVME_REG_PMRCTL);
+
+ obj_add_uint_x(r, "pmrsts", pmrsts);
+
+ obj_add_uint_x(r, "Controller Base Address Invalid (CBAI)", (pmrsts & 0x1000) >> 12);
+ obj_add_str(r, "Health Status (HSTS)",
+ nvme_register_pmr_hsts_to_string((pmrsts & 0xe00) >> 9));
+ obj_add_str(r, "Not Ready (NRDY)",
+ !(pmrsts & 0x100) && (pmrctl & 1) ? "Ready" : "Not ready");
+ obj_add_uint_x(r, "Error (ERR)", pmrsts & 0xff);
+}
+
+static void json_registers_pmrebs(uint32_t pmrebs, struct json_object *r)
+{
+ obj_add_uint_x(r, "pmrebs", pmrebs);
+
+ obj_add_uint_x(r, "PMR Elasticity Buffer Size Base (PMRWBZ)", (pmrebs & 0xffffff00) >> 8);
+ obj_add_str(r, "Read Bypass Behavior", pmrebs & 0x10 ? "Shall" : "May");
+ obj_add_str(r, "PMR Elasticity Buffer Size Units (PMRSZU)",
+ nvme_register_pmr_pmrszu_to_string(pmrebs & 0xf));
+}
+
+static void json_registers_pmrswtp(uint32_t pmrswtp, struct json_object *r)
+{
+ obj_add_uint_x(r, "pmrswtp", pmrswtp);
+
+ obj_add_uint_x(r, "PMR Sustained Write Throughput (PMRSWTV)", (pmrswtp & 0xffffff00) >> 8);
+ obj_add_key(r, "PMR Sustained Write Throughput Units (PMRSWTU)", "%s/second",
+ nvme_register_pmr_pmrszu_to_string(pmrswtp & 0xf));
+}
+
+static void json_registers_pmrmscl(uint32_t pmrmscl, struct json_object *r)
+{
+ obj_add_uint_nx(r, "pmrmscl", pmrmscl);
+
+ obj_add_uint_nx(r, "Controller Base Address (CBA)", (pmrmscl & 0xfffff000) >> 12);
+ obj_add_uint_nx(r, "Controller Memory Space Enable (CMSE)", (pmrmscl & 2) >> 1);
+}
+
+static void json_registers_pmrmscu(uint32_t pmrmscu, struct json_object *r)
+{
+ obj_add_uint_nx(r, "pmrmscu", pmrmscu);
+
+ obj_add_uint_nx(r, "Controller Base Address (CBA)", pmrmscu);
+}
+
+static void json_registers_unknown(int offset, uint64_t value64, struct json_object *r)
+{
+ obj_add_uint_02x(r, "unknown property", offset);
+ obj_add_str(r, "name", nvme_register_to_string(offset));
+ obj_add_prix64(r, "value", value64);
+}
+
+static void json_single_property_human(int offset, uint64_t value64, struct json_object *r)
+{
+ uint32_t value32 = (uint32_t)value64;
+
+ switch (offset) {
+ case NVME_REG_CAP:
+ json_registers_cap((struct nvme_bar_cap *)&value64, r);
+ break;
+ case NVME_REG_VS:
+ json_registers_version(value32, r);
+ break;
+ case NVME_REG_CC:
+ json_registers_cc(value32, r);
+ break;
+ case NVME_REG_CSTS:
+ json_registers_csts(value32, r);
+ break;
+ case NVME_REG_NSSR:
+ json_registers_nssr(value32, r);
+ break;
+ case NVME_REG_CRTO:
+ json_registers_crto(value32, r);
+ break;
+ default:
+ json_registers_unknown(offset, value64, r);
+ break;
+ }
+}
+
+static void json_single_property(int offset, uint64_t value64)
+{
+ struct json_object *r = json_create_object();
+ char json_str[STR_LEN];
+ uint32_t value32 = (uint32_t)value64;
+
+ if (human()) {
+ json_single_property_human(offset, value64, r);
+ } else {
+ sprintf(json_str, "0x%02x", offset);
+ obj_add_str(r, "property", json_str);
+
+ obj_add_str(r, "name", nvme_register_to_string(offset));
+
+ if (nvme_is_64bit_reg(offset))
+ sprintf(json_str, "%"PRIx64"", value64);
+ else
+ sprintf(json_str, "%x", value32);
+
+ obj_add_str(r, "value", json_str);
+ }
+
+ json_print(r);
+}
+
+struct json_object* json_effects_log(enum nvme_csi csi,
+ struct nvme_cmd_effects_log *effects_log)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *acs = json_create_object();
+ struct json_object *iocs = json_create_object();
+ unsigned int opcode;
+ char key[128];
+ __u32 effect;
+
+ obj_add_uint(r, "command_set_identifier", csi);
+
+ for (opcode = 0; opcode < 256; opcode++) {
+ effect = le32_to_cpu(effects_log->acs[opcode]);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ sprintf(key, "ACS_%u (%s)", opcode,
+ nvme_cmd_to_string(1, opcode));
+ obj_add_uint(acs, key, effect);
+ }
+ }
+
+ obj_add_obj(r, "admin_cmd_set", acs);
+
+ for (opcode = 0; opcode < 256; opcode++) {
+ effect = le32_to_cpu(effects_log->iocs[opcode]);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ sprintf(key, "IOCS_%u (%s)", opcode,
+ nvme_cmd_to_string(0, opcode));
+ obj_add_uint(iocs, key, effect);
+ }
+ }
+
+ obj_add_obj(r, "io_cmd_set", iocs);
+ return r;
+}
+
+static void json_effects_log_list(struct list_head *list)
+{
+ struct json_object *r = json_create_array();
+ nvme_effects_log_node_t *node;
+
+ list_for_each(list, node, node) {
+ struct json_object *json_page =
+ json_effects_log(node->csi, &node->effects);
+ array_add_obj(r, json_page);
+ }
+
+ json_print(r);
+}
+
+static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *dev = json_create_object();
+ struct json_object *sstat = json_create_object();
+ const char *status_str;
+ char str[128];
+ __u16 status = le16_to_cpu(sanitize_log->sstat);
+
+ obj_add_int(dev, "sprog", le16_to_cpu(sanitize_log->sprog));
+ obj_add_int(sstat, "global_erased", (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED) >> 8);
+ obj_add_int(sstat, "no_cmplted_passes",
+ (status >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) &
+ NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK);
+
+ status_str = nvme_sstat_status_to_string(status);
+ sprintf(str, "(%d) %s", status & NVME_SANITIZE_SSTAT_STATUS_MASK,
+ status_str);
+ obj_add_str(sstat, status_str, str);
+
+ obj_add_obj(dev, "sstat", sstat);
+ obj_add_uint(dev, "cdw10_info", le32_to_cpu(sanitize_log->scdw10));
+ obj_add_uint(dev, "time_over_write", le32_to_cpu(sanitize_log->eto));
+ obj_add_uint(dev, "time_block_erase", le32_to_cpu(sanitize_log->etbe));
+ obj_add_uint(dev, "time_crypto_erase", le32_to_cpu(sanitize_log->etce));
+ obj_add_uint(dev, "time_over_write_no_dealloc", le32_to_cpu(sanitize_log->etond));
+ obj_add_uint(dev, "time_block_erase_no_dealloc", le32_to_cpu(sanitize_log->etbend));
+ obj_add_uint(dev, "time_crypto_erase_no_dealloc", le32_to_cpu(sanitize_log->etcend));
+
+ obj_add_obj(r, devname, dev);
+
+ json_print(r);
+}
+
+static void json_predictable_latency_per_nvmset(
+ struct nvme_nvmset_predictable_lat_log *plpns_log,
+ __u16 nvmset_id, const char *devname)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "nvmset_id", le16_to_cpu(nvmset_id));
+ obj_add_uint(r, "status", plpns_log->status);
+ obj_add_uint(r, "event_type", le16_to_cpu(plpns_log->event_type));
+ obj_add_uint64(r, "dtwin_reads_typical", le64_to_cpu(plpns_log->dtwin_rt));
+ obj_add_uint64(r, "dtwin_writes_typical", le64_to_cpu(plpns_log->dtwin_wt));
+ obj_add_uint64(r, "dtwin_time_maximum", le64_to_cpu(plpns_log->dtwin_tmax));
+ obj_add_uint64(r, "ndwin_time_minimum_high", le64_to_cpu(plpns_log->ndwin_tmin_hi));
+ obj_add_uint64(r, "ndwin_time_minimum_low", le64_to_cpu(plpns_log->ndwin_tmin_lo));
+ obj_add_uint64(r, "dtwin_reads_estimate", le64_to_cpu(plpns_log->dtwin_re));
+ obj_add_uint64(r, "dtwin_writes_estimate", le64_to_cpu(plpns_log->dtwin_we));
+ obj_add_uint64(r, "dtwin_time_estimate", le64_to_cpu(plpns_log->dtwin_te));
+
+ json_print(r);
+}
+
+static void json_predictable_latency_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *pea_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid_attrs;
+ struct json_object *valid = json_create_array();
+ __u64 num_entries = le64_to_cpu(pea_log->num_entries);
+ __u64 num_iter = min(num_entries, log_entries);
+
+ obj_add_uint64(r, "num_entries_avail", num_entries);
+
+ for (int i = 0; i < num_iter; i++) {
+ valid_attrs = json_create_object();
+ obj_add_uint(valid_attrs, "entry", le16_to_cpu(pea_log->entries[i]));
+ array_add_obj(valid, valid_attrs);
+ }
+
+ obj_add_array(r, "list_of_entries", valid);
+
+ json_print(r);
+}
+
+static void json_add_bitmap(int i, __u8 seb, struct json_object *r)
+{
+ char evt_str[50];
+ char key[128];
+
+ for (int bit = 0; bit < 8; bit++) {
+ if (nvme_pel_event_to_string(bit + i * 8)) {
+ sprintf(key, "bitmap_%x", (bit + i * 8));
+ if ((seb >> bit) & 0x1)
+ snprintf(evt_str, sizeof(evt_str), "Support %s",
+ nvme_pel_event_to_string(bit + i * 8));
+ obj_add_str(r, key, evt_str);
+ }
+ }
+}
+
+static void json_pevent_log_head(struct nvme_persistent_event_log *pevent_log_head,
+ struct json_object *r)
+{
+ int i;
+ char sn[sizeof(pevent_log_head->sn) + 1];
+ char mn[sizeof(pevent_log_head->mn) + 1];
+ char 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);
+
+ obj_add_uint(r, "log_id", pevent_log_head->lid);
+ obj_add_uint(r, "total_num_of_events", le32_to_cpu(pevent_log_head->tnev));
+ obj_add_uint64(r, "total_log_len", le64_to_cpu(pevent_log_head->tll));
+ obj_add_uint(r, "log_revision", pevent_log_head->rv);
+ obj_add_uint(r, "log_header_len", le16_to_cpu(pevent_log_head->lhl));
+ obj_add_uint64(r, "timestamp", le64_to_cpu(pevent_log_head->ts));
+ obj_add_uint128(r, "power_on_hours", le128_to_cpu(pevent_log_head->poh));
+ obj_add_uint64(r, "power_cycle_count", le64_to_cpu(pevent_log_head->pcc));
+ obj_add_uint(r, "pci_vid", le16_to_cpu(pevent_log_head->vid));
+ obj_add_uint(r, "pci_ssvid", le16_to_cpu(pevent_log_head->ssvid));
+ obj_add_str(r, "sn", sn);
+ obj_add_str(r, "mn", mn);
+ obj_add_str(r, "subnqn", subnqn);
+ obj_add_uint(r, "gen_number", le16_to_cpu(pevent_log_head->gen_number));
+ obj_add_uint(r, "rci", le32_to_cpu(pevent_log_head->rci));
+
+ for (i = 0; i < ARRAY_SIZE(pevent_log_head->seb); i++) {
+ if (!pevent_log_head->seb[i])
+ continue;
+ json_add_bitmap(i, pevent_log_head->seb[i], r);
+ }
+}
+
+static void json_pel_smart_health(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ char key[128];
+ struct nvme_smart_log *smart_event = pevent_log_info + offset;
+ unsigned int temperature = (smart_event->temperature[1] << 8) | smart_event->temperature[0];
+ nvme_uint128_t data_units_read = le128_to_cpu(smart_event->data_units_read);
+ nvme_uint128_t data_units_written = le128_to_cpu(smart_event->data_units_written);
+ nvme_uint128_t host_read_commands = le128_to_cpu(smart_event->host_reads);
+ nvme_uint128_t host_write_commands = le128_to_cpu(smart_event->host_writes);
+ nvme_uint128_t controller_busy_time = le128_to_cpu(smart_event->ctrl_busy_time);
+ nvme_uint128_t power_cycles = le128_to_cpu(smart_event->power_cycles);
+ nvme_uint128_t power_on_hours = le128_to_cpu(smart_event->power_on_hours);
+ nvme_uint128_t unsafe_shutdowns = le128_to_cpu(smart_event->unsafe_shutdowns);
+ nvme_uint128_t media_errors = le128_to_cpu(smart_event->media_errors);
+ nvme_uint128_t num_err_log_entries = le128_to_cpu(smart_event->num_err_log_entries);
+ int c;
+ __s32 temp;
+
+ obj_add_int(valid_attrs, "critical_warning", smart_event->critical_warning);
+ obj_add_int(valid_attrs, "temperature", temperature);
+ obj_add_int(valid_attrs, "avail_spare", smart_event->avail_spare);
+ obj_add_int(valid_attrs, "spare_thresh", smart_event->spare_thresh);
+ obj_add_int(valid_attrs, "percent_used", smart_event->percent_used);
+ obj_add_int(valid_attrs, "endurance_grp_critical_warning_summary",
+ smart_event->endu_grp_crit_warn_sumry);
+ obj_add_uint128(valid_attrs, "data_units_read", data_units_read);
+ obj_add_uint128(valid_attrs, "data_units_written", data_units_written);
+ obj_add_uint128(valid_attrs, "host_read_commands", host_read_commands);
+ obj_add_uint128(valid_attrs, "host_write_commands", host_write_commands);
+ obj_add_uint128(valid_attrs, "controller_busy_time", controller_busy_time);
+ obj_add_uint128(valid_attrs, "power_cycles", power_cycles);
+ obj_add_uint128(valid_attrs, "power_on_hours", power_on_hours);
+ obj_add_uint128(valid_attrs, "unsafe_shutdowns", unsafe_shutdowns);
+ obj_add_uint128(valid_attrs, "media_errors", media_errors);
+ obj_add_uint128(valid_attrs, "num_err_log_entries", num_err_log_entries);
+ obj_add_uint(valid_attrs, "warning_temp_time", le32_to_cpu(smart_event->warning_temp_time));
+ obj_add_uint(valid_attrs, "critical_comp_time",
+ le32_to_cpu(smart_event->critical_comp_time));
+
+ for (c = 0; c < 8; c++) {
+ temp = le16_to_cpu(smart_event->temp_sensor[c]);
+ if (!temp)
+ continue;
+ sprintf(key, "temperature_sensor_%d",c + 1);
+ obj_add_int(valid_attrs, key, temp);
+ }
+
+ obj_add_uint(valid_attrs, "thm_temp1_trans_count",
+ le32_to_cpu(smart_event->thm_temp1_trans_count));
+ obj_add_uint(valid_attrs, "thm_temp2_trans_count",
+ le32_to_cpu(smart_event->thm_temp2_trans_count));
+ obj_add_uint(valid_attrs, "thm_temp1_total_time",
+ le32_to_cpu(smart_event->thm_temp1_total_time));
+ obj_add_uint(valid_attrs, "thm_temp2_total_time",
+ le32_to_cpu(smart_event->thm_temp2_total_time));
+}
+
+static void json_pel_fw_commit(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs)
+{
+ char fw_str[50];
+ struct nvme_fw_commit_event *fw_commit_event = pevent_log_info + offset;
+
+ snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(fw_commit_event->old_fw_rev),
+ util_fw_to_string((char *)&fw_commit_event->old_fw_rev));
+ obj_add_str(valid_attrs, "old_fw_rev", fw_str);
+ snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(fw_commit_event->new_fw_rev),
+ util_fw_to_string((char *)&fw_commit_event->new_fw_rev));
+ obj_add_str(valid_attrs, "new_fw_rev", fw_str);
+ obj_add_uint(valid_attrs, "fw_commit_action", fw_commit_event->fw_commit_action);
+ obj_add_uint(valid_attrs, "fw_slot", fw_commit_event->fw_slot);
+ obj_add_uint(valid_attrs, "sct_fw", fw_commit_event->sct_fw);
+ obj_add_uint(valid_attrs, "sc_fw", fw_commit_event->sc_fw);
+ obj_add_uint(valid_attrs, "vu_assign_fw_commit_rc",
+ le16_to_cpu(fw_commit_event->vndr_assign_fw_commit_rc));
+}
+
+static void json_pel_timestamp(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs)
+{
+ struct nvme_time_stamp_change_event *ts_change_event = pevent_log_info + offset;
+
+ obj_add_uint64(valid_attrs, "prev_ts", le64_to_cpu(ts_change_event->previous_timestamp));
+ obj_add_uint64(valid_attrs, "ml_secs_since_reset",
+ le64_to_cpu(ts_change_event->ml_secs_since_reset));
+}
+
+static void json_pel_power_on_reset(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs, __le16 vsil, __le16 el)
+{
+ __u64 *fw_rev;
+ char fw_str[50];
+ struct nvme_power_on_reset_info_list *por_event;
+ __u32 por_info_len = le16_to_cpu(el) - le16_to_cpu(vsil) - sizeof(*fw_rev);
+ __u32 por_info_list = por_info_len / sizeof(*por_event);
+ int i;
+
+ fw_rev = pevent_log_info + offset;
+ snprintf(fw_str, sizeof(fw_str), "%"PRIu64" (%s)", le64_to_cpu(*fw_rev),
+ util_fw_to_string((char *)fw_rev));
+ obj_add_str(valid_attrs, "fw_rev", fw_str);
+
+ for (i = 0; i < por_info_list; i++) {
+ por_event = pevent_log_info + offset + sizeof(*fw_rev) + i * sizeof(*por_event);
+ obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(por_event->cid));
+ obj_add_uint(valid_attrs, "fw_act", por_event->fw_act);
+ obj_add_uint(valid_attrs, "op_in_prog", por_event->op_in_prog);
+ obj_add_uint(valid_attrs, "ctrl_power_cycle",
+ le32_to_cpu(por_event->ctrl_power_cycle));
+ obj_add_uint64(valid_attrs, "power_on_ml_secs",
+ le64_to_cpu(por_event->power_on_ml_seconds));
+ obj_add_uint64(valid_attrs, "ctrl_time_stamp",
+ le64_to_cpu(por_event->ctrl_time_stamp));
+ }
+}
+
+static void json_pel_nss_hw_error(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_nss_hw_err_event *nss_hw_err_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "nss_hw_err_code",
+ le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code));
+}
+
+static void json_pel_change_ns(void *pevent_log_info, __u32 offset, struct json_object *valid_attrs)
+{
+ struct nvme_change_ns_event *ns_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "nsmgt_cdw10", le32_to_cpu(ns_event->nsmgt_cdw10));
+ obj_add_uint64(valid_attrs, "nsze", le64_to_cpu(ns_event->nsze));
+ obj_add_uint64(valid_attrs, "nscap", le64_to_cpu(ns_event->nscap));
+ obj_add_uint(valid_attrs, "flbas", ns_event->flbas);
+ obj_add_uint(valid_attrs, "dps", ns_event->dps);
+ obj_add_uint(valid_attrs, "nmic", ns_event->nmic);
+ obj_add_uint(valid_attrs, "ana_grp_id", le32_to_cpu(ns_event->ana_grp_id));
+ obj_add_uint(valid_attrs, "nvmset_id", le16_to_cpu(ns_event->nvmset_id));
+ obj_add_uint(valid_attrs, "nsid", le32_to_cpu(ns_event->nsid));
+}
+
+static void json_pel_format_start(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_format_nvm_start_event *format_start_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "nsid", le32_to_cpu(format_start_event->nsid));
+ obj_add_uint(valid_attrs, "fna", format_start_event->fna);
+ obj_add_uint(valid_attrs, "format_nvm_cdw10",
+ le32_to_cpu(format_start_event->format_nvm_cdw10));
+}
+
+static void json_pel_format_completion(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_format_nvm_compln_event *format_cmpln_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "nsid", le32_to_cpu(format_cmpln_event->nsid));
+ obj_add_uint(valid_attrs, "smallest_fpi", format_cmpln_event->smallest_fpi);
+ obj_add_uint(valid_attrs, "format_nvm_status", format_cmpln_event->format_nvm_status);
+ obj_add_uint(valid_attrs, "compln_info", le16_to_cpu(format_cmpln_event->compln_info));
+ obj_add_uint(valid_attrs, "status_field", le32_to_cpu(format_cmpln_event->status_field));
+}
+static void json_pel_sanitize_start(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_sanitize_start_event *sanitize_start_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "SANICAP", le32_to_cpu(sanitize_start_event->sani_cap));
+ obj_add_uint(valid_attrs, "sani_cdw10", le32_to_cpu(sanitize_start_event->sani_cdw10));
+ obj_add_uint(valid_attrs, "sani_cdw11", le32_to_cpu(sanitize_start_event->sani_cdw11));
+}
+
+static void json_pel_sanitize_completion(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_sanitize_compln_event *sanitize_cmpln_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "sani_prog", le16_to_cpu(sanitize_cmpln_event->sani_prog));
+ obj_add_uint(valid_attrs, "sani_status", le16_to_cpu(sanitize_cmpln_event->sani_status));
+ obj_add_uint(valid_attrs, "cmpln_info", le16_to_cpu(sanitize_cmpln_event->cmpln_info));
+}
+
+static void json_pel_thermal_excursion(void *pevent_log_info, __u32 offset,
+ struct json_object *valid_attrs)
+{
+ struct nvme_thermal_exc_event *thermal_exc_event = pevent_log_info + offset;
+
+ obj_add_uint(valid_attrs, "over_temp", thermal_exc_event->over_temp);
+ obj_add_uint(valid_attrs, "threshold", thermal_exc_event->threshold);
+}
+
+static void json_pevent_entry(void *pevent_log_info, __u8 action, __u32 size, const char *devname,
+ __u32 offset, struct json_object *valid)
+{
+ int i;
+ struct nvme_persistent_event_log *pevent_log_head = pevent_log_info;
+ struct nvme_persistent_event_entry *pevent_entry_head;
+ struct json_object *valid_attrs;
+
+ for (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();
+
+ obj_add_uint(valid_attrs, "event_number", i);
+ obj_add_str(valid_attrs, "event_type",
+ nvme_pel_event_to_string(pevent_entry_head->etype));
+ obj_add_uint(valid_attrs, "event_type_rev", pevent_entry_head->etype_rev);
+ obj_add_uint(valid_attrs, "event_header_len", pevent_entry_head->ehl);
+ obj_add_uint(valid_attrs, "event_header_additional_info", pevent_entry_head->ehai);
+ obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(pevent_entry_head->cntlid));
+ obj_add_uint64(valid_attrs, "event_time_stamp",
+ le64_to_cpu(pevent_entry_head->ets));
+ obj_add_uint(valid_attrs, "port_id", le16_to_cpu(pevent_entry_head->pelpid));
+ obj_add_uint(valid_attrs, "vu_info_len", le16_to_cpu(pevent_entry_head->vsil));
+ obj_add_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_PEL_SMART_HEALTH_EVENT:
+ json_pel_smart_health(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_FW_COMMIT_EVENT:
+ json_pel_fw_commit(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_TIMESTAMP_EVENT:
+ json_pel_timestamp(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_POWER_ON_RESET_EVENT:
+ json_pel_power_on_reset(pevent_log_info, offset, valid_attrs,
+ pevent_entry_head->el, pevent_entry_head->vsil);
+ break;
+ case NVME_PEL_NSS_HW_ERROR_EVENT:
+ json_pel_nss_hw_error(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_CHANGE_NS_EVENT:
+ json_pel_change_ns(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_FORMAT_START_EVENT:
+ json_pel_format_start(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_FORMAT_COMPLETION_EVENT:
+ json_pel_format_completion(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_SANITIZE_START_EVENT:
+ json_pel_sanitize_start(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_SANITIZE_COMPLETION_EVENT:
+ json_pel_sanitize_completion(pevent_log_info, offset, valid_attrs);
+ break;
+ case NVME_PEL_THERMAL_EXCURSION_EVENT:
+ json_pel_thermal_excursion(pevent_log_info, offset, valid_attrs);
+ break;
+ default:
+ break;
+ }
+
+ array_add_obj(valid, valid_attrs);
+ offset += le16_to_cpu(pevent_entry_head->el);
+ }
+}
+
+static void json_persistent_event_log(void *pevent_log_info, __u8 action,
+ __u32 size, const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid = json_create_array();
+ __u32 offset = sizeof(struct nvme_persistent_event_log);
+
+ if (size >= offset) {
+ json_pevent_log_head(pevent_log_info, r);
+ json_pevent_entry(pevent_log_info, action, size, devname, offset, valid);
+ obj_add_array(r, "list_of_event_entries", valid);
+ } else {
+ obj_add_result(r, "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");
+ }
+
+ json_print(r);
+}
+
+static void json_endurance_group_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid_attrs;
+ struct json_object *valid = json_create_array();
+
+ obj_add_uint64(r, "num_entries_avail", le64_to_cpu(endurance_log->num_entries));
+
+ for (int i = 0; i < log_entries; i++) {
+ valid_attrs = json_create_object();
+ obj_add_uint(valid_attrs, "entry", le16_to_cpu(endurance_log->entries[i]));
+ array_add_obj(valid, valid_attrs);
+ }
+
+ obj_add_array(r, "list_of_entries", valid);
+
+ json_print(r);
+}
+
+static void json_lba_status(struct nvme_lba_status *list,
+ unsigned long len)
+{
+ struct json_object *r = json_create_object();
+ int idx;
+ struct nvme_lba_status_desc *e;
+ struct json_object *lsde;
+ char json_str[STR_LEN];
+
+ obj_add_uint(r, "Number of LBA Status Descriptors (NLSD)", le32_to_cpu(list->nlsd));
+ obj_add_uint(r, "Completion Condition (CMPC)", list->cmpc);
+
+ switch (list->cmpc) {
+ case 1:
+ obj_add_str(r, "cmpc-definition",
+ "Completed due to transferring the amount of data specified in the MNDW field");
+ break;
+ case 2:
+ obj_add_str(r, "cmpc-definition",
+ "Completed due to having performed the action specified in the Action Type field over the number of logical blocks specified in the Range Length field");
+ break;
+ default:
+ break;
+ }
+
+ for (idx = 0; idx < list->nlsd; idx++) {
+ lsde = json_create_array();
+ sprintf(json_str, "LSD entry %d", idx);
+ obj_add_array(r, json_str, lsde);
+ e = &list->descs[idx];
+ sprintf(json_str, "0x%016"PRIu64"", le64_to_cpu(e->dslba));
+ obj_add_str(lsde, "DSLBA", json_str);
+ sprintf(json_str, "0x%08x", le32_to_cpu(e->nlb));
+ obj_add_str(lsde, "NLB", json_str);
+ sprintf(json_str, "0x%02x", e->status);
+ obj_add_str(lsde, "status", json_str);
+ }
+
+ json_print(r);
+}
+
+static void json_lba_status_log(void *lba_status, __u32 size, const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *desc;
+ struct json_object *element;
+ struct json_object *desc_list;
+ struct json_object *elements_list = json_create_array();
+ struct nvme_lba_status_log *hdr = lba_status;
+ struct nvme_lbas_ns_element *ns_element;
+ struct nvme_lba_rd *range_desc;
+ int offset = sizeof(*hdr);
+ __u32 num_lba_desc;
+ __u32 num_elements = le32_to_cpu(hdr->nlslne);
+ int ele;
+ int i;
+
+ obj_add_uint(r, "lslplen", le32_to_cpu(hdr->lslplen));
+ obj_add_uint(r, "nlslne", num_elements);
+ obj_add_uint(r, "estulb", le32_to_cpu(hdr->estulb));
+ obj_add_uint(r, "lsgc", le16_to_cpu(hdr->lsgc));
+
+ for (ele = 0; ele < num_elements; ele++) {
+ ns_element = lba_status + offset;
+ element = json_create_object();
+ obj_add_uint(element, "neid", le32_to_cpu(ns_element->neid));
+ num_lba_desc = le32_to_cpu(ns_element->nlrd);
+ obj_add_uint(element, "nlrd", num_lba_desc);
+ obj_add_uint(element, "ratype", ns_element->ratype);
+
+ offset += sizeof(*ns_element);
+ desc_list = json_create_array();
+
+ if (num_lba_desc != 0xffffffff) {
+ for (i = 0; i < num_lba_desc; i++) {
+ range_desc = lba_status + offset;
+ desc = json_create_object();
+ obj_add_uint64(desc, "rslba", le64_to_cpu(range_desc->rslba));
+ obj_add_uint(desc, "rnlb", le32_to_cpu(range_desc->rnlb));
+
+ offset += sizeof(*range_desc);
+ array_add_obj(desc_list, desc);
+ }
+ } else {
+ obj_add_result(r, "Number of LBA Range Descriptors (NLRD) set to %#x for NS element %d",
+ num_lba_desc, ele);
+ }
+
+ obj_add_array(element, "descs", desc_list);
+ array_add_obj(elements_list, element);
+ }
+
+ obj_add_array(r, "ns_elements", elements_list);
+
+ json_print(r);
+}
+
+static void json_resv_notif_log(struct nvme_resv_notification_log *resv,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint64(r, "count", le64_to_cpu(resv->lpc));
+ obj_add_uint(r, "rn_log_type", resv->rnlpt);
+ obj_add_uint(r, "num_logs", resv->nalp);
+ obj_add_uint(r, "NSID", le32_to_cpu(resv->nsid));
+
+ json_print(r);
+}
+
+static void json_fid_support_effects_log(
+ struct nvme_fid_supported_effects_log *fid_log,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *fids;
+ struct json_object *fids_list = json_create_array();
+ unsigned int fid;
+ char key[128];
+ __u32 fid_support;
+
+ for (fid = 0; fid < NVME_LOG_FID_SUPPORTED_EFFECTS_MAX; fid++) {
+ fid_support = le32_to_cpu(fid_log->fid_support[fid]);
+ if (fid_support & NVME_FID_SUPPORTED_EFFECTS_FSUPP) {
+ fids = json_create_object();
+ sprintf(key, "fid_%u", fid);
+ obj_add_uint(fids, key, fid_support);
+ array_add_obj(fids_list, fids);
+ }
+ }
+
+ obj_add_obj(r, "fid_support", fids_list);
+
+ json_print(r);
+}
+
+static void json_mi_cmd_support_effects_log(
+ struct nvme_mi_cmd_supported_effects_log *mi_cmd_log,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *mi_cmds;
+ struct json_object *mi_cmds_list = json_create_array();
+ unsigned int mi_cmd;
+ char key[128];
+ __u32 mi_cmd_support;
+
+ for (mi_cmd = 0; mi_cmd < NVME_LOG_MI_CMD_SUPPORTED_EFFECTS_MAX; mi_cmd++) {
+ mi_cmd_support = le32_to_cpu(mi_cmd_log->mi_cmd_support[mi_cmd]);
+ if (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) {
+ mi_cmds = json_create_object();
+ sprintf(key, "mi_cmd_%u", mi_cmd);
+ obj_add_uint(mi_cmds, key, mi_cmd_support);
+ array_add_obj(mi_cmds_list, mi_cmds);
+ }
+ }
+
+ obj_add_obj(r, "mi_command_support", mi_cmds_list);
+
+ json_print(r);
+}
+
+static void json_boot_part_log(void *bp_log, const char *devname,
+ __u32 size)
+{
+ struct nvme_boot_partition *hdr = bp_log;
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "count", hdr->lid);
+ obj_add_uint(r, "abpid", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1);
+ obj_add_uint(r, "bpsz", le32_to_cpu(hdr->bpinfo) & 0x7fff);
+
+ json_print(r);
+}
+
+/* Printable Eye string is allocated and returned, caller must free */
+static char *json_eom_printable_eye(struct nvme_eom_lane_desc *lane,
+ struct json_object *r)
+{
+ char *eye = (char *)lane->eye_desc;
+ char *printable = malloc(lane->nrows * lane->ncols + lane->ncols);
+ char *printable_start = printable;
+ int i, j;
+
+ if (!printable)
+ goto exit;
+
+ for (i = 0; i < lane->nrows; i++) {
+ for (j = 0; j < lane->ncols; j++, printable++)
+ sprintf(printable, "%c", eye[i * lane->ncols + j]);
+ sprintf(printable++, "\n");
+ }
+
+ obj_add_str(r, "printable_eye", printable_start);
+
+exit:
+ return printable_start;
+}
+
+static void json_phy_rx_eom_descs(struct nvme_phy_rx_eom_log *log,
+ struct json_object *r, char **allocated_eyes)
+{
+ void *p = log->descs;
+ uint16_t num_descs = le16_to_cpu(log->nd);
+ int i;
+ struct json_object *descs = json_create_array();
+
+ obj_add_array(r, "descs", descs);
+
+ for (i = 0; i < num_descs; i++) {
+ struct nvme_eom_lane_desc *desc = p;
+ struct json_object *jdesc = json_create_object();
+
+ obj_add_uint(jdesc, "lid", desc->mstatus);
+ obj_add_uint(jdesc, "lane", desc->lane);
+ obj_add_uint(jdesc, "eye", desc->eye);
+ obj_add_uint(jdesc, "top", le16_to_cpu(desc->top));
+ obj_add_uint(jdesc, "bottom", le16_to_cpu(desc->bottom));
+ obj_add_uint(jdesc, "left", le16_to_cpu(desc->left));
+ obj_add_uint(jdesc, "right", le16_to_cpu(desc->right));
+ obj_add_uint(jdesc, "nrows", le16_to_cpu(desc->nrows));
+ obj_add_uint(jdesc, "ncols", le16_to_cpu(desc->ncols));
+ obj_add_uint(jdesc, "edlen", le16_to_cpu(desc->edlen));
+
+ if (log->odp & NVME_EOM_PRINTABLE_EYE_PRESENT)
+ allocated_eyes[i] = json_eom_printable_eye(desc, r);
+
+ /* Eye Data field is vendor specific, doesn't map to JSON */
+
+ array_add_obj(descs, jdesc);
+
+ p += log->dsize;
+ }
+}
+
+static void json_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller)
+{
+ char **allocated_eyes = NULL;
+ int i;
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "lid", log->lid);
+ obj_add_uint(r, "eomip", log->eomip);
+ obj_add_uint(r, "hsize", le16_to_cpu(log->hsize));
+ obj_add_uint(r, "rsize", le32_to_cpu(log->rsize));
+ obj_add_uint(r, "eomdgn", log->eomdgn);
+ obj_add_uint(r, "lr", log->lr);
+ obj_add_uint(r, "lanes", log->lanes);
+ obj_add_uint(r, "epl", log->epl);
+ obj_add_uint(r, "lspfc", log->lspfc);
+ obj_add_uint(r, "li", log->li);
+ obj_add_uint(r, "lsic", le16_to_cpu(log->lsic));
+ obj_add_uint(r, "dsize", le32_to_cpu(log->dsize));
+ obj_add_uint(r, "nd", le16_to_cpu(log->nd));
+ obj_add_uint(r, "maxtb", le16_to_cpu(log->maxtb));
+ obj_add_uint(r, "maxlr", le16_to_cpu(log->maxlr));
+ obj_add_uint(r, "etgood", le16_to_cpu(log->etgood));
+ obj_add_uint(r, "etbetter", le16_to_cpu(log->etbetter));
+ obj_add_uint(r, "etbest", le16_to_cpu(log->etbest));
+
+ if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) {
+ /* Save Printable Eye strings allocated to free later */
+ allocated_eyes = malloc(log->nd * sizeof(char *));
+ if (allocated_eyes)
+ json_phy_rx_eom_descs(log, r, allocated_eyes);
+ }
+
+ if (allocated_eyes) {
+ for (i = 0; i < log->nd; i++) {
+ /* Free any Printable Eye strings allocated */
+ if (allocated_eyes[i])
+ free(allocated_eyes[i]);
+ }
+ free(allocated_eyes);
+ }
+
+ json_print(r);
+}
+
+static void json_media_unit_stat_log(struct nvme_media_unit_stat_log *mus)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *entries = json_create_array();
+ struct json_object *entry;
+ int i;
+
+ obj_add_uint(r, "nmu", le16_to_cpu(mus->nmu));
+ obj_add_uint(r, "cchans", le16_to_cpu(mus->cchans));
+ obj_add_uint(r, "sel_config", le16_to_cpu(mus->sel_config));
+
+ for (i = 0; i < mus->nmu; i++) {
+ entry = json_create_object();
+ obj_add_uint(entry, "muid", le16_to_cpu(mus->mus_desc[i].muid));
+ obj_add_uint(entry, "domainid", le16_to_cpu(mus->mus_desc[i].domainid));
+ obj_add_uint(entry, "endgid", le16_to_cpu(mus->mus_desc[i].endgid));
+ obj_add_uint(entry, "nvmsetid", le16_to_cpu(mus->mus_desc[i].nvmsetid));
+ obj_add_uint(entry, "cap_adj_fctr", le16_to_cpu(mus->mus_desc[i].cap_adj_fctr));
+ obj_add_uint(entry, "avl_spare", mus->mus_desc[i].avl_spare);
+ obj_add_uint(entry, "percent_used", mus->mus_desc[i].percent_used);
+ obj_add_uint(entry, "mucs", mus->mus_desc[i].mucs);
+ obj_add_uint(entry, "cio", mus->mus_desc[i].cio);
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "mus_list", entries);
+
+ json_print(r);
+}
+
+static void json_supported_cap_config_log(
+ struct nvme_supported_cap_config_list_log *cap_log)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *cap_list = json_create_array();
+ struct json_object *capacity;
+ struct json_object *end_list;
+ struct json_object *set_list;
+ struct json_object *set;
+ struct json_object *chan_list;
+ struct json_object *channel;
+ struct json_object *media_list;
+ struct json_object *media;
+ struct json_object *endurance;
+ struct nvme_end_grp_chan_desc *chan_desc;
+ int i, j, k, l, m, egcn, egsets, egchans, chmus;
+ int sccn = cap_log->sccn;
+
+ obj_add_uint(r, "sccn", cap_log->sccn);
+ for (i = 0; i < sccn; i++) {
+ capacity = json_create_object();
+ obj_add_uint(capacity, "cap_config_id",
+ le16_to_cpu(cap_log->cap_config_desc[i].cap_config_id));
+ obj_add_uint(capacity, "domainid",
+ le16_to_cpu(cap_log->cap_config_desc[i].domainid));
+ obj_add_uint(capacity, "egcn", le16_to_cpu(cap_log->cap_config_desc[i].egcn));
+ end_list = json_create_array();
+ egcn = le16_to_cpu(cap_log->cap_config_desc[i].egcn);
+ for (j = 0; j < egcn; j++) {
+ endurance = json_create_object();
+ obj_add_uint(endurance, "endgid",
+ le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].endgid));
+ obj_add_uint(endurance, "cap_adj_factor",
+ le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].cap_adj_factor));
+ obj_add_uint128(endurance, "tegcap",
+ le128_to_cpu(cap_log->cap_config_desc[i].egcd[j].tegcap));
+ obj_add_uint128(endurance, "segcap",
+ le128_to_cpu(cap_log->cap_config_desc[i].egcd[j].segcap));
+ obj_add_uint(endurance, "egsets",
+ le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets));
+ egsets = le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].egsets);
+ set_list = json_create_array();
+ for (k = 0; k < egsets; k++) {
+ set = json_create_object();
+ obj_add_uint(set, "nvmsetid",
+ le16_to_cpu(cap_log->cap_config_desc[i].egcd[j].nvmsetid[k]));
+ array_add_obj(set_list, set);
+ }
+ chan_desc = (struct nvme_end_grp_chan_desc *)
+ (cap_log->cap_config_desc[i].egcd[j].nvmsetid[0] * sizeof(__u16) * egsets);
+ egchans = le16_to_cpu(chan_desc->egchans);
+ obj_add_uint(endurance, "egchans", le16_to_cpu(chan_desc->egchans));
+ chan_list = json_create_array();
+ for (l = 0; l < egchans; l++) {
+ channel = json_create_object();
+ obj_add_uint(channel, "chanid",
+ le16_to_cpu(chan_desc->chan_config_desc[l].chanid));
+ obj_add_uint(channel, "chmus",
+ le16_to_cpu(chan_desc->chan_config_desc[l].chmus));
+ chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus);
+ media_list = json_create_array();
+ for (m = 0; m < chmus; m++) {
+ media = json_create_object();
+ obj_add_uint(media, "chanid",
+ le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid));
+ obj_add_uint(media, "chmus",
+ le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl));
+ array_add_obj(media_list, media);
+ }
+ obj_add_array(channel, "Media Descriptor", media_list);
+ array_add_obj(chan_list, channel);
+ }
+ obj_add_array(endurance, "Channel Descriptor", chan_list);
+ obj_add_array(endurance, "NVM Set IDs", set_list);
+ array_add_obj(end_list, endurance);
+ }
+ obj_add_array(capacity, "Endurance Descriptor", end_list);
+ array_add_obj(cap_list, capacity);
+ }
+
+ obj_add_array(r, "Capacity Descriptor", cap_list);
+
+ json_print(r);
+}
+
+static void json_nvme_fdp_configs(struct nvme_fdp_config_log *log, size_t len)
+{
+ struct json_object *r, *obj_configs;
+ uint16_t n;
+
+ void *p = log->configs;
+
+ r = json_create_object();
+ obj_configs = json_create_array();
+
+ n = le16_to_cpu(log->n);
+
+ obj_add_uint(r, "n", n);
+
+ for (int i = 0; i < n + 1; i++) {
+ struct nvme_fdp_config_desc *config = p;
+
+ struct json_object *obj_config = json_create_object();
+ struct json_object *obj_ruhs = json_create_array();
+
+ obj_add_uint(obj_config, "fdpa", config->fdpa);
+ obj_add_uint(obj_config, "vss", config->vss);
+ obj_add_uint(obj_config, "nrg", le32_to_cpu(config->nrg));
+ obj_add_uint(obj_config, "nruh", le16_to_cpu(config->nruh));
+ obj_add_uint(obj_config, "nnss", le32_to_cpu(config->nnss));
+ obj_add_uint64(obj_config, "runs", le64_to_cpu(config->runs));
+ obj_add_uint(obj_config, "erutl", le32_to_cpu(config->erutl));
+
+ for (int j = 0; j < le16_to_cpu(config->nruh); j++) {
+ struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j];
+
+ struct json_object *obj_ruh = json_create_object();
+
+ obj_add_uint(obj_ruh, "ruht", ruh->ruht);
+
+ array_add_obj(obj_ruhs, obj_ruh);
+ }
+
+ array_add_obj(obj_configs, obj_config);
+
+ p += config->size;
+ }
+
+ obj_add_array(r, "configs", obj_configs);
+
+ json_print(r);
+}
+
+static void json_nvme_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len)
+{
+ struct json_object *r, *obj_ruhus;
+ uint16_t nruh;
+
+ r = json_create_object();
+ obj_ruhus = json_create_array();
+
+ nruh = le16_to_cpu(log->nruh);
+
+ obj_add_uint(r, "nruh", nruh);
+
+ for (int i = 0; i < nruh; i++) {
+ struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i];
+
+ struct json_object *obj_ruhu = json_create_object();
+
+ obj_add_uint(obj_ruhu, "ruha", ruhu->ruha);
+
+ array_add_obj(obj_ruhus, obj_ruhu);
+ }
+
+ obj_add_array(r, "ruhus", obj_ruhus);
+
+ json_print(r);
+}
+
+static void json_nvme_fdp_stats(struct nvme_fdp_stats_log *log)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint128(r, "hbmw", le128_to_cpu(log->hbmw));
+ obj_add_uint128(r, "mbmw", le128_to_cpu(log->mbmw));
+ obj_add_uint128(r, "mbe", le128_to_cpu(log->mbe));
+
+ json_print(r);
+}
+
+static void json_nvme_fdp_events(struct nvme_fdp_events_log *log)
+{
+ struct json_object *r, *obj_events;
+ uint32_t n;
+
+ r = json_create_object();
+ obj_events = json_create_array();
+
+ n = le32_to_cpu(log->n);
+
+ obj_add_uint(r, "n", n);
+
+ for (unsigned int i = 0; i < n; i++) {
+ struct nvme_fdp_event *event = &log->events[i];
+
+ struct json_object *obj_event = json_create_object();
+
+ obj_add_uint(obj_event, "type", event->type);
+ obj_add_uint(obj_event, "fdpef", event->flags);
+ obj_add_uint(obj_event, "pid", le16_to_cpu(event->pid));
+ obj_add_uint64(obj_event, "timestamp", le64_to_cpu(*(uint64_t *)&event->ts));
+ obj_add_uint(obj_event, "nsid", le32_to_cpu(event->nsid));
+
+ if (event->type == NVME_FDP_EVENT_REALLOC) {
+ struct nvme_fdp_event_realloc *mr;
+ mr = (struct nvme_fdp_event_realloc *)&event->type_specific;
+
+ obj_add_uint(obj_event, "nlbam", le16_to_cpu(mr->nlbam));
+
+ if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV)
+ obj_add_uint64(obj_event, "lba", le64_to_cpu(mr->lba));
+ }
+
+ array_add_obj(obj_events, obj_event);
+ }
+
+ obj_add_array(r, "events", obj_events);
+
+ json_print(r);
+}
+
+static void json_nvme_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len)
+{
+ struct json_object *r, *obj_ruhss;
+ uint16_t nruhsd;
+
+ r = json_create_object();
+ obj_ruhss = json_create_array();
+
+ nruhsd = le16_to_cpu(status->nruhsd);
+
+ obj_add_uint(r, "nruhsd", nruhsd);
+
+ for (unsigned int i = 0; i < nruhsd; i++) {
+ struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i];
+
+ struct json_object *obj_ruhs = json_create_object();
+
+ obj_add_uint(obj_ruhs, "pid", le16_to_cpu(ruhs->pid));
+ obj_add_uint(obj_ruhs, "ruhid", le16_to_cpu(ruhs->ruhid));
+ obj_add_uint(obj_ruhs, "earutr", le32_to_cpu(ruhs->earutr));
+ obj_add_uint64(obj_ruhs, "ruamw", le64_to_cpu(ruhs->ruamw));
+
+ array_add_obj(obj_ruhss, obj_ruhs);
+ }
+
+ obj_add_array(r, "ruhss", obj_ruhss);
+
+ json_print(r);
+}
+
+static unsigned int json_print_nvme_subsystem_multipath(nvme_subsystem_t s, json_object *paths)
+{
+ nvme_ns_t n;
+ nvme_path_t p;
+ unsigned int i = 0;
+
+ n = nvme_subsystem_first_ns(s);
+ if (!n)
+ return 0;
+
+ nvme_namespace_for_each_path(n, p) {
+ struct json_object *path_attrs;
+ nvme_ctrl_t c = nvme_path_get_ctrl(p);
+
+ path_attrs = json_create_object();
+ obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c));
+ obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c));
+ obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c));
+ obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c));
+ obj_add_str(path_attrs, "ANAState", nvme_path_get_ana_state(p));
+ array_add_obj(paths, path_attrs);
+ i++;
+ }
+
+ return i;
+}
+
+static void json_print_nvme_subsystem_ctrls(nvme_subsystem_t s,
+ json_object *paths)
+{
+ nvme_ctrl_t c;
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ struct json_object *path_attrs;
+
+ path_attrs = json_create_object();
+ obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c));
+ obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c));
+ obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c));
+ obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c));
+ array_add_obj(paths, path_attrs);
+ }
+}
+
+static void json_print_nvme_subsystem_list(nvme_root_t r, bool show_ana)
+{
+ struct json_object *host_attrs, *subsystem_attrs;
+ struct json_object *subsystems, *paths;
+ struct json_object *a = json_create_array();
+ nvme_host_t h;
+
+ nvme_for_each_host(r, h) {
+ nvme_subsystem_t s;
+ const char *hostid;
+
+ host_attrs = json_create_object();
+ obj_add_str(host_attrs, "HostNQN", nvme_host_get_hostnqn(h));
+ hostid = nvme_host_get_hostid(h);
+ if (hostid)
+ obj_add_str(host_attrs, "HostID", hostid);
+ subsystems = json_create_array();
+ nvme_for_each_subsystem(h, s) {
+ subsystem_attrs = json_create_object();
+ obj_add_str(subsystem_attrs, "Name", nvme_subsystem_get_name(s));
+ obj_add_str(subsystem_attrs, "NQN", nvme_subsystem_get_nqn(s));
+ obj_add_str(subsystem_attrs, "IOPolicy", nvme_subsystem_get_iopolicy(s));
+
+ array_add_obj(subsystems, subsystem_attrs);
+ paths = json_create_array();
+
+ if (!show_ana || !json_print_nvme_subsystem_multipath(s, paths))
+ json_print_nvme_subsystem_ctrls(s, paths);
+
+ obj_add_array(subsystem_attrs, "Paths", paths);
+ }
+ obj_add_array(host_attrs, "Subsystems", subsystems);
+ array_add_obj(a, host_attrs);
+ }
+
+ json_print(a);
+}
+
+static void json_ctrl_registers_cap(void *bar, struct json_object *r)
+{
+ uint64_t cap = mmio_read64(bar + NVME_REG_CAP);
+
+ if (human())
+ json_registers_cap((struct nvme_bar_cap *)&cap, obj_create_array_obj(r, "cap"));
+ else
+ obj_add_uint64(r, "cap", cap);
+}
+
+static void json_ctrl_registers_vs(void *bar, struct json_object *r)
+{
+ uint32_t vs = mmio_read32(bar + NVME_REG_VS);
+
+ if (human())
+ json_registers_version(vs, obj_create_array_obj(r, "vs"));
+ else
+ obj_add_int(r, "vs", vs);
+}
+
+static void json_ctrl_registers_intms(void *bar, struct json_object *r)
+{
+ uint32_t intms = mmio_read32(bar + NVME_REG_INTMS);
+
+ if (human())
+ json_registers_intms(intms, obj_create_array_obj(r, "intms"));
+ else
+ obj_add_int(r, "intms", intms);
+}
+
+static void json_ctrl_registers_intmc(void *bar, struct json_object *r)
+{
+ uint32_t intmc = mmio_read32(bar + NVME_REG_INTMC);
+
+ if (human())
+ json_registers_intmc(intmc, obj_create_array_obj(r, "intmc"));
+ else
+ obj_add_int(r, "intmc", intmc);
+}
+
+static void json_ctrl_registers_cc(void *bar, struct json_object *r)
+{
+ uint32_t cc = mmio_read32(bar + NVME_REG_CC);
+
+ if (human())
+ json_registers_cc(cc, obj_create_array_obj(r, "cc"));
+ else
+ obj_add_int(r, "cc", cc);
+}
+
+static void json_ctrl_registers_csts(void *bar, struct json_object *r)
+{
+ uint32_t csts = mmio_read32(bar + NVME_REG_CSTS);
+
+ if (human())
+ json_registers_csts(csts, obj_create_array_obj(r, "csts"));
+ else
+ obj_add_int(r, "csts", csts);
+}
+
+static void json_ctrl_registers_nssr(void *bar, struct json_object *r)
+{
+ uint32_t nssr = mmio_read32(bar + NVME_REG_NSSR);
+
+ if (human())
+ json_registers_nssr(nssr, obj_create_array_obj(r, "nssr"));
+ else
+ obj_add_int(r, "nssr", nssr);
+}
+
+static void json_ctrl_registers_crto(void *bar, struct json_object *r)
+{
+ uint32_t crto = mmio_read32(bar + NVME_REG_CRTO);
+
+ if (human())
+ json_registers_crto(crto, obj_create_array_obj(r, "crto"));
+ else
+ obj_add_int(r, "crto", crto);
+}
+
+static void json_ctrl_registers_aqa(void *bar, struct json_object *r)
+{
+ uint32_t aqa = mmio_read32(bar + NVME_REG_AQA);
+
+ if (human())
+ json_registers_aqa(aqa, obj_create_array_obj(r, "aqa"));
+ else
+ obj_add_int(r, "aqa", aqa);
+}
+
+static void json_ctrl_registers_asq(void *bar, struct json_object *r)
+{
+ uint64_t asq = mmio_read64(bar + NVME_REG_ASQ);
+
+ if (human())
+ json_registers_asq(asq, obj_create_array_obj(r, "asq"));
+ else
+ obj_add_uint64(r, "asq", asq);
+}
+
+static void json_ctrl_registers_acq(void *bar, struct json_object *r)
+{
+ uint64_t acq = mmio_read64(bar + NVME_REG_ACQ);
+
+ if (human())
+ json_registers_acq(acq, obj_create_array_obj(r, "acq"));
+ else
+ obj_add_uint64(r, "acq", acq);
+}
+
+static void json_ctrl_registers_cmbloc(void *bar, struct json_object *r)
+{
+ uint32_t cmbloc = mmio_read32(bar + NVME_REG_CMBLOC);
+
+ if (human())
+ json_registers_cmbloc(cmbloc, bar, obj_create_array_obj(r, "cmbloc"));
+ else
+ obj_add_int(r, "cmbloc", cmbloc);
+}
+
+static void json_ctrl_registers_cmbsz(void *bar, struct json_object *r)
+{
+ uint32_t cmbsz = mmio_read32(bar + NVME_REG_CMBSZ);
+
+ if (human())
+ json_registers_cmbsz(cmbsz, obj_create_array_obj(r, "cmbsz"));
+ else
+ obj_add_int(r, "cmbsz", cmbsz);
+}
+
+static void json_ctrl_registers_bpinfo(void *bar, struct json_object *r)
+{
+ uint32_t bpinfo = mmio_read32(bar + NVME_REG_BPINFO);
+
+ if (human())
+ json_registers_bpinfo(bpinfo, obj_create_array_obj(r, "bpinfo"));
+ else
+ obj_add_int(r, "bpinfo", bpinfo);
+}
+
+static void json_ctrl_registers_bprsel(void *bar, struct json_object *r)
+{
+ uint32_t bprsel = mmio_read32(bar + NVME_REG_BPRSEL);
+
+ if (human())
+ json_registers_bprsel(bprsel, obj_create_array_obj(r, "bprsel"));
+ else
+ obj_add_int(r, "bprsel", bprsel);
+}
+
+static void json_ctrl_registers_bpmbl(void *bar, struct json_object *r)
+{
+ uint64_t bpmbl = mmio_read64(bar + NVME_REG_BPMBL);
+
+ if (human())
+ json_registers_bpmbl(bpmbl, obj_create_array_obj(r, "bpmbl"));
+ else
+ obj_add_uint64(r, "bpmbl", bpmbl);
+}
+
+static void json_ctrl_registers_cmbmsc(void *bar, struct json_object *r)
+{
+ uint64_t cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC);
+
+ if (human())
+ json_registers_cmbmsc(cmbmsc, obj_create_array_obj(r, "cmbmsc"));
+ else
+ obj_add_uint64(r, "cmbmsc", cmbmsc);
+}
+
+static void json_ctrl_registers_cmbsts(void *bar, struct json_object *r)
+{
+ uint32_t cmbsts = mmio_read32(bar + NVME_REG_CMBSTS);
+
+ if (human())
+ json_registers_cmbsts(cmbsts, obj_create_array_obj(r, "cmbsts"));
+ else
+ obj_add_int(r, "cmbsts", cmbsts);
+}
+
+static void json_ctrl_registers_pmrcap(void *bar, struct json_object *r)
+{
+ uint32_t pmrcap = mmio_read32(bar + NVME_REG_PMRCAP);
+
+ if (human())
+ json_registers_pmrcap(pmrcap, obj_create_array_obj(r, "pmrcap"));
+ else
+ obj_add_int(r, "pmrcap", pmrcap);
+}
+
+static void json_ctrl_registers_pmrctl(void *bar, struct json_object *r)
+{
+ uint32_t pmrctl = mmio_read32(bar + NVME_REG_PMRCTL);
+
+ if (human())
+ json_registers_pmrctl(pmrctl, obj_create_array_obj(r, "pmrctl"));
+ else
+ obj_add_int(r, "pmrctl", pmrctl);
+}
+
+static void json_ctrl_registers_pmrsts(void *bar, struct json_object *r)
+{
+ uint32_t pmrsts = mmio_read32(bar + NVME_REG_PMRSTS);
+
+ if (human())
+ json_registers_pmrsts(pmrsts, bar, obj_create_array_obj(r, "pmrsts"));
+ else
+ obj_add_int(r, "pmrsts", pmrsts);
+}
+
+static void json_ctrl_registers_pmrebs(void *bar, struct json_object *r)
+{
+ uint32_t pmrebs = mmio_read32(bar + NVME_REG_PMREBS);
+
+ if (human())
+ json_registers_pmrebs(pmrebs, obj_create_array_obj(r, "pmrebs"));
+ else
+ obj_add_int(r, "pmrebs", pmrebs);
+}
+
+static void json_ctrl_registers_pmrswtp(void *bar, struct json_object *r)
+{
+ uint32_t pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP);
+
+ if (human())
+ json_registers_pmrswtp(pmrswtp, obj_create_array_obj(r, "pmrswtp"));
+ else
+ obj_add_int(r, "pmrswtp", pmrswtp);
+}
+
+static void json_ctrl_registers_pmrmscl(void *bar, struct json_object *r)
+{
+ uint32_t pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL);
+
+ if (human())
+ json_registers_pmrmscl(pmrmscl, obj_create_array_obj(r, "pmrmscl"));
+ else
+ obj_add_uint(r, "pmrmscl", pmrmscl);
+}
+
+static void json_ctrl_registers_pmrmscu(void *bar, struct json_object *r)
+{
+ uint32_t pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU);
+
+ if (human())
+ json_registers_pmrmscu(pmrmscu, obj_create_array_obj(r, "pmrmscu"));
+ else
+ obj_add_uint(r, "pmrmscu", pmrmscu);
+}
+
+static void json_ctrl_registers(void *bar, bool fabrics)
+{
+ struct json_object *r = json_create_object();
+
+ json_ctrl_registers_cap(bar, r);
+ json_ctrl_registers_vs(bar, r);
+ json_ctrl_registers_intms(bar, r);
+ json_ctrl_registers_intmc(bar, r);
+ json_ctrl_registers_cc(bar, r);
+ json_ctrl_registers_csts(bar, r);
+ json_ctrl_registers_nssr(bar, r);
+ json_ctrl_registers_crto(bar, r);
+ json_ctrl_registers_aqa(bar, r);
+ json_ctrl_registers_asq(bar, r);
+ json_ctrl_registers_acq(bar, r);
+ json_ctrl_registers_cmbloc(bar, r);
+ json_ctrl_registers_cmbsz(bar, r);
+ json_ctrl_registers_bpinfo(bar, r);
+ json_ctrl_registers_bprsel(bar, r);
+ json_ctrl_registers_bpmbl(bar, r);
+ json_ctrl_registers_cmbmsc(bar, r);
+ json_ctrl_registers_cmbsts(bar, r);
+ json_ctrl_registers_pmrcap(bar, r);
+ json_ctrl_registers_pmrctl(bar, r);
+ json_ctrl_registers_pmrsts(bar, r);
+ json_ctrl_registers_pmrebs(bar, r);
+ json_ctrl_registers_pmrswtp(bar, r);
+ json_ctrl_registers_pmrmscl(bar, r);
+ json_ctrl_registers_pmrmscu(bar, r);
+
+ json_print(r);
+}
+
+static void json_nvme_cmd_set_independent_id_ns(struct nvme_id_independent_id_ns *ns,
+ unsigned int nsid)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_int(r, "nsfeat", ns->nsfeat);
+ obj_add_int(r, "nmic", ns->nmic);
+ obj_add_int(r, "rescap", ns->rescap);
+ obj_add_int(r, "fpi", ns->fpi);
+ obj_add_uint(r, "anagrpid", le32_to_cpu(ns->anagrpid));
+ obj_add_int(r, "nsattr", ns->nsattr);
+ obj_add_int(r, "nvmsetid", le16_to_cpu(ns->nvmsetid));
+ obj_add_int(r, "endgid", le16_to_cpu(ns->endgid));
+ obj_add_int(r, "nstat", ns->nstat);
+
+ json_print(r);
+}
+
+static void json_nvme_id_ns_descs(void *data, unsigned int nsid)
+{
+ /* large enough to hold uuid str (37) or nguid str (32) + zero byte */
+ char json_str[STR_LEN];
+ char *json_str_p;
+ union {
+ __u8 eui64[NVME_NIDT_EUI64_LEN];
+ __u8 nguid[NVME_NIDT_NGUID_LEN];
+ __u8 uuid[NVME_UUID_LEN];
+ __u8 csi;
+ } desc;
+ struct json_object *r = json_create_object();
+ struct json_object *json_array = NULL;
+ off_t off;
+ int pos, len = 0;
+ int i;
+
+ for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) {
+ struct nvme_ns_id_desc *cur = data + pos;
+ const char *nidt_name = NULL;
+
+ if (cur->nidl == 0)
+ break;
+
+ memset(json_str, 0, sizeof(json_str));
+ json_str_p = json_str;
+ off = pos + sizeof(*cur);
+
+ switch (cur->nidt) {
+ case NVME_NIDT_EUI64:
+ memcpy(desc.eui64, data + off, sizeof(desc.eui64));
+ for (i = 0; i < sizeof(desc.eui64); i++)
+ json_str_p += sprintf(json_str_p, "%02x", desc.eui64[i]);
+ len = sizeof(desc.eui64);
+ nidt_name = "eui64";
+ break;
+ case NVME_NIDT_NGUID:
+ memcpy(desc.nguid, data + off, sizeof(desc.nguid));
+ for (i = 0; i < sizeof(desc.nguid); i++)
+ json_str_p += sprintf(json_str_p, "%02x", desc.nguid[i]);
+ len = sizeof(desc.nguid);
+ nidt_name = "nguid";
+ break;
+ case NVME_NIDT_UUID:
+ memcpy(desc.uuid, data + off, sizeof(desc.uuid));
+ nvme_uuid_to_string(desc.uuid, json_str);
+ len = sizeof(desc.uuid);
+ nidt_name = "uuid";
+ break;
+ case NVME_NIDT_CSI:
+ memcpy(&desc.csi, data + off, sizeof(desc.csi));
+ sprintf(json_str_p, "%#x", desc.csi);
+ len += sizeof(desc.csi);
+ nidt_name = "csi";
+ break;
+ default:
+ /* Skip unknown types */
+ len = cur->nidl;
+ break;
+ }
+
+ if (nidt_name) {
+ struct json_object *elem = json_create_object();
+
+ obj_add_int(elem, "loc", pos);
+ obj_add_int(elem, "nidt", (int)cur->nidt);
+ obj_add_int(elem, "nidl", (int)cur->nidl);
+ obj_add_str(elem, "Type", nidt_name);
+ obj_add_str(elem, nidt_name, json_str);
+
+ if (!json_array)
+ json_array = json_create_array();
+ array_add_obj(json_array, elem);
+ }
+
+ len += sizeof(*cur);
+ }
+
+ if (json_array)
+ obj_add_array(r, "ns-descs", json_array);
+
+ json_print(r);
+}
+
+static void json_nvme_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "vsl", ctrl_nvm->vsl);
+ obj_add_uint(r, "wzsl", ctrl_nvm->wzsl);
+ obj_add_uint(r, "wusl", ctrl_nvm->wusl);
+ obj_add_uint(r, "dmrl", ctrl_nvm->dmrl);
+ obj_add_uint(r, "dmrsl", le32_to_cpu(ctrl_nvm->dmrsl));
+ obj_add_uint64(r, "dmsl", le64_to_cpu(ctrl_nvm->dmsl));
+
+ json_print(r);
+}
+
+static void json_nvme_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns,
+ unsigned int nsid, struct nvme_id_ns *ns,
+ unsigned int lba_index, bool cap_only)
+
+{
+ struct json_object *r = json_create_object();
+ struct json_object *elbafs = json_create_array();
+ int i;
+
+ if (!cap_only)
+ obj_add_uint64(r, "lbstm", le64_to_cpu(nvm_ns->lbstm));
+
+ obj_add_int(r, "pic", nvm_ns->pic);
+
+ obj_add_array(r, "elbafs", elbafs);
+
+ for (i = 0; i <= ns->nlbaf; i++) {
+ struct json_object *elbaf = json_create_object();
+ unsigned int elbaf_val = le32_to_cpu(nvm_ns->elbaf[i]);
+
+ obj_add_uint(elbaf, "sts", elbaf_val & 0x7F);
+ obj_add_uint(elbaf, "pif", (elbaf_val >> 7) & 0x3);
+
+ array_add_obj(elbafs, elbaf);
+ }
+
+ json_print(r);
+}
+
+static void json_nvme_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_int(r, "zasl", ctrl->zasl);
+
+ json_print(r);
+}
+
+static void json_nvme_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *lbafs = json_create_array();
+ int i;
+
+ obj_add_int(r, "zoc", le16_to_cpu(ns->zoc));
+ obj_add_int(r, "ozcs", le16_to_cpu(ns->ozcs));
+ obj_add_uint(r, "mar", le32_to_cpu(ns->mar));
+ obj_add_uint(r, "mor", le32_to_cpu(ns->mor));
+ obj_add_uint(r, "rrl", le32_to_cpu(ns->rrl));
+ obj_add_uint(r, "frl", le32_to_cpu(ns->frl));
+ obj_add_uint(r, "rrl1", le32_to_cpu(ns->rrl1));
+ obj_add_uint(r, "rrl2", le32_to_cpu(ns->rrl2));
+ obj_add_uint(r, "rrl3", le32_to_cpu(ns->rrl3));
+ obj_add_uint(r, "frl1", le32_to_cpu(ns->frl1));
+ obj_add_uint(r, "frl2", le32_to_cpu(ns->frl2));
+ obj_add_uint(r, "frl3", le32_to_cpu(ns->frl3));
+ obj_add_uint(r, "numzrwa", le32_to_cpu(ns->numzrwa));
+ obj_add_int(r, "zrwafg", le16_to_cpu(ns->zrwafg));
+ obj_add_int(r, "zrwasz", le16_to_cpu(ns->zrwasz));
+ obj_add_int(r, "zrwacap", ns->zrwacap);
+
+ obj_add_array(r, "lbafe", lbafs);
+
+ for (i = 0; i <= id_ns->nlbaf; i++) {
+ struct json_object *lbaf = json_create_object();
+
+ obj_add_uint64(lbaf, "zsze", le64_to_cpu(ns->lbafe[i].zsze));
+ obj_add_int(lbaf, "zdes", ns->lbafe[i].zdes);
+
+ array_add_obj(lbafs, lbaf);
+ }
+
+ json_print(r);
+}
+
+static void json_nvme_list_ns(struct nvme_ns_list *ns_list)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid_attrs;
+ struct json_object *valid = json_create_array();
+ int i;
+
+ for (i = 0; i < 1024; i++) {
+ if (ns_list->ns[i]) {
+ valid_attrs = json_create_object();
+ obj_add_uint(valid_attrs, "nsid", le32_to_cpu(ns_list->ns[i]));
+ array_add_obj(valid, valid_attrs);
+ }
+ }
+
+ obj_add_array(r, "nsid_list", valid);
+
+ json_print(r);
+}
+
+static void json_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list)
+{
+ *zone_list = json_create_array();
+}
+
+static void json_zns_changed(struct nvme_zns_changed_zone_log *log)
+{
+ struct json_object *r = json_create_object();
+ char json_str[STR_LEN];
+ uint16_t nrzid = le16_to_cpu(log->nrzid);
+ int i;
+
+ if (nrzid == 0xFFFF) {
+ obj_add_result(r, "Too many zones have changed to fit into the log. Use report zones for changes.");
+ } else {
+ obj_add_uint(r, "nrzid", nrzid);
+ for (i = 0; i < nrzid; i++) {
+ sprintf(json_str, "zid %03d", i);
+ obj_add_uint64(r, json_str, (uint64_t)le64_to_cpu(log->zid[i]));
+ }
+ }
+
+ json_print(r);
+}
+
+static void json_zns_finish_zone_list(__u64 nr_zones,
+ struct json_object *zone_list)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "nr_zones", nr_zones);
+ obj_add_array(r, "zone_list", zone_list);
+
+ json_print(r);
+}
+
+static void json_nvme_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size,
+ struct json_object *zone_list)
+{
+ struct json_object *zone;
+ struct json_object *ext_data;
+ struct nvme_zone_report *r = report;
+ struct nvme_zns_desc *desc;
+ int i;
+
+ for (i = 0; i < descs; i++) {
+ desc = (struct nvme_zns_desc *)
+ (report + sizeof(*r) + i * (sizeof(*desc) + ext_size));
+ zone = json_create_object();
+
+ obj_add_uint64(zone, "slba", le64_to_cpu(desc->zslba));
+ obj_add_uint64(zone, "wp", le64_to_cpu(desc->wp));
+ obj_add_uint64(zone, "cap", le64_to_cpu(desc->zcap));
+ obj_add_str(zone, "state", nvme_zone_state_to_string(desc->zs >> 4));
+ obj_add_str(zone, "type", nvme_zone_type_to_string(desc->zt));
+ obj_add_uint(zone, "attrs", desc->za);
+ obj_add_uint(zone, "attrs_info", desc->zai);
+
+ if (ext_size) {
+ if (desc->za & NVME_ZNS_ZA_ZDEV) {
+ ext_data = json_create_array();
+ d_json((unsigned char *)desc + sizeof(*desc),
+ ext_size, 16, 1, ext_data);
+ obj_add_array(zone, "ext_data", ext_data);
+ } else {
+ obj_add_str(zone, "ext_data", "Not valid");
+ }
+ }
+
+ array_add_obj(zone_list, zone);
+ }
+}
+
+static void json_feature_show_fields_arbitration(struct json_object *r, unsigned int result)
+{
+ char json_str[STR_LEN];
+
+ obj_add_uint(r, "High Priority Weight (HPW)", ((result & 0xff000000) >> 24) + 1);
+ obj_add_uint(r, "Medium Priority Weight (MPW)", ((result & 0xff0000) >> 16) + 1);
+ obj_add_uint(r, "Low Priority Weight (LPW)", ((result & 0xff00) >> 8) + 1);
+
+ if ((result & 7) == 7)
+ sprintf(json_str, "No limit");
+ else
+ sprintf(json_str, "%u", 1 << (result & 7));
+
+ obj_add_str(r, "Arbitration Burst (AB)", json_str);
+}
+
+static void json_feature_show_fields_power_mgmt(struct json_object *r, unsigned int result)
+{
+ __u8 field = (result & 0xe0) >> 5;
+
+ obj_add_uint(r, "Workload Hint (WH)", field);
+ obj_add_str(r, "WH description", nvme_feature_wl_hints_to_string(field));
+ obj_add_uint(r, "Power State (PS)", result & 0x1f);
+}
+
+static void json_lba_range_entry(struct nvme_lba_range_type *lbrt, int nr_ranges,
+ struct json_object *r)
+{
+ char json_str[STR_LEN];
+ struct json_object *lbare;
+ int i;
+ int j;
+ struct json_object *lbara = json_create_array();
+
+ obj_add_array(r, "LBA Ranges", lbara);
+
+ for (i = 0; i <= nr_ranges; i++) {
+ lbare = json_create_object();
+ array_add_obj(lbara, lbare);
+
+ obj_add_int(lbare, "LBA range", i);
+
+ obj_add_uint_nx(lbare, "type", lbrt->entry[i].type);
+
+ obj_add_str(lbare, "type description",
+ nvme_feature_lba_type_to_string(lbrt->entry[i].type));
+
+ obj_add_uint_nx(lbare, "attributes", lbrt->entry[i].attributes);
+
+ obj_add_str(lbare, "attribute[0]", lbrt->entry[i].attributes & 1 ?
+ "LBA range may be overwritten" : "LBA range should not be overwritten");
+
+ obj_add_str(lbare, "attribute[1]", lbrt->entry[i].attributes & 2 ?
+ "LBA range should be hidden from the OS/EFI/BIOS" :
+ "LBA range should be visible from the OS/EFI/BIOS");
+
+ obj_add_nprix64(lbare, "slba", le64_to_cpu(lbrt->entry[i].slba));
+
+ obj_add_nprix64(lbare, "nlb", le64_to_cpu(lbrt->entry[i].nlb));
+
+ for (j = 0; j < ARRAY_SIZE(lbrt->entry[i].guid); j++)
+ sprintf(&json_str[j * 2], "%02x", lbrt->entry[i].guid[j]);
+
+ obj_add_str(lbare, "guid", json_str);
+ }
+}
+
+static void json_feature_show_fields_lba_range(struct json_object *r, __u8 field,
+ unsigned char *buf)
+{
+ obj_add_uint(r, "Number of LBA Ranges (NUM)", field + 1);
+
+ if (buf)
+ json_lba_range_entry((struct nvme_lba_range_type *)buf, field, r);
+}
+
+static void json_feature_show_fields_temp_thresh(struct json_object *r, unsigned int result)
+{
+ __u8 field = (result & 0x300000) >> 20;
+ char json_str[STR_LEN];
+
+ obj_add_uint(r, "Threshold Type Select (THSEL)", field);
+ obj_add_str(r, "THSEL description", nvme_feature_temp_type_to_string(field));
+
+ field = (result & 0xf0000) >> 16;
+
+ obj_add_uint(r, "Threshold Temperature Select (TMPSEL)", field);
+ obj_add_str(r, "TMPSEL description", nvme_feature_temp_sel_to_string(field));
+
+ sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result & 0xffff));
+ obj_add_str(r, "Temperature Threshold (TMPTH)", json_str);
+
+ sprintf(json_str, "%u K", result & 0xffff);
+ obj_add_str(r, "TMPTH kelvin", json_str);
+}
+
+static void json_feature_show_fields_err_recovery(struct json_object *r, unsigned int result)
+{
+ char json_str[STR_LEN];
+
+ obj_add_str(r, "Deallocated or Unwritten Logical Block Error Enable (DULBE)",
+ (result & 0x10000) >> 16 ? "Enabled" : "Disabled");
+
+ sprintf(json_str, "%u ms", (result & 0xffff) * 100);
+ obj_add_str(r, "Time Limited Error Recovery (TLER)", json_str);
+}
+
+static void json_feature_show_fields_volatile_wc(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Volatile Write Cache Enable (WCE)", result & 1 ? "Enabled" : "Disabled");
+}
+
+static void json_feature_show_fields_num_queues(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "Number of IO Completion Queues Allocated (NCQA)",
+ ((result & 0xffff0000) >> 16) + 1);
+ obj_add_uint(r, "Number of IO Submission Queues Allocated (NSQA)", (result & 0xffff) + 1);
+}
+
+static void json_feature_show_fields_irq_coalesce(struct json_object *r, unsigned int result)
+{
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%u usec", ((result & 0xff00) >> 8) * 100);
+ obj_add_str(r, "Aggregation Time (TIME)", json_str);
+
+ obj_add_uint(r, "Aggregation Threshold (THR)", (result & 0xff) + 1);
+}
+
+static void json_feature_show_fields_irq_config(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Coalescing Disable (CD)", (result & 0x10000) >> 16 ? "True" : "False");
+ obj_add_uint(r, "Interrupt Vector (IV)", result & 0xffff);
+}
+
+static void json_feature_show_fields_write_atomic(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Disable Normal (DN)", result & 1 ? "True" : "False");
+}
+
+static void json_feature_show_fields_async_event(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Discovery Log Page Change Notices", (result & 0x80000000) >> 31 ?
+ "Send async event" : "Do not send async event");
+ obj_add_str(r, "Endurance Group Event Aggregate Log Change Notices", (result & 0x4000) >> 14 ?
+ "Send async event" : "Do not send async event");
+ obj_add_str(r, "LBA Status Information Notices", (result & 0x2000) >> 13 ?
+ "Send async event" : "Do not send async event");
+ obj_add_str(r, "Predictable Latency Event Aggregate Log Change Notices",
+ (result & 0x1000) >> 12 ? "Send async event" : "Do not send async event");
+ obj_add_str(r, "Asymmetric Namespace Access Change Notices", (result & 0x800) >> 11 ?
+ "Send async event" : "Do not send async event");
+ obj_add_str(r, "Telemetry Log Notices", (result & 0x400) >> 10 ? "Send async event" :
+ "Do not send async event");
+ obj_add_str(r, "Firmware Activation Notices", (result & 0x200) >> 9 ? "Send async event" :
+ "Do not send async event");
+ obj_add_str(r, "Namespace Attribute Notices", (result & 0x100) >> 8 ? "Send async event" :
+ "Do not send async event");
+ obj_add_str(r, "SMART / Health Critical Warnings", result & 0xff ? "Send async event" :
+ "Do not send async event");
+}
+
+static void json_auto_pst(struct nvme_feat_auto_pst *apst, struct json_object *r)
+{
+ int i;
+ __u64 value;
+ char json_str[STR_LEN];
+ struct json_object *apsta = json_create_array();
+ struct json_object *apste;
+
+ obj_add_array(r, "Auto PST Entries", apsta);
+
+ for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) {
+ apste = json_create_object();
+ array_add_obj(apsta, apste);
+ sprintf(json_str, "%2d", i);
+ obj_add_str(apste, "entry", json_str);
+ value = le64_to_cpu(apst->apst_entry[i]);
+ sprintf(json_str, "%u ms", (__u32)NVME_GET(value, APST_ENTRY_ITPT));
+ obj_add_str(apste, "Idle Time Prior to Transition (ITPT)", json_str);
+ obj_add_uint(apste, "Idle Transition Power State (ITPS)",
+ (__u32)NVME_GET(value, APST_ENTRY_ITPS));
+ }
+}
+
+static void json_feature_show_fields_auto_pst(struct json_object *r, unsigned int result,
+ unsigned char *buf)
+{
+ obj_add_str(r, "Autonomous Power State Transition Enable (APSTE)", result & 1 ? "Enabled" :
+ "Disabled");
+
+ if (buf)
+ json_auto_pst((struct nvme_feat_auto_pst *)buf, r);
+}
+
+static void json_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ obj_add_uint(r, "Host Memory Descriptor List Entry Count (HMDLEC)", le32_to_cpu(hmb->hmdlec));
+
+ sprintf(json_str, "0x%x", le32_to_cpu(hmb->hmdlau));
+ obj_add_str(r, "Host Memory Descriptor List Address (HMDLAU)", json_str);
+
+ sprintf(json_str, "0x%x", le32_to_cpu(hmb->hmdlal));
+ obj_add_str(r, "Host Memory Descriptor List Address (HMDLAL)", json_str);
+
+ obj_add_uint(r, "Host Memory Buffer Size (HSIZE)", le32_to_cpu(hmb->hsize));
+}
+
+static void json_feature_show_fields_host_mem_buf(struct json_object *r, unsigned int result,
+ unsigned char *buf)
+{
+ obj_add_str(r, "Enable Host Memory (EHM)", result & 1 ? "Enabled" : "Disabled");
+
+ if (buf)
+ json_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf, r);
+}
+
+static void json_timestamp(struct json_object *r, struct nvme_timestamp *ts)
+{
+ char buffer[BUF_LEN];
+ time_t timestamp = int48_to_long(ts->timestamp) / 1000;
+ struct tm *tm = localtime(&timestamp);
+
+ obj_add_uint64(r, "timestamp", int48_to_long(ts->timestamp));
+
+ if(!strftime(buffer, sizeof(buffer), "%c %Z", tm))
+ sprintf(buffer, "%s", "-");
+
+ obj_add_str(r, "timestamp string", buffer);
+
+ obj_add_str(r, "timestamp origin", ts->attr & 2 ?
+ "The Timestamp field was initialized with a Timestamp value using a Set Features command." :
+ "The Timestamp field was initialized to 0h by a Controller Level Reset.");
+
+ obj_add_str(r, "synch", ts->attr & 1 ?
+ "The controller may have stopped counting during vendor specific intervals after the Timestamp value was initialized." :
+ "The controller counted time in milliseconds continuously since the Timestamp value was initialized.");
+}
+
+static void json_feature_show_fields_timestamp(struct json_object *r, unsigned char *buf)
+{
+ if (buf)
+ json_timestamp(r, (struct nvme_timestamp *)buf);
+}
+
+static void json_feature_show_fields_kato(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "Keep Alive Timeout (KATO) in milliseconds", result);
+}
+
+static void json_feature_show_fields_hctm(struct json_object *r, unsigned int result)
+{
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%u K", result >> 16);
+ obj_add_str(r, "Thermal Management Temperature 1 (TMT1)", json_str);
+
+ sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result >> 16));
+ obj_add_str(r, "TMT1 celsius", json_str);
+
+ sprintf(json_str, "%u K", result & 0xffff);
+ obj_add_str(r, "Thermal Management Temperature 2", json_str);
+
+ sprintf(json_str, "%ld Celsius", kelvin_to_celsius(result & 0xffff));
+ obj_add_str(r, "TMT2 celsius", json_str);
+}
+
+static void json_feature_show_fields_nopsc(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Non-Operational Power State Permissive Mode Enable (NOPPME)", result & 1 ?
+ "True" : "False");
+}
+
+static void json_feature_show_fields_rrl(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "Read Recovery Level (RRL)", result & 0xf);
+}
+
+static void json_plm_config(struct nvme_plm_config *plmcfg, struct json_object *r)
+{
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%04x", le16_to_cpu(plmcfg->ee));
+ obj_add_str(r, "Enable Event", json_str);
+
+ obj_add_uint64(r, "DTWIN Reads Threshold", le64_to_cpu(plmcfg->dtwinrt));
+ obj_add_uint64(r, "DTWIN Writes Threshold", le64_to_cpu(plmcfg->dtwinwt));
+ obj_add_uint64(r, "DTWIN Time Threshold", le64_to_cpu(plmcfg->dtwintt));
+}
+
+static void json_feature_show_fields_plm_config(struct json_object *r, unsigned int result,
+ unsigned char *buf)
+{
+ obj_add_str(r, "Predictable Latency Window Enabled", result & 1 ? "True" : "False");
+
+ if (buf)
+ json_plm_config((struct nvme_plm_config *)buf, r);
+}
+
+static void json_feature_show_fields_plm_window(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Window Select", nvme_plm_window_to_string(result));
+}
+
+static void json_feature_show_fields_lba_sts_interval(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "LBA Status Information Poll Interval (LSIPI)", result >> 16);
+ obj_add_uint(r, "LBA Status Information Report Interval (LSIRI)", result & 0xffff);
+}
+
+static void json_feature_show_fields_host_behavior(struct json_object *r, unsigned char *buf)
+{
+ if (buf)
+ obj_add_str(r, "Host Behavior Support", buf[0] & 0x1 ? "True" : "False");
+}
+
+static void json_feature_show_fields_sanitize(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "No-Deallocate Response Mode (NODRM)", result & 1);
+}
+
+static void json_feature_show_fields_endurance_evt_cfg(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "Endurance Group Identifier (ENDGID)", result & 0xffff);
+ obj_add_uint(r, "Endurance Group Critical Warnings", result >> 16 & 0xff);
+}
+
+static void json_feature_show_fields_iocs_profile(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "I/O Command Set Profile", result & 0x1 ? "True" : "False");
+}
+
+static void json_feature_show_fields_spinup_control(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Spinup control feature Enabled", result & 1 ? "True" : "False");
+}
+
+static void json_host_metadata(struct json_object *r, enum nvme_features_id fid,
+ struct nvme_host_metadata *data)
+{
+ struct nvme_metadata_element_desc *desc = &data->descs[0];
+ int i;
+ char val[VAL_LEN];
+ __u16 len;
+ char json_str[STR_LEN];
+ struct json_object *desca = json_create_array();
+ struct json_object *desce;
+
+ obj_add_int(r, "Num Metadata Element Descriptors", data->ndesc);
+
+ obj_add_array(r, "Metadata Element Descriptors", desca);
+
+ for (i = 0; i < data->ndesc; i++) {
+ desce = json_create_object();
+ array_add_obj(desca, desce);
+
+ obj_add_int(desce, "Element", i);
+
+ sprintf(json_str, "0x%02x", desc->type);
+ obj_add_str(desce, "Type", json_str);
+
+ obj_add_str(desce, "Type definition",
+ nvme_host_metadata_type_to_string(fid, desc->type));
+
+ obj_add_int(desce, "Revision", desc->rev);
+
+ len = le16_to_cpu(desc->len);
+ obj_add_int(desce, "Length", len);
+
+ strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len));
+ obj_add_str(desce, "Value", val);
+
+ desc = (struct nvme_metadata_element_desc *)&desc->val[desc->len];
+ }
+}
+
+static void json_feature_show_fields_ns_metadata(struct json_object *r, enum nvme_features_id fid,
+ unsigned char *buf)
+{
+ if (buf)
+ json_host_metadata(r, fid, (struct nvme_host_metadata *)buf);
+}
+
+static void json_feature_show_fields_sw_progress(struct json_object *r, unsigned int result)
+{
+ obj_add_uint(r, "Pre-boot Software Load Count (PBSLC)", result & 0xff);
+}
+
+static void json_feature_show_fields_host_id(struct json_object *r, unsigned char *buf)
+{
+ uint64_t ull = 0;
+ int i;
+
+ if (buf) {
+ for (i = sizeof(ull) / sizeof(*buf); i; i--) {
+ ull |= buf[i - 1];
+ if (i - 1)
+ ull <<= BYTE_TO_BIT(sizeof(buf[i]));
+ }
+ obj_add_uint64(r, "Host Identifier (HOSTID)", ull);
+ }
+}
+
+static void json_feature_show_fields_resv_mask(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Mask Reservation Preempted Notification (RESPRE)", (result & 8) >> 3 ?
+ "True" : "False");
+ obj_add_str(r, "Mask Reservation Released Notification (RESREL)", (result & 4) >> 2 ?
+ "True" : "False");
+ obj_add_str(r, "Mask Registration Preempted Notification (REGPRE)", (result & 2) >> 1 ?
+ "True" : "False");
+}
+
+static void json_feature_show_fields_resv_persist(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Persist Through Power Loss (PTPL)", result & 1 ? "True" : "False");
+}
+
+static void json_feature_show_fields_write_protect(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Namespace Write Protect", nvme_ns_wp_cfg_to_string(result));
+}
+
+static void json_feature_show_fields_fdp(struct json_object *r, unsigned int result)
+{
+ obj_add_str(r, "Flexible Direct Placement Enable (FDPE)", result & 1 ? "Yes" : "No");
+ obj_add_uint(r, "Flexible Direct Placement Configuration Index", result >> 8 & 0xf);
+}
+
+static void json_feature_show_fields_fdp_events(struct json_object *r, unsigned int result,
+ unsigned char *buf)
+{
+ unsigned int i;
+ struct nvme_fdp_supported_event_desc *d;
+ char json_str[STR_LEN];
+
+ for (i = 0; i < result; i++) {
+ d = &((struct nvme_fdp_supported_event_desc *)buf)[i];
+ sprintf(json_str, "%s", d->evta & 0x1 ? "Enabled" : "Not enabled");
+ obj_add_str(r, nvme_fdp_event_to_string(d->evt), json_str);
+ }
+}
+
+static void json_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
+{
+ struct json_object *r;
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "feature: %#0*x", fid ? 4 : 2, fid);
+ r = obj_create(json_str);
+
+ obj_add_str(r, "name", nvme_feature_to_string(fid));
+
+ sprintf(json_str, "%#0*x", result ? 10 : 8, result);
+ obj_add_str(r, nvme_select_to_string(sel), json_str);
+
+ json_print(r);
+}
+
+static void json_feature_show_fields(enum nvme_features_id fid, unsigned int result,
+ unsigned char *buf)
+{
+ struct json_object *r;
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "Feature: %#0*x", fid ? 4 : 2, fid);
+ r = obj_create(json_str);
+
+ switch (fid) {
+ case NVME_FEAT_FID_ARBITRATION:
+ json_feature_show_fields_arbitration(r, result);
+ break;
+ case NVME_FEAT_FID_POWER_MGMT:
+ json_feature_show_fields_power_mgmt(r, result);
+ break;
+ case NVME_FEAT_FID_LBA_RANGE:
+ json_feature_show_fields_lba_range(r, result & 0x3f, buf);
+ break;
+ case NVME_FEAT_FID_TEMP_THRESH:
+ json_feature_show_fields_temp_thresh(r, result);
+ break;
+ case NVME_FEAT_FID_ERR_RECOVERY:
+ json_feature_show_fields_err_recovery(r, result);
+ break;
+ case NVME_FEAT_FID_VOLATILE_WC:
+ json_feature_show_fields_volatile_wc(r, result);
+ break;
+ case NVME_FEAT_FID_NUM_QUEUES:
+ json_feature_show_fields_num_queues(r, result);
+ break;
+ case NVME_FEAT_FID_IRQ_COALESCE:
+ json_feature_show_fields_irq_coalesce(r, result);
+ break;
+ case NVME_FEAT_FID_IRQ_CONFIG:
+ json_feature_show_fields_irq_config(r, result);
+ break;
+ case NVME_FEAT_FID_WRITE_ATOMIC:
+ json_feature_show_fields_write_atomic(r, result);
+ break;
+ case NVME_FEAT_FID_ASYNC_EVENT:
+ json_feature_show_fields_async_event(r, result);
+ break;
+ case NVME_FEAT_FID_AUTO_PST:
+ json_feature_show_fields_auto_pst(r, result, buf);
+ break;
+ case NVME_FEAT_FID_HOST_MEM_BUF:
+ json_feature_show_fields_host_mem_buf(r, result, buf);
+ break;
+ case NVME_FEAT_FID_TIMESTAMP:
+ json_feature_show_fields_timestamp(r, buf);
+ break;
+ case NVME_FEAT_FID_KATO:
+ json_feature_show_fields_kato(r, result);
+ break;
+ case NVME_FEAT_FID_HCTM:
+ json_feature_show_fields_hctm(r, result);
+ break;
+ case NVME_FEAT_FID_NOPSC:
+ json_feature_show_fields_nopsc(r, result);
+ break;
+ case NVME_FEAT_FID_RRL:
+ json_feature_show_fields_rrl(r, result);
+ break;
+ case NVME_FEAT_FID_PLM_CONFIG:
+ json_feature_show_fields_plm_config(r, result, buf);
+ break;
+ case NVME_FEAT_FID_PLM_WINDOW:
+ json_feature_show_fields_plm_window(r, result);
+ break;
+ case NVME_FEAT_FID_LBA_STS_INTERVAL:
+ json_feature_show_fields_lba_sts_interval(r, result);
+ break;
+ case NVME_FEAT_FID_HOST_BEHAVIOR:
+ json_feature_show_fields_host_behavior(r, buf);
+ break;
+ case NVME_FEAT_FID_SANITIZE:
+ json_feature_show_fields_sanitize(r, result);
+ break;
+ case NVME_FEAT_FID_ENDURANCE_EVT_CFG:
+ json_feature_show_fields_endurance_evt_cfg(r, result);
+ break;
+ case NVME_FEAT_FID_IOCS_PROFILE:
+ json_feature_show_fields_iocs_profile(r, result);
+ break;
+ case NVME_FEAT_FID_SPINUP_CONTROL:
+ json_feature_show_fields_spinup_control(r, result);
+ break;
+ case NVME_FEAT_FID_ENH_CTRL_METADATA:
+ fallthrough;
+ case NVME_FEAT_FID_CTRL_METADATA:
+ fallthrough;
+ case NVME_FEAT_FID_NS_METADATA:
+ json_feature_show_fields_ns_metadata(r, fid, buf);
+ break;
+ case NVME_FEAT_FID_SW_PROGRESS:
+ json_feature_show_fields_sw_progress(r, result);
+ break;
+ case NVME_FEAT_FID_HOST_ID:
+ json_feature_show_fields_host_id(r, buf);
+ break;
+ case NVME_FEAT_FID_RESV_MASK:
+ json_feature_show_fields_resv_mask(r, result);
+ break;
+ case NVME_FEAT_FID_RESV_PERSIST:
+ json_feature_show_fields_resv_persist(r, result);
+ break;
+ case NVME_FEAT_FID_WRITE_PROTECT:
+ json_feature_show_fields_write_protect(r, result);
+ break;
+ case NVME_FEAT_FID_FDP:
+ json_feature_show_fields_fdp(r, result);
+ break;
+ case NVME_FEAT_FID_FDP_EVENTS:
+ json_feature_show_fields_fdp_events(r, result, buf);
+ break;
+ default:
+ break;
+ }
+
+ json_print(r);
+}
+
+void json_id_ctrl_rpmbs(__le32 ctrl_rpmbs)
+{
+ struct json_object *r = json_create_object();
+ __u32 rpmbs = le32_to_cpu(ctrl_rpmbs);
+ __u32 asz = (rpmbs & 0xFF000000) >> 24;
+ __u32 tsz = (rpmbs & 0xFF0000) >> 16;
+ __u32 rsvd = (rpmbs & 0xFFC0) >> 6;
+ __u32 auth = (rpmbs & 0x38) >> 3;
+ __u32 rpmb = rpmbs & 7;
+
+ obj_add_uint_nx(r, "[31:24]: Access Size", asz);
+ obj_add_uint_nx(r, "[23:16]: Total Size", tsz);
+
+ if (rsvd)
+ obj_add_uint_nx(r, "[15:6]: Reserved", rsvd);
+
+ obj_add_uint_nx(r, "[5:3]: Authentication Method", auth);
+ obj_add_uint_nx(r, "[2:0]: Number of RPMB Units", rpmb);
+
+ json_print(r);
+}
+
+static void json_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges)
+{
+ struct json_object *r = json_create_object();
+
+ json_lba_range_entry(lbrt, nr_ranges, r);
+
+ json_print(r);
+}
+
+static void json_lba_status_info(__u32 result)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "LBA Status Information Poll Interval (LSIPI)", (result >> 16) & 0xffff);
+ obj_add_uint(r, "LBA Status Information Report Interval (LSIRI)", result & 0xffff);
+
+ json_print(r);
+}
+
+void json_d(unsigned char *buf, int len, int width, int group)
+{
+ struct json_object *r = json_r ? json_r : json_create_object();
+ char json_str[STR_LEN];
+ struct json_object *data = json_create_array();
+
+ sprintf(json_str, "data: buf=%p len=%d width=%d group=%d", buf, len, width, group);
+ d_json(buf, len, width, group, data);
+ obj_add_array(r, json_str, data);
+
+ json_print(r);
+}
+
+static void json_nvme_list_ctrl(struct nvme_ctrl_list *ctrl_list)
+{
+ __u16 num = le16_to_cpu(ctrl_list->num);
+ struct json_object *r = json_create_object();
+ struct json_object *valid_attrs;
+ struct json_object *valid = json_create_array();
+ int i;
+
+ obj_add_uint(r, "num_ctrl", le16_to_cpu(ctrl_list->num));
+
+ for (i = 0; i < min(num, 2047); i++) {
+ valid_attrs = json_create_object();
+ obj_add_uint(valid_attrs, "ctrl_id", le16_to_cpu(ctrl_list->identifier[i]));
+ array_add_obj(valid, valid_attrs);
+ }
+
+ obj_add_array(r, "ctrl_list", valid);
+
+ json_print(r);
+}
+
+static void json_nvme_id_nvmset(struct nvme_id_nvmset_list *nvmset,
+ unsigned int nvmeset_id)
+{
+ __u32 nent = nvmset->nid;
+ struct json_object *entries = json_create_array();
+ struct json_object *r = json_create_object();
+ int i;
+
+ obj_add_int(r, "nid", nent);
+
+ for (i = 0; i < nent; i++) {
+ struct json_object *entry = json_create_object();
+
+ obj_add_int(entry, "nvmset_id", le16_to_cpu(nvmset->ent[i].nvmsetid));
+ obj_add_int(entry, "endurance_group_id", le16_to_cpu(nvmset->ent[i].endgid));
+ obj_add_uint(entry, "random_4k_read_typical", le32_to_cpu(nvmset->ent[i].rr4kt));
+ obj_add_uint(entry, "optimal_write_size", le32_to_cpu(nvmset->ent[i].ows));
+ obj_add_uint128(entry, "total_nvmset_cap", le128_to_cpu(nvmset->ent[i].tnvmsetcap));
+ obj_add_uint128(entry, "unalloc_nvmset_cap",
+ le128_to_cpu(nvmset->ent[i].unvmsetcap));
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "NVMSet", entries);
+
+ json_print(r);
+}
+
+static void json_nvme_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_uint(r, "cntlid", le16_to_cpu(caps->cntlid));
+ obj_add_uint(r, "portid", le16_to_cpu(caps->portid));
+ obj_add_uint(r, "crt", caps->crt);
+
+ obj_add_uint(r, "vqfrt", le32_to_cpu(caps->vqfrt));
+ obj_add_uint(r, "vqrfa", le32_to_cpu(caps->vqrfa));
+ obj_add_int(r, "vqrfap", le16_to_cpu(caps->vqrfap));
+ obj_add_int(r, "vqprt", le16_to_cpu(caps->vqprt));
+ obj_add_int(r, "vqfrsm", le16_to_cpu(caps->vqfrsm));
+ obj_add_int(r, "vqgran", le16_to_cpu(caps->vqgran));
+
+ obj_add_uint(r, "vifrt", le32_to_cpu(caps->vifrt));
+ obj_add_uint(r, "virfa", le32_to_cpu(caps->virfa));
+ obj_add_int(r, "virfap", le16_to_cpu(caps->virfap));
+ obj_add_int(r, "viprt", le16_to_cpu(caps->viprt));
+ obj_add_int(r, "vifrsm", le16_to_cpu(caps->vifrsm));
+ obj_add_int(r, "vigran", le16_to_cpu(caps->vigran));
+
+ json_print(r);
+}
+
+static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_ctrl_list *sc_list,
+ __u32 count)
+{
+ const struct nvme_secondary_ctrl *sc_entry = &sc_list->sc_entry[0];
+ __u32 nent = min(sc_list->num, count);
+ struct json_object *entries = json_create_array();
+ struct json_object *r = json_create_object();
+ int i;
+
+ obj_add_int(r, "num", nent);
+
+ for (i = 0; i < nent; i++) {
+ struct json_object *entry = json_create_object();
+
+ obj_add_int(entry, "secondary-controller-identifier",
+ le16_to_cpu(sc_entry[i].scid));
+ obj_add_int(entry, "primary-controller-identifier", le16_to_cpu(sc_entry[i].pcid));
+ obj_add_int(entry, "secondary-controller-state", sc_entry[i].scs);
+ obj_add_int(entry, "virtual-function-number", le16_to_cpu(sc_entry[i].vfn));
+ obj_add_int(entry, "num-virtual-queues", le16_to_cpu(sc_entry[i].nvq));
+ obj_add_int(entry, "num-virtual-interrupts", le16_to_cpu(sc_entry[i].nvi));
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "secondary-controllers", entries);
+
+ json_print(r);
+}
+
+static void json_nvme_id_ns_granularity_list(
+ const struct nvme_id_ns_granularity_list *glist)
+{
+ int i;
+ struct json_object *r = json_create_object();
+ struct json_object *entries = json_create_array();
+
+ obj_add_int(r, "attributes", glist->attributes);
+ obj_add_int(r, "num-descriptors", glist->num_descriptors);
+
+ for (i = 0; i <= glist->num_descriptors; i++) {
+ struct json_object *entry = json_create_object();
+
+ obj_add_uint64(entry, "namespace-size-granularity",
+ le64_to_cpu(glist->entry[i].nszegran));
+ obj_add_uint64(entry, "namespace-capacity-granularity",
+ le64_to_cpu(glist->entry[i].ncapgran));
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "namespace-granularity-list", entries);
+
+ json_print(r);
+}
+
+static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *entries = json_create_array();
+ int i;
+
+ for (i = 0; i < NVME_ID_UUID_LIST_MAX; i++) {
+ __u8 uuid[NVME_UUID_LEN];
+ struct json_object *entry = json_create_object();
+
+ /* The list is terminated by a zero UUID value */
+ if (memcmp(uuid_list->entry[i].uuid, zero_uuid, sizeof(zero_uuid)) == 0)
+ break;
+ memcpy(&uuid, uuid_list->entry[i].uuid, sizeof(uuid));
+ obj_add_int(entry, "association",
+ uuid_list->entry[i].header & 0x3);
+ obj_add_str(entry, "uuid",
+ util_uuid_to_string(uuid));
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "UUID-list", entries);
+
+ json_print(r);
+}
+
+static void json_id_domain_list(struct nvme_id_domain_list *id_dom)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *entries = json_create_array();
+ struct json_object *entry;
+ int i;
+ nvme_uint128_t dom_cap, unalloc_dom_cap, max_egrp_dom_cap;
+
+ obj_add_uint(r, "num_dom_entries", id_dom->num);
+
+ for (i = 0; i < id_dom->num; i++) {
+ entry = json_create_object();
+ dom_cap = le128_to_cpu(id_dom->domain_attr[i].dom_cap);
+ unalloc_dom_cap = le128_to_cpu(id_dom->domain_attr[i].unalloc_dom_cap);
+ max_egrp_dom_cap = le128_to_cpu(id_dom->domain_attr[i].max_egrp_dom_cap);
+
+ obj_add_uint(entry, "dom_id", le16_to_cpu(id_dom->domain_attr[i].dom_id));
+ obj_add_uint128(entry, "dom_cap", dom_cap);
+ obj_add_uint128(entry, "unalloc_dom_cap", unalloc_dom_cap);
+ obj_add_uint128(entry, "max_egrp_dom_cap", max_egrp_dom_cap);
+
+ array_add_obj(entries, entry);
+ }
+
+ obj_add_array(r, "domain_list", entries);
+
+ json_print(r);
+}
+
+static void json_nvme_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid_attrs;
+ struct json_object *valid = json_create_array();
+ int i;
+
+ obj_add_uint(r, "num_endgrp_id", le16_to_cpu(endgrp_list->num));
+
+ for (i = 0; i < min(le16_to_cpu(endgrp_list->num), 2047); i++) {
+ valid_attrs = json_create_object();
+ obj_add_uint(valid_attrs, "endgrp_id", le16_to_cpu(endgrp_list->identifier[i]));
+ array_add_obj(valid, valid_attrs);
+ }
+
+ obj_add_array(r, "endgrp_list", valid);
+
+ json_print(r);
+}
+
+static void json_support_log(struct nvme_supported_log_pages *support_log,
+ const char *devname)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *valid = json_create_array();
+ struct json_object *valid_attrs;
+ unsigned int lid;
+ char key[128];
+ __u32 support;
+
+ for (lid = 0; lid < 256; lid++) {
+ support = le32_to_cpu(support_log->lid_support[lid]);
+ if (support & 0x1) {
+ valid_attrs = json_create_object();
+ sprintf(key, "lid_0x%x ", lid);
+ obj_add_uint(valid_attrs, key, support);
+ array_add_obj(valid, valid_attrs);
+ }
+ }
+
+ obj_add_array(r, "supported_logs", valid);
+
+ json_print(r);
+}
+
+static void json_detail_list(nvme_root_t t)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *jdev = json_create_array();
+
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_path_t p;
+ nvme_ns_t n;
+
+ nvme_for_each_host(t, h) {
+ struct json_object *hss = json_create_object();
+ struct json_object *jsslist = json_create_array();
+ const char *hostid;
+
+ obj_add_str(hss, "HostNQN", nvme_host_get_hostnqn(h));
+ hostid = nvme_host_get_hostid(h);
+ if (hostid)
+ obj_add_str(hss, "HostID", hostid);
+
+ nvme_for_each_subsystem(h , s) {
+ struct json_object *jss = json_create_object();
+ struct json_object *jctrls = json_create_array();
+ struct json_object *jnss = json_create_array();
+
+ obj_add_str(jss, "Subsystem", nvme_subsystem_get_name(s));
+ obj_add_str(jss, "SubsystemNQN", nvme_subsystem_get_nqn(s));
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ struct json_object *jctrl = json_create_object();
+ struct json_object *jnss = json_create_array();
+ struct json_object *jpaths = json_create_array();
+
+ obj_add_str(jctrl, "Controller", nvme_ctrl_get_name(c));
+ obj_add_str(jctrl, "SerialNumber", nvme_ctrl_get_serial(c));
+ obj_add_str(jctrl, "ModelNumber", nvme_ctrl_get_model(c));
+ obj_add_str(jctrl, "Firmware", nvme_ctrl_get_firmware(c));
+ obj_add_str(jctrl, "Transport", nvme_ctrl_get_transport(c));
+ obj_add_str(jctrl, "Address", nvme_ctrl_get_address(c));
+ obj_add_str(jctrl, "Slot", nvme_ctrl_get_phy_slot(c));
+
+ nvme_ctrl_for_each_ns(c, n) {
+ struct json_object *jns = json_create_object();
+ int lba = nvme_ns_get_lba_size(n);
+ uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
+ uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
+
+ obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
+ obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
+ obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
+ obj_add_uint64(jns, "UsedBytes", nuse);
+ obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
+ obj_add_uint64(jns, "PhysicalSize", nsze);
+ obj_add_int(jns, "SectorSize", lba);
+
+ array_add_obj(jnss, jns);
+ }
+ obj_add_obj(jctrl, "Namespaces", jnss);
+
+ nvme_ctrl_for_each_path(c, p) {
+ struct json_object *jpath = json_create_object();
+
+ obj_add_str(jpath, "Path", nvme_path_get_name(p));
+ obj_add_str(jpath, "ANAState", nvme_path_get_ana_state(p));
+
+ array_add_obj(jpaths, jpath);
+ }
+ obj_add_obj(jctrl, "Paths", jpaths);
+
+ array_add_obj(jctrls, jctrl);
+ }
+ obj_add_obj(jss, "Controllers", jctrls);
+
+ nvme_subsystem_for_each_ns(s, n) {
+ struct json_object *jns = json_create_object();
+
+ int lba = nvme_ns_get_lba_size(n);
+ uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
+ uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
+
+ obj_add_str(jns, "NameSpace", nvme_ns_get_name(n));
+ obj_add_str(jns, "Generic", nvme_ns_get_generic_name(n));
+ obj_add_int(jns, "NSID", nvme_ns_get_nsid(n));
+ obj_add_uint64(jns, "UsedBytes", nuse);
+ obj_add_uint64(jns, "MaximumLBA", nvme_ns_get_lba_count(n));
+ obj_add_uint64(jns, "PhysicalSize", nsze);
+ obj_add_int(jns, "SectorSize", lba);
+
+ array_add_obj(jnss, jns);
+ }
+ obj_add_obj(jss, "Namespaces", jnss);
+
+ array_add_obj(jsslist, jss);
+ }
+
+ obj_add_obj(hss, "Subsystems", jsslist);
+ array_add_obj(jdev, hss);
+ }
+
+ obj_add_array(r, "Devices", jdev);
+
+ json_print(r);
+}
+
+static struct json_object *json_list_item_obj(nvme_ns_t n)
+{
+ struct json_object *r = json_create_object();
+ char devname[NAME_LEN] = { 0 };
+ char genname[NAME_LEN] = { 0 };
+ int lba = nvme_ns_get_lba_size(n);
+ uint64_t nsze = nvme_ns_get_lba_count(n) * lba;
+ uint64_t nuse = nvme_ns_get_lba_util(n) * lba;
+
+ nvme_dev_full_path(n, devname, sizeof(devname));
+ nvme_generic_full_path(n, genname, sizeof(genname));
+
+ obj_add_int(r, "NameSpace", nvme_ns_get_nsid(n));
+ obj_add_str(r, "DevicePath", devname);
+ obj_add_str(r, "GenericPath", genname);
+ obj_add_str(r, "Firmware", nvme_ns_get_firmware(n));
+ obj_add_str(r, "ModelNumber", nvme_ns_get_model(n));
+ obj_add_str(r, "SerialNumber", nvme_ns_get_serial(n));
+ obj_add_uint64(r, "UsedBytes", nuse);
+ obj_add_uint64(r, "MaximumLBA", nvme_ns_get_lba_count(n));
+ obj_add_uint64(r, "PhysicalSize", nsze);
+ obj_add_int(r, "SectorSize", lba);
+
+ return r;
+}
+
+static void json_simple_list(nvme_root_t t)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *jdevices = json_create_array();
+
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+
+ nvme_for_each_host(t, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ns(s, n)
+ array_add_obj(jdevices, json_list_item_obj(n));
+
+ nvme_subsystem_for_each_ctrl(s, c)
+ nvme_ctrl_for_each_ns(c, n)
+ array_add_obj(jdevices, json_list_item_obj(n));
+ }
+ }
+
+ obj_add_array(r, "Devices", jdevices);
+
+ json_print(r);
+}
+
+static void json_list_item(nvme_ns_t n)
+{
+ struct json_object *r = json_list_item_obj(n);
+
+ json_print(r);
+}
+
+static void json_print_list_items(nvme_root_t t)
+{
+ if (json_print_ops.flags & VERBOSE)
+ json_detail_list(t);
+ else
+ json_simple_list(t);
+}
+
+static unsigned int json_subsystem_topology_multipath(nvme_subsystem_t s,
+ json_object *namespaces)
+{
+ nvme_ns_t n;
+ nvme_path_t p;
+ unsigned int i = 0;
+
+ nvme_subsystem_for_each_ns(s, n) {
+ struct json_object *ns_attrs;
+ struct json_object *paths;
+
+ ns_attrs = json_create_object();
+ obj_add_int(ns_attrs, "NSID", nvme_ns_get_nsid(n));
+
+ paths = json_create_array();
+ nvme_namespace_for_each_path(n, p) {
+ struct json_object *path_attrs;
+
+ nvme_ctrl_t c = nvme_path_get_ctrl(p);
+
+ path_attrs = json_create_object();
+ obj_add_str(path_attrs, "Name", nvme_ctrl_get_name(c));
+ obj_add_str(path_attrs, "Transport", nvme_ctrl_get_transport(c));
+ obj_add_str(path_attrs, "Address", nvme_ctrl_get_address(c));
+ obj_add_str(path_attrs, "State", nvme_ctrl_get_state(c));
+ obj_add_str(path_attrs, "ANAState", nvme_path_get_ana_state(p));
+ array_add_obj(paths, path_attrs);
+ }
+ obj_add_array(ns_attrs, "Paths", paths);
+ array_add_obj(namespaces, ns_attrs);
+ i++;
+ }
+
+ return i;
+}
+
+static void json_print_nvme_subsystem_topology(nvme_subsystem_t s,
+ json_object *namespaces)
+{
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ nvme_ctrl_for_each_ns(c, n) {
+ struct json_object *ctrl_attrs;
+ struct json_object *ns_attrs;
+ struct json_object *ctrl;
+
+ ns_attrs = json_create_object();
+ obj_add_int(ns_attrs, "NSID", nvme_ns_get_nsid(n));
+
+ ctrl = json_create_array();
+ ctrl_attrs = json_create_object();
+ obj_add_str(ctrl_attrs, "Name",
+ nvme_ctrl_get_name(c));
+ obj_add_str(ctrl_attrs, "Transport",
+ nvme_ctrl_get_transport(c));
+ obj_add_str(ctrl_attrs, "Address",
+ nvme_ctrl_get_address(c));
+ obj_add_str(ctrl_attrs, "State",
+ nvme_ctrl_get_state(c));
+
+ array_add_obj(ctrl, ctrl_attrs);
+ obj_add_array(ns_attrs, "Controller", ctrl);
+ array_add_obj(namespaces, ns_attrs);
+ }
+ }
+}
+
+static void json_simple_topology(nvme_root_t r)
+{
+ struct json_object *host_attrs, *subsystem_attrs;
+ struct json_object *subsystems, *namespaces;
+ struct json_object *a = json_create_array();
+ nvme_host_t h;
+
+ nvme_for_each_host(r, h) {
+ nvme_subsystem_t s;
+ const char *hostid;
+
+ host_attrs = json_create_object();
+ obj_add_str(host_attrs, "HostNQN", nvme_host_get_hostnqn(h));
+ hostid = nvme_host_get_hostid(h);
+ if (hostid)
+ obj_add_str(host_attrs, "HostID", hostid);
+ subsystems = json_create_array();
+ nvme_for_each_subsystem(h, s) {
+ subsystem_attrs = json_create_object();
+ obj_add_str(subsystem_attrs, "Name", nvme_subsystem_get_name(s));
+ obj_add_str(subsystem_attrs, "NQN", nvme_subsystem_get_nqn(s));
+ obj_add_str(subsystem_attrs, "IOPolicy", nvme_subsystem_get_iopolicy(s));
+
+ array_add_obj(subsystems, subsystem_attrs);
+ namespaces = json_create_array();
+
+ if (!json_subsystem_topology_multipath(s, namespaces))
+ json_print_nvme_subsystem_topology(s, namespaces);
+
+ obj_add_array(subsystem_attrs, "Namespaces", namespaces);
+ }
+ obj_add_array(host_attrs, "Subsystems", subsystems);
+ array_add_obj(a, host_attrs);
+ }
+
+ json_print(a);
+}
+
+static void json_directive_show_fields_identify(__u8 doper, __u8 *field, struct json_object *r)
+{
+ struct json_object *support;
+ struct json_object *enabled;
+ struct json_object *persistent;
+
+ switch (doper) {
+ case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM:
+ support = json_create_array();
+ obj_add_array(r, "Directive support", support);
+ obj_add_str(support, "Identify Directive",
+ *field & 0x1 ? "Supported" : "Not supported");
+ obj_add_str(support, "Stream Directive",
+ *field & 0x2 ? "Supported" : "Not supported");
+ obj_add_str(support, "Data Placement Directive",
+ *field & 0x4 ? "Supported" : "Not supported");
+ enabled = json_create_array();
+ obj_add_array(r, "Directive enabled", enabled);
+ obj_add_str(enabled, "Identify Directive",
+ *(field + 32) & 0x1 ? "Enabled" : "Disabled");
+ obj_add_str(enabled, "Stream Directive",
+ *(field + 32) & 0x2 ? "Enabled" : "Disabled");
+ obj_add_str(enabled, "Data Placement Directive",
+ *(field + 32) & 0x4 ? "Enabled" : "Disabled");
+ persistent = json_create_array();
+ obj_add_array(r, "Directive Persistent Across Controller Level Resets",
+ persistent);
+ obj_add_str(persistent, "Identify Directive",
+ *(field + 64) & 0x1 ? "Enabled" : "Disabled");
+ obj_add_str(persistent, "Stream Directive",
+ *(field + 64) & 0x2 ? "Enabled" : "Disabled");
+ obj_add_str(persistent, "Data Placement Directive",
+ *(field + 64) & 0x4 ? "Enabled" : "Disabled");
+ break;
+ default:
+ obj_add_str(r, "Error", "invalid directive operations for Identify Directives");
+ break;
+ }
+}
+
+static void json_directive_show_fields_streams(__u8 doper, unsigned int result, __u16 *field,
+ struct json_object *r)
+{
+ int count;
+ int i;
+ char json_str[STR_LEN];
+
+ switch (doper) {
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM:
+ obj_add_uint(r, "Max Streams Limit (MSL)", le16_to_cpu(*field));
+ obj_add_uint(r, "NVM Subsystem Streams Available (NSSA)", le16_to_cpu(*(field + 2)));
+ obj_add_uint(r, "NVM Subsystem Streams Open (NSSO)", le16_to_cpu(*(field + 4)));
+ obj_add_uint(r, "NVM Subsystem Stream Capability (NSSC)", le16_to_cpu(*(field + 6)));
+ obj_add_uint(r, "Stream Write Size (in unit of LB size) (SWS)",
+ le16_to_cpu(*(__u32 *)(field + 16)));
+ obj_add_uint(r, "Stream Granularity Size (in unit of SWS) (SGS)",
+ le16_to_cpu(*(field + 20)));
+ obj_add_uint(r, "Namespace Streams Allocated (NSA)", le16_to_cpu(*(field + 22)));
+ obj_add_uint(r, "Namespace Streams Open (NSO)", le16_to_cpu(*(field + 24)));
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS:
+ count = *field;
+ obj_add_uint(r, "Open Stream Count", le16_to_cpu(*field));
+ for (i = 0; i < count; i++) {
+ sprintf(json_str, "Stream Identifier %.6u", i + 1);
+ obj_add_uint(r, json_str, le16_to_cpu(*(field + (i + 1) * 2)));
+ }
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE:
+ obj_add_uint(r, "Namespace Streams Allocated (NSA)", result & 0xffff);
+ break;
+ default:
+ obj_add_str(r, "Error",
+ "invalid directive operations for Streams Directives");
+ break;
+ }
+}
+
+static void json_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result,
+ __u8 *field, struct json_object *r)
+{
+ switch (dtype) {
+ case NVME_DIRECTIVE_DTYPE_IDENTIFY:
+ json_directive_show_fields_identify(doper, field, r);
+ break;
+ case NVME_DIRECTIVE_DTYPE_STREAMS:
+ json_directive_show_fields_streams(doper, result, (__u16 *)field, r);
+ break;
+ default:
+ obj_add_str(r, "Error", "invalid directive type");
+ break;
+ }
+}
+
+static void json_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *data;
+ char json_str[STR_LEN];
+
+ sprintf(json_str, "%#x", type);
+ obj_add_str(r, "Type", json_str);
+ sprintf(json_str, "%#x", oper);
+ obj_add_str(r, "Operation", json_str);
+ sprintf(json_str, "%#x", spec);
+ obj_add_str(r, "spec", json_str);
+ sprintf(json_str, "%#x", nsid);
+ obj_add_str(r, "NSID", json_str);
+ sprintf(json_str, "%#x", result);
+ obj_add_result(r, json_str);
+
+ if (json_print_ops.flags & VERBOSE) {
+ json_directive_show_fields(type, oper, result, buf, r);
+ } else if (buf) {
+ data = json_create_array();
+ d_json((unsigned char *)buf, len, 16, 1, data);
+ obj_add_array(r, "data", data);
+ }
+
+ json_print(r);
+}
+
+static void json_discovery_log(struct nvmf_discovery_log *log, int numrec)
+{
+ struct json_object *r = json_create_object();
+ struct json_object *entries = json_create_array();
+ int i;
+
+ obj_add_uint64(r, "genctr", le64_to_cpu(log->genctr));
+ obj_add_array(r, "records", entries);
+
+ for (i = 0; i < numrec; i++) {
+ struct nvmf_disc_log_entry *e = &log->entries[i];
+ struct json_object *entry = json_create_object();
+
+ obj_add_str(entry, "trtype", nvmf_trtype_str(e->trtype));
+ obj_add_str(entry, "adrfam", nvmf_adrfam_str(e->adrfam));
+ obj_add_str(entry, "subtype", nvmf_subtype_str(e->subtype));
+ obj_add_str(entry,"treq", nvmf_treq_str(e->treq));
+ obj_add_uint(entry, "portid", le16_to_cpu(e->portid));
+ obj_add_str(entry, "trsvcid", e->trsvcid);
+ obj_add_str(entry, "subnqn", e->subnqn);
+ obj_add_str(entry, "traddr", e->traddr);
+ obj_add_str(entry, "eflags", nvmf_eflags_str(le16_to_cpu(e->eflags)));
+
+ switch (e->trtype) {
+ case NVMF_TRTYPE_RDMA:
+ obj_add_str(entry, "rdma_prtype", nvmf_prtype_str(e->tsas.rdma.prtype));
+ obj_add_str(entry, "rdma_qptype", nvmf_qptype_str(e->tsas.rdma.qptype));
+ obj_add_str(entry, "rdma_cms", nvmf_cms_str(e->tsas.rdma.cms));
+ obj_add_uint(entry, "rdma_pkey", le16_to_cpu(e->tsas.rdma.pkey));
+ break;
+ case NVMF_TRTYPE_TCP:
+ obj_add_str(entry, "sectype", nvmf_sectype_str(e->tsas.tcp.sectype));
+ break;
+ default:
+ break;
+ }
+ array_add_obj(entries, entry);
+ }
+
+ json_print(r);
+}
+
+static void json_connect_msg(nvme_ctrl_t c)
+{
+ struct json_object *r = json_create_object();
+
+ obj_add_str(r, "device", nvme_ctrl_get_name(c));
+
+ json_print(r);
+}
+
+static void json_output_object(struct json_object *r)
+{
+ json_print(r);
+}
+
+static void json_output_status(int status)
+{
+ struct json_object *r;
+ char json_str[STR_LEN];
+ int val;
+ int type;
+
+ sprintf(json_str, "status: %d", status);
+ r = obj_create(json_str);
+
+ if (status < 0) {
+ obj_add_str(r, "error", nvme_strerror(errno));
+ json_print(r);
+ return;
+ }
+
+ val = nvme_status_get_value(status);
+ type = nvme_status_get_type(status);
+
+ switch (type) {
+ case NVME_STATUS_TYPE_NVME:
+ obj_add_str(r, "error", nvme_status_to_string(val, false));
+ obj_add_str(r, "type", "nvme");
+ break;
+ case NVME_STATUS_TYPE_MI:
+ obj_add_str(r, "error", nvme_mi_status_to_string(val));
+ obj_add_str(r, "type", "nvme-mi");
+ break;
+ default:
+ obj_add_str(r, "type", "Unknown");
+ break;
+ }
+
+ json_print(r);
+}
+
+static void json_output_error_status(int status, const char *msg, va_list ap)
+{
+ struct json_object *r;
+ char json_str[STR_LEN];
+ char *value;
+ int val;
+ int type;
+
+ if (vasprintf(&value, msg, ap) < 0)
+ value = NULL;
+
+ sprintf(json_str, "Error: %s", value ? value : "Could not allocate string");
+ r = obj_create(json_str);
+
+ free(value);
+
+ if (status < 0) {
+ obj_add_str(r, "error", nvme_strerror(errno));
+ json_print(r);
+ return;
+ }
+
+ val = nvme_status_get_value(status);
+ type = nvme_status_get_type(status);
+
+ switch (type) {
+ case NVME_STATUS_TYPE_NVME:
+ obj_add_str(r, "status", nvme_status_to_string(val, false));
+ obj_add_str(r, "type", "nvme");
+ break;
+ case NVME_STATUS_TYPE_MI:
+ obj_add_str(r, "status", nvme_mi_status_to_string(val));
+ obj_add_str(r, "type", "nvme-mi");
+ break;
+ default:
+ obj_add_str(r, "type", "Unknown");
+ break;
+ }
+
+ obj_add_int(r, "value", val);
+
+ json_print(r);
+}
+
+static void json_output_message(bool error, const char *msg, va_list ap)
+{
+ struct json_object *r = json_r ? json_r : json_create_object();
+ char *value;
+
+ if (vasprintf(&value, msg, ap) < 0)
+ value = NULL;
+
+ obj_add_str(r, error ? "error" : "result", value ? value : "Could not allocate string");
+
+ free(value);
+
+ json_print(r);
+}
+
+static void json_output_perror(const char *msg)
+{
+ struct json_object *r = json_create_object();
+ char *error;
+
+ if (asprintf(&error, "%s: %s", msg, strerror(errno)) < 0)
+ error = NULL;
+
+ if (error)
+ obj_add_str(r, "error", error);
+ else
+ obj_add_str(r, "error", "Could not allocate string");
+
+ json_output_object(r);
+
+ free(error);
+}
+
+void json_show_init(void)
+{
+ json_r = json_create_object();
+}
+
+void json_show_finish(void)
+{
+ if (json_r)
+ json_output_object(json_r);
+
+ json_r = NULL;
+}
+
+static struct print_ops json_print_ops = {
+ /* libnvme types.h print functions */
+ .ana_log = json_ana_log,
+ .boot_part_log = json_boot_part_log,
+ .phy_rx_eom_log = json_phy_rx_eom_log,
+ .ctrl_list = json_nvme_list_ctrl,
+ .ctrl_registers = json_ctrl_registers,
+ .directive = json_directive_show,
+ .discovery_log = json_discovery_log,
+ .effects_log_list = json_effects_log_list,
+ .endurance_group_event_agg_log = json_endurance_group_event_agg_log,
+ .endurance_group_list = json_nvme_endurance_group_list,
+ .endurance_log = json_endurance_log,
+ .error_log = json_error_log,
+ .fdp_config_log = json_nvme_fdp_configs,
+ .fdp_event_log = json_nvme_fdp_events,
+ .fdp_ruh_status = json_nvme_fdp_ruh_status,
+ .fdp_stats_log = json_nvme_fdp_stats,
+ .fdp_usage_log = json_nvme_fdp_usage,
+ .fid_supported_effects_log = json_fid_support_effects_log,
+ .fw_log = json_fw_log,
+ .id_ctrl = json_nvme_id_ctrl,
+ .id_ctrl_nvm = json_nvme_id_ctrl_nvm,
+ .id_domain_list = json_id_domain_list,
+ .id_independent_id_ns = json_nvme_cmd_set_independent_id_ns,
+ .id_iocs = json_id_iocs,
+ .id_ns = json_nvme_id_ns,
+ .id_ns_descs = json_nvme_id_ns_descs,
+ .id_ns_granularity_list = json_nvme_id_ns_granularity_list,
+ .id_nvmset_list = json_nvme_id_nvmset,
+ .id_uuid_list = json_nvme_id_uuid_list,
+ .lba_status = json_lba_status,
+ .lba_status_log = json_lba_status_log,
+ .media_unit_stat_log = json_media_unit_stat_log,
+ .mi_cmd_support_effects_log = json_mi_cmd_support_effects_log,
+ .ns_list = json_nvme_list_ns,
+ .ns_list_log = json_changed_ns_list_log,
+ .nvm_id_ns = json_nvme_nvm_id_ns,
+ .persistent_event_log = json_persistent_event_log,
+ .predictable_latency_event_agg_log = json_predictable_latency_event_agg_log,
+ .predictable_latency_per_nvmset = json_predictable_latency_per_nvmset,
+ .primary_ctrl_cap = json_nvme_primary_ctrl_cap,
+ .resv_notification_log = json_resv_notif_log,
+ .resv_report = json_nvme_resv_report,
+ .sanitize_log_page = json_sanitize_log,
+ .secondary_ctrl_list = json_nvme_list_secondary_ctrl,
+ .select_result = json_select_result,
+ .self_test_log = json_self_test_log,
+ .single_property = json_single_property,
+ .smart_log = json_smart_log,
+ .supported_cap_config_list_log = json_supported_cap_config_log,
+ .supported_log_pages = json_support_log,
+ .zns_start_zone_list = json_zns_start_zone_list,
+ .zns_changed_zone_log = json_zns_changed,
+ .zns_finish_zone_list = json_zns_finish_zone_list,
+ .zns_id_ctrl = json_nvme_zns_id_ctrl,
+ .zns_id_ns = json_nvme_zns_id_ns,
+ .zns_report_zones = json_nvme_zns_report_zones,
+ .show_feature = json_feature_show,
+ .show_feature_fields = json_feature_show_fields,
+ .id_ctrl_rpmbs = json_id_ctrl_rpmbs,
+ .lba_range = json_lba_range,
+ .lba_status_info = json_lba_status_info,
+ .d = json_d,
+ .show_init = json_show_init,
+ .show_finish = json_show_finish,
+
+ /* libnvme tree print functions */
+ .list_item = json_list_item,
+ .list_items = json_print_list_items,
+ .print_nvme_subsystem_list = json_print_nvme_subsystem_list,
+ .topology_ctrl = json_simple_topology,
+ .topology_namespace = json_simple_topology,
+
+ /* status and error messages */
+ .connect_msg = json_connect_msg,
+ .show_message = json_output_message,
+ .show_perror = json_output_perror,
+ .show_status = json_output_status,
+ .show_error_status = json_output_error_status,
+};
+
+struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags)
+{
+ json_print_ops.flags = flags;
+ return &json_print_ops;
+}
diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c
new file mode 100644
index 0000000..63462ea
--- /dev/null
+++ b/nvme-print-stdout.c
@@ -0,0 +1,5174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include <ccan/ccan/strset/strset.h>
+#include <ccan/ccan/htable/htable_type.h>
+#include <ccan/ccan/htable/htable.h>
+#include <ccan/ccan/hash/hash.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "nvme-models.h"
+#include "util/suffix.h"
+#include "util/types.h"
+#include "common.h"
+
+static const uint8_t zero_uuid[16] = { 0 };
+static const uint8_t invalid_uuid[16] = {[0 ... 15] = 0xff };
+static const char dash[100] = {[0 ... 99] = '-'};
+
+static struct print_ops stdout_print_ops;
+
+static const char *subsys_key(const struct nvme_subsystem *s)
+{
+ return nvme_subsystem_get_name((nvme_subsystem_t)s);
+}
+
+static const char *ctrl_key(const struct nvme_ctrl *c)
+{
+ return nvme_ctrl_get_name((nvme_ctrl_t)c);
+}
+
+static const char *ns_key(const struct nvme_ns *n)
+{
+ return nvme_ns_get_name((nvme_ns_t)n);
+}
+
+static bool subsys_cmp(const struct nvme_subsystem *s, const char *name)
+{
+ return !strcmp(nvme_subsystem_get_name((nvme_subsystem_t)s), name);
+}
+
+static bool ctrl_cmp(const struct nvme_ctrl *c, const char *name)
+{
+ return !strcmp(nvme_ctrl_get_name((nvme_ctrl_t)c), name);
+}
+
+static bool ns_cmp(const struct nvme_ns *n, const char *name)
+{
+ return !strcmp(nvme_ns_get_name((nvme_ns_t)n), name);
+}
+
+HTABLE_DEFINE_TYPE(struct nvme_subsystem, subsys_key, hash_string,
+ subsys_cmp, htable_subsys);
+HTABLE_DEFINE_TYPE(struct nvme_ctrl, ctrl_key, hash_string,
+ ctrl_cmp, htable_ctrl);
+HTABLE_DEFINE_TYPE(struct nvme_ns, ns_key, hash_string,
+ ns_cmp, htable_ns);
+
+static void htable_ctrl_add_unique(struct htable_ctrl *ht, nvme_ctrl_t c)
+{
+ if (htable_ctrl_get(ht, nvme_ctrl_get_name(c)))
+ return;
+
+ htable_ctrl_add(ht, c);
+}
+
+static void htable_ns_add_unique(struct htable_ns *ht, nvme_ns_t n)
+{
+ struct htable_ns_iter it;
+ nvme_ns_t _n;
+
+ /*
+ * Test if namespace pointer is already in the hash, and thus avoid
+ * inserting severaltimes the same pointer.
+ */
+ for (_n = htable_ns_getfirst(ht, nvme_ns_get_name(n), &it);
+ _n;
+ _n = htable_ns_getnext(ht, nvme_ns_get_name(n), &it)) {
+ if (_n == n)
+ return;
+ }
+ htable_ns_add(ht, n);
+}
+
+struct nvme_resources {
+ nvme_root_t r;
+
+ struct htable_subsys ht_s;
+ struct htable_ctrl ht_c;
+ struct htable_ns ht_n;
+ struct strset subsystems;
+ struct strset ctrls;
+ struct strset namespaces;
+};
+
+static int nvme_resources_init(nvme_root_t r, struct nvme_resources *res)
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+ nvme_path_t p;
+
+ res->r = r;
+ htable_subsys_init(&res->ht_s);
+ htable_ctrl_init(&res->ht_c);
+ htable_ns_init(&res->ht_n);
+ strset_init(&res->subsystems);
+ strset_init(&res->ctrls);
+ strset_init(&res->namespaces);
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ htable_subsys_add(&res->ht_s, s);
+ strset_add(&res->subsystems, nvme_subsystem_get_name(s));
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ htable_ctrl_add_unique(&res->ht_c, c);
+ strset_add(&res->ctrls, nvme_ctrl_get_name(c));
+
+ nvme_ctrl_for_each_ns(c, n) {
+ htable_ns_add_unique(&res->ht_n, n);
+ strset_add(&res->namespaces, nvme_ns_get_name(n));
+ }
+
+ nvme_ctrl_for_each_path(c, p) {
+ n = nvme_path_get_ns(p);
+ if (n) {
+ htable_ns_add_unique(&res->ht_n, n);
+ strset_add(&res->namespaces, nvme_ns_get_name(n));
+ }
+ }
+ }
+
+ nvme_subsystem_for_each_ns(s, n) {
+ htable_ns_add_unique(&res->ht_n, n);
+ strset_add(&res->namespaces, nvme_ns_get_name(n));
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void nvme_resources_free(struct nvme_resources *res)
+{
+ strset_clear(&res->namespaces);
+ strset_clear(&res->ctrls);
+ strset_clear(&res->subsystems);
+ htable_ns_clear(&res->ht_n);
+ htable_ctrl_clear(&res->ht_c);
+ htable_subsys_clear(&res->ht_s);
+}
+
+static void stdout_feature_show_fields(enum nvme_features_id fid,
+ unsigned int result,
+ unsigned char *buf);
+static void stdout_smart_log(struct nvme_smart_log *smart,
+ unsigned int nsid,
+ const char *devname);
+
+static void stdout_predictable_latency_per_nvmset(
+ struct nvme_nvmset_predictable_lat_log *plpns_log,
+ __u16 nvmset_id, const char *devname)
+{
+ 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_rt));
+ printf("DTWIN Writes Typical: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_wt));
+ printf("DTWIN Time Maximum: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_tmax));
+ printf("NDWIN Time Minimum High: %"PRIu64" \n",
+ le64_to_cpu(plpns_log->ndwin_tmin_hi));
+ printf("NDWIN Time Minimum Low: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->ndwin_tmin_lo));
+ printf("DTWIN Reads Estimate: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_re));
+ printf("DTWIN Writes Estimate: %"PRIu64"\n",
+ le64_to_cpu(plpns_log->dtwin_we));
+ printf("DTWIN Time Estimate: %"PRIu64"\n\n\n",
+ le64_to_cpu(plpns_log->dtwin_te));
+}
+
+static void stdout_predictable_latency_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *pea_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ __u64 num_iter;
+ __u64 num_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 void stdout_persistent_event_log_rci(__le32 pel_header_rci)
+{
+ __u32 rci = le32_to_cpu(pel_header_rci);
+ __u32 rsvd19 = (rci & 0xfff80000) >> 19;
+ __u8 rce = (rci & 0x40000) >> 18;
+ __u8 rcpit = (rci & 0x30000) >> 16;
+ __u16 rcpid = rci & 0xffff;
+
+ if(rsvd19)
+ printf(" [31:19] : %#x\tReserved\n", rsvd19);
+ printf("\tReporting Context Exists (RCE): %s(%u)\n",
+ rce ? "true" : "false", rce);
+ printf("\tReporting Context Port Identifier Type (RCPIT): %u(%s)\n", rcpit,
+ (rcpit == 0x00) ? "Does not already exist" :
+ (rcpit == 0x01) ? "NVM subsystem port" :
+ (rcpit == 0x02) ? "NVMe-MI port" : "Reserved");
+ printf("\tReporting Context Port Identifier (RCPID): %#x\n\n", rcpid);
+}
+
+static void stdout_persistent_event_entry_ehai(__u8 ehai)
+{
+ __u8 rsvd1 = (ehai & 0xfc) >> 2;
+ __u8 pit = ehai & 0x03;
+
+ printf(" [7:2] : %#x\tReserved\n", rsvd1);
+ printf("\tPort Identifier Type (PIT): %u(%s)\n", pit,
+ (pit == 0x00) ? "PIT not reported and PELPID does not apply" :
+ (pit == 0x01) ? "NVM subsystem port" :
+ (pit == 0x02) ? "NVMe-MI port" :
+ "Event not associated with any port and PELPID does not apply");
+}
+
+static void stdout_add_bitmap(int i, __u8 seb)
+{
+ for (int bit = 0; bit < 8; bit++) {
+ if (nvme_pel_event_to_string(bit + i * 8)) {
+ if (nvme_pel_event_to_string(bit + i * 8))
+ if ((seb >> bit) & 0x1)
+ printf(" Support %s\n",
+ nvme_pel_event_to_string(bit + i * 8));
+ }
+ }
+}
+
+static void stdout_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size,
+ const char *devname)
+{
+ __u32 offset, por_info_len, por_info_list;
+ __u64 *fw_rev;
+ int fid, cdw11, dword_cnt;
+ unsigned char *mem_buf = NULL;
+ 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_set_feature_event *set_feat_event;
+ struct nvme_thermal_exc_event *thermal_exc_event;
+ struct nvme_persistent_event_log *pevent_log_head;
+ struct nvme_persistent_event_entry *pevent_entry_head;
+
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ 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->lid);
+ 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->rv);
+ printf("Log Header Length: %u\n", pevent_log_head->lhl);
+ printf("Timestamp: %"PRIu64"\n",
+ le64_to_cpu(pevent_log_head->ts));
+ printf("Power On Hours (POH): %s",
+ uint128_t_to_l10n_string(le128_to_cpu(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("Generation Number: %u\n",
+ le16_to_cpu(pevent_log_head->gen_number));
+ printf("Reporting Context Information (RCI): %u\n",
+ le32_to_cpu(pevent_log_head->rci));
+ if (human)
+ stdout_persistent_event_log_rci(pevent_log_head->rci);
+ printf("Supported Events Bitmap: \n");
+ for (int i = 0; i < 32; i++) {
+ if (pevent_log_head->seb[i] == 0)
+ continue;
+ stdout_add_bitmap(i, pevent_log_head->seb[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 Number: %u\n", i);
+ printf("Event Type: %s\n", nvme_pel_event_to_string(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("Event Header Additional Info: %u\n", pevent_entry_head->ehai);
+ if (human)
+ stdout_persistent_event_entry_ehai(pevent_entry_head->ehai);
+ printf("Controller Identifier: %u\n",
+ le16_to_cpu(pevent_entry_head->cntlid));
+ printf("Event Timestamp: %"PRIu64"\n",
+ le64_to_cpu(pevent_entry_head->ets));
+ printf("Port Identifier: %u\n",
+ le16_to_cpu(pevent_entry_head->pelpid));
+ 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_PEL_SMART_HEALTH_EVENT:
+ smart_event = pevent_log_info + offset;
+ printf("Smart Health Event Entry: \n");
+ stdout_smart_log(smart_event, NVME_NSID_ALL, devname);
+ break;
+ case NVME_PEL_FW_COMMIT_EVENT:
+ fw_commit_event = pevent_log_info + offset;
+ printf("FW Commit Event Entry: \n");
+ printf("Old Firmware Revision: %"PRIu64" (%s)\n",
+ le64_to_cpu(fw_commit_event->old_fw_rev),
+ util_fw_to_string((char *)&fw_commit_event->old_fw_rev));
+ printf("New Firmware Revision: %"PRIu64" (%s)\n",
+ le64_to_cpu(fw_commit_event->new_fw_rev),
+ util_fw_to_string((char *)&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_PEL_TIMESTAMP_EVENT:
+ ts_change_event = pevent_log_info + offset;
+ printf("Time Stamp Change Event Entry: \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_PEL_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 Entry: \n");
+ fw_rev = pevent_log_info + offset;
+ printf("Firmware Revision: %"PRIu64" (%s)\n", le64_to_cpu(*fw_rev),
+ util_fw_to_string((char *)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_PEL_NSS_HW_ERROR_EVENT:
+ nss_hw_err_event = pevent_log_info + offset;
+ printf("NVM Subsystem Hardware Error Event Code Entry: %u, %s\n",
+ le16_to_cpu(nss_hw_err_event->nss_hw_err_event_code),
+ nvme_nss_hw_error_to_string(nss_hw_err_event->nss_hw_err_event_code));
+ break;
+ case NVME_PEL_CHANGE_NS_EVENT:
+ ns_event = pevent_log_info + offset;
+ printf("Change Namespace Event Entry: \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_PEL_FORMAT_START_EVENT:
+ format_start_event = pevent_log_info + offset;
+ printf("Format NVM Start Event Entry: \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_PEL_FORMAT_COMPLETION_EVENT:
+ format_cmpln_event = pevent_log_info + offset;
+ printf("Format NVM Completion Event Entry: \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_PEL_SANITIZE_START_EVENT:
+ sanitize_start_event = pevent_log_info + offset;
+ printf("Sanitize Start Event Entry: \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_PEL_SANITIZE_COMPLETION_EVENT:
+ sanitize_cmpln_event = pevent_log_info + offset;
+ printf("Sanitize Completion Event Entry: \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_PEL_SET_FEATURE_EVENT:
+ set_feat_event = pevent_log_info + offset;
+ printf("Set Feature Event Entry: \n");
+ dword_cnt = set_feat_event->layout & 0x03;
+ fid = le32_to_cpu(set_feat_event->cdw_mem[0]) & 0x000f;
+ cdw11 = le32_to_cpu(set_feat_event->cdw_mem[1]);
+
+ printf("Set Feature ID :%#02x (%s), value:%#08x\n", fid,
+ nvme_feature_to_string(fid), cdw11);
+ if (((set_feat_event->layout & 0xff) >> 2) != 0) {
+ mem_buf = (unsigned char *)(set_feat_event + 4 + dword_cnt * 4);
+ stdout_feature_show_fields(fid, cdw11, mem_buf);
+ }
+ break;
+ case NVME_PEL_TELEMETRY_CRT:
+ d(pevent_log_info + offset, 512, 16, 1);
+ break;
+ case NVME_PEL_THERMAL_EXCURSION_EVENT:
+ thermal_exc_event = pevent_log_info + offset;
+ printf("Thermal Excursion Event Entry: \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");
+ break;
+ }
+ offset += le16_to_cpu(pevent_entry_head->el);
+ printf("\n");
+ }
+}
+
+static void stdout_endurance_group_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname)
+{
+ 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]));
+ }
+}
+
+static void stdout_lba_status_log(void *lba_status, __u32 size,
+ const char *devname)
+{
+ struct nvme_lba_status_log *hdr;
+ struct nvme_lbas_ns_element *ns_element;
+ struct nvme_lba_rd *range_desc;
+ int offset = sizeof(*hdr);
+ __u32 num_lba_desc, num_elements;
+
+ hdr = lba_status;
+ printf("LBA Status Log for device: %s\n", devname);
+ printf("LBA Status Log Page Length: %"PRIu32"\n",
+ le32_to_cpu(hdr->lslplen));
+ num_elements = le32_to_cpu(hdr->nlslne);
+ printf("Number of LBA Status Log Namespace Elements: %"PRIu32"\n",
+ num_elements);
+ printf("Estimate of Unrecoverable Logical Blocks: %"PRIu32"\n",
+ le32_to_cpu(hdr->estulb));
+ printf("LBA Status Generation Counter: %"PRIu16"\n", le16_to_cpu(hdr->lsgc));
+ for (int ele = 0; ele < num_elements; ele++) {
+ ns_element = lba_status + offset;
+ printf("Namespace Element Identifier: %"PRIu32"\n",
+ le32_to_cpu(ns_element->neid));
+ num_lba_desc = le32_to_cpu(ns_element->nlrd);
+ printf("Number of LBA Range Descriptors: %"PRIu32"\n", num_lba_desc);
+ printf("Recommended Action Type: %u\n", ns_element->ratype);
+
+ offset += sizeof(*ns_element);
+ if (num_lba_desc != 0xffffffff) {
+ for (int i = 0; i < num_lba_desc; i++) {
+ range_desc = lba_status + offset;
+ printf("RSLBA[%d]: %"PRIu64"\n", i,
+ le64_to_cpu(range_desc->rslba));
+ printf("RNLB[%d]: %"PRIu32"\n", i,
+ le32_to_cpu(range_desc->rnlb));
+ offset += sizeof(*range_desc);
+ }
+ } else {
+ printf("Number of LBA Range Descriptors (NLRD) set to %#x for "\
+ "NS element %d\n", num_lba_desc, ele);
+ }
+ }
+}
+
+static void stdout_resv_notif_log(struct nvme_resv_notification_log *resv,
+ const char *devname)
+{
+ printf("Reservation Notif Log for device: %s\n", devname);
+ printf("Log Page Count : %"PRIx64"\n",
+ le64_to_cpu(resv->lpc));
+ printf("Resv Notif Log Page Type : %u (%s)\n",
+ resv->rnlpt,
+ nvme_resv_notif_to_string(resv->rnlpt));
+ printf("Num of Available Log Pages : %u\n", resv->nalp);
+ printf("Namespace ID: : %"PRIx32"\n",
+ le32_to_cpu(resv->nsid));
+}
+
+static void stdout_fid_support_effects_log_human(__u32 fid_support)
+{
+ const char *set = "+";
+ const char *clr = "-";
+ __u16 fsp;
+
+ printf(" FSUPP+");
+ printf(" UDCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UDCC) ? set : clr);
+ printf(" NCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NCC) ? set : clr);
+ printf(" NIC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_NIC) ? set : clr);
+ printf(" CCC%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_CCC) ? set : clr);
+ printf(" USS%s", (fid_support & NVME_FID_SUPPORTED_EFFECTS_UUID_SEL) ? set : clr);
+
+ fsp = (fid_support >> NVME_FID_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_FID_SUPPORTED_EFFECTS_SCOPE_MASK;
+
+ printf(" NAMESPACE SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr);
+ printf(" CONTROLLER SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr);
+ printf(" NVM SET SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr);
+ printf(" ENDURANCE GROUP SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr);
+ printf(" DOMAIN SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr);
+ printf(" NVM Subsystem SCOPE%s", (fsp & NVME_FID_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr);
+}
+
+static void stdout_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log,
+ const char *devname)
+{
+ __u32 fid_effect;
+ int i, human = stdout_print_ops.flags & VERBOSE;
+
+ printf("FID Supports Effects Log for device: %s\n", devname);
+ printf("Admin Command Set\n");
+ for (i = 0; i < 256; i++) {
+ fid_effect = le32_to_cpu(fid_log->fid_support[i]);
+ if (fid_effect & NVME_FID_SUPPORTED_EFFECTS_FSUPP) {
+ printf("FID %02x -> Support Effects Log: %08x", i,
+ fid_effect);
+ if (human)
+ stdout_fid_support_effects_log_human(fid_effect);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static void stdout_mi_cmd_support_effects_log_human(__u32 mi_cmd_support)
+{
+ const char *set = "+";
+ const char *clr = "-";
+ __u16 csp;
+
+ printf(" CSUPP+");
+ printf(" UDCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_UDCC) ? set : clr);
+ printf(" NCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NCC) ? set : clr);
+ printf(" NIC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_NIC) ? set : clr);
+ printf(" CCC%s", (mi_cmd_support & NVME_MI_CMD_SUPPORTED_EFFECTS_CCC) ? set : clr);
+
+ csp = (mi_cmd_support >> NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_SHIFT) & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_MASK;
+
+ printf(" NAMESPACE SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NS) ? set : clr);
+ printf(" CONTROLLER SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_CTRL) ? set : clr);
+ printf(" NVM SET SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NVM_SET) ? set : clr);
+ printf(" ENDURANCE GROUP SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_ENDGRP) ? set : clr);
+ printf(" DOMAIN SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_DOMAIN) ? set : clr);
+ printf(" NVM Subsystem SCOPE%s", (csp & NVME_MI_CMD_SUPPORTED_EFFECTS_SCOPE_NSS) ? set : clr);
+}
+
+static void stdout_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log,
+ const char *devname)
+{
+ __u32 mi_cmd_effect;
+ int i, human = stdout_print_ops.flags & VERBOSE;
+
+ printf("MI Commands Support Effects Log for device: %s\n", devname);
+ printf("Admin Command Set\n");
+ for (i = 0; i < NVME_LOG_MI_CMD_SUPPORTED_EFFECTS_MAX; i++) {
+ mi_cmd_effect = le32_to_cpu(mi_cmd_log->mi_cmd_support[i]);
+ if (mi_cmd_effect & NVME_MI_CMD_SUPPORTED_EFFECTS_CSUPP) {
+ printf("MI CMD %02x -> Support Effects Log: %08x", i,
+ mi_cmd_effect);
+ if (human)
+ stdout_mi_cmd_support_effects_log_human(mi_cmd_effect);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static void stdout_boot_part_log(void *bp_log, const char *devname,
+ __u32 size)
+{
+ struct nvme_boot_partition *hdr;
+
+ hdr = bp_log;
+ printf("Boot Partition Log for device: %s\n", devname);
+ printf("Log ID: %u\n", hdr->lid);
+ printf("Boot Partition Size: %u KiB\n", le32_to_cpu(hdr->bpinfo) & 0x7fff);
+ printf("Active BPID: %u\n", (le32_to_cpu(hdr->bpinfo) >> 31) & 0x1);
+}
+
+static const char *eomip_to_string(__u8 eomip)
+{
+ const char *string;
+ switch (eomip) {
+ case NVME_PHY_RX_EOM_NOT_STARTED:
+ string = "Not Started";
+ break;
+ case NVME_PHY_RX_EOM_IN_PROGRESS:
+ string = "In Progress";
+ break;
+ case NVME_PHY_RX_EOM_COMPLETED:
+ string = "Completed";
+ break;
+ default:
+ string = "Unknown";
+ break;
+ }
+ return string;
+}
+
+static void stdout_phy_rx_eom_odp(uint8_t odp)
+{
+ __u8 rsvd = (odp >> 2) & 0x3F;
+ __u8 edfp = (odp >> 1) & 0x1;
+ __u8 pefp = odp & 0x1;
+
+ if (rsvd)
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] : %#x\tEye Data Field %sPresent\n",
+ edfp, edfp ? "" : "Not ");
+ printf(" [0:0] : %#x\tPrintable Eye Field %sPresent\n",
+ pefp, pefp ? "" : "Not ");
+}
+
+static void stdout_eom_printable_eye(struct nvme_eom_lane_desc *lane)
+{
+ char *eye = (char *)lane->eye_desc;
+ int i, j;
+ for (i = 0; i < lane->nrows; i++) {
+ for (j = 0; j < lane->ncols; j++)
+ printf("%c", eye[i * lane->ncols + j]);
+ printf("\n");
+ }
+}
+
+static void stdout_phy_rx_eom_descs(struct nvme_phy_rx_eom_log *log)
+{
+ void *p = log->descs;
+ int i;
+
+ for (i = 0; i < log->nd; i++) {
+ struct nvme_eom_lane_desc *desc = p;
+
+ printf("Measurement Status: %s\n",
+ desc->mstatus ? "Successful" : "Not Successful");
+ printf("Lane: %u\n", desc->lane);
+ printf("Eye: %u\n", desc->eye);
+ printf("Top: %u\n", le16_to_cpu(desc->top));
+ printf("Bottom: %u\n", le16_to_cpu(desc->bottom));
+ printf("Left: %u\n", le16_to_cpu(desc->left));
+ printf("Right: %u\n", le16_to_cpu(desc->right));
+ printf("Number of Rows: %u\n", le16_to_cpu(desc->nrows));
+ printf("Number of Columns: %u\n", le16_to_cpu(desc->ncols));
+ printf("Eye Data Length: %u\n", le16_to_cpu(desc->edlen));
+
+ if (log->odp & NVME_EOM_PRINTABLE_EYE_PRESENT)
+ stdout_eom_printable_eye(desc);
+
+ /* Eye Data field is vendor specific */
+
+ p += log->dsize;
+ }
+}
+
+static void stdout_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ printf("Physical Interface Receiver Eye Opening Measurement Log for controller ID: %u\n", controller);
+ printf("Log ID: %u\n", log->lid);
+ printf("EOM In Progress: %s\n", eomip_to_string(log->eomip));
+ printf("Header Size: %u\n", le16_to_cpu(log->hsize));
+ printf("Result Size: %u\n", le32_to_cpu(log->rsize));
+ printf("EOM Data Generation Number: %u\n", log->eomdgn);
+ printf("Log Revision: %u\n", log->lr);
+ printf("Optional Data Present: %u\n", log->odp);
+ if (human)
+ stdout_phy_rx_eom_odp(log->odp);
+ printf("Lanes: %u\n", log->lanes);
+ printf("Eyes Per Lane: %u\n", log->epl);
+ printf("Log Specific Parameter Field Copy: %u\n", log->lspfc);
+ printf("Link Information: %u\n", log->li);
+ printf("Log Specific Identifier Copy: %u\n", le16_to_cpu(log->lsic));
+ printf("Descriptor Size: %u\n", le32_to_cpu(log->dsize));
+ printf("Number of Descriptors: %u\n", le16_to_cpu(log->nd));
+ printf("Maximum Top Bottom: %u\n", le16_to_cpu(log->maxtb));
+ printf("Maximum Left Right: %u\n", le16_to_cpu(log->maxlr));
+ printf("Estimated Time for Good Quality: %u\n", le16_to_cpu(log->etgood));
+ printf("Estimated Time for Better Quality: %u\n", le16_to_cpu(log->etbetter));
+ printf("Estimated Time for Best Quality: %u\n", le16_to_cpu(log->etbest));
+
+ if (log->eomip == NVME_PHY_RX_EOM_COMPLETED) {
+ stdout_phy_rx_eom_descs(log);
+ }
+}
+
+static void stdout_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log)
+{
+ int i;
+ int nmu = le16_to_cpu(mus_log->nmu);
+
+ printf("Number of Media Unit Status Descriptors: %u\n", nmu);
+ printf("Number of Channels: %u\n", le16_to_cpu(mus_log->cchans));
+ printf("Selected Configuration: %u\n", le16_to_cpu(mus_log->sel_config));
+ for (i = 0; i < nmu; i++) {
+ printf("Media Unit Status Descriptor: %u\n", i);
+ printf("Media Unit Identifier: %u\n",
+ le16_to_cpu(mus_log->mus_desc[i].muid));
+ printf("Domain Identifier: %u\n",
+ le16_to_cpu(mus_log->mus_desc[i].domainid));
+ printf("Endurance Group Identifier: %u\n",
+ le16_to_cpu(mus_log->mus_desc[i].endgid));
+ printf("NVM Set Identifier: %u\n",
+ le16_to_cpu(mus_log->mus_desc[i].nvmsetid));
+ printf("Capacity Adjustment Factor: %u\n",
+ le16_to_cpu(mus_log->mus_desc[i].cap_adj_fctr));
+ printf("Available Spare: %u\n", mus_log->mus_desc[i].avl_spare);
+ printf("Percentage Used: %u\n", mus_log->mus_desc[i].percent_used);
+ printf("Number of Channels: %u\n", mus_log->mus_desc[i].mucs);
+ printf("Channel Identifiers Offset: %u\n", mus_log->mus_desc[i].cio);
+ }
+}
+
+static void stdout_fdp_config_fdpa(uint8_t fdpa)
+{
+ __u8 valid = (fdpa >> 7) & 0x1;
+ __u8 rsvd = (fdpa >> 5) & 0x3;
+ __u8 fdpvwc = (fdpa >> 4) & 0x1;
+ __u8 rgif = fdpa & 0xf;
+
+ printf(" [7:7] : %#x\tFDP Configuration %sValid\n",
+ valid, valid ? "" : "Not ");
+ if (rsvd)
+ printf(" [6:5] : %#x\tReserved\n", rsvd);
+ printf(" [4:4] : %#x\tFDP Volatile Write Cache %sPresent\n",
+ fdpvwc, fdpvwc ? "" : "Not ");
+ printf(" [3:0] : %#x\tReclaim Group Identifier Format\n", rgif);
+}
+
+static void stdout_fdp_configs(struct nvme_fdp_config_log *log, size_t len)
+{
+ void *p = log->configs;
+ int human = stdout_print_ops.flags & VERBOSE;
+ uint16_t n;
+
+ n = le16_to_cpu(log->n) + 1;
+
+ for (int i = 0; i < n; i++) {
+ struct nvme_fdp_config_desc *config = p;
+
+ printf("FDP Attributes: %#x\n", config->fdpa);
+ if (human)
+ stdout_fdp_config_fdpa(config->fdpa);
+
+ printf("Vendor Specific Size: %u\n", config->vss);
+ printf("Number of Reclaim Groups: %"PRIu32"\n", le32_to_cpu(config->nrg));
+ printf("Number of Reclaim Unit Handles: %"PRIu16"\n", le16_to_cpu(config->nruh));
+ printf("Number of Namespaces Supported: %"PRIu32"\n", le32_to_cpu(config->nnss));
+ printf("Reclaim Unit Nominal Size: %"PRIu64"\n", le64_to_cpu(config->runs));
+ printf("Estimated Reclaim Unit Time Limit: %"PRIu32"\n", le32_to_cpu(config->erutl));
+
+ printf("Reclaim Unit Handle List:\n");
+ for (int j = 0; j < le16_to_cpu(config->nruh); j++) {
+ struct nvme_fdp_ruh_desc *ruh = &config->ruhs[j];
+
+ printf(" [%d]: %s\n", j, ruh->ruht == NVME_FDP_RUHT_INITIALLY_ISOLATED ? "Initially Isolated" : "Persistently Isolated");
+ }
+
+ p += config->size;
+ }
+}
+
+static void stdout_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len)
+{
+ uint16_t nruh = le16_to_cpu(log->nruh);
+
+ for (int i = 0; i < nruh; i++) {
+ struct nvme_fdp_ruhu_desc *ruhu = &log->ruhus[i];
+
+ printf("Reclaim Unit Handle %d Attributes: 0x%"PRIx8" (%s)\n", i, ruhu->ruha,
+ ruhu->ruha == 0x0 ? "Unused" : (
+ ruhu->ruha == 0x1 ? "Host Specified" : (
+ ruhu->ruha == 0x2 ? "Controller Specified" : "Unknown")));
+ }
+}
+
+static void stdout_fdp_stats(struct nvme_fdp_stats_log *log)
+{
+ printf("Host Bytes with Metadata Written (HBMW): %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(log->hbmw)));
+ printf("Media Bytes with Metadata Written (MBMW): %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(log->mbmw)));
+ printf("Media Bytes Erased (MBE): %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(log->mbe)));
+}
+
+static void stdout_fdp_events(struct nvme_fdp_events_log *log)
+{
+ struct tm *tm;
+ char buffer[320];
+ time_t ts;
+ uint32_t n = le32_to_cpu(log->n);
+
+ for (unsigned int i = 0; i < n; i++) {
+ struct nvme_fdp_event *event = &log->events[i];
+
+ ts = int48_to_long(event->ts.timestamp) / 1000;
+ tm = localtime(&ts);
+
+ printf("Event[%u]\n", i);
+ printf(" Event Type: 0x%"PRIx8" (%s)\n", event->type, nvme_fdp_event_to_string(event->type));
+ printf(" Event Timestamp: %"PRIu64" (%s)\n", int48_to_long(event->ts.timestamp),
+ strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-");
+
+ if (event->flags & NVME_FDP_EVENT_F_PIV)
+ printf(" Placement Identifier (PID): 0x%"PRIx16"\n", le16_to_cpu(event->pid));
+
+ if (event->flags & NVME_FDP_EVENT_F_NSIDV)
+ printf(" Namespace Identifier (NSID): %"PRIu32"\n", le32_to_cpu(event->nsid));
+
+ if (event->type == NVME_FDP_EVENT_REALLOC) {
+ struct nvme_fdp_event_realloc *mr;
+ mr = (struct nvme_fdp_event_realloc *)&event->type_specific;
+
+ printf(" Number of LBAs Moved (NLBAM): %"PRIu16"\n", le16_to_cpu(mr->nlbam));
+
+ if (mr->flags & NVME_FDP_EVENT_REALLOC_F_LBAV) {
+ printf(" Logical Block Address (LBA): 0x%"PRIx64"\n", le64_to_cpu(mr->lba));
+ }
+ }
+
+ if (event->flags & NVME_FDP_EVENT_F_LV) {
+ printf(" Reclaim Group Identifier: %"PRIu16"\n", le16_to_cpu(event->rgid));
+ printf(" Reclaim Unit Handle Identifier %"PRIu8"\n", event->ruhid);
+ }
+
+ printf("\n");
+ }
+}
+
+static void stdout_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len)
+{
+ uint16_t nruhsd = le16_to_cpu(status->nruhsd);
+
+ for (unsigned int i = 0; i < nruhsd; i++) {
+ struct nvme_fdp_ruh_status_desc *ruhs = &status->ruhss[i];
+
+ printf("Placement Identifier %"PRIu16"; Reclaim Unit Handle Identifier %"PRIu16"\n",
+ le16_to_cpu(ruhs->pid), le16_to_cpu(ruhs->ruhid));
+ printf(" Estimated Active Reclaim Unit Time Remaining (EARUTR): %"PRIu32"\n",
+ le32_to_cpu(ruhs->earutr));
+ printf(" Reclaim Unit Available Media Writes (RUAMW): %"PRIu64"\n",
+ le64_to_cpu(ruhs->ruamw));
+
+ printf("\n");
+ }
+}
+
+static void stdout_supported_cap_config_log(struct nvme_supported_cap_config_list_log *cap)
+{
+ struct nvme_end_grp_chan_desc *chan_desc;
+ int i, j, k, l, m, sccn, egcn, egsets, egchans, chmus;
+
+ sccn = cap->sccn;
+ printf("Number of Supported Capacity Configurations: %u\n", sccn);
+ for (i = 0; i < sccn; i++) {
+ printf("Capacity Configuration Descriptor: %u\n", i);
+ printf("Capacity Configuration Identifier: %u\n",
+ le16_to_cpu(cap->cap_config_desc[i].cap_config_id));
+ printf("Domain Identifier: %u\n",
+ le16_to_cpu(cap->cap_config_desc[i].domainid));
+ egcn = le16_to_cpu(cap->cap_config_desc[i].egcn);
+ printf("Number of Endurance Group Configuration Descriptors: %u\n", egcn);
+ for(j = 0; j < egcn; j++) {
+ printf("Endurance Group Identifier: %u\n",
+ le16_to_cpu(cap->cap_config_desc[i].egcd[j].endgid));
+ printf("Capacity Adjustment Factor: %u\n",
+ le16_to_cpu(cap->cap_config_desc[i].egcd[j].cap_adj_factor));
+ printf("Total Endurance Group Capacity: %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(
+ cap->cap_config_desc[i].egcd[j].tegcap)));
+ printf("Spare Endurance Group Capacity: %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(
+ cap->cap_config_desc[i].egcd[j].segcap)));
+ printf("Endurance Estimate: %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(
+ cap->cap_config_desc[i].egcd[j].end_est)));
+ egsets = le16_to_cpu(cap->cap_config_desc[i].egcd[j].egsets);
+ printf("Number of NVM Sets: %u\n", egsets);
+ for(k = 0; k < egsets; k++) {
+ printf("NVM Set %d Identifier: %u\n", i,
+ le16_to_cpu(cap->cap_config_desc[i].egcd[j].nvmsetid[k]));
+ }
+ chan_desc = (struct nvme_end_grp_chan_desc *) \
+ ((cap->cap_config_desc[i].egcd[j].nvmsetid[0]) * (sizeof(__u16)*egsets));
+ egchans = le16_to_cpu(chan_desc->egchans);
+ printf("Number of Channels: %u\n", egchans);
+ for(l = 0; l < egchans; l++) {
+ printf("Channel Identifier: %u\n",
+ le16_to_cpu(chan_desc->chan_config_desc[l].chanid));
+ chmus = le16_to_cpu(chan_desc->chan_config_desc[l].chmus);
+ printf("Number of Channel Media Units: %u\n", chmus);
+ for(m = 0; m < chmus; m++) {
+ printf("Media Unit Identifier: %u\n",
+ le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].muid));
+ printf("Media Unit Descriptor Length: %u\n",
+ le16_to_cpu(chan_desc->chan_config_desc[l].mu_config_desc[m].mudl));
+ }
+ }
+ }
+ }
+}
+
+static unsigned int stdout_subsystem_multipath(nvme_subsystem_t s)
+{
+ nvme_ns_t n;
+ nvme_path_t p;
+ unsigned int i = 0;
+
+ n = nvme_subsystem_first_ns(s);
+ if (!n)
+ return 0;
+
+ nvme_namespace_for_each_path(n, p) {
+ nvme_ctrl_t c = nvme_path_get_ctrl(p);
+ const char *ana_state = ana_state = nvme_path_get_ana_state(p);
+
+ printf(" +- %s %s %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c),
+ ana_state);
+ i++;
+ }
+
+ return i;
+}
+
+static void stdout_subsystem_ctrls(nvme_subsystem_t s)
+{
+ nvme_ctrl_t c;
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf(" +- %s %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c));
+ }
+}
+
+static void stdout_subsystem(nvme_root_t r, bool show_ana)
+{
+ nvme_host_t h;
+ bool first = true;
+
+ nvme_for_each_host(r, h) {
+ nvme_subsystem_t s;
+
+ nvme_for_each_subsystem(h, s) {
+ int len = strlen(nvme_subsystem_get_name(s));
+
+ if (!first)
+ printf("\n");
+ first = false;
+
+ printf("%s - NQN=%s\n", nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+ printf("%*s hostnqn=%s\n", len, " ",
+ nvme_host_get_hostnqn(nvme_subsystem_get_host(s)));
+ printf("%*s iopolicy=%s\n", len, " ",
+ nvme_subsystem_get_iopolicy(s));
+ printf("\\\n");
+
+ if (!show_ana || !stdout_subsystem_multipath(s))
+ stdout_subsystem_ctrls(s);
+ }
+ }
+}
+
+static void stdout_subsystem_list(nvme_root_t r, bool show_ana)
+{
+ stdout_subsystem(r, show_ana);
+}
+
+static void stdout_registers_cap(struct nvme_bar_cap *cap)
+{
+ printf("\tController Ready With Media Support (CRWMS): %s\n",
+ cap->crwms ? "Supported" : "Not Supported");
+ printf("\tController Ready Independent of Media Support (CRIMS): %s\n",
+ cap->crims ? "Supported" : "Not Supported");
+ printf("\tNVM Subsystem Shutdown Supported (NSSS): %s\n", cap->nsss ? "Supported" : "Not Supported");
+ printf("\tController Memory Buffer Supported (CMBS): The Controller Memory Buffer is %s\n",
+ cap->cmbs ? "Supported" : "Not Supported");
+ printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n",
+ cap->pmrs ? "Supported" : "Not Supported");
+ printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n", 1 << (12 + cap->mpsmax));
+ printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n", 1 << (12 + cap->mpsmin));
+ printf("\tController Power Scope (CPS): %s\n",
+ !cap->cps ? "Not Reported" : cap->cps == 1 ? "Controller scope" :
+ cap->cps == 2 ? "Domain scope" : "NVM subsystem scope");
+ printf("\tBoot Partition Support (BPS): %s\n", cap->bps ? "Yes" : "No");
+ printf("\tCommand Sets Supported (CSS): NVM command set is %s\n",
+ cap->css & 0x01 ? "Supported" : "Not Supported");
+ printf("\t One or more I/O Command Sets are %s\n",
+ cap->css & 0x40 ? "Supported" : "Not Supported");
+ printf("\t %s\n",
+ cap->css & 0x80 ? "Only Admin Command Set Supported" : "I/O Command Set is Supported");
+ printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n", cap->nssrs ? "Yes" : "No");
+ printf("\tDoorbell Stride (DSTRD): %u bytes\n", 1 << (2 + cap->dstrd));
+ printf("\tTimeout (TO): %u ms\n", cap->to * 500);
+ printf("\tArbitration Mechanism Supported (AMS): Weighted Round Robin with Urgent Priority Class is %s\n",
+ cap->ams & 0x02 ? "Supported" : "Not supported");
+ printf("\tContiguous Queues Required (CQR): %s\n", cap->cqr ? "Yes" : "No");
+ printf("\tMaximum Queue Entries Supported (MQES): %u\n\n", cap->mqes + 1);
+}
+
+static void stdout_registers_version(__u32 vs)
+{
+ printf("\tNVMe specification %d.%d\n\n", (vs & 0xffff0000) >> 16,
+ (vs & 0x0000ff00) >> 8);
+}
+
+static void stdout_registers_cc_ams (__u8 ams)
+{
+ printf("\tArbitration Mechanism Selected (AMS): ");
+ switch (ams) {
+ case 0:
+ printf("Round Robin\n");
+ break;
+ case 1:
+ printf("Weighted Round Robin with Urgent Priority Class\n");
+ break;
+ case 7:
+ printf("Vendor Specific\n");
+ break;
+ default:
+ printf("Reserved\n");
+ break;
+ }
+}
+
+static void stdout_registers_cc_shn (__u8 shn)
+{
+ printf("\tShutdown Notification (SHN): ");
+ switch (shn) {
+ case 0:
+ printf("No notification; no effect\n");
+ break;
+ case 1:
+ printf("Normal shutdown notification\n");
+ break;
+ case 2:
+ printf("Abrupt shutdown notification\n");
+ break;
+ default:
+ printf("Reserved\n");
+ break;
+ }
+}
+
+static void stdout_registers_cc(__u32 cc)
+{
+ printf("\tController Ready Independent of Media Enable (CRIME): %s\n",
+ NVME_CC_CRIME(cc) ? "Enabled" : "Disabled");
+
+ printf("\tI/O Completion Queue Entry Size (IOCQES): %u bytes\n",
+ 1 << ((cc & 0x00f00000) >> NVME_CC_IOCQES_SHIFT));
+ printf("\tI/O Submission Queue Entry Size (IOSQES): %u bytes\n",
+ 1 << ((cc & 0x000f0000) >> NVME_CC_IOSQES_SHIFT));
+ stdout_registers_cc_shn((cc & 0x0000c000) >> NVME_CC_SHN_SHIFT);
+ stdout_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 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");
+}
+
+static void stdout_registers_csts_shst(__u8 shst)
+{
+ printf("\tShutdown Status (SHST): ");
+ switch (shst) {
+ case 0:
+ printf("Normal operation (no shutdown has been requested)\n");
+ break;
+ case 1:
+ printf("Shutdown processing occurring\n");
+ break;
+ case 2:
+ printf("Shutdown processing complete\n");
+ break;
+ default:
+ printf("Reserved\n");
+ break;
+ }
+}
+
+static void stdout_registers_csts(__u32 csts)
+{
+ printf("\tProcessing Paused (PP): %s\n",
+ (csts & 0x00000020) ? "Yes" : "No");
+ printf("\tNVM Subsystem Reset Occurred (NSSRO): %s\n",
+ (csts & 0x00000010) ? "Yes" : "No");
+ stdout_registers_csts_shst((csts & 0x0000000c) >> 2);
+ printf("\tController Fatal Status (CFS): %s\n",
+ (csts & 0x00000002) ? "True" : "False");
+ printf("\tReady (RDY): %s\n\n",
+ (csts & 0x00000001) ? "Yes" : "No");
+
+}
+
+static void stdout_registers_crto(__u32 crto)
+{
+ printf("\tCRIMT : %d secs\n", NVME_CRTO_CRIMT(crto) / 2);
+ printf("\tCRWMT : %d secs\n", NVME_CRTO_CRWMT(crto) / 2);
+}
+
+static void stdout_registers_aqa(__u32 aqa)
+{
+ printf("\tAdmin Completion Queue Size (ACQS): %u\n",
+ ((aqa & 0x0fff0000) >> 16) + 1);
+ printf("\tAdmin Submission Queue Size (ASQS): %u\n\n",
+ (aqa & 0x00000fff) + 1);
+
+}
+
+static void stdout_registers_cmbloc(__u32 cmbloc, __u32 cmbsz)
+{
+ static const char *enforced[] = { "Enforced", "Not Enforced" };
+
+ if (cmbsz == 0) {
+ printf("\tController Memory Buffer feature is not supported\n\n");
+ return;
+ }
+ printf("\tOffset (OFST): 0x%x (See cmbsz.szu for granularity)\n",
+ (cmbloc & 0xfffff000) >> 12);
+
+ printf("\tCMB Queue Dword Alignment (CQDA): %d\n",
+ (cmbloc & 0x00000100) >> 8);
+
+ printf("\tCMB Data Metadata Mixed Memory Support (CDMMMS): %s\n",
+ enforced[(cmbloc & 0x00000080) >> 7]);
+
+ printf("\tCMB Data Pointer and Command Independent Locations Support (CDPCILS): %s\n",
+ enforced[(cmbloc & 0x00000040) >> 6]);
+
+ printf("\tCMB Data Pointer Mixed Locations Support (CDPMLS): %s\n",
+ enforced[(cmbloc & 0x00000020) >> 5]);
+
+ printf("\tCMB Queue Physically Discontiguous Support (CQPDS): %s\n",
+ enforced[(cmbloc & 0x00000010) >> 4]);
+
+ printf("\tCMB Queue Mixed Memory Support (CQMMS): %s\n",
+ enforced[(cmbloc & 0x00000008) >> 3]);
+
+ printf("\tBase Indicator Register (BIR): 0x%x\n\n",
+ (cmbloc & 0x00000007));
+}
+
+static void stdout_registers_cmbsz(__u32 cmbsz)
+{
+ if (cmbsz == 0) {
+ printf("\tController Memory Buffer feature is not supported\n\n");
+ return;
+ }
+ printf("\tSize (SZ): %u\n", (cmbsz & 0xfffff000) >> 12);
+ printf("\tSize Units (SZU): %s\n",
+ nvme_register_szu_to_string((cmbsz & 0x00000f00) >> 8));
+ printf("\tWrite Data Support (WDS): Write Data and metadata transfer in Controller Memory Buffer is %s\n",
+ (cmbsz & 0x00000010) ? "Supported" : "Not supported");
+ printf("\tRead Data Support (RDS): Read Data and metadata transfer in Controller Memory Buffer is %s\n",
+ (cmbsz & 0x00000008) ? "Supported" : "Not supported");
+ printf("\tPRP SGL List Support (LISTS): PRP/SG Lists in Controller Memory Buffer is %s\n",
+ (cmbsz & 0x00000004) ? "Supported" : "Not supported");
+ printf("\tCompletion Queue Support (CQS): Admin and I/O Completion Queues in Controller Memory Buffer is %s\n",
+ (cmbsz & 0x00000002) ? "Supported" : "Not supported");
+ printf("\tSubmission Queue Support (SQS): Admin and I/O Submission Queues in Controller Memory Buffer is %s\n\n",
+ (cmbsz & 0x00000001) ? "Supported" : "Not supported");
+}
+
+static void stdout_registers_bpinfo_brs(__u8 brs)
+{
+ printf("\tBoot Read Status (BRS): ");
+ switch (brs) {
+ case 0:
+ printf("No Boot Partition read operation requested\n");
+ break;
+ case 1:
+ printf("Boot Partition read in progress\n");
+ break;
+ case 2:
+ printf("Boot Partition read completed successfully\n");
+ break;
+ case 3:
+ printf("Error completing Boot Partition read\n");
+ break;
+ default:
+ printf("Invalid\n");
+ break;
+ }
+}
+
+static void stdout_registers_bpinfo(__u32 bpinfo)
+{
+ printf("\tActive Boot Partition ID (ABPID): %u\n",
+ (bpinfo & 0x80000000) >> 31);
+ stdout_registers_bpinfo_brs((bpinfo & 0x03000000) >> 24);
+ printf("\tBoot Partition Size (BPSZ): %u\n",
+ bpinfo & 0x00007fff);
+}
+
+static void stdout_registers_bprsel(__u32 bprsel)
+{
+ printf("\tBoot Partition Identifier (BPID): %u\n",
+ (bprsel & 0x80000000) >> 31);
+ printf("\tBoot Partition Read Offset (BPROF): %x\n",
+ (bprsel & 0x3ffffc00) >> 10);
+ printf("\tBoot Partition Read Size (BPRSZ): %x\n",
+ bprsel & 0x000003ff);
+}
+
+static void stdout_registers_bpmbl(uint64_t bpmbl)
+{
+ printf("\tBoot Partition Memory Buffer Base Address (BMBBA): %"PRIx64"\n",
+ bpmbl);
+}
+
+static void stdout_registers_cmbmsc(uint64_t cmbmsc)
+{
+ 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 "\
+ "CMBSZ registers are%senabled\n\n",
+ (cmbmsc & 0x0000000000000001) ? " " : " NOT ");
+}
+
+static void stdout_registers_cmbsts(__u32 cmbsts)
+{
+ printf("\tController Base Address Invalid (CBAI): %x\n\n",
+ (cmbsts & 0x00000001));
+}
+
+static void stdout_registers_pmrcap(__u32 pmrcap)
+{
+ 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",
+ (pmrcap & 0x00ff0000) >> 16);
+ 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",
+ (pmrcap & 0x00000300) >> 8 ? "minutes" : "500 milliseconds");
+ printf("\tBase Indicator Register (BIR): %x\n",
+ (pmrcap & 0x000000e0) >> 5);
+ 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",
+ (pmrcap & 0x00000008) ? "supported" : "not supported");
+}
+
+static void stdout_registers_pmrctl(__u32 pmrctl)
+{
+ printf("\tEnable (EN): PMR is %s\n", (pmrctl & 0x00000001) ?
+ "READY" : "Disabled");
+}
+
+static void stdout_registers_pmrsts(__u32 pmrsts, __u32 pmrctl)
+{
+ printf("\tController Base Address Invalid (CBAI): %x\n",
+ (pmrsts & 0x00001000) >> 12);
+ printf("\tHealth Status (HSTS): %s\n",
+ nvme_register_pmr_hsts_to_string((pmrsts & 0x00000e00) >> 9));
+ 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));
+}
+
+static void stdout_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 "\
+ "in the PMR Elasticity Buffer %s bypass those memory writes\n",
+ (pmrebs & 0x00000010) ? "SHALL" : "MAY");
+ printf("\tPMR Elasticity Buffer Size Units (PMRSZU): %s\n",
+ nvme_register_pmr_pmrszu_to_string(pmrebs & 0x0000000f));
+}
+
+static void stdout_registers_pmrswtp(__u32 pmrswtp)
+{
+ printf("\tPMR Sustained Write Throughput (PMRSWTV): %x\n",
+ (pmrswtp & 0xffffff00) >> 8);
+ printf("\tPMR Sustained Write Throughput Units (PMRSWTU): %s/second\n",
+ nvme_register_pmr_pmrszu_to_string(pmrswtp & 0x0000000f));
+}
+
+static void stdout_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 stdout_registers_pmrmscu(uint32_t pmrmscu)
+{
+ printf("\tController Base Address (CBA): %#x\n",
+ pmrmscu);
+}
+
+void stdout_ctrl_registers(void *bar, bool fabrics)
+{
+ uint64_t cap, asq, acq, bpmbl, cmbmsc;
+ uint32_t vs, intms, intmc, cc, csts, nssr, crto, aqa, cmbsz, cmbloc, bpinfo,
+ bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp,
+ pmrmscl, pmrmscu;
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ cap = mmio_read64(bar + NVME_REG_CAP);
+ vs = mmio_read32(bar + NVME_REG_VS);
+ intms = mmio_read32(bar + NVME_REG_INTMS);
+ intmc = mmio_read32(bar + NVME_REG_INTMC);
+ cc = mmio_read32(bar + NVME_REG_CC);
+ csts = mmio_read32(bar + NVME_REG_CSTS);
+ nssr = mmio_read32(bar + NVME_REG_NSSR);
+ crto = mmio_read32(bar + NVME_REG_CRTO);
+ aqa = mmio_read32(bar + NVME_REG_AQA);
+ asq = mmio_read64(bar + NVME_REG_ASQ);
+ acq = mmio_read64(bar + NVME_REG_ACQ);
+ cmbloc = mmio_read32(bar + NVME_REG_CMBLOC);
+ cmbsz = mmio_read32(bar + NVME_REG_CMBSZ);
+ bpinfo = mmio_read32(bar + NVME_REG_BPINFO);
+ bprsel = mmio_read32(bar + NVME_REG_BPRSEL);
+ bpmbl = mmio_read64(bar + NVME_REG_BPMBL);
+ cmbmsc = mmio_read64(bar + NVME_REG_CMBMSC);
+ cmbsts = mmio_read32(bar + NVME_REG_CMBSTS);
+ pmrcap = mmio_read32(bar + NVME_REG_PMRCAP);
+ pmrctl = mmio_read32(bar + NVME_REG_PMRCTL);
+ pmrsts = mmio_read32(bar + NVME_REG_PMRSTS);
+ pmrebs = mmio_read32(bar + NVME_REG_PMREBS);
+ pmrswtp = mmio_read32(bar + NVME_REG_PMRSWTP);
+ pmrmscl = mmio_read32(bar + NVME_REG_PMRMSCL);
+ pmrmscu = mmio_read32(bar + NVME_REG_PMRMSCU);
+
+ if (human) {
+ if (cap != 0xffffffff) {
+ printf("cap : %"PRIx64"\n", cap);
+ stdout_registers_cap((struct nvme_bar_cap *)&cap);
+ }
+ if (vs != 0xffffffff) {
+ printf("version : %x\n", vs);
+ stdout_registers_version(vs);
+ }
+ if (cc != 0xffffffff) {
+ printf("cc : %x\n", cc);
+ stdout_registers_cc(cc);
+ }
+ if (csts != 0xffffffff) {
+ printf("csts : %x\n", csts);
+ stdout_registers_csts(csts);
+ }
+ if (nssr != 0xffffffff) {
+ printf("nssr : %x\n", nssr);
+ printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n",
+ nssr);
+ }
+ if (crto != 0xffffffff) {
+ printf("crto : %x\n", crto);
+ stdout_registers_crto(crto);
+ }
+ if (!fabrics) {
+ printf("intms : %x\n", intms);
+ printf("\tInterrupt Vector Mask Set (IVMS): %x\n\n",
+ intms);
+
+ printf("intmc : %x\n", intmc);
+ printf("\tInterrupt Vector Mask Clear (IVMC): %x\n\n",
+ intmc);
+ printf("aqa : %x\n", aqa);
+ stdout_registers_aqa(aqa);
+
+ printf("asq : %"PRIx64"\n", asq);
+ printf("\tAdmin Submission Queue Base (ASQB): %"PRIx64"\n\n",
+ asq);
+
+ printf("acq : %"PRIx64"\n", acq);
+ printf("\tAdmin Completion Queue Base (ACQB): %"PRIx64"\n\n",
+ acq);
+
+ printf("cmbloc : %x\n", cmbloc);
+ stdout_registers_cmbloc(cmbloc, cmbsz);
+
+ printf("cmbsz : %x\n", cmbsz);
+ stdout_registers_cmbsz(cmbsz);
+
+ printf("bpinfo : %x\n", bpinfo);
+ stdout_registers_bpinfo(bpinfo);
+
+ printf("bprsel : %x\n", bprsel);
+ stdout_registers_bprsel(bprsel);
+
+ printf("bpmbl : %"PRIx64"\n", bpmbl);
+ stdout_registers_bpmbl(bpmbl);
+
+ printf("cmbmsc : %"PRIx64"\n", cmbmsc);
+ stdout_registers_cmbmsc(cmbmsc);
+
+ printf("cmbsts : %x\n", cmbsts);
+ stdout_registers_cmbsts(cmbsts);
+
+ printf("pmrcap : %x\n", pmrcap);
+ stdout_registers_pmrcap(pmrcap);
+
+ printf("pmrctl : %x\n", pmrctl);
+ stdout_registers_pmrctl(pmrctl);
+
+ printf("pmrsts : %x\n", pmrsts);
+ stdout_registers_pmrsts(pmrsts, pmrctl);
+
+ printf("pmrebs : %x\n", pmrebs);
+ stdout_registers_pmrebs(pmrebs);
+
+ printf("pmrswtp : %x\n", pmrswtp);
+ stdout_registers_pmrswtp(pmrswtp);
+
+ printf("pmrmscl : %#x\n", pmrmscl);
+ stdout_registers_pmrmscl(pmrmscl);
+
+ printf("pmrmscu : %#x\n", pmrmscu);
+ stdout_registers_pmrmscu(pmrmscu);
+ }
+ } else {
+ if (cap != 0xffffffff)
+ printf("cap : %"PRIx64"\n", cap);
+ if (vs != 0xffffffff)
+ printf("version : %x\n", vs);
+ if (cc != 0xffffffff)
+ printf("cc : %x\n", cc);
+ if (csts != 0xffffffff)
+ printf("csts : %x\n", csts);
+ if (nssr != 0xffffffff)
+ printf("nssr : %x\n", nssr);
+ if (crto != 0xffffffff)
+ printf("crto : %x\n", crto);
+ if (!fabrics) {
+ printf("intms : %x\n", intms);
+ printf("intmc : %x\n", intmc);
+ printf("aqa : %x\n", aqa);
+ printf("asq : %"PRIx64"\n", asq);
+ printf("acq : %"PRIx64"\n", acq);
+ printf("cmbloc : %x\n", cmbloc);
+ printf("cmbsz : %x\n", cmbsz);
+ printf("bpinfo : %x\n", bpinfo);
+ printf("bprsel : %x\n", bprsel);
+ printf("bpmbl : %"PRIx64"\n", bpmbl);
+ printf("cmbmsc : %"PRIx64"\n", cmbmsc);
+ printf("cmbsts : %x\n", cmbsts);
+ printf("pmrcap : %x\n", pmrcap);
+ printf("pmrctl : %x\n", pmrctl);
+ printf("pmrsts : %x\n", pmrsts);
+ printf("pmrebs : %x\n", pmrebs);
+ printf("pmrswtp : %x\n", pmrswtp);
+ printf("pmrmscl : %#x\n", pmrmscl);
+ printf("pmrmscu : %#x\n", pmrmscu);
+ }
+ }
+}
+
+static void stdout_single_property(int offset, uint64_t value64)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+ uint32_t value32 = (uint32_t)value64;
+
+ if (!human) {
+ if (nvme_is_64bit_reg(offset))
+ printf("property: 0x%02x (%s), value: %"PRIx64"\n",
+ offset, nvme_register_to_string(offset), value64);
+ else
+ printf("property: 0x%02x (%s), value: %x\n", offset,
+ nvme_register_to_string(offset), value32);
+ return;
+ }
+
+ switch (offset) {
+ case NVME_REG_CAP:
+ printf("cap : %"PRIx64"\n", value64);
+ stdout_registers_cap((struct nvme_bar_cap *)&value64);
+ break;
+ case NVME_REG_VS:
+ printf("version : %x\n", value32);
+ stdout_registers_version(value32);
+ break;
+ case NVME_REG_CC:
+ printf("cc : %x\n", value32);
+ stdout_registers_cc(value32);
+ break;
+ case NVME_REG_CSTS:
+ printf("csts : %x\n", value32);
+ stdout_registers_csts(value32);
+ break;
+ case NVME_REG_NSSR:
+ printf("nssr : %x\n", value32);
+ printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n", value32);
+ break;
+ case NVME_REG_CRTO:
+ printf("crto : %x\n", value32);
+ stdout_registers_crto(value32);
+ break;
+ default:
+ printf("unknown property: 0x%02x (%s), value: %"PRIx64"\n",
+ offset, nvme_register_to_string(offset), value64);
+ break;
+ }
+}
+
+static void stdout_status(int status)
+{
+ int val;
+ int type;
+
+ /*
+ * Callers should be checking for negative values first, but provide a
+ * sensible fallback anyway
+ */
+ if (status < 0) {
+ fprintf(stderr, "Error: %s\n", nvme_strerror(errno));
+ return;
+ }
+
+ val = nvme_status_get_value(status);
+ type = nvme_status_get_type(status);
+
+ switch (type) {
+ case NVME_STATUS_TYPE_NVME:
+ fprintf(stderr, "NVMe status: %s(%#x)\n",
+ nvme_status_to_string(val, false), val);
+ break;
+ case NVME_STATUS_TYPE_MI:
+ fprintf(stderr, "NVMe-MI status: %s(%#x)\n",
+ nvme_mi_status_to_string(val), val);
+ break;
+ default:
+ fprintf(stderr, "Unknown status type %d, value %#x\n", type,
+ val);
+ break;
+ }
+}
+
+static void stdout_error_status(int status, const char *msg, va_list ap)
+{
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, ": ");
+ stdout_status(status);
+}
+
+static void stdout_id_ctrl_cmic(__u8 cmic)
+{
+ __u8 rsvd = (cmic & 0xF0) >> 4;
+ __u8 ana = (cmic & 0x8) >> 3;
+ __u8 sriov = (cmic & 0x4) >> 2;
+ __u8 mctl = (cmic & 0x2) >> 1;
+ __u8 mp = cmic & 0x1;
+
+ if (rsvd)
+ printf(" [7:4] : %#x\tReserved\n", rsvd);
+ printf(" [3:3] : %#x\tANA %ssupported\n", ana, ana ? "" : "not ");
+ printf(" [2:2] : %#x\t%s\n", sriov, sriov ? "SR-IOV" : "PCI");
+ printf(" [1:1] : %#x\t%s Controller\n",
+ mctl, mctl ? "Multi" : "Single");
+ printf(" [0:0] : %#x\t%s Port\n", mp, mp ? "Multi" : "Single");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_oaes(__le32 ctrl_oaes)
+{
+ __u32 oaes = le32_to_cpu(ctrl_oaes);
+ __u32 disc = (oaes >> 31) & 0x1;
+ __u32 rsvd0 = (oaes & 0x70000000) >> 28;
+ __u32 zicn = (oaes & 0x08000000) >> 27;
+ __u32 rsvd1 = (oaes & 0x07FF0000) >> 16;
+ __u32 normal_shn = (oaes >> 15) & 0x1;
+ __u32 egealpcn = (oaes & 0x4000) >> 14;
+ __u32 lbasin = (oaes & 0x2000) >> 13;
+ __u32 plealcn = (oaes & 0x1000) >> 12;
+ __u32 anacn = (oaes & 0x800) >> 11;
+ __u32 rsvd2 = (oaes >> 10) & 0x1;
+ __u32 fan = (oaes & 0x200) >> 9;
+ __u32 nace = (oaes & 0x100) >> 8;
+ __u32 rsvd3 = oaes & 0xFF;
+
+ printf(" [31:31] : %#x\tDiscovery Log Change Notice %sSupported\n",
+ disc, disc ? "" : "Not ");
+ if (rsvd0)
+ printf(" [30:28] : %#x\tReserved\n", rsvd0);
+ printf(" [27:27] : %#x\tZone Descriptor Changed Notices %sSupported\n",
+ zicn, zicn ? "" : "Not ");
+ if (rsvd1)
+ printf(" [26:16] : %#x\tReserved\n", rsvd1);
+ printf(" [15:15] : %#x\tNormal NSS Shutdown Event %sSupported\n",
+ normal_shn, normal_shn ? "" : "Not ");
+ printf(" [14:14] : %#x\tEndurance Group Event Aggregate Log Page"\
+ " Change Notice %sSupported\n",
+ egealpcn, egealpcn ? "" : "Not ");
+ printf(" [13:13] : %#x\tLBA Status Information Notices %sSupported\n",
+ lbasin, lbasin ? "" : "Not ");
+ printf(" [12:12] : %#x\tPredictable Latency Event Aggregate Log Change"\
+ " Notices %sSupported\n",
+ plealcn, plealcn ? "" : "Not ");
+ printf(" [11:11] : %#x\tAsymmetric Namespace Access Change Notices"\
+ " %sSupported\n", anacn, anacn ? "" : "Not ");
+ if (rsvd2)
+ printf(" [10:10] : %#x\tReserved\n", rsvd2);
+ printf(" [9:9] : %#x\tFirmware Activation Notices %sSupported\n",
+ fan, fan ? "" : "Not ");
+ printf(" [8:8] : %#x\tNamespace Attribute Changed Event %sSupported\n",
+ nace, nace ? "" : "Not ");
+ if (rsvd3)
+ printf(" [7:0] : %#x\tReserved\n", rsvd3);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_ctratt(__le32 ctrl_ctratt)
+{
+ __u32 ctratt = le32_to_cpu(ctrl_ctratt);
+ __u32 rsvd20 = (ctratt >> 20);
+ __u32 fdps = (ctratt >> 19) & 0x1;
+ __u32 rsvd16 = (ctratt >> 16) & 0x7;
+ __u32 elbas = (ctratt >> 15) & 0x1;
+ __u32 delnvmset = (ctratt >> 14) & 0x1;
+ __u32 delegrp = (ctratt >> 13) & 0x1;
+ __u32 vcap = (ctratt >> 12) & 0x1;
+ __u32 fcap = (ctratt >> 11) & 0x1;
+ __u32 mds = (ctratt >> 10) & 0x1;
+ __u32 hostid128 = (ctratt & NVME_CTRL_CTRATT_128_ID) >> 0;
+ __u32 psp = (ctratt & NVME_CTRL_CTRATT_NON_OP_PSP) >> 1;
+ __u32 sets = (ctratt & NVME_CTRL_CTRATT_NVM_SETS) >> 2;
+ __u32 rrl = (ctratt & NVME_CTRL_CTRATT_READ_RECV_LVLS) >> 3;
+ __u32 eg = (ctratt & NVME_CTRL_CTRATT_ENDURANCE_GROUPS) >> 4;
+ __u32 iod = (ctratt & NVME_CTRL_CTRATT_PREDICTABLE_LAT) >> 5;
+ __u32 tbkas = (ctratt & NVME_CTRL_CTRATT_TBKAS) >> 6;
+ __u32 ng = (ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) >> 7;
+ __u32 sqa = (ctratt & NVME_CTRL_CTRATT_SQ_ASSOCIATIONS) >> 8;
+ __u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9;
+
+ if (rsvd20)
+ printf(" [31:20] : %#x\tReserved\n", rsvd20);
+ printf(" [19:19] : %#x\tFlexible Data Placement %sSupported\n",
+ fdps, fdps ? "" : "Not ");
+ if (rsvd16)
+ printf(" [18:16] : %#x\tReserved\n", rsvd16);
+ printf(" [15:15] : %#x\tExtended LBA Formats %sSupported\n",
+ elbas, elbas ? "" : "Not ");
+ printf(" [14:14] : %#x\tDelete NVM Set %sSupported\n",
+ delnvmset, delnvmset ? "" : "Not ");
+ printf(" [13:13] : %#x\tDelete Endurance Group %sSupported\n",
+ delegrp, delegrp ? "" : "Not ");
+ printf(" [12:12] : %#x\tVariable Capacity Management %sSupported\n",
+ vcap, vcap ? "" : "Not ");
+ printf(" [11:11] : %#x\tFixed Capacity Management %sSupported\n",
+ fcap, fcap ? "" : "Not ");
+ printf(" [10:10] : %#x\tMulti Domain Subsystem %sSupported\n",
+ mds, mds ? "" : "Not ");
+ printf(" [9:9] : %#x\tUUID List %sSupported\n",
+ uuidlist, uuidlist ? "" : "Not ");
+ printf(" [8:8] : %#x\tSQ Associations %sSupported\n",
+ sqa, sqa ? "" : "Not ");
+ printf(" [7:7] : %#x\tNamespace Granularity %sSupported\n",
+ ng, ng ? "" : "Not ");
+ printf(" [6:6] : %#x\tTraffic Based Keep Alive %sSupported\n",
+ tbkas, tbkas ? "" : "Not ");
+ printf(" [5:5] : %#x\tPredictable Latency Mode %sSupported\n",
+ iod, iod ? "" : "Not ");
+ printf(" [4:4] : %#x\tEndurance Groups %sSupported\n",
+ eg, eg ? "" : "Not ");
+ printf(" [3:3] : %#x\tRead Recovery Levels %sSupported\n",
+ rrl, rrl ? "" : "Not ");
+ printf(" [2:2] : %#x\tNVM Sets %sSupported\n",
+ sets, sets ? "" : "Not ");
+ printf(" [1:1] : %#x\tNon-Operational Power State Permissive %sSupported\n",
+ psp, psp ? "" : "Not ");
+ printf(" [0:0] : %#x\t128-bit Host Identifier %sSupported\n",
+ hostid128, hostid128 ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_cntrltype(__u8 cntrltype)
+{
+ __u8 rsvd = (cntrltype & 0xFC) >> 2;
+ __u8 cntrl = cntrltype & 0x3;
+
+ static const char *type[] = {
+ "Controller type not reported",
+ "I/O Controller",
+ "Discovery Controller",
+ "Administrative Controller"
+ };
+
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:0] : %#x\t%s\n", cntrltype, type[cntrl]);
+}
+
+static void stdout_id_ctrl_nvmsr(__u8 nvmsr)
+{
+ __u8 rsvd = (nvmsr >> 2) & 0xfc;
+ __u8 nvmee = (nvmsr >> 1) & 0x1;
+ __u8 nvmesd = nvmsr & 0x1;
+
+ if (rsvd)
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] : %#x\tNVM subsystem %spart of an Enclosure\n",
+ nvmee, nvmee ? "" : "Not ");
+ printf(" [0:0] : %#x\tNVM subsystem %spart of a Storage Device\n",
+ nvmesd, nvmesd ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_vwci(__u8 vwci)
+{
+ __u8 vwcrv = (vwci >> 7) & 0x1;
+ __u8 vwcr = vwci & 0xfe;
+
+ printf(" [7:7] : %#x\tVPD Write Cycles Remaining field is %svalid.\n",
+ vwcrv, vwcrv ? "" : "Not ");
+ printf(" [6:0] : %#x\tVPD Write Cycles Remaining \n", vwcr);
+ printf("\n");
+
+}
+
+static void stdout_id_ctrl_mec(__u8 mec)
+{
+ __u8 rsvd = (mec >> 2) & 0xfc;
+ __u8 pcieme = (mec >> 1) & 0x1;
+ __u8 smbusme = mec & 0x1;
+
+ if (rsvd)
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] : %#x\tNVM subsystem %scontains a Management Endpoint"\
+ " on a PCIe port\n", pcieme, pcieme ? "" : "Not ");
+ printf(" [0:0] : %#x\tNVM subsystem %scontains a Management Endpoint"\
+ " on an SMBus/I2C port\n", smbusme, smbusme ? "" : "Not ");
+ printf("\n");
+
+}
+
+static void stdout_id_ctrl_oacs(__le16 ctrl_oacs)
+{
+ __u16 oacs = le16_to_cpu(ctrl_oacs);
+ __u16 rsvd = (oacs & 0xF800) >> 11;
+ __u16 lock = (oacs >> 10) & 0x1;
+ __u16 glbas = (oacs & 0x200) >> 9;
+ __u16 dbc = (oacs & 0x100) >> 8;
+ __u16 vir = (oacs & 0x80) >> 7;
+ __u16 nmi = (oacs & 0x40) >> 6;
+ __u16 dir = (oacs & 0x20) >> 5;
+ __u16 sft = (oacs & 0x10) >> 4;
+ __u16 nsm = (oacs & 0x8) >> 3;
+ __u16 fwc = (oacs & 0x4) >> 2;
+ __u16 fmt = (oacs & 0x2) >> 1;
+ __u16 sec = oacs & 0x1;
+
+ if (rsvd)
+ printf(" [15:11] : %#x\tReserved\n", rsvd);
+ printf(" [10:10] : %#x\tLockdown Command and Feature %sSupported\n",
+ lock, lock ? "" : "Not ");
+ printf(" [9:9] : %#x\tGet LBA Status Capability %sSupported\n",
+ glbas, glbas ? "" : "Not ");
+ printf(" [8:8] : %#x\tDoorbell Buffer Config %sSupported\n",
+ dbc, dbc ? "" : "Not ");
+ printf(" [7:7] : %#x\tVirtualization Management %sSupported\n",
+ vir, vir ? "" : "Not ");
+ printf(" [6:6] : %#x\tNVMe-MI Send and Receive %sSupported\n",
+ nmi, nmi ? "" : "Not ");
+ printf(" [5:5] : %#x\tDirectives %sSupported\n",
+ dir, dir ? "" : "Not ");
+ printf(" [4:4] : %#x\tDevice Self-test %sSupported\n",
+ sft, sft ? "" : "Not ");
+ printf(" [3:3] : %#x\tNS Management and Attachment %sSupported\n",
+ nsm, nsm ? "" : "Not ");
+ printf(" [2:2] : %#x\tFW Commit and Download %sSupported\n",
+ fwc, fwc ? "" : "Not ");
+ printf(" [1:1] : %#x\tFormat NVM %sSupported\n",
+ fmt, fmt ? "" : "Not ");
+ printf(" [0:0] : %#x\tSecurity Send and Receive %sSupported\n",
+ sec, sec ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_frmw(__u8 frmw)
+{
+ __u8 rsvd = (frmw & 0xC0) >> 6;
+ __u8 smud = (frmw >> 5) & 0x1;
+ __u8 fawr = (frmw & 0x10) >> 4;
+ __u8 nfws = (frmw & 0xE) >> 1;
+ __u8 s1ro = frmw & 0x1;
+
+ if (rsvd)
+ printf(" [7:6] : %#x\tReserved\n", rsvd);
+ printf(" [5:5] : %#x\tMultiple FW or Boot Update Detection %sSupported\n",
+ smud, smud ? "" : "Not ");
+ printf(" [4:4] : %#x\tFirmware Activate Without Reset %sSupported\n",
+ fawr, fawr ? "" : "Not ");
+ printf(" [3:1] : %#x\tNumber of Firmware Slots\n", nfws);
+ printf(" [0:0] : %#x\tFirmware Slot 1 Read%s\n",
+ s1ro, s1ro ? "-Only" : "/Write");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_lpa(__u8 lpa)
+{
+ __u8 rsvd = (lpa & 0x80) >> 7;
+ __u8 tel = (lpa >> 6) & 0x1;
+ __u8 lid_sup = (lpa >> 5) & 0x1;
+ __u8 persevnt = (lpa & 0x10) >> 4;
+ __u8 telem = (lpa & 0x8) >> 3;
+ __u8 ed = (lpa & 0x4) >> 2;
+ __u8 celp = (lpa & 0x2) >> 1;
+ __u8 smlp = lpa & 0x1;
+
+ if (rsvd)
+ printf(" [7:7] : %#x\tReserved\n", rsvd);
+ printf(" [6:6] : %#x\tTelemetry Log Data Area 4 %sSupported\n",
+ tel, tel ? "" : "Not ");
+ printf(" [5:5] : %#x\tLID 0x0, Scope of each command in LID 0x5, "\
+ "0x12, 0x13 %sSupported\n", lid_sup, lid_sup ? "" : "Not ");
+ printf(" [4:4] : %#x\tPersistent Event log %sSupported\n",
+ persevnt, persevnt ? "" : "Not ");
+ printf(" [3:3] : %#x\tTelemetry host/controller initiated log page %sSupported\n",
+ telem, telem ? "" : "Not ");
+ printf(" [2:2] : %#x\tExtended data for Get Log Page %sSupported\n",
+ ed, ed ? "" : "Not ");
+ printf(" [1:1] : %#x\tCommand Effects Log Page %sSupported\n",
+ celp, celp ? "" : "Not ");
+ printf(" [0:0] : %#x\tSMART/Health Log Page per NS %sSupported\n",
+ smlp, smlp ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_elpe(__u8 elpe)
+{
+ printf(" [7:0] : %d (0's based)\tError Log Page Entries (ELPE)\n",
+ elpe);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_npss(__u8 npss)
+{
+ printf(" [7:0] : %d (0's based)\tNumber of Power States Support (NPSS)\n",
+ npss);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_avscc(__u8 avscc)
+{
+ __u8 rsvd = (avscc & 0xFE) >> 1;
+ __u8 fmt = avscc & 0x1;
+ if (rsvd)
+ printf(" [7:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tAdmin Vendor Specific Commands uses %s Format\n",
+ fmt, fmt ? "NVMe" : "Vendor Specific");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_apsta(__u8 apsta)
+{
+ __u8 rsvd = (apsta & 0xFE) >> 1;
+ __u8 apst = apsta & 0x1;
+ if (rsvd)
+ printf(" [7:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tAutonomous Power State Transitions %sSupported\n",
+ apst, apst ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_wctemp(__le16 wctemp)
+{
+ printf(" [15:0] : %ld °C (%u K)\tWarning Composite Temperature Threshold (WCTEMP)\n",
+ kelvin_to_celsius(le16_to_cpu(wctemp)), le16_to_cpu(wctemp));
+ printf("\n");
+}
+
+static void stdout_id_ctrl_cctemp(__le16 cctemp)
+{
+ printf(" [15:0] : %ld °C (%u K)\tCritical Composite Temperature Threshold (CCTEMP)\n",
+ kelvin_to_celsius(le16_to_cpu(cctemp)), le16_to_cpu(cctemp));
+ printf("\n");
+}
+
+static void stdout_id_ctrl_tnvmcap(__u8 *tnvmcap)
+{
+ printf("[127:0] : %s\n", uint128_t_to_l10n_string(le128_to_cpu(tnvmcap)));
+ printf("\tTotal NVM Capacity (TNVMCAP)\n\n");
+}
+
+static void stdout_id_ctrl_unvmcap(__u8 *unvmcap)
+{
+ printf("[127:0] : %s\n", uint128_t_to_l10n_string(le128_to_cpu(unvmcap)));
+ printf("\tUnallocated NVM Capacity (UNVMCAP)\n\n");
+}
+
+void stdout_id_ctrl_rpmbs(__le32 ctrl_rpmbs)
+{
+ __u32 rpmbs = le32_to_cpu(ctrl_rpmbs);
+ __u32 asz = (rpmbs & 0xFF000000) >> 24;
+ __u32 tsz = (rpmbs & 0xFF0000) >> 16;
+ __u32 rsvd = (rpmbs & 0xFFC0) >> 6;
+ __u32 auth = (rpmbs & 0x38) >> 3;
+ __u32 rpmb = rpmbs & 0x7;
+
+ printf(" [31:24]: %#x\tAccess Size\n", asz);
+ printf(" [23:16]: %#x\tTotal Size\n", tsz);
+ if (rsvd)
+ printf(" [15:6] : %#x\tReserved\n", rsvd);
+ printf(" [5:3] : %#x\tAuthentication Method\n", auth);
+ printf(" [2:0] : %#x\tNumber of RPMB Units\n", rpmb);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_hctma(__le16 ctrl_hctma)
+{
+ __u16 hctma = le16_to_cpu(ctrl_hctma);
+ __u16 rsvd = (hctma & 0xFFFE) >> 1;
+ __u16 hctm = hctma & 0x1;
+
+ if (rsvd)
+ printf(" [15:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tHost Controlled Thermal Management %sSupported\n",
+ hctm, hctm ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_mntmt(__le16 mntmt)
+{
+ printf(" [15:0] : %ld °C (%u K)\tMinimum Thermal Management Temperature (MNTMT)\n",
+ kelvin_to_celsius(le16_to_cpu(mntmt)), le16_to_cpu(mntmt));
+ printf("\n");
+}
+
+static void stdout_id_ctrl_mxtmt(__le16 mxtmt)
+{
+ printf(" [15:0] : %ld °C (%u K)\tMaximum Thermal Management Temperature (MXTMT)\n",
+ kelvin_to_celsius(le16_to_cpu(mxtmt)), le16_to_cpu(mxtmt));
+ printf("\n");
+}
+
+static void stdout_id_ctrl_sanicap(__le32 ctrl_sanicap)
+{
+ __u32 sanicap = le32_to_cpu(ctrl_sanicap);
+ __u32 rsvd = (sanicap & 0x1FFFFFF8) >> 3;
+ __u32 owr = (sanicap & 0x4) >> 2;
+ __u32 ber = (sanicap & 0x2) >> 1;
+ __u32 cer = sanicap & 0x1;
+ __u32 ndi = (sanicap & 0x20000000) >> 29;
+ __u32 nodmmas = (sanicap & 0xC0000000) >> 30;
+
+ static const char *modifies_media[] = {
+ "Additional media modification after sanitize operation completes successfully is not defined",
+ "Media is not additionally modified after sanitize operation completes successfully",
+ "Media is additionally modified after sanitize operation completes successfully",
+ "Reserved"
+ };
+
+ printf(" [31:30] : %#x\t%s\n", nodmmas, modifies_media[nodmmas]);
+ printf(" [29:29] : %#x\tNo-Deallocate After Sanitize bit in Sanitize command %sSupported\n",
+ ndi, ndi ? "Not " : "");
+ if (rsvd)
+ printf(" [28:3] : %#x\tReserved\n", rsvd);
+ printf(" [2:2] : %#x\tOverwrite Sanitize Operation %sSupported\n",
+ owr, owr ? "" : "Not ");
+ printf(" [1:1] : %#x\tBlock Erase Sanitize Operation %sSupported\n",
+ ber, ber ? "" : "Not ");
+ printf(" [0:0] : %#x\tCrypto Erase Sanitize Operation %sSupported\n",
+ cer, cer ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_anacap(__u8 anacap)
+{
+ __u8 nz = (anacap & 0x80) >> 7;
+ __u8 grpid_static = (anacap & 0x40) >> 6;
+ __u8 rsvd = (anacap & 0x20) >> 5;
+ __u8 ana_change = (anacap & 0x10) >> 4;
+ __u8 ana_persist_loss = (anacap & 0x08) >> 3;
+ __u8 ana_inaccessible = (anacap & 0x04) >> 2;
+ __u8 ana_nonopt = (anacap & 0x02) >> 1;
+ __u8 ana_opt = (anacap & 0x01);
+
+ printf(" [7:7] : %#x\tNon-zero group ID %sSupported\n",
+ nz, nz ? "" : "Not ");
+ printf(" [6:6] : %#x\tGroup ID does %schange\n",
+ grpid_static, grpid_static ? "not " : "");
+ if (rsvd)
+ printf(" [5:5] : %#x\tReserved\n", rsvd);
+ printf(" [4:4] : %#x\tANA Change state %sSupported\n",
+ ana_change, ana_change ? "" : "Not ");
+ printf(" [3:3] : %#x\tANA Persistent Loss state %sSupported\n",
+ ana_persist_loss, ana_persist_loss ? "" : "Not ");
+ printf(" [2:2] : %#x\tANA Inaccessible state %sSupported\n",
+ ana_inaccessible, ana_inaccessible ? "" : "Not ");
+ printf(" [1:1] : %#x\tANA Non-optimized state %sSupported\n",
+ ana_nonopt, ana_nonopt ? "" : "Not ");
+ printf(" [0:0] : %#x\tANA Optimized state %sSupported\n",
+ ana_opt, ana_opt ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_sqes(__u8 sqes)
+{
+ __u8 msqes = (sqes & 0xF0) >> 4;
+ __u8 rsqes = sqes & 0xF;
+ printf(" [7:4] : %#x\tMax SQ Entry Size (%d)\n", msqes, 1 << msqes);
+ printf(" [3:0] : %#x\tMin SQ Entry Size (%d)\n", rsqes, 1 << rsqes);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_cqes(__u8 cqes)
+{
+ __u8 mcqes = (cqes & 0xF0) >> 4;
+ __u8 rcqes = cqes & 0xF;
+ printf(" [7:4] : %#x\tMax CQ Entry Size (%d)\n", mcqes, 1 << mcqes);
+ printf(" [3:0] : %#x\tMin CQ Entry Size (%d)\n", rcqes, 1 << rcqes);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_oncs(__le16 ctrl_oncs)
+{
+ __u16 oncs = le16_to_cpu(ctrl_oncs);
+ __u16 rsvd = oncs >> 11;
+ bool afc = !!(oncs & NVME_CTRL_ONCS_ALL_FAST_COPY);
+ bool csa = !!(oncs & NVME_CTRL_ONCS_COPY_SINGLE_ATOMICITY);
+ bool copy = !!(oncs & NVME_CTRL_ONCS_COPY);
+ bool vrfy = !!(oncs & NVME_CTRL_ONCS_VERIFY);
+ bool tmst = !!(oncs & NVME_CTRL_ONCS_TIMESTAMP);
+ bool resv = !!(oncs & NVME_CTRL_ONCS_RESERVATIONS);
+ bool save = !!(oncs & NVME_CTRL_ONCS_SAVE_FEATURES);
+ bool wzro = !!(oncs & NVME_CTRL_ONCS_WRITE_ZEROES);
+ bool dsms = !!(oncs & NVME_CTRL_ONCS_DSM);
+ bool wunc = !!(oncs & NVME_CTRL_ONCS_WRITE_UNCORRECTABLE);
+ bool cmp = !!(oncs & NVME_CTRL_ONCS_COMPARE);
+
+ if (rsvd)
+ printf(" [15:11] : %#x\tReserved\n", rsvd);
+ printf(" [10:10] : %#x\tAll Fast Copy %sSupported\n",
+ afc, afc ? "" : "Not ");
+ printf(" [9:9] : %#x\tCopy Single Atomicity %sSupported\n",
+ csa, csa ? "" : "Not ");
+ 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",
+ tmst, tmst ? "" : "Not ");
+ printf(" [5:5] : %#x\tReservations %sSupported\n",
+ resv, resv ? "" : "Not ");
+ printf(" [4:4] : %#x\tSave and Select %sSupported\n",
+ save, save ? "" : "Not ");
+ printf(" [3:3] : %#x\tWrite Zeroes %sSupported\n",
+ wzro, wzro ? "" : "Not ");
+ printf(" [2:2] : %#x\tData Set Management %sSupported\n",
+ dsms, dsms ? "" : "Not ");
+ printf(" [1:1] : %#x\tWrite Uncorrectable %sSupported\n",
+ wunc, wunc ? "" : "Not ");
+ printf(" [0:0] : %#x\tCompare %sSupported\n",
+ cmp, cmp ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_fuses(__le16 ctrl_fuses)
+{
+ __u16 fuses = le16_to_cpu(ctrl_fuses);
+ __u16 rsvd = (fuses & 0xFE) >> 1;
+ __u16 cmpw = fuses & 0x1;
+
+ if (rsvd)
+ printf(" [15:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tFused Compare and Write %sSupported\n",
+ cmpw, cmpw ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_fna(__u8 fna)
+{
+ __u8 rsvd = (fna & 0xF0) >> 4;
+ __u8 bcnsid = (fna & 0x8) >> 3;
+ __u8 cese = (fna & 0x4) >> 2;
+ __u8 cens = (fna & 0x2) >> 1;
+ __u8 fmns = fna & 0x1;
+ if (rsvd)
+ printf(" [7:4] : %#x\tReserved\n", rsvd);
+ printf(" [3:3] : %#x\tFormat NVM Broadcast NSID (FFFFFFFFh) %sSupported\n",
+ bcnsid, bcnsid ? "Not " : "");
+ printf(" [2:2] : %#x\tCrypto Erase %sSupported as part of Secure Erase\n",
+ cese, cese ? "" : "Not ");
+ printf(" [1:1] : %#x\tCrypto Erase Applies to %s Namespace(s)\n",
+ cens, cens ? "All" : "Single");
+ printf(" [0:0] : %#x\tFormat Applies to %s Namespace(s)\n",
+ fmns, fmns ? "All" : "Single");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_vwc(__u8 vwc)
+{
+ __u8 rsvd = (vwc & 0xF8) >> 3;
+ __u8 flush = (vwc & 0x6) >> 1;
+ __u8 vwcp = vwc & 0x1;
+
+ static const char *flush_behavior[] = {
+ "Support for the NSID field set to FFFFFFFFh is not indicated",
+ "Reserved",
+ "The Flush command does not support NSID set to FFFFFFFFh",
+ "The Flush command supports NSID set to FFFFFFFFh"
+ };
+
+ if (rsvd)
+ printf(" [7:3] : %#x\tReserved\n", rsvd);
+ printf(" [2:1] : %#x\t%s\n", flush, flush_behavior[flush]);
+ printf(" [0:0] : %#x\tVolatile Write Cache %sPresent\n",
+ vwcp, vwcp ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_icsvscc(__u8 icsvscc)
+{
+ __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",
+ fmt, fmt ? "NVMe" : "Vendor Specific");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_nwpc(__u8 nwpc)
+{
+ __u8 no_wp_wp = (nwpc & 0x01);
+ __u8 wp_power_cycle = (nwpc & 0x02) >> 1;
+ __u8 wp_permanent = (nwpc & 0x04) >> 2;
+ __u8 rsvd = (nwpc & 0xF8) >> 3;
+
+ if (rsvd)
+ printf(" [7:3] : %#x\tReserved\n", rsvd);
+
+ printf(" [2:2] : %#x\tPermanent Write Protect %sSupported\n",
+ wp_permanent, wp_permanent ? "" : "Not ");
+ printf(" [1:1] : %#x\tWrite Protect Until Power Supply %sSupported\n",
+ wp_power_cycle, wp_power_cycle ? "" : "Not ");
+ printf(" [0:0] : %#x\tNo Write Protect and Write Protect Namespace %sSupported\n",
+ no_wp_wp, no_wp_wp ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ctrl_ocfs(__le16 ctrl_ocfs)
+{
+ __u16 ocfs = le16_to_cpu(ctrl_ocfs);
+ __u16 rsvd = ocfs >> 4;
+ __u8 copy_fmt_supported;
+ int copy_fmt;
+ if (rsvd)
+ printf(" [15:4] : %#x\tReserved\n", rsvd);
+ for (copy_fmt = 3; copy_fmt >= 0; copy_fmt--) {
+ copy_fmt_supported = ocfs >> copy_fmt & 1;
+ printf(" [%d:%d] : %#x\tController Copy Format %xh %sSupported\n", copy_fmt, copy_fmt,
+ copy_fmt_supported, copy_fmt, copy_fmt_supported ? "" : "Not ");
+ }
+ printf("\n");
+}
+
+static void stdout_id_ctrl_sgls(__le32 ctrl_sgls)
+{
+ __u32 sgls = le32_to_cpu(ctrl_sgls);
+ __u32 rsvd0 = (sgls & 0xFFC00000) >> 22;
+ __u32 trsdbd = (sgls & 0x200000) >> 21;
+ __u32 aofdsl = (sgls & 0x100000) >> 20;
+ __u32 mpcsd = (sgls & 0x80000) >> 19;
+ __u32 sglltb = (sgls & 0x40000) >> 18;
+ __u32 bacmdb = (sgls & 0x20000) >> 17;
+ __u32 bbs = (sgls & 0x10000) >> 16;
+ __u32 sdt = (sgls >> 8) & 0xff;
+ __u32 rsvd1 = (sgls & 0xF8) >> 3;
+ __u32 key = (sgls & 0x4) >> 2;
+ __u32 sglsp = sgls & 0x3;
+
+ if (rsvd0)
+ printf(" [31:22]: %#x\tReserved\n", rsvd0);
+ if (sglsp || (!sglsp && trsdbd))
+ printf(" [21:21]: %#x\tTransport SGL Data Block Descriptor %sSupported\n",
+ trsdbd, trsdbd ? "" : "Not ");
+ if (sglsp || (!sglsp && aofdsl))
+ printf(" [20:20]: %#x\tAddress Offsets %sSupported\n",
+ aofdsl, aofdsl ? "" : "Not ");
+ if (sglsp || (!sglsp && mpcsd))
+ printf(" [19:19]: %#x\tMetadata Pointer Containing "
+ "SGL Descriptor is %sSupported\n",
+ mpcsd, mpcsd ? "" : "Not ");
+ if (sglsp || (!sglsp && sglltb))
+ printf(" [18:18]: %#x\tSGL Length Larger than Buffer %sSupported\n",
+ sglltb, sglltb ? "" : "Not ");
+ if (sglsp || (!sglsp && bacmdb))
+ printf(" [17:17]: %#x\tByte-Aligned Contig. MD Buffer %sSupported\n",
+ bacmdb, bacmdb ? "" : "Not ");
+ if (sglsp || (!sglsp && bbs))
+ printf(" [16:16]: %#x\tSGL Bit-Bucket %sSupported\n",
+ bbs, bbs ? "" : "Not ");
+ printf(" [15:8] : %#x\tSGL Descriptor Threshold\n", sdt);
+ if (rsvd1)
+ printf(" [7:3] : %#x\tReserved\n", rsvd1);
+ if (sglsp || (!sglsp && key))
+ printf(" [2:2] : %#x\tKeyed SGL Data Block descriptor %sSupported\n",
+ key, key ? "" : "Not ");
+ if (sglsp == 0x3)
+ printf(" [1:0] : %#x\tReserved\n", sglsp);
+ else if (sglsp == 0x2)
+ printf(" [1:0] : %#x\tScatter-Gather Lists Supported."
+ " Dword alignment required.\n", sglsp);
+ else if (sglsp == 0x1)
+ printf(" [1:0] : %#x\tScatter-Gather Lists Supported."
+ " No Dword alignment required.\n", sglsp);
+ else
+ printf(" [1:0] : %#x\tScatter-Gather Lists Not Supported\n", sglsp);
+ printf("\n");
+}
+
+static void stdout_id_ctrl_fcatt(__u8 fcatt)
+{
+ __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",
+ scm, scm ? "Static" : "Dynamic");
+ printf("\n");
+}
+
+static void stdout_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 stdout_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;
+ if (rsvd)
+ 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",
+ na, na ? "NAWUN, NAWUPF, and NACWU" : "AWUN, AWUPF, and ACWU");
+ printf(" [0:0] : %#x\tThin Provisioning %sSupported\n",
+ thin, thin ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_flbas(__u8 flbas)
+{
+ __u8 rsvd = (flbas & 0x80) >> 7;
+ __u8 msb2_lbaf = (flbas & NVME_NS_FLBAS_HIGHER_MASK) >> 5;
+ __u8 mdedata = (flbas & 0x10) >> 4;
+ __u8 lsb4_lbaf = flbas & NVME_NS_FLBAS_LOWER_MASK;
+
+ if (rsvd)
+ printf(" [7:7] : %#x\tReserved\n", rsvd);
+ printf(" [6:5] : %#x\tMost significant 2 bits of Current LBA Format Selected\n",
+ msb2_lbaf);
+ printf(" [4:4] : %#x\tMetadata Transferred %s\n",
+ mdedata, mdedata ? "at End of Data LBA" : "in Separate Contiguous Buffer");
+ printf(" [3:0] : %#x\tLeast significant 4 bits of Current LBA Format Selected\n",
+ lsb4_lbaf);
+ printf("\n");
+}
+
+static void stdout_id_ns_mc(__u8 mc)
+{
+ __u8 rsvd = (mc & 0xFC) >> 2;
+ __u8 mdp = (mc & 0x2) >> 1;
+ __u8 extdlba = mc & 0x1;
+ if (rsvd)
+ printf(" [7:2] : %#x\tReserved\n", rsvd);
+ printf(" [1:1] : %#x\tMetadata Pointer %sSupported\n",
+ mdp, mdp ? "" : "Not ");
+ printf(" [0:0] : %#x\tMetadata as Part of Extended Data LBA %sSupported\n",
+ extdlba, extdlba ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_dpc(__u8 dpc)
+{
+ __u8 rsvd = (dpc & 0xE0) >> 5;
+ __u8 pil8 = (dpc & 0x10) >> 4;
+ __u8 pif8 = (dpc & 0x8) >> 3;
+ __u8 pit3 = (dpc & 0x4) >> 2;
+ __u8 pit2 = (dpc & 0x2) >> 1;
+ __u8 pit1 = dpc & 0x1;
+ if (rsvd)
+ printf(" [7:5] : %#x\tReserved\n", rsvd);
+ printf(" [4:4] : %#x\tProtection Information Transferred as Last Bytes of Metadata %sSupported\n",
+ pil8, pil8 ? "" : "Not ");
+ printf(" [3:3] : %#x\tProtection Information Transferred as First Bytes of Metadata %sSupported\n",
+ pif8, pif8 ? "" : "Not ");
+ printf(" [2:2] : %#x\tProtection Information Type 3 %sSupported\n",
+ pit3, pit3 ? "" : "Not ");
+ printf(" [1:1] : %#x\tProtection Information Type 2 %sSupported\n",
+ pit2, pit2 ? "" : "Not ");
+ printf(" [0:0] : %#x\tProtection Information Type 1 %sSupported\n",
+ pit1, pit1 ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_dps(__u8 dps)
+{
+ __u8 rsvd = (dps & 0xF0) >> 4;
+ __u8 pif8 = (dps & 0x8) >> 3;
+ __u8 pit = dps & 0x7;
+ if (rsvd)
+ printf(" [7:4] : %#x\tReserved\n", rsvd);
+ printf(" [3:3] : %#x\tProtection Information is Transferred as %s Bytes of Metadata\n",
+ pif8, pif8 ? "First" : "Last");
+ printf(" [2:0] : %#x\tProtection Information %s\n", pit,
+ pit == 3 ? "Type 3 Enabled" :
+ pit == 2 ? "Type 2 Enabled" :
+ pit == 1 ? "Type 1 Enabled" :
+ pit == 0 ? "Disabled" : "Reserved Enabled");
+ printf("\n");
+}
+
+static void stdout_id_ns_nmic(__u8 nmic)
+{
+ __u8 rsvd = (nmic & 0xFE) >> 1;
+ __u8 mp = nmic & 0x1;
+ if (rsvd)
+ printf(" [7:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tNamespace Multipath %sCapable\n",
+ mp, mp ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_rescap(__u8 rescap)
+{
+ __u8 iekr = (rescap & 0x80) >> 7;
+ __u8 eaar = (rescap & 0x40) >> 6;
+ __u8 wear = (rescap & 0x20) >> 5;
+ __u8 earo = (rescap & 0x10) >> 4;
+ __u8 wero = (rescap & 0x8) >> 3;
+ __u8 ea = (rescap & 0x4) >> 2;
+ __u8 we = (rescap & 0x2) >> 1;
+ __u8 ptpl = rescap & 0x1;
+
+ 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",
+ wear, wear ? "" : "Not ");
+ printf(" [4:4] : %#x\tExclusive Access - Registrants Only %sSupported\n",
+ earo, earo ? "" : "Not ");
+ printf(" [3:3] : %#x\tWrite Exclusive - Registrants Only %sSupported\n",
+ wero, wero ? "" : "Not ");
+ printf(" [2:2] : %#x\tExclusive Access %sSupported\n",
+ ea, ea ? "" : "Not ");
+ printf(" [1:1] : %#x\tWrite Exclusive %sSupported\n",
+ we, we ? "" : "Not ");
+ printf(" [0:0] : %#x\tPersist Through Power Loss %sSupported\n",
+ ptpl, ptpl ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_fpi(__u8 fpi)
+{
+ __u8 fpis = (fpi & 0x80) >> 7;
+ __u8 fpii = fpi & 0x7F;
+ printf(" [7:7] : %#x\tFormat Progress Indicator %sSupported\n",
+ fpis, fpis ? "" : "Not ");
+ if (fpis || (!fpis && fpii))
+ printf(" [6:0] : %#x\tFormat Progress Indicator (Remaining %d%%)\n",
+ fpii, fpii);
+ printf("\n");
+}
+
+static void stdout_id_ns_nsattr(__u8 nsattr)
+{
+ __u8 rsvd = (nsattr & 0xFE) >> 1;
+ __u8 write_protected = nsattr & 0x1;
+ if (rsvd)
+ printf(" [7:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\tNamespace %sWrite Protected\n",
+ write_protected, write_protected ? "" : "Not ");
+ printf("\n");
+}
+
+static void stdout_id_ns_dlfeat(__u8 dlfeat)
+{
+ __u8 rsvd = (dlfeat & 0xE0) >> 5;
+ __u8 guard = (dlfeat & 0x10) >> 4;
+ __u8 dwz = (dlfeat & 0x8) >> 3;
+ __u8 val = dlfeat & 0x7;
+ if (rsvd)
+ printf(" [7:5] : %#x\tReserved\n", rsvd);
+ printf(" [4:4] : %#x\tGuard Field of Deallocated Logical Blocks is set to %s\n",
+ guard, guard ? "CRC of The Value Read" : "0xFFFF");
+ printf(" [3:3] : %#x\tDeallocate Bit in the Write Zeroes Command is %sSupported\n",
+ dwz, dwz ? "" : "Not ");
+ printf(" [2:0] : %#x\tBytes Read From a Deallocated Logical Block and its Metadata are %s\n",
+ val, val == 2 ? "0xFF" :
+ val == 1 ? "0x00" :
+ val == 0 ? "Not Reported" : "Reserved Value");
+ printf("\n");
+}
+
+static void stdout_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ unsigned int lba_index, bool cap_only)
+{
+ bool human = stdout_print_ops.flags & VERBOSE;
+ int vs = stdout_print_ops.flags & VS;
+ int i;
+ __u8 flbas;
+ char *in_use = "(in use)";
+
+ if (!cap_only) {
+ printf("NVME Identify Namespace %d:\n", nsid);
+ printf("nsze : %#"PRIx64"\n", le64_to_cpu(ns->nsze));
+ printf("ncap : %#"PRIx64"\n", le64_to_cpu(ns->ncap));
+ printf("nuse : %#"PRIx64"\n", le64_to_cpu(ns->nuse));
+ printf("nsfeat : %#x\n", ns->nsfeat);
+ if (human)
+ stdout_id_ns_nsfeat(ns->nsfeat);
+ } else
+ printf("NVMe Identify Namespace for LBA format[%d]:\n", lba_index);
+
+ printf("nlbaf : %d\n", ns->nlbaf);
+ if (!cap_only) {
+ printf("flbas : %#x\n", ns->flbas);
+ if (human)
+ stdout_id_ns_flbas(ns->flbas);
+ } else
+ in_use = "";
+
+ printf("mc : %#x\n", ns->mc);
+ if (human)
+ stdout_id_ns_mc(ns->mc);
+ printf("dpc : %#x\n", ns->dpc);
+ if (human)
+ stdout_id_ns_dpc(ns->dpc);
+ if (!cap_only) {
+ printf("dps : %#x\n", ns->dps);
+ if (human)
+ stdout_id_ns_dps(ns->dps);
+ printf("nmic : %#x\n", ns->nmic);
+ if (human)
+ stdout_id_ns_nmic(ns->nmic);
+ printf("rescap : %#x\n", ns->rescap);
+ if (human)
+ stdout_id_ns_rescap(ns->rescap);
+ printf("fpi : %#x\n", ns->fpi);
+ if (human)
+ stdout_id_ns_fpi(ns->fpi);
+ printf("dlfeat : %d\n", ns->dlfeat);
+ if (human)
+ stdout_id_ns_dlfeat(ns->dlfeat);
+ printf("nawun : %d\n", le16_to_cpu(ns->nawun));
+ printf("nawupf : %d\n", le16_to_cpu(ns->nawupf));
+ printf("nacwu : %d\n", le16_to_cpu(ns->nacwu));
+ printf("nabsn : %d\n", le16_to_cpu(ns->nabsn));
+ printf("nabo : %d\n", le16_to_cpu(ns->nabo));
+ printf("nabspf : %d\n", le16_to_cpu(ns->nabspf));
+ printf("noiob : %d\n", le16_to_cpu(ns->noiob));
+ printf("nvmcap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(ns->nvmcap)));
+ if (ns->nsfeat & 0x10) {
+ printf("npwg : %u\n", le16_to_cpu(ns->npwg));
+ printf("npwa : %u\n", le16_to_cpu(ns->npwa));
+ printf("npdg : %u\n", le16_to_cpu(ns->npdg));
+ 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 : %u\n", le32_to_cpu(ns->mcl));
+ printf("msrc : %u\n", ns->msrc);
+ }
+ printf("nulbaf : %u\n", ns->nulbaf);
+ if (!cap_only) {
+ 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("endgid : %d\n", le16_to_cpu(ns->endgid));
+
+ printf("nguid : ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", ns->nguid[i]);
+ printf("\n");
+
+ printf("eui64 : ");
+ for (i = 0; i < 8; i++)
+ printf("%02x", ns->eui64[i]);
+ printf("\n");
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &flbas);
+ for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) {
+ if (human)
+ printf("LBA Format %2d : Metadata Size: %-3d bytes - "
+ "Data Size: %-2d bytes - Relative Performance: %#x %s %s\n",
+ i, le16_to_cpu(ns->lbaf[i].ms),
+ 1 << ns->lbaf[i].ds, ns->lbaf[i].rp,
+ ns->lbaf[i].rp == 3 ? "Degraded" :
+ ns->lbaf[i].rp == 2 ? "Good" :
+ ns->lbaf[i].rp == 1 ? "Better" : "Best",
+ i == flbas ? in_use : "");
+ else
+ printf("lbaf %2d : ms:%-3d lbads:%-2d rp:%#x %s\n", i,
+ le16_to_cpu(ns->lbaf[i].ms), ns->lbaf[i].ds,
+ ns->lbaf[i].rp, i == flbas ? in_use : "");
+ }
+
+ if (vs && !cap_only) {
+ printf("vs[]:\n");
+ d(ns->vs, sizeof(ns->vs), 16, 1);
+ }
+}
+
+static void stdout_cmd_set_independent_id_ns_nsfeat(__u8 nsfeat)
+{
+ __u8 rsvd6 = (nsfeat & 0xE0) >> 6;
+ __u8 vwcnp = (nsfeat & 0x20) >> 5;
+ __u8 rmedia = (nsfeat & 0x10) >> 4;
+ __u8 uidreuse = (nsfeat & 0x8) >> 3;
+ __u8 rsvd0 = (nsfeat & 0x7);
+ if (rsvd6)
+ printf(" [7:6] : %#x\tReserved\n", rsvd6);
+ printf(" [5:5] : %#x\tVolatile Write Cache is %sPresent\n",
+ vwcnp, vwcnp ? "" : "Not ");
+ printf(" [4:4] : %#x\tNamespace %sstore data on rotational media\n",
+ rmedia, rmedia ? "" : "does not ");
+ printf(" [3:3] : %#x\tNGUID and EUI64 fields if non-zero, %sReused\n",
+ uidreuse, uidreuse ? "Never " : "");
+ if (rsvd0)
+ printf(" [2:0] : %#x\tReserved\n", rsvd0);
+ printf("\n");
+}
+
+static void stdout_cmd_set_independent_id_ns_nstat(__u8 nstat)
+{
+ __u8 rsvd1 = (nstat & 0xfe) >> 1;
+ __u8 nrdy = nstat & 0x1;
+ if (rsvd1)
+ printf(" [7:1] : %#x\tReserved\n", rsvd1);
+ printf(" [0:0] : %#x\tName space is %sready\n",
+ nrdy, nrdy ? "" : "not ");
+ printf("\n");
+}
+
+static void stdout_cmd_set_independent_id_ns(struct nvme_id_independent_id_ns *ns,
+ unsigned int nsid)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ printf("NVME Identify Command Set Independent Namespace %d:\n", nsid);
+ printf("nsfeat : %#x\n", ns->nsfeat);
+ if (human)
+ stdout_cmd_set_independent_id_ns_nsfeat(ns->nsfeat);
+ printf("nmic : %#x\n", ns->nmic);
+ if (human)
+ stdout_id_ns_nmic(ns->nmic);
+ printf("rescap : %#x\n", ns->rescap);
+ if (human)
+ stdout_id_ns_rescap(ns->rescap);
+ printf("fpi : %#x\n", ns->fpi);
+ if (human)
+ stdout_id_ns_fpi(ns->fpi);
+ printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid));
+ printf("nsattr : %u\n", ns->nsattr);
+ if (human)
+ stdout_id_ns_nsattr(ns->nsattr);
+ printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid));
+ printf("endgid : %d\n", le16_to_cpu(ns->endgid));
+
+ printf("nstat : %#x\n", ns->nstat);
+ if (human)
+ stdout_cmd_set_independent_id_ns_nstat(ns->nstat);
+}
+
+static void stdout_id_ns_descs(void *data, unsigned int nsid)
+{
+ int pos, len = 0;
+ int i;
+ __u8 uuid[NVME_UUID_LEN];
+ char uuid_str[NVME_UUID_LEN_STRING];
+ __u8 eui64[8];
+ __u8 nguid[16];
+ __u8 csi;
+
+ printf("NVME Namespace Identification Descriptors NS %d:\n", nsid);
+ for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) {
+ struct nvme_ns_id_desc *cur = data + pos;
+
+ if (cur->nidl == 0)
+ break;
+
+ switch (cur->nidt) {
+ case NVME_NIDT_EUI64:
+ memcpy(eui64, data + pos + sizeof(*cur), sizeof(eui64));
+ printf("eui64 : ");
+ for (i = 0; i < 8; i++)
+ printf("%02x", eui64[i]);
+ printf("\n");
+ len = sizeof(eui64);
+ break;
+ case NVME_NIDT_NGUID:
+ memcpy(nguid, data + pos + sizeof(*cur), sizeof(nguid));
+ printf("nguid : ");
+ for (i = 0; i < 16; i++)
+ printf("%02x", nguid[i]);
+ printf("\n");
+ len = sizeof(nguid);
+ break;
+ case NVME_NIDT_UUID:
+ memcpy(uuid, data + pos + sizeof(*cur), 16);
+ nvme_uuid_to_string(uuid, uuid_str);
+ printf("uuid : %s\n", uuid_str);
+ len = sizeof(uuid);
+ break;
+ case NVME_NIDT_CSI:
+ memcpy(&csi, data + pos + sizeof(*cur), 1);
+ printf("csi : %#x\n", csi);
+ len += sizeof(csi);
+ break;
+ default:
+ /* Skip unknown types */
+ len = cur->nidl;
+ break;
+ }
+
+ len += sizeof(*cur);
+ }
+}
+
+static void print_psd_workload(__u8 apw)
+{
+ switch (apw & 0x7) {
+ case NVME_PSD_WORKLOAD_NP:
+ /* Unknown or not provided */
+ printf("-");
+ break;
+ case 1:
+ /* Extended idle period with burst of random write */
+ printf("1MiB 32 RW, 30s idle");
+ break;
+ case 2:
+ /* Heavy sequential writes */
+ printf("80K 128KiB SW");
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+}
+
+static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
+{
+ __u16 power = le16_to_cpu(ctr_power);
+
+ switch (scale & 0x3) {
+ case NVME_PSD_PS_NOT_REPORTED:
+ /* Not reported for this power state */
+ printf("-");
+ break;
+ case NVME_PSD_PS_100_MICRO_WATT:
+ /* Units of 0.0001W */
+ printf("%01u.%04uW", power / 10000, power % 10000);
+ break;
+ case NVME_PSD_PS_10_MILLI_WATT:
+ /* Units of 0.01W */
+ printf("%01u.%02uW", power / 100, power % 100);
+ break;
+ default:
+ printf("reserved");
+ break;
+ }
+}
+
+static void stdout_id_ctrl_power(struct nvme_id_ctrl *ctrl)
+{
+ int i;
+
+ for (i = 0; i <= ctrl->npss; i++) {
+ __u16 max_power = le16_to_cpu(ctrl->psd[i].mp);
+
+ printf("ps %4d : mp:", i);
+
+ if (ctrl->psd[i].flags & NVME_PSD_FLAGS_MXPS)
+ printf("%01u.%04uW ", max_power / 10000, max_power % 10000);
+ else
+ printf("%01u.%02uW ", max_power / 100, max_power % 100);
+
+ if (ctrl->psd[i].flags & NVME_PSD_FLAGS_NOPS)
+ printf("non-");
+
+ printf("operational enlat:%d exlat:%d rrt:%d rrl:%d\n"
+ " rwt:%d rwl:%d idle_power:",
+ le32_to_cpu(ctrl->psd[i].enlat),
+ le32_to_cpu(ctrl->psd[i].exlat),
+ ctrl->psd[i].rrt, ctrl->psd[i].rrl,
+ ctrl->psd[i].rwt, ctrl->psd[i].rwl);
+ print_ps_power_and_scale(ctrl->psd[i].idlp,
+ nvme_psd_power_scale(ctrl->psd[i].ips));
+ printf(" active_power:");
+ print_ps_power_and_scale(ctrl->psd[i].actp,
+ nvme_psd_power_scale(ctrl->psd[i].apws));
+ printf("\n active_power_workload:");
+ print_psd_workload(ctrl->psd[i].apws);
+ printf("\n");
+
+ }
+}
+
+static void stdout_id_ctrl(struct nvme_id_ctrl *ctrl,
+ void (*vendor_show)(__u8 *vs, struct json_object *root))
+{
+ bool human = stdout_print_ops.flags & VERBOSE, vs = stdout_print_ops.flags & VS;
+
+ printf("NVME Identify Controller:\n");
+ printf("vid : %#x\n", le16_to_cpu(ctrl->vid));
+ printf("ssvid : %#x\n", le16_to_cpu(ctrl->ssvid));
+ printf("sn : %-.*s\n", (int)sizeof(ctrl->sn), ctrl->sn);
+ printf("mn : %-.*s\n", (int)sizeof(ctrl->mn), ctrl->mn);
+ printf("fr : %-.*s\n", (int)sizeof(ctrl->fr), ctrl->fr);
+ printf("rab : %d\n", ctrl->rab);
+ printf("ieee : %02x%02x%02x\n",
+ ctrl->ieee[2], ctrl->ieee[1], ctrl->ieee[0]);
+ printf("cmic : %#x\n", ctrl->cmic);
+ if (human)
+ stdout_id_ctrl_cmic(ctrl->cmic);
+ printf("mdts : %d\n", ctrl->mdts);
+ printf("cntlid : %#x\n", le16_to_cpu(ctrl->cntlid));
+ printf("ver : %#x\n", le32_to_cpu(ctrl->ver));
+ printf("rtd3r : %#x\n", le32_to_cpu(ctrl->rtd3r));
+ printf("rtd3e : %#x\n", le32_to_cpu(ctrl->rtd3e));
+ printf("oaes : %#x\n", le32_to_cpu(ctrl->oaes));
+ if (human)
+ stdout_id_ctrl_oaes(ctrl->oaes);
+ printf("ctratt : %#x\n", le32_to_cpu(ctrl->ctratt));
+ if (human)
+ stdout_id_ctrl_ctratt(ctrl->ctratt);
+ printf("rrls : %#x\n", le16_to_cpu(ctrl->rrls));
+ printf("cntrltype : %d\n", ctrl->cntrltype);
+ if (human)
+ stdout_id_ctrl_cntrltype(ctrl->cntrltype);
+ printf("fguid : %s\n", util_uuid_to_string(ctrl->fguid));
+ printf("crdt1 : %u\n", le16_to_cpu(ctrl->crdt1));
+ printf("crdt2 : %u\n", le16_to_cpu(ctrl->crdt2));
+ printf("crdt3 : %u\n", le16_to_cpu(ctrl->crdt3));
+ printf("nvmsr : %u\n", ctrl->nvmsr);
+ if (human)
+ stdout_id_ctrl_nvmsr(ctrl->nvmsr);
+ printf("vwci : %u\n", ctrl->vwci);
+ if (human)
+ stdout_id_ctrl_vwci(ctrl->vwci);
+ printf("mec : %u\n", ctrl->mec);
+ if (human)
+ stdout_id_ctrl_mec(ctrl->mec);
+
+ printf("oacs : %#x\n", le16_to_cpu(ctrl->oacs));
+ if (human)
+ stdout_id_ctrl_oacs(ctrl->oacs);
+ printf("acl : %d\n", ctrl->acl);
+ printf("aerl : %d\n", ctrl->aerl);
+ printf("frmw : %#x\n", ctrl->frmw);
+ if (human)
+ stdout_id_ctrl_frmw(ctrl->frmw);
+ printf("lpa : %#x\n", ctrl->lpa);
+ if (human)
+ stdout_id_ctrl_lpa(ctrl->lpa);
+ printf("elpe : %d\n", ctrl->elpe);
+ if (human)
+ stdout_id_ctrl_elpe(ctrl->elpe);
+ printf("npss : %d\n", ctrl->npss);
+ if (human)
+ stdout_id_ctrl_npss(ctrl->npss);
+ printf("avscc : %#x\n", ctrl->avscc);
+ if (human)
+ stdout_id_ctrl_avscc(ctrl->avscc);
+ printf("apsta : %#x\n", ctrl->apsta);
+ if (human)
+ stdout_id_ctrl_apsta(ctrl->apsta);
+ printf("wctemp : %d\n", le16_to_cpu(ctrl->wctemp));
+ if (human)
+ stdout_id_ctrl_wctemp(ctrl->wctemp);
+ printf("cctemp : %d\n", le16_to_cpu(ctrl->cctemp));
+ if (human)
+ stdout_id_ctrl_cctemp(ctrl->cctemp);
+ printf("mtfa : %d\n", le16_to_cpu(ctrl->mtfa));
+ printf("hmpre : %u\n", le32_to_cpu(ctrl->hmpre));
+ printf("hmmin : %u\n", le32_to_cpu(ctrl->hmmin));
+ printf("tnvmcap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(ctrl->tnvmcap)));
+ if (human)
+ stdout_id_ctrl_tnvmcap(ctrl->tnvmcap);
+ printf("unvmcap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(ctrl->unvmcap)));
+ if (human)
+ stdout_id_ctrl_unvmcap(ctrl->unvmcap);
+ printf("rpmbs : %#x\n", le32_to_cpu(ctrl->rpmbs));
+ if (human)
+ stdout_id_ctrl_rpmbs(ctrl->rpmbs);
+ printf("edstt : %d\n", le16_to_cpu(ctrl->edstt));
+ printf("dsto : %d\n", ctrl->dsto);
+ printf("fwug : %d\n", ctrl->fwug);
+ printf("kas : %d\n", le16_to_cpu(ctrl->kas));
+ printf("hctma : %#x\n", le16_to_cpu(ctrl->hctma));
+ if (human)
+ stdout_id_ctrl_hctma(ctrl->hctma);
+ printf("mntmt : %d\n", le16_to_cpu(ctrl->mntmt));
+ if (human)
+ stdout_id_ctrl_mntmt(ctrl->mntmt);
+ printf("mxtmt : %d\n", le16_to_cpu(ctrl->mxtmt));
+ if (human)
+ stdout_id_ctrl_mxtmt(ctrl->mxtmt);
+ printf("sanicap : %#x\n", le32_to_cpu(ctrl->sanicap));
+ if (human)
+ stdout_id_ctrl_sanicap(ctrl->sanicap);
+ printf("hmminds : %u\n", le32_to_cpu(ctrl->hmminds));
+ printf("hmmaxd : %d\n", le16_to_cpu(ctrl->hmmaxd));
+ printf("nsetidmax : %d\n", le16_to_cpu(ctrl->nsetidmax));
+ printf("endgidmax : %d\n", le16_to_cpu(ctrl->endgidmax));
+ printf("anatt : %d\n", ctrl->anatt);
+ printf("anacap : %d\n", ctrl->anacap);
+ if (human)
+ stdout_id_ctrl_anacap(ctrl->anacap);
+ printf("anagrpmax : %u\n", ctrl->anagrpmax);
+ printf("nanagrpid : %u\n", le32_to_cpu(ctrl->nanagrpid));
+ printf("pels : %u\n", le32_to_cpu(ctrl->pels));
+ printf("domainid : %d\n", le16_to_cpu(ctrl->domainid));
+ printf("megcap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(ctrl->megcap)));
+ printf("sqes : %#x\n", ctrl->sqes);
+ if (human)
+ stdout_id_ctrl_sqes(ctrl->sqes);
+ printf("cqes : %#x\n", ctrl->cqes);
+ if (human)
+ stdout_id_ctrl_cqes(ctrl->cqes);
+ printf("maxcmd : %d\n", le16_to_cpu(ctrl->maxcmd));
+ printf("nn : %u\n", le32_to_cpu(ctrl->nn));
+ printf("oncs : %#x\n", le16_to_cpu(ctrl->oncs));
+ if (human)
+ stdout_id_ctrl_oncs(ctrl->oncs);
+ printf("fuses : %#x\n", le16_to_cpu(ctrl->fuses));
+ if (human)
+ stdout_id_ctrl_fuses(ctrl->fuses);
+ printf("fna : %#x\n", ctrl->fna);
+ if (human)
+ stdout_id_ctrl_fna(ctrl->fna);
+ printf("vwc : %#x\n", ctrl->vwc);
+ if (human)
+ stdout_id_ctrl_vwc(ctrl->vwc);
+ printf("awun : %d\n", le16_to_cpu(ctrl->awun));
+ printf("awupf : %d\n", le16_to_cpu(ctrl->awupf));
+ printf("icsvscc : %d\n", ctrl->icsvscc);
+ if (human)
+ stdout_id_ctrl_icsvscc(ctrl->icsvscc);
+ printf("nwpc : %d\n", ctrl->nwpc);
+ if (human)
+ stdout_id_ctrl_nwpc(ctrl->nwpc);
+ printf("acwu : %d\n", le16_to_cpu(ctrl->acwu));
+ printf("ocfs : %#x\n", le16_to_cpu(ctrl->ocfs));
+ if (human)
+ stdout_id_ctrl_ocfs(ctrl->ocfs);
+ printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls));
+ if (human)
+ stdout_id_ctrl_sgls(ctrl->sgls);
+ printf("mnan : %u\n", le32_to_cpu(ctrl->mnan));
+ printf("maxdna : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(ctrl->maxdna)));
+ printf("maxcna : %u\n", le32_to_cpu(ctrl->maxcna));
+ printf("oaqd : %u\n", le32_to_cpu(ctrl->oaqd));
+ printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn);
+ printf("ioccsz : %u\n", le32_to_cpu(ctrl->ioccsz));
+ printf("iorcsz : %u\n", le32_to_cpu(ctrl->iorcsz));
+ printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff));
+ printf("fcatt : %#x\n", ctrl->fcatt);
+ if (human)
+ stdout_id_ctrl_fcatt(ctrl->fcatt);
+ printf("msdbd : %d\n", ctrl->msdbd);
+ printf("ofcs : %d\n", le16_to_cpu(ctrl->ofcs));
+ if (human)
+ stdout_id_ctrl_ofcs(ctrl->ofcs);
+
+ stdout_id_ctrl_power(ctrl);
+ if (vendor_show)
+ vendor_show(ctrl->vs, NULL);
+ else if (vs) {
+ printf("vs[]:\n");
+ d(ctrl->vs, sizeof(ctrl->vs), 16, 1);
+ }
+}
+
+static void stdout_id_ctrl_nvm(struct 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 stdout_nvm_id_ns_pic(__u8 pic)
+{
+ __u8 rsvd = (pic & 0xF8) >> 3;
+ __u8 stcrs = (pic & 0x3) >> 2;
+ __u8 pic_16bpistm = (pic & 0x2) >> 1;
+ __u8 pic_16bpists = pic & 0x1;
+
+ if (rsvd)
+ printf(" [7:3] : %#x\tReserved\n", rsvd);
+ printf(" [2:2] : %#x\tStorage Tag Check Read Support\n", stcrs);
+ printf(" [1:1] : %#x\t16b Guard Protection Information Storage Tag Mask\n",
+ pic_16bpistm);
+ printf(" [0:0] : %#x\t16b Guard Protection Information Storage Tag Support\n",
+ pic_16bpists);
+ printf("\n");
+}
+
+static void stdout_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid,
+ struct nvme_id_ns *ns, unsigned int lba_index,
+ bool cap_only)
+{
+ int i, verbose = stdout_print_ops.flags & VERBOSE;
+ __u32 elbaf;
+ int pif, sts;
+ char *in_use = "(in use)";
+
+ if (!cap_only) {
+ printf("NVMe NVM Identify Namespace %d:\n", nsid);
+ printf("lbstm : %#"PRIx64"\n", le64_to_cpu(nvm_ns->lbstm));
+ } else {
+ printf("NVMe NVM Identify Namespace for LBA format[%d]:\n", lba_index);
+ in_use = "";
+ }
+ printf("pic : %#x\n", nvm_ns->pic);
+ if (verbose)
+ stdout_nvm_id_ns_pic(nvm_ns->pic);
+
+ for (i = 0; i <= ns->nlbaf + ns->nulbaf; i++) {
+ elbaf = le32_to_cpu(nvm_ns->elbaf[i]);
+ pif = (elbaf >> 7) & 0x3;
+ sts = elbaf & 0x7f;
+ if (verbose)
+ printf("Extended LBA Format %2d : Protection Information Format: "
+ "%s(%d) - Storage Tag Size (MSB): %-2d %s\n",
+ i, pif == 3 ? "Reserved" :
+ pif == 2 ? "64b Guard" :
+ pif == 1 ? "32b Guard" : "16b Guard",
+ pif, sts, i == (ns->flbas & 0xf) ? in_use : "");
+ else
+ printf("elbaf %2d : pif:%d sts:%-2d %s\n", i,
+ pif, sts, i == (ns->flbas & 0xf) ? in_use : "");
+ }
+}
+
+static void stdout_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl)
+{
+ printf("NVMe ZNS Identify Controller:\n");
+ printf("zasl : %u\n", ctrl->zasl);
+}
+
+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 & 0xfffc) >> 2;
+ __u8 razb = ozcs & 0x1;
+ __u8 zrwasup = (ozcs & 0x2) >> 1;
+
+ if (rsvd)
+ printf(" [15:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\t Read Across Zone Boundaries: %s\n",
+ razb, razb ? "Yes" : "No");
+ printf(" [1:1] : %#x\t Zone Random Write Area: %s\n", zrwasup,
+ zrwasup ? "Yes" : "No");
+}
+
+static void stdout_zns_id_ns_recommended_limit(__le32 ns_rl, int human,
+ const char *target_limit)
+{
+ unsigned int recommended_limit = le32_to_cpu(ns_rl);
+ if (!recommended_limit && human)
+ printf("%s : Not Reported\n", target_limit);
+ else
+ printf("%s : %u\n", target_limit, recommended_limit);
+}
+
+static void stdout_zns_id_ns_zrwacap(__u8 zrwacap)
+{
+ __u8 rsvd = (zrwacap & 0xfe) >> 1;
+ __u8 expflushsup = zrwacap & 0x1;
+
+ if (rsvd)
+ printf(" [7:1] : %#x\tReserved\n", rsvd);
+ printf(" [0:0] : %#x\t Explicit ZRWA Flush Operations: %s\n",
+ expflushsup, expflushsup ? "Yes" : "No");
+}
+
+static void stdout_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns)
+{
+ int human = stdout_print_ops.flags & VERBOSE, vs = stdout_print_ops.flags & VS;
+ uint8_t lbaf;
+ int i;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(id_ns->flbas, &lbaf);
+
+ 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));
+ }
+
+ stdout_zns_id_ns_recommended_limit(ns->rrl, human, "rrl ");
+ stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl ");
+ stdout_zns_id_ns_recommended_limit(ns->rrl1, human, "rrl1");
+ stdout_zns_id_ns_recommended_limit(ns->rrl2, human, "rrl2");
+ stdout_zns_id_ns_recommended_limit(ns->rrl3, human, "rrl3");
+ stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl1");
+ stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl2");
+ stdout_zns_id_ns_recommended_limit(ns->frl, human, "frl3");
+
+ printf("numzrwa : %#x\n", le32_to_cpu(ns->numzrwa));
+ printf("zrwafg : %u\n", le16_to_cpu(ns->zrwafg));
+ printf("zrwasz : %u\n", le16_to_cpu(ns->zrwasz));
+ if (human) {
+ printf("zrwacap : %u\tZone Random Write Area Capability\n", ns->zrwacap);
+ stdout_zns_id_ns_zrwacap(ns->zrwacap);
+ } else {
+ printf("zrwacap : %u\n", ns->zrwacap);
+ }
+
+ 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);
+ }
+}
+
+static void stdout_list_ns(struct nvme_ns_list *ns_list)
+{
+ int i;
+
+ for (i = 0; i < 1024; i++) {
+ if (ns_list->ns[i])
+ printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list->ns[i]));
+ }
+}
+
+static void stdout_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list)
+{
+ printf("nr_zones: %"PRIu64"\n", (uint64_t)le64_to_cpu(nr_zones));
+}
+
+static void stdout_zns_changed(struct nvme_zns_changed_zone_log *log)
+{
+ uint16_t nrzid;
+ int i;
+
+ 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]));
+}
+
+static void stdout_zns_report_zone_attributes(__u8 za, __u8 zai)
+{
+ const char *const recommended_limit[4] = {"","1","2","3"};
+ printf("Attrs: Zone Descriptor Extension is %sVaild\n",
+ (za & NVME_ZNS_ZA_ZDEV)? "" : "Not ");
+ if(za & NVME_ZNS_ZA_RZR) {
+ printf(" Reset Zone Recommended with Reset Recommended Limit%s\n",
+ recommended_limit[(zai&0xd)>>2]);
+ }
+ if (za & NVME_ZNS_ZA_FZR) {
+ printf(" Finish Zone Recommended with Finish Recommended Limit%s\n",
+ recommended_limit[zai&0x3]);
+ }
+ if (za & NVME_ZNS_ZA_ZFC) {
+ printf(" Zone Finished by Controller\n");
+ }
+}
+
+static void stdout_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size,
+ struct json_object *zone_list)
+{
+ struct nvme_zone_report *r = report;
+ struct nvme_zns_desc *desc;
+ int i, verbose = stdout_print_ops.flags & VERBOSE;
+ __u64 nr_zones = le64_to_cpu(r->nr_zones);
+
+ if (nr_zones < descs)
+ descs = nr_zones;
+
+ for (i = 0; i < descs; i++) {
+ desc = (struct nvme_zns_desc *)
+ (report + sizeof(*r) + i * (sizeof(*desc) + ext_size));
+ if(verbose) {
+ printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %-12s Type: %-14s\n",
+ (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp),
+ (uint64_t)le64_to_cpu(desc->zcap), nvme_zone_state_to_string(desc->zs >> 4),
+ nvme_zone_type_to_string(desc->zt));
+ stdout_zns_report_zone_attributes(desc->za, desc->zai);
+ } else {
+ printf("SLBA: %#-10"PRIx64" WP: %#-10"PRIx64" Cap: %#-10"PRIx64" State: %#-4x Type: %#-4x Attrs: %#-4x AttrsInfo: %#-4x\n",
+ (uint64_t)le64_to_cpu(desc->zslba), (uint64_t)le64_to_cpu(desc->wp),
+ (uint64_t)le64_to_cpu(desc->zcap), desc->zs, desc->zt,
+ desc->za, desc->zai);
+ }
+
+ if (ext_size && (desc->za & NVME_ZNS_ZA_ZDEV)) {
+ printf("Extension Data: ");
+ d((unsigned char *)desc + sizeof(*desc), ext_size, 16, 1);
+ printf("..\n");
+ }
+ }
+}
+
+static void stdout_list_ctrl(struct nvme_ctrl_list *ctrl_list)
+{
+ __u16 num = le16_to_cpu(ctrl_list->num);
+ int i;
+
+ printf("num of ctrls present: %u\n", num);
+ for (i = 0; i < min(num, 2047); i++)
+ printf("[%4u]:%#x\n", i, le16_to_cpu(ctrl_list->identifier[i]));
+}
+
+static void stdout_id_nvmset(struct nvme_id_nvmset_list *nvmset,
+ unsigned int nvmset_id)
+{
+ int i;
+
+ printf("NVME Identify NVM Set List %d:\n", nvmset_id);
+ printf("nid : %d\n", nvmset->nid);
+ printf(".................\n");
+ for (i = 0; i < nvmset->nid; i++) {
+ printf(" NVM Set Attribute Entry[%2d]\n", i);
+ printf(".................\n");
+ printf("nvmset_id : %d\n",
+ le16_to_cpu(nvmset->ent[i].endgid));
+ printf("endurance_group_id : %d\n",
+ le16_to_cpu(nvmset->ent[i].endgid));
+ printf("random_4k_read_typical : %u\n",
+ le32_to_cpu(nvmset->ent[i].rr4kt));
+ printf("optimal_write_size : %u\n",
+ le32_to_cpu(nvmset->ent[i].ows));
+ printf("total_nvmset_cap : %s\n",
+ uint128_t_to_l10n_string(
+ le128_to_cpu(nvmset->ent[i].tnvmsetcap)));
+ printf("unalloc_nvmset_cap : %s\n",
+ uint128_t_to_l10n_string(
+ le128_to_cpu(nvmset->ent[i].unvmsetcap)));
+ printf(".................\n");
+ }
+}
+
+static void stdout_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 ");
+}
+
+static void stdout_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ 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)
+ stdout_primary_ctrl_caps_crt(caps->crt);
+ printf("vqfrt : %u\n", le32_to_cpu(caps->vqfrt));
+ printf("vqrfa : %u\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 : %u\n", le32_to_cpu(caps->vifrt));
+ printf("virfa : %u\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 stdout_list_secondary_ctrl(const struct nvme_secondary_ctrl_list *sc_list,
+ __u32 count)
+{
+ const struct nvme_secondary_ctrl *sc_entry =
+ &sc_list->sc_entry[0];
+ static const char * const state_desc[] = { "Offline", "Online" };
+
+ __u16 num = sc_list->num;
+ __u32 entries = min(num, count);
+ int i;
+
+ printf("Identify Secondary Controller List:\n");
+ printf(" NUMID : Number of Identifiers : %d\n", num);
+
+ for (i = 0; i < entries; i++) {
+ printf(" SCEntry[%-3d]:\n", i);
+ printf("................\n");
+ printf(" SCID : Secondary Controller Identifier : 0x%.04x\n",
+ le16_to_cpu(sc_entry[i].scid));
+ printf(" PCID : Primary Controller Identifier : 0x%.04x\n",
+ le16_to_cpu(sc_entry[i].pcid));
+ printf(" SCS : Secondary Controller State : 0x%.04x (%s)\n",
+ sc_entry[i].scs,
+ state_desc[sc_entry[i].scs & 0x1]);
+ printf(" VFN : Virtual Function Number : 0x%.04x\n",
+ le16_to_cpu(sc_entry[i].vfn));
+ printf(" NVQ : Num VQ Flex Resources Assigned : 0x%.04x\n",
+ le16_to_cpu(sc_entry[i].nvq));
+ printf(" NVI : Num VI Flex Resources Assigned : 0x%.04x\n",
+ le16_to_cpu(sc_entry[i].nvi));
+ }
+}
+
+static void stdout_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist)
+{
+ int i;
+
+ printf("Identify Namespace Granularity List:\n");
+ printf(" ATTR : Namespace Granularity Attributes: 0x%x\n",
+ glist->attributes);
+ printf(" NUMD : Number of Descriptors : %d\n",
+ glist->num_descriptors);
+
+ /* Number of Descriptors is a 0's based value */
+ for (i = 0; i <= glist->num_descriptors; i++) {
+ printf("\n Entry[%2d] :\n", i);
+ printf("................\n");
+ printf(" NSG : Namespace Size Granularity : 0x%"PRIx64"\n",
+ le64_to_cpu(glist->entry[i].nszegran));
+ printf(" NCG : Namespace Capacity Granularity : 0x%"PRIx64"\n",
+ le64_to_cpu(glist->entry[i].ncapgran));
+ }
+}
+
+static void stdout_id_uuid_list(const struct nvme_id_uuid_list *uuid_list)
+{
+ int i, human = stdout_print_ops.flags & VERBOSE;
+
+ printf("NVME Identify UUID:\n");
+
+ for (i = 0; i < NVME_ID_UUID_LIST_MAX; i++) {
+ __u8 uuid[NVME_UUID_LEN];
+ char *association = "";
+ uint8_t identifier_association = uuid_list->entry[i].header & 0x3;
+ /* The list is terminated by a zero UUID value */
+ if (memcmp(uuid_list->entry[i].uuid, zero_uuid, NVME_UUID_LEN) == 0)
+ break;
+ memcpy(&uuid, uuid_list->entry[i].uuid, NVME_UUID_LEN);
+ if (human) {
+ switch (identifier_association) {
+ case 0x0:
+ association = "No association reported";
+ break;
+ case 0x1:
+ association = "associated with PCI Vendor ID";
+ break;
+ case 0x2:
+ association = "associated with PCI Subsystem Vendor ID";
+ break;
+ default:
+ association = "Reserved";
+ break;
+ }
+ }
+ printf(" Entry[%3d]\n", i+1);
+ printf(".................\n");
+ printf("association : 0x%x %s\n", identifier_association, association);
+ printf("UUID : %s", util_uuid_to_string(uuid));
+ if (memcmp(uuid_list->entry[i].uuid, invalid_uuid,
+ sizeof(zero_uuid)) == 0)
+ printf(" (Invalid UUID)");
+ printf("\n.................\n");
+ }
+}
+
+static void stdout_id_domain_list(struct nvme_id_domain_list *id_dom)
+{
+ int i;
+
+ printf("Number of Domain Entries: %u\n", id_dom->num);
+ for (i = 0; i < id_dom->num; i++) {
+ printf("Domain Id for Attr Entry[%u]: %u\n", i,
+ le16_to_cpu(id_dom->domain_attr[i].dom_id));
+ printf("Domain Capacity for Attr Entry[%u]: %s\n", i,
+ uint128_t_to_l10n_string(
+ le128_to_cpu(id_dom->domain_attr[i].dom_cap)));
+ printf("Unallocated Domain Capacity for Attr Entry[%u]: %s\n", i,
+ uint128_t_to_l10n_string(
+ le128_to_cpu(id_dom->domain_attr[i].unalloc_dom_cap)));
+ printf("Max Endurance Group Domain Capacity for Attr Entry[%u]: %s\n", i,
+ uint128_t_to_l10n_string(
+ le128_to_cpu(id_dom->domain_attr[i].max_egrp_dom_cap)));
+ }
+}
+
+static void stdout_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list)
+{
+ int i;
+ __u16 num = le16_to_cpu(endgrp_list->num);
+
+ printf("num of endurance group ids: %u\n", num);
+ for (i = 0; i < min(num, 2047); i++) {
+ printf("[%4u]:%#x\n", i, le16_to_cpu(endgrp_list->identifier[i]));
+ }
+}
+
+static void stdout_id_iocs(struct nvme_id_iocs *iocs)
+{
+ __u16 i;
+
+ for (i = 0; i < ARRAY_SIZE(iocs->iocsc); i++)
+ if (iocs->iocsc[i])
+ printf("I/O Command Set Combination[%u]:%"PRIx64"\n", i,
+ (uint64_t)le64_to_cpu(iocs->iocsc[i]));
+}
+
+static void stdout_error_log(struct nvme_error_log_page *err_log, int entries,
+ const char *devname)
+{
+ int i;
+
+ printf("Error Log Entries for device:%s entries:%d\n", devname,
+ entries);
+ printf(".................\n");
+ for (i = 0; i < entries; i++) {
+ __u16 status = le16_to_cpu(err_log[i].status_field) >> 0x1;
+
+ printf(" Entry[%2d] \n", i);
+ printf(".................\n");
+ printf("error_count : %"PRIu64"\n",
+ 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", status,
+ nvme_status_to_string(status, false));
+ 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",
+ le64_to_cpu(err_log[i].lba));
+ printf("nsid : %#x\n", err_log[i].nsid);
+ printf("vs : %d\n", err_log[i].vs);
+ printf("trtype : %s\n",
+ nvme_trtype_to_string(err_log[i].trtype));
+ printf("csi : %d\n", err_log[i].csi);
+ printf("opcode : %#x\n", err_log[i].opcode);
+ printf("cs : %#"PRIx64"\n",
+ le64_to_cpu(err_log[i].cs));
+ printf("trtype_spec_info: %#x\n", err_log[i].trtype_spec_info);
+ printf("log_page_version: %d\n", err_log[i].log_page_version);
+ printf(".................\n");
+ }
+}
+
+static void stdout_resv_report(struct nvme_resv_status *status, int bytes,
+ bool eds)
+{
+ int i, j, regctl, entries;
+
+ regctl = status->regctl[0] | (status->regctl[1] << 8);
+
+ printf("\nNVME Reservation status:\n\n");
+ printf("gen : %u\n", le32_to_cpu(status->gen));
+ printf("rtype : %d\n", status->rtype);
+ printf("regctl : %d\n", regctl);
+ printf("ptpls : %d\n", status->ptpls);
+
+ /* check Extended Data Structure bit */
+ if (!eds) {
+ /*
+ * if status buffer was too small, don't loop past the end of
+ * the buffer
+ */
+ entries = (bytes - 24) / 24;
+ if (entries < regctl)
+ regctl = entries;
+
+ for (i = 0; i < regctl; i++) {
+ printf("regctl[%d] :\n", i);
+ printf(" cntlid : %x\n",
+ le16_to_cpu(status->regctl_ds[i].cntlid));
+ printf(" rcsts : %x\n",
+ status->regctl_ds[i].rcsts);
+ printf(" hostid : %"PRIx64"\n",
+ le64_to_cpu(status->regctl_ds[i].hostid));
+ printf(" rkey : %"PRIx64"\n",
+ le64_to_cpu(status->regctl_ds[i].rkey));
+ }
+ } else {
+ /* if status buffer was too small, don't loop past the end of the buffer */
+ entries = (bytes - 64) / 64;
+ if (entries < regctl)
+ regctl = entries;
+
+ for (i = 0; i < regctl; i++) {
+ printf("regctlext[%d] :\n", i);
+ printf(" cntlid : %x\n",
+ le16_to_cpu(status->regctl_eds[i].cntlid));
+ printf(" rcsts : %x\n",
+ status->regctl_eds[i].rcsts);
+ printf(" rkey : %"PRIx64"\n",
+ le64_to_cpu(status->regctl_eds[i].rkey));
+ printf(" hostid : ");
+ for (j = 0; j < 16; j++)
+ printf("%02x",
+ status->regctl_eds[i].hostid[j]);
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
+static void stdout_fw_log(struct nvme_firmware_slot *fw_log,
+ const char *devname)
+{
+ int i;
+ __le64 *frs;
+
+ printf("Firmware Log for device:%s\n", devname);
+ printf("afi : %#x\n", fw_log->afi);
+ for (i = 0; i < 7; i++) {
+ if (fw_log->frs[i][0]) {
+ frs = (__le64 *)&fw_log->frs[i];
+ printf("frs%d : %#016"PRIx64" (%s)\n", i + 1,
+ le64_to_cpu(*frs),
+ util_fw_to_string(fw_log->frs[i]));
+ }
+ }
+}
+
+static void stdout_changed_ns_list_log(struct nvme_ns_list *log,
+ const char *devname)
+{
+ __u32 nsid;
+ int i;
+
+ if (log->ns[0] != cpu_to_le32(NVME_NSID_ALL)) {
+ for (i = 0; i < NVME_ID_NS_LIST_MAX; i++) {
+ nsid = le32_to_cpu(log->ns[i]);
+ if (nsid == 0)
+ break;
+
+ printf("[%4u]:%#x\n", i, nsid);
+ }
+ } else
+ printf("more than %d ns changed\n",
+ NVME_ID_NS_LIST_MAX);
+}
+
+static void stdout_effects_log_human(FILE *stream, __u32 effect)
+{
+ const char *set = "+";
+ const char *clr = "-";
+
+ fprintf(stream, " CSUPP+");
+ fprintf(stream, " LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr);
+ fprintf(stream, " NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr);
+ fprintf(stream, " NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr);
+ fprintf(stream, " CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr);
+ fprintf(stream, " USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr);
+
+ if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0)
+ fprintf(stream, " No command restriction\n");
+ else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 1)
+ fprintf(stream, " No other command for same namespace\n");
+ else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 2)
+ fprintf(stream, " No other command for any namespace\n");
+ else
+ fprintf(stream, " Reserved CSE\n");
+}
+
+static void stdout_effects_entry(FILE* stream, int admin, int index,
+ __le32 entry, unsigned int human)
+{
+ __u32 effect;
+ char *format_string;
+
+ format_string = admin ? "ACS%-6d[%-32s] %08x" : "IOCS%-5d[%-32s] %08x";
+
+ effect = le32_to_cpu(entry);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ fprintf(stream, format_string, index, nvme_cmd_to_string(admin, index),
+ effect);
+ if (human)
+ stdout_effects_log_human(stream, effect);
+ else
+ fprintf(stream, "\n");
+ }
+}
+
+static void stdout_effects_log_segment(int admin, int a, int b,
+ struct nvme_cmd_effects_log *effects,
+ char* header, int human)
+{
+ FILE *stream;
+ char *stream_location;
+ size_t stream_size;
+
+ stream = open_memstream(&stream_location, &stream_size);
+ if (!stream) {
+ perror("Failed to open stream");
+ return;
+ }
+
+ for (int i = a; i < b; i++) {
+ if (admin) {
+ stdout_effects_entry(stream, admin, i, effects->acs[i], human);
+ }
+ else {
+ stdout_effects_entry(stream, admin, i,
+ effects->iocs[i], human);
+ }
+ }
+
+ fclose(stream);
+
+ if (stream_size && header) {
+ printf("%s\n", header);
+ fwrite(stream_location, stream_size, 1, stdout);
+ printf("\n");
+ }
+
+ free(stream_location);
+}
+
+static void stdout_effects_log_page(enum nvme_csi csi,
+ struct nvme_cmd_effects_log *effects)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+
+ switch (csi) {
+ case NVME_CSI_NVM:
+ printf("NVM Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ case NVME_CSI_ZNS:
+ printf("ZNS Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ default:
+ printf("Unknown Command Set Log Page\n");
+ printf("%-.80s\n", dash);
+ break;
+ }
+
+ stdout_effects_log_segment(1, 0, 0xbf, effects, "Admin Commands", human);
+ stdout_effects_log_segment(1, 0xc0, 0xff, effects, "Vendor Specific Admin Commands", human);
+ stdout_effects_log_segment(0, 0, 0x80, effects, "I/O Commands", human);
+ stdout_effects_log_segment(0, 0x80, 0x100, effects, "Vendor Specific I/O Commands", human);
+}
+
+static void stdout_effects_log_pages(struct list_head *list)
+{
+ nvme_effects_log_node_t *node;
+
+ list_for_each(list, node, node) {
+ stdout_effects_log_page(node->csi, &node->effects);
+ }
+}
+
+static void stdout_support_log_human(__u32 support, __u8 lid)
+{
+ const char *set = "supported";
+ const char *clr = "not supported";
+
+ printf(" LSUPP is %s\n", (support & 0x1) ? set : clr);
+ printf(" IOS is %s\n", ((support >> 0x1) & 0x1) ? set : clr);
+ if (lid == NVME_LOG_LID_PERSISTENT_EVENT) {
+ printf(" Establish Context and Read 512 Bytes of Header is %s\n",
+ ((support >> 0x16) & 0x1) ? set : clr);
+ }
+}
+
+static void stdout_supported_log(struct nvme_supported_log_pages *support_log,
+ const char *devname)
+{
+ int lid, human = stdout_print_ops.flags& VERBOSE;
+ __u32 support = 0;
+
+ printf("Support Log Pages Details for %s:\n", devname);
+ for (lid = 0; lid < 256; lid++) {
+ support = le32_to_cpu(support_log->lid_support[lid]);
+ if (support & 0x1) {
+ printf("LID 0x%x - %s\n", lid, nvme_log_to_string(lid));
+ if (human)
+ stdout_support_log_human(support, lid);
+ }
+ }
+}
+
+static void stdout_endurance_log(struct nvme_endurance_group_log *endurance_log, __u16 group_id,
+ const char *devname)
+{
+ printf("Endurance Group Log for NVME device:%s Group ID:%x\n", devname, group_id);
+ printf("critical_warning : %u\n", endurance_log->critical_warning);
+ printf("endurance_group_features: %u\n", endurance_log->endurance_group_features);
+ printf("avl_spare : %u\n", endurance_log->avl_spare);
+ printf("avl_spare_threshold : %u\n", endurance_log->avl_spare_threshold);
+ printf("percent_used : %u%%\n", endurance_log->percent_used);
+ printf("domain_identifier : %u\n", endurance_log->domain_identifier);
+ printf("endurance_estimate : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->endurance_estimate)));
+ printf("data_units_read : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_read)));
+ printf("data_units_written : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->data_units_written)));
+ printf("media_units_written : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_units_written)));
+ printf("host_read_cmds : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_read_cmds)));
+ printf("host_write_cmds : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->host_write_cmds)));
+ printf("media_data_integrity_err: %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->media_data_integrity_err)));
+ printf("num_err_info_log_entries: %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->num_err_info_log_entries)));
+ printf("total_end_grp_cap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->total_end_grp_cap)));
+ printf("unalloc_end_grp_cap : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(endurance_log->unalloc_end_grp_cap)));
+}
+
+static void stdout_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ const char *devname)
+{
+ __u16 temperature = smart->temperature[1] << 8 | smart->temperature[0];
+ int i;
+ bool human = stdout_print_ops.flags & VERBOSE;
+
+ printf("Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
+ printf("critical_warning : %#x\n",
+ smart->critical_warning);
+
+ if (human) {
+ printf(" Available Spare[0] : %d\n", smart->critical_warning & 0x01);
+ printf(" Temp. Threshold[1] : %d\n", (smart->critical_warning & 0x02) >> 1);
+ printf(" NVM subsystem Reliability[2] : %d\n", (smart->critical_warning & 0x04) >> 2);
+ printf(" Read-only[3] : %d\n", (smart->critical_warning & 0x08) >> 3);
+ printf(" Volatile mem. backup failed[4] : %d\n", (smart->critical_warning & 0x10) >> 4);
+ printf(" Persistent Mem. RO[5] : %d\n", (smart->critical_warning & 0x20) >> 5);
+ }
+
+ printf("temperature : %ld °C (%u K)\n",
+ kelvin_to_celsius(temperature), temperature);
+ printf("available_spare : %u%%\n",
+ smart->avail_spare);
+ printf("available_spare_threshold : %u%%\n",
+ smart->spare_thresh);
+ printf("percentage_used : %u%%\n",
+ smart->percent_used);
+ printf("endurance group critical warning summary: %#x\n",
+ smart->endu_grp_crit_warn_sumry);
+ printf("Data Units Read : %s (%s)\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->data_units_read)),
+ uint128_t_to_si_string(le128_to_cpu(smart->data_units_read),
+ 1000 * 512));
+ printf("Data Units Written : %s (%s)\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->data_units_written)),
+ uint128_t_to_si_string(le128_to_cpu(smart->data_units_written),
+ 1000 * 512));
+ printf("host_read_commands : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->host_reads)));
+ printf("host_write_commands : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->host_writes)));
+ printf("controller_busy_time : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->ctrl_busy_time)));
+ printf("power_cycles : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->power_cycles)));
+ printf("power_on_hours : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->power_on_hours)));
+ printf("unsafe_shutdowns : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->unsafe_shutdowns)));
+ printf("media_errors : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->media_errors)));
+ printf("num_err_log_entries : %s\n",
+ uint128_t_to_l10n_string(le128_to_cpu(smart->num_err_log_entries)));
+ printf("Warning Temperature Time : %u\n",
+ le32_to_cpu(smart->warning_temp_time));
+ printf("Critical Composite Temperature Time : %u\n",
+ le32_to_cpu(smart->critical_comp_time));
+ for (i = 0; i < 8; i++) {
+ __s32 temp = le16_to_cpu(smart->temp_sensor[i]);
+
+ if (temp == 0)
+ continue;
+ printf("Temperature Sensor %d : %ld °C (%u K)\n",
+ i + 1, kelvin_to_celsius(temp), temp);
+ }
+ printf("Thermal Management T1 Trans Count : %u\n",
+ le32_to_cpu(smart->thm_temp1_trans_count));
+ printf("Thermal Management T2 Trans Count : %u\n",
+ le32_to_cpu(smart->thm_temp2_trans_count));
+ printf("Thermal Management T1 Total Time : %u\n",
+ le32_to_cpu(smart->thm_temp1_total_time));
+ printf("Thermal Management T2 Total Time : %u\n",
+ le32_to_cpu(smart->thm_temp2_total_time));
+}
+
+static void stdout_ana_log(struct nvme_ana_log *ana_log, const char *devname,
+ size_t len)
+{
+ int offset = sizeof(struct nvme_ana_log);
+ struct nvme_ana_log *hdr = ana_log;
+ struct nvme_ana_group_desc *desc;
+ size_t nsid_buf_size;
+ void *base = ana_log;
+ __u32 nr_nsids;
+ int i, j;
+
+ printf("Asymmetric Namespace Access Log for NVMe device: %s\n",
+ devname);
+ printf("ANA LOG HEADER :-\n");
+ printf("chgcnt : %"PRIu64"\n",
+ le64_to_cpu(hdr->chgcnt));
+ printf("ngrps : %u\n", le16_to_cpu(hdr->ngrps));
+ printf("ANA Log Desc :-\n");
+
+ for (i = 0; i < le16_to_cpu(ana_log->ngrps); i++) {
+ desc = base + offset;
+ nr_nsids = le32_to_cpu(desc->nnsids);
+ nsid_buf_size = nr_nsids * sizeof(__le32);
+
+ offset += sizeof(*desc);
+ printf("grpid : %u\n", le32_to_cpu(desc->grpid));
+ printf("nnsids : %u\n", le32_to_cpu(desc->nnsids));
+ printf("chgcnt : %"PRIu64"\n",
+ le64_to_cpu(desc->chgcnt));
+ printf("state : %s\n",
+ nvme_ana_state_to_string(desc->state));
+ for (j = 0; j < le32_to_cpu(desc->nnsids); j++)
+ printf(" nsid : %u\n",
+ le32_to_cpu(desc->nsids[j]));
+ printf("\n");
+ offset += nsid_buf_size;
+ }
+}
+
+static void stdout_self_test_result(struct nvme_st_result *res)
+{
+ static const char *const test_res[] = {
+ "Operation completed without error",
+ "Operation was aborted by a Device Self-test command",
+ "Operation was aborted by a Controller Level Reset",
+ "Operation was aborted due to a removal of a namespace from the namespace inventory",
+ "Operation was aborted due to the processing of a Format NVM command",
+ "A fatal error or unknown test error occurred while the controller was executing the"\
+ " device self-test operation and the operation did not complete",
+ "Operation completed with a segment that failed and the segment that failed is not known",
+ "Operation completed with one or more failed segments and the first segment that failed "\
+ "is indicated in the SegmentNumber field",
+ "Operation was aborted for unknown reason",
+ "Operation was aborted due to a sanitize operation",
+ "Reserved",
+ [NVME_ST_RESULT_NOT_USED] = "Entry not used (does not contain a result)",
+ };
+ __u8 op, code;
+
+ op = res->dsts & NVME_ST_RESULT_MASK;
+ printf(" Operation Result : %#x", op);
+ if (stdout_print_ops.flags & VERBOSE)
+ printf(" %s", (op < ARRAY_SIZE(test_res) && test_res[op]) ?
+ test_res[op] : test_res[ARRAY_SIZE(test_res) - 1]);
+ printf("\n");
+ if (op == NVME_ST_RESULT_NOT_USED)
+ return;
+
+ code = res->dsts >> NVME_ST_CODE_SHIFT;
+ printf(" Self Test Code : %x", code);
+
+ if (stdout_print_ops.flags & VERBOSE) {
+ switch (code) {
+ case NVME_ST_CODE_SHORT:
+ printf(" Short device self-test operation");
+ break;
+ case NVME_ST_CODE_EXTENDED:
+ printf(" Extended device self-test operation");
+ break;
+ case NVME_ST_CODE_VS:
+ printf(" Vendor specific");
+ break;
+ default:
+ printf(" Reserved");
+ break;
+ }
+ }
+ printf("\n");
+
+ if (op == NVME_ST_RESULT_KNOWN_SEG_FAIL)
+ printf(" Segment Number : %#x\n", res->seg);
+
+ printf(" Valid Diagnostic Information : %#x\n", res->vdi);
+ printf(" Power on hours (POH) : %#"PRIx64"\n",
+ (uint64_t)le64_to_cpu(res->poh));
+
+ if (res->vdi & NVME_ST_VALID_DIAG_INFO_NSID)
+ printf(" Namespace Identifier : %#x\n",
+ le32_to_cpu(res->nsid));
+ if (res->vdi & NVME_ST_VALID_DIAG_INFO_FLBA)
+ printf(" Failing LBA : %#"PRIx64"\n",
+ (uint64_t)le64_to_cpu(res->flba));
+ if (res->vdi & NVME_ST_VALID_DIAG_INFO_SCT)
+ printf(" Status Code Type : %#x\n", res->sct);
+ if (res->vdi & NVME_ST_VALID_DIAG_INFO_SC) {
+ printf(" Status Code : %#x", res->sc);
+ if (stdout_print_ops.flags & VERBOSE)
+ printf(" %s", nvme_status_to_string(
+ (res->sct & 7) << 8 | res->sc, false));
+ printf("\n");
+ }
+ printf(" Vendor Specific : %#x %#x\n",
+ res->vs[0], res->vs[1]);
+}
+
+static void stdout_self_test_log(struct nvme_self_test_log *self_test,
+ __u8 dst_entries, __u32 size,
+ const char *devname)
+{
+ int i;
+ __u8 num_entries;
+
+ printf("Device Self Test Log for NVME device:%s\n", devname);
+ printf("Current operation : %#x\n", self_test->current_operation);
+ printf("Current Completion : %u%%\n", self_test->completion);
+ num_entries = min(dst_entries, NVME_LOG_ST_MAX_RESULTS);
+ for (i = 0; i < num_entries; i++) {
+ printf("Self Test Result[%d]:\n", i);
+ stdout_self_test_result(&self_test->result[i]);
+ }
+}
+
+static void stdout_sanitize_log_sprog(__u32 sprog)
+{
+ double percent;
+
+ percent = (((double)sprog * 100) / 0x10000);
+ printf("\t(%f%%)\n", percent);
+}
+
+static void stdout_sanitize_log_sstat(__u16 status)
+{
+ const char *str = nvme_sstat_status_to_string(status);
+
+ printf("\t[2:0]\t%s\n", str);
+ str = "Number of completed passes if most recent operation was overwrite";
+ printf("\t[7:3]\t%s:\t%u\n", str,
+ (status >> NVME_SANITIZE_SSTAT_COMPLETED_PASSES_SHIFT) &
+ NVME_SANITIZE_SSTAT_COMPLETED_PASSES_MASK);
+
+ printf("\t [8]\t");
+ if (status & NVME_SANITIZE_SSTAT_GLOBAL_DATA_ERASED)
+ str = "Global Data Erased set: no NS LB in the NVM subsystem "\
+ "has been written to and no PMR in the NVM subsystem "\
+ "has been enabled";
+ else
+ str = "Global Data Erased cleared: a NS LB in the NVM "\
+ "subsystem has been written to or a PMR in the NVM "\
+ "subsystem has been enabled";
+ printf("%s\n", str);
+}
+
+static void stdout_estimate_sanitize_time(const char *text, uint32_t value)
+{
+ printf("%s: %u%s\n", text, value,
+ value == 0xffffffff ? " (No time period reported)" : "");
+}
+
+static void stdout_sanitize_log(struct nvme_sanitize_log_page *sanitize,
+ const char *devname)
+{
+ int human = stdout_print_ops.flags & VERBOSE;
+ __u16 status = le16_to_cpu(sanitize->sstat) & NVME_SANITIZE_SSTAT_STATUS_MASK;
+
+ printf("Sanitize Progress (SPROG) : %u",
+ le16_to_cpu(sanitize->sprog));
+
+ if (human && status == NVME_SANITIZE_SSTAT_STATUS_IN_PROGESS)
+ stdout_sanitize_log_sprog(le16_to_cpu(sanitize->sprog));
+ else
+ printf("\n");
+
+ printf("Sanitize Status (SSTAT) : %#x\n",
+ le16_to_cpu(sanitize->sstat));
+ if (human)
+ stdout_sanitize_log_sstat(le16_to_cpu(sanitize->sstat));
+
+ printf("Sanitize Command Dword 10 Information (SCDW10) : %#x\n",
+ le32_to_cpu(sanitize->scdw10));
+ stdout_estimate_sanitize_time("Estimated Time For Overwrite ",
+ le32_to_cpu(sanitize->eto));
+ stdout_estimate_sanitize_time("Estimated Time For Block Erase ",
+ le32_to_cpu(sanitize->etbe));
+ stdout_estimate_sanitize_time("Estimated Time For Crypto Erase ",
+ le32_to_cpu(sanitize->etce));
+ stdout_estimate_sanitize_time("Estimated Time For Overwrite (No-Deallocate) ",
+ le32_to_cpu(sanitize->etond));
+ stdout_estimate_sanitize_time("Estimated Time For Block Erase (No-Deallocate) ",
+ le32_to_cpu(sanitize->etbend));
+ stdout_estimate_sanitize_time("Estimated Time For Crypto Erase (No-Deallocate)",
+ le32_to_cpu(sanitize->etcend));
+}
+
+static void stdout_select_result(enum nvme_features_id fid, __u32 result)
+{
+ if (result & 0x1)
+ printf(" Feature is saveable\n");
+ if (result & 0x2)
+ printf(" Feature is per-namespace\n");
+ if (result & 0x4)
+ printf(" Feature is changeable\n");
+}
+
+static void stdout_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges)
+{
+ int i, j;
+
+ for (i = 0; i <= nr_ranges; i++) {
+ printf("\ttype : %#x - %s\n", lbrt->entry[i].type,
+ nvme_feature_lba_type_to_string(lbrt->entry[i].type));
+ printf("\tattributes : %#x - %s, %s\n", lbrt->entry[i].attributes,
+ (lbrt->entry[i].attributes & 0x0001) ?
+ "LBA range may be overwritten" :
+ "LBA range should not be overwritten",
+ ((lbrt->entry[i].attributes & 0x0002) >> 1) ?
+ "LBA range should be hidden from the OS/EFI/BIOS" :
+ "LBA range should be visible from the OS/EFI/BIOS");
+ printf("\tslba : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].slba));
+ printf("\tnlb : %#"PRIx64"\n", le64_to_cpu(lbrt->entry[i].nlb));
+ printf("\tguid : ");
+ for (j = 0; j < ARRAY_SIZE(lbrt->entry[i].guid); j++)
+ printf("%02x", lbrt->entry[i].guid[j]);
+ printf("\n");
+ }
+}
+
+static void stdout_auto_pst(struct nvme_feat_auto_pst *apst)
+{
+ int i;
+ __u64 value;
+
+ printf( "\tAuto PST Entries");
+ printf("\t.................\n");
+ for (i = 0; i < ARRAY_SIZE(apst->apst_entry); i++) {
+ value = le64_to_cpu(apst->apst_entry[i]);
+
+ printf("\tEntry[%2d] \n", i);
+ printf("\t.................\n");
+ printf("\tIdle Time Prior to Transition (ITPT): %u ms\n",
+ (__u32)NVME_GET(value, APST_ENTRY_ITPT));
+ printf("\tIdle Transition Power State (ITPS): %u\n",
+ (__u32)NVME_GET(value, APST_ENTRY_ITPS));
+ printf("\t.................\n");
+ }
+}
+
+static void stdout_timestamp(struct nvme_timestamp *ts)
+{
+ struct tm *tm;
+ char buffer[320];
+ time_t timestamp = int48_to_long(ts->timestamp) / 1000;
+
+ tm = localtime(&timestamp);
+
+ printf("\tThe timestamp is : %'"PRIu64" (%s)\n",
+ int48_to_long(ts->timestamp),
+ strftime(buffer, sizeof(buffer), "%c %Z", tm) ? buffer : "-");
+ printf("\t%s\n", (ts->attr & 2) ?
+ "The Timestamp field was initialized with a "\
+ "Timestamp value using a Set Features command." :
+ "The Timestamp field was initialized "\
+ "to ‘0’ by a Controller Level Reset.");
+ printf("\t%s\n", (ts->attr & 1) ?
+ "The controller may have stopped counting during vendor specific "\
+ "intervals after the Timestamp value was initialized" :
+ "The controller counted time in milliseconds "\
+ "continuously since the Timestamp value was initialized.");
+}
+
+static void stdout_host_mem_buffer(struct nvme_host_mem_buf_attrs *hmb)
+{
+ printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n",
+ le32_to_cpu(hmb->hmdlec));
+ printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n",
+ le32_to_cpu(hmb->hmdlau));
+ printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n",
+ le32_to_cpu(hmb->hmdlal));
+ printf("\tHost Memory Buffer Size (HSIZE): %u\n",
+ le32_to_cpu(hmb->hsize));
+}
+
+static void stdout_directive_show_fields(__u8 dtype, __u8 doper,
+ unsigned int result, unsigned char *buf)
+{
+ __u8 *field = buf;
+ int count, i;
+
+ switch (dtype) {
+ case NVME_DIRECTIVE_DTYPE_IDENTIFY:
+ switch (doper) {
+ case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM:
+ printf("\tDirective support \n");
+ printf("\t\tIdentify Directive : %s\n",
+ (*field & 0x1) ? "supported" : "not supported");
+ printf("\t\tStream Directive : %s\n",
+ (*field & 0x2) ? "supported" : "not supported");
+ printf("\t\tData Placement Directive : %s\n",
+ (*field & 0x4) ? "supported" : "not supported");
+ printf("\tDirective enabled \n");
+ printf("\t\tIdentify Directive : %s\n",
+ (*(field + 32) & 0x1) ? "enabled" : "disabled");
+ printf("\t\tStream Directive : %s\n",
+ (*(field + 32) & 0x2) ? "enabled" : "disabled");
+ printf("\t\tData Placement Directive : %s\n",
+ (*(field + 32) & 0x4) ? "enabled" : "disabled");
+ printf("\tDirective Persistent Across Controller Level Resets \n");
+ printf("\t\tIdentify Directive : %s\n",
+ (*(field + 64) & 0x1) ? "enabled" : "disabled");
+ printf("\t\tStream Directive : %s\n",
+ (*(field + 64) & 0x2) ? "enabled" : "disabled");
+ printf("\t\tData Placement Directive : %s\n",
+ (*(field + 64) & 0x4) ? "enabled" : "disabled");
+ break;
+ default:
+ fprintf(stderr,
+ "invalid directive operations for Identify Directives\n");
+ break;
+ }
+ break;
+ case NVME_DIRECTIVE_DTYPE_STREAMS:
+ switch (doper) {
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM:
+ printf("\tMax Streams Limit (MSL): %u\n",
+ *(__u16 *)field);
+ printf("\tNVM Subsystem Streams Available (NSSA): %u\n",
+ *(__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",
+ *(__u16 *)(field + 20));
+ printf("\tNamespace Streams Allocated (NSA): %u\n",
+ *(__u16 *)(field + 22));
+ printf("\tNamespace Streams Open (NSO): %u\n",
+ *(__u16 *)(field + 24));
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS:
+ count = *(__u16 *)field;
+ printf("\tOpen Stream Count : %u\n", *(__u16 *)field);
+ for (i = 0; i < count; i++)
+ printf("\tStream Identifier %.6u : %u\n", i + 1,
+ *(__u16 *)(field + ((i + 1) * 2)));
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE:
+ printf("\tNamespace Streams Allocated (NSA): %u\n",
+ result & 0xffff);
+ break;
+ default:
+ fprintf(stderr,
+ "invalid directive operations for Streams Directives\n");
+ break;
+ }
+ break;
+ default:
+ fprintf(stderr, "invalid directive type\n");
+ break;
+ }
+}
+
+static void stdout_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len)
+{
+ printf("dir-receive: type:%#x operation:%#x spec:%#x nsid:%#x result:%#x\n",
+ type, oper, spec, nsid, result);
+ if (stdout_print_ops.flags & VERBOSE)
+ stdout_directive_show_fields(type, oper, result, buf);
+ else if (buf)
+ d(buf, len, 16, 1);
+}
+
+static void stdout_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);
+}
+
+void stdout_d(unsigned char *buf, int len, int width, int group)
+{
+ int i, offset = 0;
+ char ascii[32 + 1] = { 0 };
+
+ assert(width < sizeof(ascii));
+
+ printf(" ");
+
+ for (i = 0; i <= 15; i++)
+ printf("%3x", i);
+
+ for (i = 0; i < len; i++) {
+ if (!(i % width))
+ printf( "\n%04x:", offset);
+ if (i % group)
+ printf( "%02x", buf[i]);
+ else
+ printf( " %02x", buf[i]);
+ ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.';
+ if (!((i + 1) % width)) {
+ printf( " \"%.*s\"", width, ascii);
+ offset += width;
+ memset(ascii, 0, sizeof(ascii));
+ }
+ }
+
+ if (strlen(ascii)) {
+ unsigned b = width - (i % width);
+ printf( " %*s \"%.*s\"", 2 * b + b / group + (b % group ? 1 : 0), "", width, ascii);
+ }
+
+ printf( "\n");
+}
+
+static void stdout_plm_config(struct nvme_plm_config *plmcfg)
+{
+ printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->ee));
+ printf("\tDTWIN Reads Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinrt));
+ printf("\tDTWIN Writes Threshold:%"PRIu64"\n", le64_to_cpu(plmcfg->dtwinwt));
+ printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwintt));
+}
+
+static void stdout_host_metadata(enum nvme_features_id fid,
+ struct nvme_host_metadata *data)
+{
+ struct nvme_metadata_element_desc *desc = &data->descs[0];
+ int i;
+ char val[4096];
+ __u16 len;
+
+ printf("\tNum Metadata Element Descriptors: %d\n", data->ndesc);
+ for (i = 0; i < data->ndesc; i++) {
+ len = le16_to_cpu(desc->len);
+ strncpy(val, (char *)desc->val, min(sizeof(val) - 1, len));
+
+ printf("\tElement[%-3d]:\n", i);
+ printf("\t\tType : 0x%02x (%s)\n", desc->type,
+ nvme_host_metadata_type_to_string(fid, desc->type));
+ printf("\t\tRevision : %d\n", desc->rev);
+ printf("\t\tLength : %d\n", len);
+ printf("\t\tValue : %s\n", val);
+
+ desc = (struct nvme_metadata_element_desc *)&desc->val[desc->len];
+ }
+}
+
+static void stdout_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
+{
+ printf("get-feature:%#0*x (%s), %s value:%#0*x\n", fid ? 4 : 2, fid,
+ nvme_feature_to_string(fid), nvme_select_to_string(sel), result ? 10 : 8, result);
+}
+
+static void stdout_feature_show_fields(enum nvme_features_id fid,
+ unsigned int result,
+ unsigned char *buf)
+{
+ __u8 field;
+ uint64_t ull;
+
+ switch (fid) {
+ case NVME_FEAT_FID_ARBITRATION:
+ printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1);
+ printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1);
+ printf("\tLow Priority Weight (LPW): %u\n", ((result & 0x0000ff00) >> 8) + 1);
+ printf("\tArbitration Burst (AB): ");
+ if ((result & 0x00000007) == 7)
+ printf("No limit\n");
+ else
+ printf("%u\n", 1 << (result & 0x00000007));
+ break;
+ case NVME_FEAT_FID_POWER_MGMT:
+ field = (result & 0x000000E0) >> 5;
+ printf("\tWorkload Hint (WH): %u - %s\n", field, nvme_feature_wl_hints_to_string(field));
+ printf("\tPower State (PS): %u\n", result & 0x0000001f);
+ break;
+ case NVME_FEAT_FID_LBA_RANGE:
+ field = result & 0x0000003f;
+ printf("\tNumber of LBA Ranges (NUM): %u\n", field + 1);
+ if (buf)
+ stdout_lba_range((struct nvme_lba_range_type *)buf, field);
+ break;
+ case NVME_FEAT_FID_TEMP_THRESH:
+ field = (result & 0x00300000) >> 20;
+ printf("\tThreshold Type Select (THSEL): %u - %s\n", field,
+ nvme_feature_temp_type_to_string(field));
+ field = (result & 0x000f0000) >> 16;
+ printf("\tThreshold Temperature Select (TMPSEL): %u - %s\n",
+ field, nvme_feature_temp_sel_to_string(field));
+ printf("\tTemperature Threshold (TMPTH): %ld °C (%u K)\n",
+ kelvin_to_celsius(result & 0x0000ffff), result & 0x0000ffff);
+ break;
+ case NVME_FEAT_FID_ERR_RECOVERY:
+ printf("\tDeallocated or Unwritten Logical Block Error Enable (DULBE): %s\n",
+ ((result & 0x00010000) >> 16) ? "Enabled" : "Disabled");
+ printf("\tTime Limited Error Recovery (TLER): %u ms\n",
+ (result & 0x0000ffff) * 100);
+ break;
+ case NVME_FEAT_FID_VOLATILE_WC:
+ printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled");
+ break;
+ case NVME_FEAT_FID_NUM_QUEUES:
+ printf("\tNumber of IO Completion Queues Allocated (NCQA): %u\n", ((result & 0xffff0000) >> 16) + 1);
+ printf("\tNumber of IO Submission Queues Allocated (NSQA): %u\n", (result & 0x0000ffff) + 1);
+ break;
+ case NVME_FEAT_FID_IRQ_COALESCE:
+ printf("\tAggregation Time (TIME): %u usec\n", ((result & 0x0000ff00) >> 8) * 100);
+ printf("\tAggregation Threshold (THR): %u\n", (result & 0x000000ff) + 1);
+ break;
+ case NVME_FEAT_FID_IRQ_CONFIG:
+ printf("\tCoalescing Disable (CD): %s\n", ((result & 0x00010000) >> 16) ? "True" : "False");
+ printf("\tInterrupt Vector (IV): %u\n", result & 0x0000ffff);
+ break;
+ case NVME_FEAT_FID_WRITE_ATOMIC:
+ printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_ASYNC_EVENT:
+ printf("\tDiscovery Log Page Change Notices : %s\n",
+ ((result & 0x80000000) >> 31) ? "Send async event" : "Do not send async event");
+ printf("\tEndurance Group Event Aggregate Log Change Notices : %s\n",
+ ((result & 0x00004000) >> 14) ? "Send async event" : "Do not send async event");
+ printf("\tLBA Status Information Notices : %s\n",
+ ((result & 0x00002000) >> 13) ? "Send async event" : "Do not send async event");
+ printf("\tPredictable Latency Event Aggregate Log Change Notices : %s\n",
+ ((result & 0x00001000) >> 12) ? "Send async event" : "Do not send async event");
+ 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");
+ printf("\tSMART / Health Critical Warnings : %s\n",
+ (result & 0x000000ff) ? "Send async event" : "Do not send async event");
+ break;
+ case NVME_FEAT_FID_AUTO_PST:
+ printf("\tAutonomous Power State Transition Enable (APSTE): %s\n",
+ (result & 0x00000001) ? "Enabled" : "Disabled");
+ if (buf)
+ stdout_auto_pst((struct nvme_feat_auto_pst *)buf);
+ break;
+ case NVME_FEAT_FID_HOST_MEM_BUF:
+ printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled" : "Disabled");
+ if (buf)
+ stdout_host_mem_buffer((struct nvme_host_mem_buf_attrs *)buf);
+ break;
+ case NVME_FEAT_FID_TIMESTAMP:
+ if (buf)
+ stdout_timestamp((struct nvme_timestamp *)buf);
+ break;
+ case NVME_FEAT_FID_KATO:
+ printf("\tKeep Alive Timeout (KATO) in milliseconds: %u\n", result);
+ break;
+ case NVME_FEAT_FID_HCTM:
+ printf("\tThermal Management Temperature 1 (TMT1) : %u K (%ld °C)\n",
+ result >> 16, kelvin_to_celsius(result >> 16));
+ printf("\tThermal Management Temperature 2 (TMT2) : %u K (%ld °C)\n",
+ result & 0x0000ffff, kelvin_to_celsius(result & 0x0000ffff));
+ break;
+ case NVME_FEAT_FID_NOPSC:
+ printf("\tNon-Operational Power State Permissive Mode Enable (NOPPME): %s\n",
+ (result & 1) ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_RRL:
+ printf("\tRead Recovery Level (RRL): %u\n", result & 0xf);
+ break;
+ case NVME_FEAT_FID_PLM_CONFIG:
+ printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True" : "False");
+ if (buf)
+ stdout_plm_config((struct nvme_plm_config *)buf);
+ break;
+ case NVME_FEAT_FID_PLM_WINDOW:
+ printf("\tWindow Select: %s", nvme_plm_window_to_string(result));
+ break;
+ case NVME_FEAT_FID_LBA_STS_INTERVAL:
+ stdout_lba_status_info(result);
+ break;
+ case NVME_FEAT_FID_HOST_BEHAVIOR:
+ if (buf) {
+ struct nvme_feat_host_behavior *host_behavior =
+ (struct nvme_feat_host_behavior *)buf;
+ printf("\tAdvanced Command Retry Enable (ACRE): %s\n",
+ host_behavior->acre ? "True" : "False");
+ printf("\tExtended Telemetry Data Area 4 Supported (ETDAS): %s\n",
+ host_behavior->etdas ? "True" : "False");
+ printf("\tLBA Format Extension Enable (LBAFEE): %s\n",
+ host_behavior->lbafee ? "True" : "False");
+ printf("\tCopy Descriptor Format 2h Enabled (CDFE): %s\n",
+ host_behavior->cdfe & (1 << 2) ? "True" : "False");
+ printf("\tCopy Descriptor Format 3h Enabled (CDFE): %s\n",
+ host_behavior->cdfe & (1 << 3) ? "True" : "False");
+ }
+ break;
+ case NVME_FEAT_FID_SANITIZE:
+ printf("\tNo-Deallocate Response Mode (NODRM) : %u\n", result & 0x1);
+ break;
+ case NVME_FEAT_FID_ENDURANCE_EVT_CFG:
+ printf("\tEndurance Group Identifier (ENDGID): %u\n", result & 0xffff);
+ printf("\tEndurance Group Critical Warnings : %u\n", (result >> 16) & 0xff);
+ break;
+ case NVME_FEAT_FID_IOCS_PROFILE:
+ printf("\tI/O Command Set Profile: %s\n", result & 0x1 ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_SPINUP_CONTROL:
+ printf("\tSpinup control feature Enabled: %s\n", (result & 1) ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_ENH_CTRL_METADATA:
+ fallthrough;
+ case NVME_FEAT_FID_CTRL_METADATA:
+ fallthrough;
+ case NVME_FEAT_FID_NS_METADATA:
+ if (buf)
+ stdout_host_metadata(fid, (struct nvme_host_metadata *)buf);
+ break;
+ case NVME_FEAT_FID_SW_PROGRESS:
+ printf("\tPre-boot Software Load Count (PBSLC): %u\n", result & 0x000000ff);
+ break;
+ case NVME_FEAT_FID_HOST_ID:
+ if (buf) {
+ 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;
+ ull |= buf[1]; ull <<= 8; ull |= buf[0];
+ printf("\tHost Identifier (HOSTID): %" PRIu64 "\n", ull);
+ }
+ break;
+ case NVME_FEAT_FID_RESV_MASK:
+ printf("\tMask Reservation Preempted Notification (RESPRE): %s\n",
+ ((result & 0x00000008) >> 3) ? "True" : "False");
+ printf("\tMask Reservation Released Notification (RESREL): %s\n",
+ ((result & 0x00000004) >> 2) ? "True" : "False");
+ printf("\tMask Registration Preempted Notification (REGPRE): %s\n",
+ ((result & 0x00000002) >> 1) ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_RESV_PERSIST:
+ printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True" : "False");
+ break;
+ case NVME_FEAT_FID_WRITE_PROTECT:
+ printf("\tNamespace Write Protect: %s\n", nvme_ns_wp_cfg_to_string(result));
+ break;
+ case NVME_FEAT_FID_FDP:
+ printf("\tFlexible Direct Placement Enable (FDPE) : %s\n",
+ (result & 0x1) ? "Yes" : "No");
+ printf("\tFlexible Direct Placement Configuration Index : %u\n",
+ (result >> 8) & 0xf);
+ break;
+ case NVME_FEAT_FID_FDP_EVENTS:
+ for (unsigned int i = 0; i < result; i++) {
+ struct nvme_fdp_supported_event_desc *d;
+
+ d = &((struct nvme_fdp_supported_event_desc *)buf)[i];
+
+ printf("\t%-53s: %sEnabled\n", nvme_fdp_event_to_string(d->evt),
+ d->evta & 0x1 ? "" : "Not ");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void stdout_lba_status(struct nvme_lba_status *list,
+ unsigned long len)
+{
+ int idx;
+
+ printf("Number of LBA Status Descriptors(NLSD): %" PRIu32 "\n",
+ le32_to_cpu(list->nlsd));
+ printf("Completion Condition(CMPC): %u\n", list->cmpc);
+
+ switch (list->cmpc) {
+ case 1:
+ printf("\tCompleted due to transferring the amount of data"\
+ " specified in the MNDW field\n");
+ break;
+ case 2:
+ printf("\tCompleted due to having performed the action\n"\
+ "\tspecified in the Action Type field over the\n"\
+ "\tnumber of logical blocks specified in the\n"\
+ "\tRange Length field\n");
+ break;
+ default:
+ break;
+ }
+
+ for (idx = 0; idx < list->nlsd; idx++) {
+ struct nvme_lba_status_desc *e = &list->descs[idx];
+ printf("{ DSLBA: 0x%016"PRIu64", NLB: 0x%08x, Status: 0x%02x }\n",
+ le64_to_cpu(e->dslba), le32_to_cpu(e->nlb),
+ e->status);
+ }
+}
+
+static void stdout_dev_full_path(nvme_ns_t n, char *path, size_t len)
+{
+ struct stat st;
+
+ snprintf(path, len, "/dev/%s", nvme_ns_get_name(n));
+ if (stat(path, &st) == 0)
+ return;
+
+ snprintf(path, len, "/dev/spdk/%s", nvme_ns_get_name(n));
+ if (stat(path, &st) == 0)
+ return;
+
+ /*
+ * We could start trying to search for it but let's make
+ * it simple and just don't show the path at all.
+ */
+ snprintf(path, len, "%s", nvme_ns_get_name(n));
+}
+
+static void stdout_generic_full_path(nvme_ns_t n, char *path, size_t len)
+{
+ int head_instance;
+ int instance;
+ struct stat st;
+
+ sscanf(nvme_ns_get_name(n), "nvme%dn%d", &instance, &head_instance);
+ snprintf(path, len, "/dev/ng%dn%d", instance, head_instance);
+
+ if (stat(path, &st) == 0)
+ return;
+
+ snprintf(path, len, "/dev/spdk/ng%dn%d", instance, head_instance);
+ if (stat(path, &st) == 0)
+ return;
+ /*
+ * We could start trying to search for it but let's make
+ * it simple and just don't show the path at all.
+ */
+ snprintf(path, len, "ng%dn%d", instance, head_instance);
+}
+
+static void stdout_list_item(nvme_ns_t n)
+{
+ char usage[128] = { 0 }, format[128] = { 0 };
+ char devname[128] = { 0 }; char genname[128] = { 0 };
+
+ long long lba = nvme_ns_get_lba_size(n);
+ double nsze = nvme_ns_get_lba_count(n) * lba;
+ double nuse = nvme_ns_get_lba_util(n) * lba;
+
+ const char *s_suffix = suffix_si_get(&nsze);
+ const char *u_suffix = suffix_si_get(&nuse);
+ const char *l_suffix = suffix_binary_get(&lba);
+
+ snprintf(usage, sizeof(usage), "%6.2f %2sB / %6.2f %2sB", nuse,
+ u_suffix, nsze, s_suffix);
+ snprintf(format, sizeof(format), "%3.0f %2sB + %2d B", (double)lba,
+ l_suffix, nvme_ns_get_meta_size(n));
+
+ stdout_dev_full_path(n, devname, sizeof(devname));
+ stdout_generic_full_path(n, genname, sizeof(genname));
+
+ printf("%-21s %-21s %-20s %-40s %#-10x %-26s %-16s %-8s\n",
+ devname, genname, nvme_ns_get_serial(n),
+ nvme_ns_get_model(n), nvme_ns_get_nsid(n), usage, format,
+ nvme_ns_get_firmware(n));
+}
+
+static bool stdout_simple_ns(const char *name, void *arg)
+{
+ struct nvme_resources *res = arg;
+ nvme_ns_t n;
+
+ n = htable_ns_get(&res->ht_n, name);
+ stdout_list_item(n);
+
+ return true;
+}
+
+static void stdout_simple_list(nvme_root_t r)
+{
+ struct nvme_resources res;
+
+ nvme_resources_init(r, &res);
+
+ printf("%-21s %-21s %-20s %-40s %-10s %-26s %-16s %-8s\n",
+ "Node", "Generic", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev");
+ printf("%-.21s %-.21s %-.20s %-.40s %-.10s %-.26s %-.16s %-.8s\n",
+ dash, dash, dash, dash, dash, dash, dash, dash);
+ strset_iterate(&res.namespaces, stdout_simple_ns, &res);
+
+ nvme_resources_free(&res);
+}
+
+static void stdout_ns_details(nvme_ns_t n)
+{
+ char usage[128] = { 0 }, format[128] = { 0 };
+ char devname[128] = { 0 }, genname[128] = { 0 };
+
+ long long lba = nvme_ns_get_lba_size(n);
+ double nsze = nvme_ns_get_lba_count(n) * lba;
+ double nuse = nvme_ns_get_lba_util(n) * lba;
+
+ const char *s_suffix = suffix_si_get(&nsze);
+ const char *u_suffix = suffix_si_get(&nuse);
+ const char *l_suffix = suffix_binary_get(&lba);
+
+ 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,
+ nvme_ns_get_meta_size(n));
+
+ nvme_dev_full_path(n, devname, sizeof(devname));
+ nvme_generic_full_path(n, genname, sizeof(genname));
+
+ printf("%-12s %-12s %#-10x %-26s %-16s ", devname,
+ genname, nvme_ns_get_nsid(n), usage, format);
+}
+
+static bool stdout_detailed_name(const char *name, void *arg)
+{
+ bool *first = arg;
+
+ printf("%s%s", *first ? "" : ", ", name);
+ *first = false;
+
+ return true;
+}
+
+static bool stdout_detailed_subsys(const char *name, void *arg)
+{
+ struct nvme_resources *res = arg;
+ struct htable_subsys_iter it;
+ struct strset ctrls;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ bool first;
+
+ strset_init(&ctrls);
+ first = true;
+ for (s = htable_subsys_getfirst(&res->ht_s, name, &it);
+ s;
+ s = htable_subsys_getnext(&res->ht_s, name, &it)) {
+ if (first) {
+ printf("%-16s %-96s ", name, nvme_subsystem_get_nqn(s));
+ first = false;
+ }
+
+ nvme_subsystem_for_each_ctrl(s, c)
+ strset_add(&ctrls, nvme_ctrl_get_name(c));
+ }
+
+ first = true;
+ strset_iterate(&ctrls, stdout_detailed_name, &first);
+ strset_clear(&ctrls);
+ printf("\n");
+
+ return true;
+}
+
+static bool stdout_detailed_ctrl(const char *name, void *arg)
+{
+ struct nvme_resources *res = arg;
+ struct strset namespaces;
+ nvme_ctrl_t c;
+ nvme_path_t p;
+ nvme_ns_t n;
+ bool first;
+
+ c = htable_ctrl_get(&res->ht_c, name);
+ assert(c);
+
+ printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s ",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_serial(c),
+ nvme_ctrl_get_model(c),
+ nvme_ctrl_get_firmware(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_phy_slot(c),
+ nvme_subsystem_get_name(nvme_ctrl_get_subsystem(c)));
+
+ strset_init(&namespaces);
+
+ nvme_ctrl_for_each_ns(c, n)
+ strset_add(&namespaces, nvme_ns_get_name(n));
+ nvme_ctrl_for_each_path(c, p) {
+ n = nvme_path_get_ns(p);
+ if (!n)
+ continue;
+ strset_add(&namespaces, nvme_ns_get_name(n));
+ }
+
+ first = true;
+ strset_iterate(&namespaces, stdout_detailed_name, &first);
+ strset_clear(&namespaces);
+
+ printf("\n");
+
+ return true;
+}
+
+static bool stdout_detailed_ns(const char *name, void *arg)
+{
+ struct nvme_resources *res = arg;
+ struct htable_ns_iter it;
+ struct strset ctrls;
+ nvme_ctrl_t c;
+ nvme_path_t p;
+ nvme_ns_t n;
+ bool first;
+
+ strset_init(&ctrls);
+ first = true;
+ for (n = htable_ns_getfirst(&res->ht_n, name, &it);
+ n;
+ n = htable_ns_getnext(&res->ht_n, name, &it)) {
+ if (first) {
+ stdout_ns_details(n);
+ first = false;
+ }
+
+ if (nvme_ns_get_ctrl(n)) {
+ printf("%s\n", nvme_ctrl_get_name(nvme_ns_get_ctrl(n)));
+ return true;
+ }
+
+ nvme_namespace_for_each_path(n, p) {
+ c = nvme_path_get_ctrl(p);
+ strset_add(&ctrls, nvme_ctrl_get_name(c));
+ }
+ }
+
+ first = true;
+ strset_iterate(&ctrls, stdout_detailed_name, &first);
+ strset_clear(&ctrls);
+
+ printf("\n");
+ return true;
+}
+
+static void stdout_detailed_list(nvme_root_t r)
+{
+ struct nvme_resources res;
+
+ nvme_resources_init(r, &res);
+
+ printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers");
+ printf("%-.16s %-.96s %-.16s\n", dash, dash, dash);
+ strset_iterate(&res.subsystems, stdout_detailed_subsys, &res);
+ printf("\n");
+
+ printf("%-8s %-20s %-40s %-8s %-6s %-14s %-6s %-12s %-16s\n", "Device",
+ "SN", "MN", "FR", "TxPort", "Address", "Slot", "Subsystem", "Namespaces");
+ printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.6s %-.12s %-.16s\n", dash,
+ dash, dash, dash, dash, dash, dash, dash, dash);
+ strset_iterate(&res.ctrls, stdout_detailed_ctrl, &res);
+ printf("\n");
+
+ printf("%-12s %-12s %-10s %-26s %-16s %-16s\n", "Device", "Generic",
+ "NSID", "Usage", "Format", "Controllers");
+ printf("%-.12s %-.12s %-.10s %-.26s %-.16s %-.16s\n", dash, dash, dash,
+ dash, dash, dash);
+ strset_iterate(&res.namespaces, stdout_detailed_ns, &res);
+
+ nvme_resources_free(&res);
+}
+
+static void stdout_list_items(nvme_root_t r)
+{
+ if (stdout_print_ops.flags & VERBOSE)
+ stdout_detailed_list(r);
+ else
+ stdout_simple_list(r);
+}
+
+static bool nvme_is_multipath(nvme_subsystem_t s)
+{
+ nvme_ns_t n;
+ nvme_path_t p;
+
+ nvme_subsystem_for_each_ns(s, n)
+ nvme_namespace_for_each_path(n, p)
+ return true;
+
+ return false;
+}
+
+static void stdout_subsystem_topology_multipath(nvme_subsystem_t s,
+ enum nvme_cli_topo_ranking ranking)
+{
+ nvme_ns_t n;
+ nvme_path_t p;
+ nvme_ctrl_t c;
+
+ if (ranking == NVME_CLI_TOPO_NAMESPACE) {
+ nvme_subsystem_for_each_ns(s, n) {
+ if (!nvme_namespace_first_path(n))
+ continue;
+
+ printf(" +- ns %d\n", nvme_ns_get_nsid(n));
+ printf(" \\\n");
+
+ nvme_namespace_for_each_path(n, p) {
+ c = nvme_path_get_ctrl(p);
+
+ printf(" +- %s %s %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c),
+ nvme_path_get_ana_state(p));
+ }
+ }
+ } else {
+ /* NVME_CLI_TOPO_CTRL */
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf(" +- %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c));
+ printf(" \\\n");
+
+ nvme_subsystem_for_each_ns(s, n) {
+ nvme_namespace_for_each_path(n, p) {
+ if (nvme_path_get_ctrl(p) != c)
+ continue;
+
+ printf(" +- ns %d %s %s\n",
+ nvme_ns_get_nsid(n),
+ nvme_ctrl_get_state(c),
+ nvme_path_get_ana_state(p));
+ }
+ }
+ }
+ }
+}
+
+static void stdout_subsystem_topology(nvme_subsystem_t s,
+ enum nvme_cli_topo_ranking ranking)
+{
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+
+ if (ranking == NVME_CLI_TOPO_NAMESPACE) {
+ nvme_subsystem_for_each_ctrl(s, c) {
+ nvme_ctrl_for_each_ns(c, n) {
+ printf(" +- ns %d\n", nvme_ns_get_nsid(n));
+ printf(" \\\n");
+ printf(" +- %s %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c),
+ nvme_ctrl_get_state(c));
+ }
+ }
+ } else {
+ /* NVME_CLI_TOPO_CTRL */
+ nvme_subsystem_for_each_ctrl(s, c) {
+ printf(" +- %s %s %s\n",
+ nvme_ctrl_get_name(c),
+ nvme_ctrl_get_transport(c),
+ nvme_ctrl_get_address(c));
+ printf(" \\\n");
+ nvme_ctrl_for_each_ns(c, n) {
+ printf(" +- ns %d %s\n",
+ nvme_ns_get_nsid(n),
+ nvme_ctrl_get_state(c));
+ }
+ }
+ }
+}
+
+static void stdout_simple_topology(nvme_root_t r,
+ enum nvme_cli_topo_ranking ranking)
+{
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ bool first = true;
+
+ nvme_for_each_host(r, h) {
+ nvme_for_each_subsystem(h, s) {
+ int len = strlen(nvme_subsystem_get_name(s));
+
+ if (!first)
+ printf("\n");
+ first = false;
+
+ printf("%s - NQN=%s\n", nvme_subsystem_get_name(s),
+ nvme_subsystem_get_nqn(s));
+ printf("%*s hostnqn=%s\n", len, " ",
+ nvme_host_get_hostnqn(nvme_subsystem_get_host(s)));
+ printf("%*s iopolicy=%s\n", len, " ",
+ nvme_subsystem_get_iopolicy(s));
+ printf("\\\n");
+
+ if (nvme_is_multipath(s))
+ stdout_subsystem_topology_multipath(s, ranking);
+ else
+ stdout_subsystem_topology(s, ranking);
+ }
+ }
+}
+
+static void stdout_topology_namespace(nvme_root_t r)
+{
+ stdout_simple_topology(r, NVME_CLI_TOPO_NAMESPACE);
+}
+
+static void stdout_topology_ctrl(nvme_root_t r)
+{
+ stdout_simple_topology(r, NVME_CLI_TOPO_CTRL);
+}
+
+static void stdout_message(bool error, const char *msg, va_list ap)
+{
+ vfprintf(error ? stderr : stdout, msg, ap);
+
+ fprintf(error ? stderr : stdout, "\n");
+}
+
+static void stdout_perror(const char *msg)
+{
+ perror(msg);
+}
+
+static void stdout_discovery_log(struct nvmf_discovery_log *log, int numrec)
+{
+ int i;
+
+ printf("\nDiscovery Log Number of Records %d, Generation counter %"PRIu64"\n",
+ numrec, le64_to_cpu(log->genctr));
+
+ for (i = 0; i < numrec; i++) {
+ struct nvmf_disc_log_entry *e = &log->entries[i];
+
+ printf("=====Discovery Log Entry %d======\n", i);
+ printf("trtype: %s\n", nvmf_trtype_str(e->trtype));
+ printf("adrfam: %s\n",
+ strlen(e->traddr) ?
+ nvmf_adrfam_str(e->adrfam) : "");
+ printf("subtype: %s\n", nvmf_subtype_str(e->subtype));
+ printf("treq: %s\n", nvmf_treq_str(e->treq));
+ printf("portid: %d\n", le16_to_cpu(e->portid));
+ printf("trsvcid: %s\n", e->trsvcid);
+ printf("subnqn: %s\n", e->subnqn);
+ printf("traddr: %s\n", e->traddr);
+ printf("eflags: %s\n",
+ nvmf_eflags_str(le16_to_cpu(e->eflags)));
+
+ switch (e->trtype) {
+ case NVMF_TRTYPE_RDMA:
+ printf("rdma_prtype: %s\n",
+ nvmf_prtype_str(e->tsas.rdma.prtype));
+ printf("rdma_qptype: %s\n",
+ nvmf_qptype_str(e->tsas.rdma.qptype));
+ printf("rdma_cms: %s\n",
+ nvmf_cms_str(e->tsas.rdma.cms));
+ printf("rdma_pkey: 0x%04x\n",
+ le16_to_cpu(e->tsas.rdma.pkey));
+ break;
+ case NVMF_TRTYPE_TCP:
+ printf("sectype: %s\n",
+ nvmf_sectype_str(e->tsas.tcp.sectype));
+ break;
+ }
+ }
+}
+
+static void stdout_connect_msg(nvme_ctrl_t c)
+{
+ printf("connecting to device: %s\n", nvme_ctrl_get_name(c));
+}
+
+static struct print_ops stdout_print_ops = {
+ /* libnvme types.h print functions */
+ .ana_log = stdout_ana_log,
+ .boot_part_log = stdout_boot_part_log,
+ .phy_rx_eom_log = stdout_phy_rx_eom_log,
+ .ctrl_list = stdout_list_ctrl,
+ .ctrl_registers = stdout_ctrl_registers,
+ .directive = stdout_directive_show,
+ .discovery_log = stdout_discovery_log,
+ .effects_log_list = stdout_effects_log_pages,
+ .endurance_group_event_agg_log = stdout_endurance_group_event_agg_log,
+ .endurance_group_list = stdout_endurance_group_list,
+ .endurance_log = stdout_endurance_log,
+ .error_log = stdout_error_log,
+ .fdp_config_log = stdout_fdp_configs,
+ .fdp_event_log = stdout_fdp_events,
+ .fdp_ruh_status = stdout_fdp_ruh_status,
+ .fdp_stats_log = stdout_fdp_stats,
+ .fdp_usage_log = stdout_fdp_usage,
+ .fid_supported_effects_log = stdout_fid_support_effects_log,
+ .fw_log = stdout_fw_log,
+ .id_ctrl = stdout_id_ctrl,
+ .id_ctrl_nvm = stdout_id_ctrl_nvm,
+ .id_domain_list = stdout_id_domain_list,
+ .id_independent_id_ns = stdout_cmd_set_independent_id_ns,
+ .id_iocs = stdout_id_iocs,
+ .id_ns = stdout_id_ns,
+ .id_ns_descs = stdout_id_ns_descs,
+ .id_ns_granularity_list = stdout_id_ns_granularity_list,
+ .id_nvmset_list = stdout_id_nvmset,
+ .id_uuid_list = stdout_id_uuid_list,
+ .lba_status = stdout_lba_status,
+ .lba_status_log = stdout_lba_status_log,
+ .media_unit_stat_log = stdout_media_unit_stat_log,
+ .mi_cmd_support_effects_log = stdout_mi_cmd_support_effects_log,
+ .ns_list = stdout_list_ns,
+ .ns_list_log = stdout_changed_ns_list_log,
+ .nvm_id_ns = stdout_nvm_id_ns,
+ .persistent_event_log = stdout_persistent_event_log,
+ .predictable_latency_event_agg_log = stdout_predictable_latency_event_agg_log,
+ .predictable_latency_per_nvmset = stdout_predictable_latency_per_nvmset,
+ .primary_ctrl_cap = stdout_primary_ctrl_cap,
+ .resv_notification_log = stdout_resv_notif_log,
+ .resv_report = stdout_resv_report,
+ .sanitize_log_page = stdout_sanitize_log,
+ .secondary_ctrl_list = stdout_list_secondary_ctrl,
+ .select_result = stdout_select_result,
+ .self_test_log = stdout_self_test_log,
+ .single_property = stdout_single_property,
+ .smart_log = stdout_smart_log,
+ .supported_cap_config_list_log = stdout_supported_cap_config_log,
+ .supported_log_pages = stdout_supported_log,
+ .zns_start_zone_list = stdout_zns_start_zone_list,
+ .zns_changed_zone_log = stdout_zns_changed,
+ .zns_finish_zone_list = NULL,
+ .zns_id_ctrl = stdout_zns_id_ctrl,
+ .zns_id_ns = stdout_zns_id_ns,
+ .zns_report_zones = stdout_zns_report_zones,
+ .show_feature = stdout_feature_show,
+ .show_feature_fields = stdout_feature_show_fields,
+ .id_ctrl_rpmbs = stdout_id_ctrl_rpmbs,
+ .lba_range = stdout_lba_range,
+ .lba_status_info = stdout_lba_status_info,
+ .d = stdout_d,
+ .show_init = NULL,
+ .show_finish = NULL,
+
+ /* libnvme tree print functions */
+ .list_item = stdout_list_item,
+ .list_items = stdout_list_items,
+ .print_nvme_subsystem_list = stdout_subsystem_list,
+ .topology_ctrl = stdout_topology_ctrl,
+ .topology_namespace = stdout_topology_namespace,
+
+ /* status and error messages */
+ .connect_msg = stdout_connect_msg,
+ .show_message = stdout_message,
+ .show_perror = stdout_perror,
+ .show_status = stdout_status,
+ .show_error_status = stdout_error_status,
+};
+
+struct print_ops *nvme_get_stdout_print_ops(enum nvme_print_flags flags)
+{
+ stdout_print_ops.flags = flags;
+ return &stdout_print_ops;
+}
diff --git a/nvme-print.c b/nvme-print.c
new file mode 100644
index 0000000..1086aad
--- /dev/null
+++ b/nvme-print.c
@@ -0,0 +1,1076 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/stat.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "nvme-models.h"
+#include "util/suffix.h"
+#include "util/types.h"
+#include "common.h"
+
+#define nvme_print(name, flags, ...) \
+ do { \
+ struct print_ops *ops = nvme_print_ops(flags); \
+ if (ops && ops->name) \
+ ops->name(__VA_ARGS__); \
+ } while (false)
+
+#define nvme_print_output_format(name, ...) \
+ nvme_print(name, nvme_is_output_format_json() ? JSON : NORMAL, ##__VA_ARGS__);
+
+static struct print_ops *nvme_print_ops(enum nvme_print_flags flags)
+{
+ struct print_ops *ops = NULL;
+
+ if (flags & JSON || nvme_is_output_format_json())
+ ops = nvme_get_json_print_ops(flags);
+ else if (flags & BINARY)
+ ops = nvme_get_binary_print_ops(flags);
+ else
+ ops = nvme_get_stdout_print_ops(flags);
+
+ return ops;
+}
+
+const char *nvme_ana_state_to_string(enum nvme_ana_state state)
+{
+ switch (state) {
+ case NVME_ANA_STATE_OPTIMIZED:
+ return "optimized";
+ case NVME_ANA_STATE_NONOPTIMIZED:
+ return "non-optimized";
+ case NVME_ANA_STATE_INACCESSIBLE:
+ return "inaccessible";
+ case NVME_ANA_STATE_PERSISTENT_LOSS:
+ return "persistent-loss";
+ case NVME_ANA_STATE_CHANGE:
+ return "change";
+ }
+ return "invalid state";
+}
+
+const char *nvme_cmd_to_string(int admin, __u8 opcode)
+{
+ if (admin) {
+ switch (opcode) {
+ case nvme_admin_delete_sq: return "Delete I/O Submission Queue";
+ case nvme_admin_create_sq: return "Create I/O Submission Queue";
+ case nvme_admin_get_log_page: return "Get Log Page";
+ case nvme_admin_delete_cq: return "Delete I/O Completion Queue";
+ case nvme_admin_create_cq: return "Create I/O Completion Queue";
+ case nvme_admin_identify: return "Identify";
+ case nvme_admin_abort_cmd: return "Abort";
+ case nvme_admin_set_features: return "Set Features";
+ case nvme_admin_get_features: return "Get Features";
+ case nvme_admin_async_event: return "Asynchronous Event Request";
+ case nvme_admin_ns_mgmt: return "Namespace Management";
+ case nvme_admin_fw_commit: return "Firmware Commit";
+ case nvme_admin_fw_download: return "Firmware Image Download";
+ case nvme_admin_dev_self_test: return "Device Self-test";
+ case nvme_admin_ns_attach: return "Namespace Attachment";
+ case nvme_admin_keep_alive: return "Keep Alive";
+ case nvme_admin_directive_send: return "Directive Send";
+ case nvme_admin_directive_recv: return "Directive Receive";
+ case nvme_admin_virtual_mgmt: return "Virtualization Management";
+ case nvme_admin_nvme_mi_send: return "NVMe-MI Send";
+ case nvme_admin_nvme_mi_recv: return "NVMe-MI Receive";
+ case nvme_admin_dbbuf: return "Doorbell Buffer Config";
+ case nvme_admin_format_nvm: return "Format NVM";
+ 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) {
+ case nvme_cmd_flush: return "Flush";
+ case nvme_cmd_write: return "Write";
+ case nvme_cmd_read: return "Read";
+ case nvme_cmd_write_uncor: return "Write Uncorrectable";
+ case nvme_cmd_compare: return "Compare";
+ case nvme_cmd_write_zeroes: return "Write Zeroes";
+ case nvme_cmd_dsm: return "Dataset Management";
+ case nvme_cmd_resv_register: return "Reservation Register";
+ 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";
+ case nvme_zns_cmd_mgmt_send: return "Zone Management Send";
+ case nvme_zns_cmd_mgmt_recv: return "Zone Management Receive";
+ case nvme_zns_cmd_append: return "Zone Append";
+ }
+ }
+
+ return "Unknown";
+}
+
+const char *nvme_sstat_status_to_string(__u16 status)
+{
+ switch (status & NVME_SANITIZE_SSTAT_STATUS_MASK) {
+ case NVME_SANITIZE_SSTAT_STATUS_NEVER_SANITIZED:
+ return "NVM Subsystem has never been sanitized.";
+ case NVME_SANITIZE_SSTAT_STATUS_COMPLETE_SUCCESS:
+ return "Most Recent Sanitize Command Completed Successfully.";
+ case NVME_SANITIZE_SSTAT_STATUS_IN_PROGESS:
+ return "Sanitize in Progress.";
+ case NVME_SANITIZE_SSTAT_STATUS_COMPLETED_FAILED:
+ return "Most Recent Sanitize Command Failed.";
+ case NVME_SANITIZE_SSTAT_STATUS_ND_COMPLETE_SUCCESS:
+ return "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully.";
+ default:
+ return "Unknown";
+ }
+}
+
+void nvme_show_predictable_latency_per_nvmset(
+ struct nvme_nvmset_predictable_lat_log *plpns_log,
+ __u16 nvmset_id, const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(predictable_latency_per_nvmset, flags,
+ plpns_log, nvmset_id, devname);
+}
+
+void nvme_show_predictable_latency_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *pea_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(predictable_latency_event_agg_log, flags,
+ pea_log, log_entries, size, devname);
+}
+
+const char *nvme_pel_event_to_string(int type)
+{
+ switch (type) {
+ case NVME_PEL_SMART_HEALTH_EVENT: return "SMART/Health Log Snapshot Event(0x1)";
+ case NVME_PEL_FW_COMMIT_EVENT: return "Firmware Commit Event(0x2)";
+ case NVME_PEL_TIMESTAMP_EVENT: return "Timestamp Change Event(0x3)";
+ case NVME_PEL_POWER_ON_RESET_EVENT: return "Power-on or Reset Event(0x4)";
+ case NVME_PEL_NSS_HW_ERROR_EVENT: return "NVM Subsystem Hardware Error Event(0x5)";
+ case NVME_PEL_CHANGE_NS_EVENT: return "Change Namespace Event(0x6)";
+ case NVME_PEL_FORMAT_START_EVENT: return "Format NVM Start Event(0x7)";
+ case NVME_PEL_FORMAT_COMPLETION_EVENT: return "Format NVM Completion Event(0x8)";
+ case NVME_PEL_SANITIZE_START_EVENT: return "Sanitize Start Event(0x9)";
+ case NVME_PEL_SANITIZE_COMPLETION_EVENT: return "Sanitize Completion Event(0xa)";
+ case NVME_PEL_SET_FEATURE_EVENT: return "Set Feature Event(0xb)";
+ case NVME_PEL_TELEMETRY_CRT: return "Set Telemetry CRT Event(0xc)";
+ case NVME_PEL_THERMAL_EXCURSION_EVENT: return "Thermal Excursion Event(0xd)";
+ default: return NULL;
+ }
+}
+
+const char *nvme_nss_hw_error_to_string(__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";
+ case 0xB:
+ return "Controller Ready Timeout Exceeded";
+ default:
+ return "Reserved";
+ }
+}
+
+void nvme_show_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(persistent_event_log, flags,
+ pevent_log_info, action, size, devname);
+}
+
+void nvme_show_endurance_group_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(endurance_group_event_agg_log, flags,
+ endurance_log, log_entries, size, devname);
+}
+
+void nvme_show_lba_status_log(void *lba_status, __u32 size,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(lba_status_log, flags, lba_status, size, devname);
+}
+
+const char *nvme_resv_notif_to_string(__u8 type)
+{
+ switch (type) {
+ case 0x0: return "Empty Log Page";
+ case 0x1: return "Registration Preempted";
+ case 0x2: return "Reservation Released";
+ case 0x3: return "Reservation Preempted";
+ default: return "Reserved";
+ }
+}
+
+void nvme_show_resv_notif_log(struct nvme_resv_notification_log *resv,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(resv_notification_log, flags, resv, devname);
+}
+
+void nvme_show_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(fid_supported_effects_log, flags, fid_log, devname);
+}
+
+void nvme_show_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(mi_cmd_support_effects_log, flags,
+ mi_cmd_log, devname);
+}
+
+void nvme_show_boot_part_log(void *bp_log, const char *devname,
+ __u32 size, enum nvme_print_flags flags)
+{
+ nvme_print(boot_part_log, flags, bp_log, devname, size);
+}
+
+void nvme_show_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log, __u16 controller,
+ enum nvme_print_flags flags)
+{
+ nvme_print(phy_rx_eom_log, flags, log, controller);
+}
+
+void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus_log,
+ enum nvme_print_flags flags)
+{
+ nvme_print(media_unit_stat_log, flags, mus_log);
+}
+
+void nvme_show_fdp_configs(struct nvme_fdp_config_log *log, size_t len,
+ enum nvme_print_flags flags)
+{
+ nvme_print(fdp_config_log, flags, log, len);
+}
+
+void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len,
+ enum nvme_print_flags flags)
+{
+ nvme_print(fdp_usage_log, flags,log, len);
+}
+
+void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log,
+ enum nvme_print_flags flags)
+{
+ nvme_print(fdp_stats_log, flags, log);
+}
+
+const char *nvme_fdp_event_to_string(enum nvme_fdp_event_type event)
+{
+ switch (event) {
+ case NVME_FDP_EVENT_RUNFW: return "Reclaim Unit Not Fully Written";
+ case NVME_FDP_EVENT_RUTLE: return "Reclaim Unit Active Time Limit Exceeded";
+ case NVME_FDP_EVENT_RESET: return "Controller Level Reset Modified Reclaim Unit Handles";
+ case NVME_FDP_EVENT_PID: return "Invalid Placement Identifier";
+ case NVME_FDP_EVENT_REALLOC: return "Media Reallocated";
+ case NVME_FDP_EVENT_MODIFY: return "Implicitly Modified Reclaim Unit Handle";
+ }
+
+ return "Unknown";
+}
+
+void nvme_show_fdp_events(struct nvme_fdp_events_log *log,
+ enum nvme_print_flags flags)
+{
+ nvme_print(fdp_event_log, flags, log);
+}
+
+void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len,
+ enum nvme_print_flags flags)
+{
+ nvme_print(fdp_ruh_status, flags, status, len);
+}
+
+void nvme_show_supported_cap_config_log(
+ struct nvme_supported_cap_config_list_log *cap,
+ enum nvme_print_flags flags)
+{
+ nvme_print(supported_cap_config_list_log, flags, cap);
+}
+
+void nvme_show_subsystem_list(nvme_root_t r, bool show_ana,
+ enum nvme_print_flags flags)
+{
+ nvme_print(print_nvme_subsystem_list, flags, r, show_ana);
+}
+
+const char *nvme_register_szu_to_string(__u8 szu)
+{
+ switch (szu) {
+ case 0: return "4 KB";
+ case 1: return "64 KB";
+ case 2: return "1 MB";
+ case 3: return "16 MB";
+ case 4: return "256 MB";
+ case 5: return "4 GB";
+ case 6: return "64 GB";
+ default:return "Reserved";
+ }
+}
+
+const char *nvme_register_pmr_hsts_to_string(__u8 hsts)
+{
+ switch (hsts) {
+ case 0: return "Normal Operation";
+ case 1: return "Restore Error";
+ case 2: return "Read Only";
+ case 3: return "Unreliable";
+ default: return "Reserved";
+ }
+}
+
+const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu)
+{
+ switch (pmrszu) {
+ case 0: return "Bytes";
+ case 1: return "One KB";
+ case 2: return "One MB";
+ case 3: return "One GB";
+ default: return "Reserved";
+ }
+}
+
+void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags)
+{
+ nvme_print(ctrl_registers, flags, bar, fabrics);
+}
+
+void nvme_show_single_property(int offset, uint64_t value64, enum nvme_print_flags flags)
+{
+ nvme_print(single_property, flags, offset, value64);
+}
+
+void nvme_show_relatives(const char *name)
+{
+ /* XXX: TBD */
+}
+
+void d(unsigned char *buf, int len, int width, int group)
+{
+ nvme_print(d, NORMAL, buf, len, width, group);
+}
+
+void d_raw(unsigned char *buf, unsigned len)
+{
+ unsigned i;
+ for (i = 0; i < len; i++)
+ putchar(*(buf+i));
+}
+
+void nvme_show_status(int status)
+{
+ struct print_ops *ops = nvme_print_ops(NORMAL);
+
+ if (nvme_is_output_format_json())
+ ops = nvme_print_ops(JSON);
+
+ if (ops && ops->show_status)
+ ops->show_status(status);
+}
+
+void nvme_show_error_status(int status, const char *msg, ...)
+{
+ struct print_ops *ops = nvme_print_ops(NORMAL);
+ va_list ap;
+
+ va_start(ap, msg);
+
+ if (nvme_is_output_format_json())
+ ops = nvme_print_ops(JSON);
+
+ if (ops && ops->show_status)
+ ops->show_error_status(status, msg, ap);
+
+ va_end(ap);
+}
+
+void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs, enum nvme_print_flags flags)
+{
+ nvme_print(id_ctrl_rpmbs, flags, ctrl_rpmbs);
+}
+
+void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ unsigned int lba_index, bool cap_only, enum nvme_print_flags flags)
+{
+ nvme_print(id_ns, flags, ns, nsid, lba_index, cap_only);
+}
+
+
+void nvme_show_cmd_set_independent_id_ns(
+ struct nvme_id_independent_id_ns *ns, unsigned int nsid,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_independent_id_ns, flags, ns, nsid);
+}
+
+void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags)
+{
+ nvme_print(id_ns_descs, flags, data, nsid);
+}
+
+void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
+ void (*vendor_show)(__u8 *vs, struct json_object *root))
+{
+ nvme_print(id_ctrl, flags, ctrl, vendor_show);
+}
+
+void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_ctrl_nvm, flags, ctrl_nvm);
+}
+
+void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid,
+ struct nvme_id_ns *ns, unsigned int lba_index,
+ bool cap_only, enum nvme_print_flags flags)
+{
+ nvme_print(nvm_id_ns, flags, nvm_ns, nsid, ns, lba_index, cap_only);
+}
+
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_id_ctrl, flags, ctrl);
+}
+
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_id_ns, flags, ns, id_ns);
+}
+
+void nvme_show_list_ns(struct nvme_ns_list *ns_list, enum nvme_print_flags flags)
+{
+ nvme_print(ns_list, flags, ns_list);
+}
+
+void nvme_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_start_zone_list, flags, nr_zones, zone_list);
+}
+
+void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_changed_zone_log, flags, log);
+}
+
+void nvme_zns_finish_zone_list(__u64 nr_zones, struct json_object *zone_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_finish_zone_list, flags, nr_zones, zone_list);
+}
+
+const char *nvme_zone_type_to_string(__u8 cond)
+{
+ switch (cond) {
+ case NVME_ZONE_TYPE_SEQWRITE_REQ:
+ return "SEQWRITE_REQ";
+ default:
+ return "Unknown";
+ }
+}
+
+const char *nvme_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,
+ struct json_object *zone_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(zns_report_zones, flags,
+ report, descs, ext_size, report_size, zone_list);
+}
+
+void nvme_show_list_ctrl(struct nvme_ctrl_list *ctrl_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(ctrl_list, flags, ctrl_list);
+}
+
+void nvme_show_id_nvmset(struct nvme_id_nvmset_list *nvmset, unsigned nvmset_id,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_nvmset_list, flags, nvmset, nvmset_id);
+}
+
+void nvme_show_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *caps,
+ enum nvme_print_flags flags)
+{
+ nvme_print(primary_ctrl_cap, flags, caps);
+}
+
+void nvme_show_list_secondary_ctrl(
+ const struct nvme_secondary_ctrl_list *sc_list,
+ __u32 count, enum nvme_print_flags flags)
+{
+ __u16 num = sc_list->num;
+ __u32 entries = min(num, count);
+
+ nvme_print(secondary_ctrl_list, flags, sc_list, entries);
+}
+
+void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_ns_granularity_list, flags, glist);
+}
+
+void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_uuid_list, flags, uuid_list);
+}
+
+void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom,
+ enum nvme_print_flags flags)
+{
+ nvme_print(id_domain_list, flags, id_dom);
+}
+
+void nvme_show_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(endurance_group_list, flags, endgrp_list);
+}
+
+void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags)
+{
+ nvme_print(id_iocs, flags, iocs);
+}
+
+const char *nvme_trtype_to_string(__u8 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.";
+ case 2: return "Fibre Channel Transport error.";
+ case 3: return "TCP Transport error.";
+ case 254: return "Intra-host Transport error.";
+ default: return "Reserved";
+ };
+}
+
+void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(error_log, flags, err_log, entries, devname);
+}
+
+void nvme_show_resv_report(struct nvme_resv_status *status, int bytes,
+ bool eds, enum nvme_print_flags flags)
+{
+ nvme_print(resv_report, flags, status, bytes, eds);
+}
+
+void nvme_show_fw_log(struct nvme_firmware_slot *fw_log,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(fw_log, flags, fw_log, devname);
+}
+
+void nvme_show_changed_ns_list_log(struct nvme_ns_list *log,
+ const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(ns_list_log, flags, log, devname);
+}
+
+void nvme_print_effects_log_pages(struct list_head *list,
+ enum nvme_print_flags flags)
+{
+ nvme_print(effects_log_list, flags, list);
+}
+
+const char *nvme_log_to_string(__u8 lid)
+{
+ switch (lid) {
+ case NVME_LOG_LID_SUPPORTED_LOG_PAGES: return "Supported Log Pages";
+ case NVME_LOG_LID_ERROR: return "Error Information";
+ case NVME_LOG_LID_SMART: return "SMART / Health Information";
+ case NVME_LOG_LID_FW_SLOT: return "Firmware Slot Information";
+ case NVME_LOG_LID_CHANGED_NS: return "Changed Namespace List";
+ case NVME_LOG_LID_CMD_EFFECTS: return "Commands Supported and Effects";
+ case NVME_LOG_LID_DEVICE_SELF_TEST: return "Device Self-test";
+ case NVME_LOG_LID_TELEMETRY_HOST: return "Telemetry Host-Initiated";
+ case NVME_LOG_LID_TELEMETRY_CTRL: return "Telemetry Controller-Initiated";
+ case NVME_LOG_LID_ENDURANCE_GROUP: return "Endurance Group Information";
+ case NVME_LOG_LID_PREDICTABLE_LAT_NVMSET: return "Predictable Latency Per NVM Set";
+ case NVME_LOG_LID_PREDICTABLE_LAT_AGG: return "Predictable Latency Event Aggregate";
+ case NVME_LOG_LID_MEDIA_UNIT_STATUS: return "Media Unit Status";
+ case NVME_LOG_LID_SUPPORTED_CAP_CONFIG_LIST: return "Supported Capacity Configuration List";
+ case NVME_LOG_LID_ANA: return "Asymmetric Namespace Access";
+ case NVME_LOG_LID_PERSISTENT_EVENT: return "Persistent Event Log";
+ case NVME_LOG_LID_LBA_STATUS: return "LBA Status Information";
+ case NVME_LOG_LID_ENDURANCE_GRP_EVT: return "Endurance Group Event Aggregate";
+ case NVME_LOG_LID_FID_SUPPORTED_EFFECTS: return "Feature Identifiers Supported and Effects";
+ case NVME_LOG_LID_MI_CMD_SUPPORTED_EFFECTS: return "NVMe-MI Commands Supported and Effects";
+ case NVME_LOG_LID_BOOT_PARTITION: return "Boot Partition";
+ case NVME_LOG_LID_FDP_CONFIGS: return "FDP Configurations";
+ case NVME_LOG_LID_FDP_RUH_USAGE: return "Reclaim Unit Handle Usage";
+ case NVME_LOG_LID_FDP_STATS: return "FDP Statistics";
+ case NVME_LOG_LID_FDP_EVENTS: return "FDP Events";
+ case NVME_LOG_LID_DISCOVER: return "Discovery";
+ case NVME_LOG_LID_RESERVATION: return "Reservation Notification";
+ case NVME_LOG_LID_SANITIZE: return "Sanitize Status";
+ case NVME_LOG_LID_ZNS_CHANGED_ZONES: return "Changed Zone List";
+ default: return "Unknown";
+ }
+}
+
+void nvme_show_supported_log(struct nvme_supported_log_pages *support_log,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(supported_log_pages, flags, support_log, devname);
+}
+
+void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
+ __u16 group_id, const char *devname,
+ enum nvme_print_flags flags)
+{
+ nvme_print(endurance_log, flags, endurance_log, group_id, devname);
+}
+
+void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(smart_log, flags, smart, nsid, devname);
+}
+
+void nvme_show_ana_log(struct nvme_ana_log *ana_log, const char *devname,
+ size_t len, enum nvme_print_flags flags)
+{
+ nvme_print(ana_log, flags, ana_log, devname, len);
+}
+
+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)
+{
+ nvme_print(self_test_log, flags, self_test, dst_entries, size, devname);
+}
+
+void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
+ const char *devname, enum nvme_print_flags flags)
+{
+ nvme_print(sanitize_log_page, flags, sanitize, devname);
+}
+
+const char *nvme_feature_to_string(enum nvme_features_id feature)
+{
+ switch (feature) {
+ case NVME_FEAT_FID_ARBITRATION: return "Arbitration";
+ case NVME_FEAT_FID_POWER_MGMT: return "Power Management";
+ case NVME_FEAT_FID_LBA_RANGE: return "LBA Range Type";
+ case NVME_FEAT_FID_TEMP_THRESH: return "Temperature Threshold";
+ case NVME_FEAT_FID_ERR_RECOVERY:return "Error Recovery";
+ case NVME_FEAT_FID_VOLATILE_WC: return "Volatile Write Cache";
+ case NVME_FEAT_FID_NUM_QUEUES: return "Number of Queues";
+ case NVME_FEAT_FID_IRQ_COALESCE:return "Interrupt Coalescing";
+ case NVME_FEAT_FID_IRQ_CONFIG: return "Interrupt Vector Configuration";
+ case NVME_FEAT_FID_WRITE_ATOMIC:return "Write Atomicity Normal";
+ case NVME_FEAT_FID_ASYNC_EVENT: return "Async Event Configuration";
+ case NVME_FEAT_FID_AUTO_PST: return "Autonomous Power State Transition";
+ case NVME_FEAT_FID_HOST_MEM_BUF:return "Host Memory Buffer";
+ case NVME_FEAT_FID_TIMESTAMP: return "Timestamp";
+ case NVME_FEAT_FID_KATO: return "Keep Alive Timer";
+ case NVME_FEAT_FID_HCTM: return "Host Controlled Thermal Management";
+ case NVME_FEAT_FID_NOPSC: return "Non-Operational Power State Config";
+ case NVME_FEAT_FID_RRL: return "Read Recovery Level";
+ case NVME_FEAT_FID_PLM_CONFIG: return "Predictable Latency Mode Config";
+ case NVME_FEAT_FID_PLM_WINDOW: return "Predictable Latency Mode Window";
+ case NVME_FEAT_FID_LBA_STS_INTERVAL: return "LBA Status Interval";
+ case NVME_FEAT_FID_HOST_BEHAVIOR: return "Host Behavior";
+ case NVME_FEAT_FID_SANITIZE: return "Sanitize";
+ case NVME_FEAT_FID_ENDURANCE_EVT_CFG: return "Endurance Event Group Configuration";
+ case NVME_FEAT_FID_IOCS_PROFILE: return "I/O Command Set Profile";
+ case NVME_FEAT_FID_SPINUP_CONTROL: return "Spinup Control";
+ case NVME_FEAT_FID_ENH_CTRL_METADATA: return "Enhanced Controller Metadata";
+ case NVME_FEAT_FID_CTRL_METADATA: return "Controller Metadata";
+ case NVME_FEAT_FID_NS_METADATA: return "Namespace Metadata";
+ case NVME_FEAT_FID_SW_PROGRESS: return "Software Progress";
+ case NVME_FEAT_FID_HOST_ID: return "Host Identifier";
+ case NVME_FEAT_FID_RESV_MASK: return "Reservation Notification Mask";
+ case NVME_FEAT_FID_RESV_PERSIST:return "Reservation Persistence";
+ case NVME_FEAT_FID_WRITE_PROTECT: return "Namespace Write Protect";
+ case NVME_FEAT_FID_FDP: return "Flexible Direct Placement";
+ case NVME_FEAT_FID_FDP_EVENTS: return "Flexible Direct Placement Events";
+ }
+ /*
+ * We don't use the "default:" statement to let the compiler warning if
+ * some values of the enum nvme_features_id are missing in the switch().
+ * The following return is acting as the default: statement.
+ */
+ return "Unknown";
+}
+
+const char *nvme_register_to_string(int reg)
+{
+ switch (reg) {
+ case NVME_REG_CAP: return "Controller Capabilities";
+ case NVME_REG_VS: return "Version";
+ case NVME_REG_INTMS: return "Interrupt Vector Mask Set";
+ case NVME_REG_INTMC: return "Interrupt Vector Mask Clear";
+ case NVME_REG_CC: return "Controller Configuration";
+ case NVME_REG_CSTS: return "Controller Status";
+ case NVME_REG_NSSR: return "NVM Subsystem Reset";
+ case NVME_REG_AQA: return "Admin Queue Attributes";
+ case NVME_REG_ASQ: return "Admin Submission Queue Base Address";
+ case NVME_REG_ACQ: return "Admin Completion Queue Base Address";
+ case NVME_REG_CMBLOC: return "Controller Memory Buffer Location";
+ case NVME_REG_CMBSZ: return "Controller Memory Buffer Size";
+ default: return "Unknown";
+ }
+}
+
+const char *nvme_select_to_string(int sel)
+{
+ switch (sel) {
+ case 0: return "Current";
+ case 1: return "Default";
+ case 2: return "Saved";
+ case 3: return "Supported capabilities";
+ case 8: return "Changed";
+ default: return "Reserved";
+ }
+}
+
+void nvme_show_select_result(enum nvme_features_id fid, __u32 result)
+{
+ nvme_print(select_result, NORMAL, fid, result);
+}
+
+const char *nvme_feature_lba_type_to_string(__u8 type)
+{
+ switch (type) {
+ case 0: return "Reserved";
+ case 1: return "Filesystem";
+ case 2: return "RAID";
+ case 3: return "Cache";
+ case 4: return "Page / Swap file";
+ default:
+ if (type >= 0x05 && type <= 0x7f)
+ return "Reserved";
+ else
+ return "Vendor Specific";
+ }
+}
+
+void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges,
+ enum nvme_print_flags flags)
+{
+ nvme_print(lba_range, flags, lbrt, nr_ranges);
+}
+
+const char *nvme_feature_wl_hints_to_string(__u8 wh)
+{
+ switch (wh) {
+ case 0: return "No Workload";
+ case 1: return "Extended Idle Period with a Burst of Random Writes";
+ case 2: return "Heavy Sequential Writes";
+ default:return "Reserved";
+ }
+}
+
+const char *nvme_feature_temp_type_to_string(__u8 type)
+{
+ switch (type) {
+ case 0: return "Over Temperature Threshold";
+ case 1: return "Under Temperature Threshold";
+ default:return "Reserved";
+ }
+}
+
+const char *nvme_feature_temp_sel_to_string(__u8 sel)
+{
+ switch (sel) {
+ case 0: return "Composite Temperature";
+ case 1: return "Temperature Sensor 1";
+ case 2: return "Temperature Sensor 2";
+ case 3: return "Temperature Sensor 3";
+ case 4: return "Temperature Sensor 4";
+ case 5: return "Temperature Sensor 5";
+ case 6: return "Temperature Sensor 6";
+ case 7: return "Temperature Sensor 7";
+ case 8: return "Temperature Sensor 8";
+ default:return "Reserved";
+ }
+}
+
+const char *nvme_ns_wp_cfg_to_string(enum nvme_ns_write_protect_cfg state)
+{
+ switch (state) {
+ case NVME_NS_WP_CFG_NONE:
+ return "No Write Protect";
+ case NVME_NS_WP_CFG_PROTECT:
+ return "Write Protect";
+ case NVME_NS_WP_CFG_PROTECT_POWER_CYCLE:
+ return "Write Protect Until Power Cycle";
+ case NVME_NS_WP_CFG_PROTECT_PERMANENT:
+ return "Permanent Write Protect";
+ default:
+ return "Reserved";
+ }
+}
+
+void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len, enum nvme_print_flags flags)
+{
+ nvme_print(directive, flags, type, oper, spec, nsid, result, buf, len);
+}
+
+const char *nvme_plm_window_to_string(__u32 plm)
+{
+ switch (plm & 0x7) {
+ case 1:
+ return "Deterministic Window (DTWIN)";
+ case 2:
+ return "Non-deterministic Window (NDWIN)";
+ default:
+ return "Reserved";
+ }
+}
+
+void nvme_show_lba_status_info(__u32 result)
+{
+ nvme_print(lba_status_info, NORMAL, result);
+}
+
+const char *nvme_host_metadata_type_to_string(enum nvme_features_id fid,
+ __u8 type)
+{
+ switch (fid) {
+ case NVME_FEAT_FID_ENH_CTRL_METADATA:
+ case NVME_FEAT_FID_CTRL_METADATA:
+ switch (type) {
+ case NVME_CTRL_METADATA_OS_CTRL_NAME:
+ return "Operating System Controller Name";
+ case NVME_CTRL_METADATA_OS_DRIVER_NAME:
+ return "Operating System Driver Name";
+ case NVME_CTRL_METADATA_OS_DRIVER_VER:
+ return "Operating System Driver Version";
+ case NVME_CTRL_METADATA_PRE_BOOT_CTRL_NAME:
+ return "Pre-boot Controller Name";
+ case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_NAME:
+ return "Pre-boot Driver Name";
+ case NVME_CTRL_METADATA_PRE_BOOT_DRIVER_VER:
+ return "Pre-boot Driver Version";
+ case NVME_CTRL_METADATA_SYS_PROC_MODEL:
+ return "System Processor Model";
+ case NVME_CTRL_METADATA_CHIPSET_DRV_NAME:
+ return "Chipset Driver Name";
+ case NVME_CTRL_METADATA_CHIPSET_DRV_VERSION:
+ return "Chipset Driver Version";
+ case NVME_CTRL_METADATA_OS_NAME_AND_BUILD:
+ return "Operating System Name and Build";
+ case NVME_CTRL_METADATA_SYS_PROD_NAME:
+ return "System Product Name";
+ case NVME_CTRL_METADATA_FIRMWARE_VERSION:
+ return "Firmware Version";
+ case NVME_CTRL_METADATA_OS_DRIVER_FILENAME:
+ return "Operating System Driver Filename";
+ case NVME_CTRL_METADATA_DISPLAY_DRV_NAME:
+ return "Display Driver Name";
+ case NVME_CTRL_METADATA_DISPLAY_DRV_VERSION:
+ return "Display Driver Version";
+ case NVME_CTRL_METADATA_HOST_DET_FAIL_REC:
+ return "Host-Determined Failure Record";
+ default:
+ return "Unknown Controller Type";
+ }
+ case NVME_FEAT_FID_NS_METADATA:
+ switch (type) {
+ case NVME_NS_METADATA_OS_NS_NAME:
+ return "Operating System Namespace Name";
+ case NVME_NS_METADATA_PRE_BOOT_NS_NAME:
+ return "Pre-boot Namespace Name";
+ case NVME_NS_METADATA_OS_NS_QUAL_1:
+ return "Operating System Namespace Name Qualifier 1";
+ case NVME_NS_METADATA_OS_NS_QUAL_2:
+ return "Operating System Namespace Name Qualifier 2";
+ default:
+ return "Unknown Namespace Type";
+ }
+ default:
+ return "Unknown Feature";
+ }
+}
+
+void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result)
+{
+ nvme_print(show_feature, NORMAL, fid, sel, result);
+}
+
+void nvme_feature_show_fields(enum nvme_features_id fid, unsigned int result, unsigned char *buf)
+{
+ nvme_print(show_feature_fields, NORMAL, fid, result, buf);
+}
+
+void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len,
+ enum nvme_print_flags flags)
+{
+ nvme_print(lba_status, flags, list, len);
+}
+
+void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len)
+{
+ struct stat st;
+
+ snprintf(path, len, "/dev/%s", nvme_ns_get_name(n));
+ if (stat(path, &st) == 0)
+ return;
+
+ snprintf(path, len, "/dev/spdk/%s", nvme_ns_get_name(n));
+ if (stat(path, &st) == 0)
+ return;
+
+ /*
+ * We could start trying to search for it but let's make
+ * it simple and just don't show the path at all.
+ */
+ snprintf(path, len, "%s", nvme_ns_get_name(n));
+}
+
+void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len)
+{
+ int head_instance;
+ int instance;
+ struct stat st;
+
+ sscanf(nvme_ns_get_name(n), "nvme%dn%d", &instance, &head_instance);
+ snprintf(path, len, "/dev/ng%dn%d", instance, head_instance);
+
+ if (stat(path, &st) == 0)
+ return;
+
+ snprintf(path, len, "/dev/spdk/ng%dn%d", instance, head_instance);
+ if (stat(path, &st) == 0)
+ return;
+ /*
+ * We could start trying to search for it but let's make
+ * it simple and just don't show the path at all.
+ */
+ snprintf(path, len, "ng%dn%d", instance, head_instance);
+}
+
+void nvme_show_list_item(nvme_ns_t n)
+{
+ nvme_print(list_item, NORMAL, n);
+}
+
+void nvme_show_list_items(nvme_root_t r, enum nvme_print_flags flags)
+{
+ nvme_print(list_items, flags, r);
+}
+
+void nvme_show_topology(nvme_root_t r,
+ enum nvme_cli_topo_ranking ranking,
+ enum nvme_print_flags flags)
+{
+ if (ranking == NVME_CLI_TOPO_NAMESPACE)
+ nvme_print(topology_namespace, flags, r);
+ else
+ nvme_print(topology_ctrl, flags, r);
+}
+
+void nvme_show_message(bool error, const char *msg, ...)
+{
+ struct print_ops *ops = nvme_print_ops(NORMAL);
+ va_list ap;
+
+ va_start(ap, msg);
+
+ if (nvme_is_output_format_json())
+ ops = nvme_print_ops(JSON);
+
+ if (ops && ops->show_message)
+ ops->show_message(error, msg, ap);
+
+ va_end(ap);
+}
+
+void nvme_show_perror(const char *msg)
+{
+ struct print_ops *ops = nvme_print_ops(NORMAL);
+
+ if (nvme_is_output_format_json())
+ ops = nvme_print_ops(JSON);
+
+ if (ops && ops->show_perror)
+ ops->show_perror(msg);
+}
+
+void nvme_show_discovery_log(struct nvmf_discovery_log *log, uint64_t numrec,
+ enum nvme_print_flags flags)
+{
+ nvme_print(discovery_log, flags, log, numrec);
+}
+
+void nvme_show_connect_msg(nvme_ctrl_t c, enum nvme_print_flags flags)
+{
+ nvme_print(connect_msg, flags, c);
+}
+
+void nvme_show_init(void)
+{
+ nvme_print_output_format(show_init);
+}
+
+void nvme_show_finish(void)
+{
+ nvme_print_output_format(show_finish);
+}
diff --git a/nvme-print.h b/nvme-print.h
new file mode 100644
index 0000000..4533474
--- /dev/null
+++ b/nvme-print.h
@@ -0,0 +1,313 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef NVME_PRINT_H
+#define NVME_PRINT_H
+
+#include "nvme.h"
+#include <inttypes.h>
+
+#include <ccan/list/list.h>
+
+typedef struct nvme_effects_log_node {
+ struct nvme_cmd_effects_log effects; /* needs to be first member because of alignment requirement. */
+ enum nvme_csi csi;
+ struct list_node node;
+} nvme_effects_log_node_t;
+
+#define nvme_show_error(msg, ...) nvme_show_message(true, msg, ##__VA_ARGS__)
+#define nvme_show_result(msg, ...) nvme_show_message(false, msg, ##__VA_ARGS__)
+
+void d(unsigned char *buf, int len, int width, int group);
+void d_raw(unsigned char *buf, unsigned len);
+
+struct print_ops {
+ /* libnvme types.h print functions */
+ void (*ana_log)(struct nvme_ana_log *ana_log, const char *devname, size_t len);
+ void (*boot_part_log)(void *bp_log, const char *devname, __u32 size);
+ void (*phy_rx_eom_log)(struct nvme_phy_rx_eom_log *log, __u16 controller);
+ void (*ctrl_list)(struct nvme_ctrl_list *ctrl_list);
+ void (*ctrl_registers)(void *bar, bool fabrics);
+ void (*directive)(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result, void *buf, __u32 len);
+ void (*discovery_log)(struct nvmf_discovery_log *log, int numrec);
+ void (*effects_log_list)(struct list_head *list);
+ void (*endurance_group_event_agg_log)(struct nvme_aggregate_predictable_lat_event *endurance_log, __u64 log_entries, __u32 size, const char *devname);
+ void (*endurance_group_list)(struct nvme_id_endurance_group_list *endgrp_list);
+ void (*endurance_log)(struct nvme_endurance_group_log *endurance_group, __u16 group_id, const char *devname);
+ void (*error_log)(struct nvme_error_log_page *err_log, int entries, const char *devname);
+ void (*fdp_config_log)(struct nvme_fdp_config_log *log, size_t len);
+ void (*fdp_event_log)(struct nvme_fdp_events_log *log);
+ void (*fdp_ruh_status)(struct nvme_fdp_ruh_status *status, size_t len);
+ void (*fdp_stats_log)(struct nvme_fdp_stats_log *log);
+ void (*fdp_usage_log)(struct nvme_fdp_ruhu_log *log, size_t len);
+ void (*fid_supported_effects_log)(struct nvme_fid_supported_effects_log *fid_log, const char *devname);
+ void (*fw_log)(struct nvme_firmware_slot *fw_log, const char *devname);
+ void (*id_ctrl)(struct nvme_id_ctrl *ctrl, void (*vs)(__u8 *vs, struct json_object *root));
+ void (*id_ctrl_nvm)(struct nvme_id_ctrl_nvm *ctrl_nvm);
+ void (*id_domain_list)(struct nvme_id_domain_list *id_dom);
+ void (*id_independent_id_ns)(struct nvme_id_independent_id_ns *ns, unsigned int nsid);
+ void (*id_iocs)(struct nvme_id_iocs *ioscs);
+ void (*id_ns)(struct nvme_id_ns *ns, unsigned int nsid, unsigned int lba_index, bool cap_only);
+ void (*id_ns_descs)(void *data, unsigned int nsid);
+ void (*id_ns_granularity_list)(const struct nvme_id_ns_granularity_list *list);
+ void (*id_nvmset_list)(struct nvme_id_nvmset_list *nvmset, unsigned int nvmeset_id);
+ void (*id_uuid_list)(const struct nvme_id_uuid_list *uuid_list);
+ void (*lba_status)(struct nvme_lba_status *list, unsigned long len);
+ void (*lba_status_log)(void *lba_status, __u32 size, const char *devname);
+ void (*media_unit_stat_log)(struct nvme_media_unit_stat_log *mus);
+ void (*mi_cmd_support_effects_log)(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log, const char *devname);
+ void (*ns_list)(struct nvme_ns_list *ns_list);
+ void (*ns_list_log)(struct nvme_ns_list *log, const char *devname);
+ void (*nvm_id_ns)(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid, struct nvme_id_ns *ns, unsigned int lba_index, bool cap_only);
+ void (*persistent_event_log)(void *pevent_log_info, __u8 action, __u32 size, const char *devname);
+ void (*predictable_latency_event_agg_log)(struct nvme_aggregate_predictable_lat_event *pea_log, __u64 log_entries, __u32 size, const char *devname);
+ void (*predictable_latency_per_nvmset)(struct nvme_nvmset_predictable_lat_log *plpns_log, __u16 nvmset_id, const char *devname);
+ void (*primary_ctrl_cap)(const struct nvme_primary_ctrl_cap *caps);
+ void (*resv_notification_log)(struct nvme_resv_notification_log *resv, const char *devname);
+ void (*resv_report)(struct nvme_resv_status *status, int bytes, bool eds);
+ void (*sanitize_log_page)(struct nvme_sanitize_log_page *sanitize_log, const char *devname);
+ void (*secondary_ctrl_list)(const struct nvme_secondary_ctrl_list *sc_list, __u32 count);
+ void (*select_result)(enum nvme_features_id fid, __u32 result);
+ void (*self_test_log)(struct nvme_self_test_log *self_test, __u8 dst_entries, __u32 size, const char *devname);
+ void (*single_property)(int offset, uint64_t value64);
+ void (*smart_log)(struct nvme_smart_log *smart, unsigned int nsid, const char *devname);
+ void (*supported_cap_config_list_log)(struct nvme_supported_cap_config_list_log *cap_log);
+ void (*supported_log_pages)(struct nvme_supported_log_pages *support_log, const char *devname);
+ void (*zns_start_zone_list)(__u64 nr_zones, struct json_object **zone_list);
+ void (*zns_changed_zone_log)(struct nvme_zns_changed_zone_log *log);
+ void (*zns_finish_zone_list)(__u64 nr_zones, struct json_object *zone_list);
+ void (*zns_id_ctrl)(struct nvme_zns_id_ctrl *ctrl);
+ void (*zns_id_ns)(struct nvme_zns_id_ns *ns, struct nvme_id_ns *id_ns);
+ void (*zns_report_zones)(void *report, __u32 descs, __u8 ext_size, __u32 report_size, struct json_object *zone_list);
+ void (*show_feature)(enum nvme_features_id fid, int sel, unsigned int result);
+ void (*show_feature_fields)(enum nvme_features_id fid, unsigned int result, unsigned char *buf);
+ void (*id_ctrl_rpmbs)(__le32 ctrl_rpmbs);
+ void (*lba_range)(struct nvme_lba_range_type *lbrt, int nr_ranges);
+ void (*lba_status_info)(__u32 result);
+ void (*d)(unsigned char *buf, int len, int width, int group);
+ void (*show_init)(void);
+ void (*show_finish)(void);
+
+ /* libnvme tree print functions */
+ void (*list_item)(nvme_ns_t n);
+ void (*list_items)(nvme_root_t t);
+ void (*print_nvme_subsystem_list)(nvme_root_t r, bool show_ana);
+ void (*topology_ctrl)(nvme_root_t r);
+ void (*topology_namespace)(nvme_root_t r);
+
+ /* status and error messages */
+ void (*connect_msg)(nvme_ctrl_t c);
+ void (*show_message)(bool error, const char *msg, va_list ap);
+ void (*show_perror)(const char *msg);
+ void (*show_status)(int status);
+ void (*show_error_status)(int status, const char *msg, va_list ap);
+
+ enum nvme_print_flags flags;
+};
+
+struct nvme_bar_cap {
+ __u16 mqes;
+ __u8 cqr:1;
+ __u8 ams:2;
+ __u8 rsvd19:5;
+ __u8 to;
+ __u16 dstrd:4;
+ __u16 nssrs:1;
+ __u16 css:8;
+ __u16 bps:1;
+ __u8 cps:2;
+ __u8 mpsmin:4;
+ __u8 mpsmax:4;
+ __u8 pmrs:1;
+ __u8 cmbs:1;
+ __u8 nsss:1;
+ __u8 crwms:1;
+ __u8 crims:1;
+ __u8 rsvd61:3;
+};
+
+#ifdef CONFIG_JSONC
+
+struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags);
+
+#else /* !CONFIG_JSONC */
+
+static inline struct print_ops *nvme_get_json_print_ops(enum nvme_print_flags flags) { return NULL; }
+
+#endif /* !CONFIG_JSONC */
+
+struct print_ops *nvme_get_stdout_print_ops(enum nvme_print_flags flags);
+struct print_ops *nvme_get_binary_print_ops(enum nvme_print_flags flags);
+
+void nvme_show_status(int status);
+void nvme_show_lba_status_info(__u32 result);
+void nvme_show_relatives(const char *name);
+
+void nvme_show_id_iocs(struct nvme_id_iocs *iocs, enum nvme_print_flags flags);
+void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
+ void (*vendor_show)(__u8 *vs, struct json_object *root));
+void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs, enum nvme_print_flags flags);
+void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ unsigned int lba_index, bool cap_only, enum nvme_print_flags flags);
+void nvme_show_cmd_set_independent_id_ns(
+ struct nvme_id_independent_id_ns *ns, unsigned int nsid,
+ enum nvme_print_flags flags);
+void nvme_show_resv_report(struct nvme_resv_status *status, int bytes, bool eds,
+ enum nvme_print_flags flags);
+void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges,
+ enum nvme_print_flags flags);
+void nvme_show_supported_log(struct nvme_supported_log_pages *support,
+ const char *devname, enum nvme_print_flags flags);
+void nvme_show_error_log(struct nvme_error_log_page *err_log, int entries,
+ const char *devname, enum nvme_print_flags flags);
+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_log *ana_log, const char *devname,
+ size_t len, 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_slot *fw_log, const char *devname,
+ enum nvme_print_flags flags);
+void nvme_print_effects_log_pages(struct list_head *list,
+ enum nvme_print_flags flags);
+void nvme_show_changed_ns_list_log(struct nvme_ns_list *log,
+ const char *devname, enum nvme_print_flags flags);
+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 nvme_show_predictable_latency_per_nvmset(
+ struct nvme_nvmset_predictable_lat_log *plpns_log,
+ __u16 nvmset_id, const char *devname, enum nvme_print_flags flags);
+void nvme_show_predictable_latency_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *pea_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+void nvme_show_persistent_event_log(void *pevent_log_info,
+ __u8 action, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+void nvme_show_endurance_group_event_agg_log(
+ struct nvme_aggregate_predictable_lat_event *endurance_log,
+ __u64 log_entries, __u32 size, const char *devname,
+ enum nvme_print_flags flags);
+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_notification_log *resv,
+ const char *devname, enum nvme_print_flags flags);
+void nvme_show_boot_part_log(void *bp_log, const char *devname,
+ __u32 size, enum nvme_print_flags flags);
+void nvme_show_phy_rx_eom_log(struct nvme_phy_rx_eom_log *log,
+ __u16 controller, enum nvme_print_flags flags);
+void nvme_show_fid_support_effects_log(struct nvme_fid_supported_effects_log *fid_log,
+ const char *devname, enum nvme_print_flags flags);
+void nvme_show_mi_cmd_support_effects_log(struct nvme_mi_cmd_supported_effects_log *mi_cmd_log,
+ const char *devname, enum nvme_print_flags flags);
+void nvme_show_media_unit_stat_log(struct nvme_media_unit_stat_log *mus,
+ enum nvme_print_flags flags);
+void nvme_show_supported_cap_config_log(struct nvme_supported_cap_config_list_log *caplog,
+ 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, enum nvme_print_flags flags);
+void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags);
+void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len,
+ enum nvme_print_flags flags);
+void nvme_show_list_items(nvme_root_t t, enum nvme_print_flags flags);
+void nvme_show_subsystem_list(nvme_root_t t, bool show_ana,
+ enum nvme_print_flags flags);
+void nvme_show_id_nvmset(struct nvme_id_nvmset_list *nvmset, unsigned nvmset_id,
+ enum nvme_print_flags flags);
+void nvme_show_primary_ctrl_cap(const struct nvme_primary_ctrl_cap *cap,
+ enum nvme_print_flags flags);
+void nvme_show_list_secondary_ctrl(const struct nvme_secondary_ctrl_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_list_ctrl(struct nvme_ctrl_list *ctrl_list,
+ enum nvme_print_flags flags);
+void nvme_show_id_domain_list(struct nvme_id_domain_list *id_dom,
+ enum nvme_print_flags flags);
+void nvme_show_endurance_group_list(struct nvme_id_endurance_group_list *endgrp_list,
+ enum nvme_print_flags flags);
+void nvme_show_list_ns(struct nvme_ns_list *ns_list,
+ enum nvme_print_flags flags);
+void nvme_show_topology(nvme_root_t t,
+ enum nvme_cli_topo_ranking ranking,
+ enum nvme_print_flags flags);
+
+void nvme_feature_show(enum nvme_features_id fid, int sel, unsigned int result);
+void nvme_feature_show_fields(enum nvme_features_id 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(enum nvme_features_id fid, __u32 result);
+
+void nvme_show_zns_id_ctrl(struct nvme_zns_id_ctrl *ctrl,
+ enum nvme_print_flags flags);
+void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm,
+ enum nvme_print_flags flags);
+void nvme_show_nvm_id_ns(struct nvme_nvm_id_ns *nvm_ns, unsigned int nsid,
+ struct nvme_id_ns *ns, unsigned int lba_index,
+ bool cap_only, enum nvme_print_flags flags);
+void nvme_show_zns_id_ns(struct nvme_zns_id_ns *ns,
+ struct nvme_id_ns *id_ns, enum nvme_print_flags flags);
+void nvme_zns_start_zone_list(__u64 nr_zones, struct json_object **zone_list,
+ enum nvme_print_flags flags);
+void nvme_show_zns_changed(struct nvme_zns_changed_zone_log *log,
+ enum nvme_print_flags flags);
+void nvme_zns_finish_zone_list(__u64 nr_zones, struct json_object *zone_list,
+ enum nvme_print_flags flags);
+void nvme_show_zns_report_zones(void *report, __u32 descs,
+ __u8 ext_size, __u32 report_size,
+ struct json_object *zone_list,
+ enum nvme_print_flags flags);
+void json_nvme_finish_zone_list(__u64 nr_zones,
+ struct json_object *zone_list);
+void nvme_show_list_item(nvme_ns_t n);
+
+void nvme_show_fdp_configs(struct nvme_fdp_config_log *configs, size_t len,
+ enum nvme_print_flags flags);
+void nvme_show_fdp_stats(struct nvme_fdp_stats_log *log,
+ enum nvme_print_flags flags);
+void nvme_show_fdp_events(struct nvme_fdp_events_log *log,
+ enum nvme_print_flags flags);
+void nvme_show_fdp_usage(struct nvme_fdp_ruhu_log *log, size_t len,
+ enum nvme_print_flags flags);
+void nvme_show_fdp_ruh_status(struct nvme_fdp_ruh_status *status, size_t len,
+ enum nvme_print_flags flags);
+
+void nvme_show_discovery_log(struct nvmf_discovery_log *log, uint64_t numrec,
+ enum nvme_print_flags flags);
+void nvme_show_connect_msg(nvme_ctrl_t c, enum nvme_print_flags flags);
+
+const char *nvme_ana_state_to_string(enum nvme_ana_state state);
+const char *nvme_cmd_to_string(int admin, __u8 opcode);
+const char *nvme_fdp_event_to_string(enum nvme_fdp_event_type event);
+const char *nvme_feature_lba_type_to_string(__u8 type);
+const char *nvme_feature_temp_sel_to_string(__u8 sel);
+const char *nvme_feature_temp_type_to_string(__u8 type);
+const char *nvme_feature_to_string(enum nvme_features_id feature);
+const char *nvme_feature_wl_hints_to_string(__u8 wh);
+const char *nvme_host_metadata_type_to_string(enum nvme_features_id fid, __u8 type);
+const char *nvme_log_to_string(__u8 lid);
+const char *nvme_nss_hw_error_to_string(__u16 error_code);
+const char *nvme_pel_event_to_string(int type);
+const char *nvme_register_pmr_hsts_to_string(__u8 hsts);
+const char *nvme_register_pmr_pmrszu_to_string(__u8 pmrszu);
+const char *nvme_register_szu_to_string(__u8 szu);
+const char *nvme_register_to_string(int reg);
+const char *nvme_resv_notif_to_string(__u8 type);
+const char *nvme_select_to_string(int sel);
+const char *nvme_sstat_status_to_string(__u16 status);
+const char *nvme_trtype_to_string(__u8 trtype);
+const char *nvme_zone_state_to_string(__u8 state);
+const char *nvme_zone_type_to_string(__u8 cond);
+const char *nvme_plm_window_to_string(__u32 plm);
+const char *nvme_ns_wp_cfg_to_string(enum nvme_ns_write_protect_cfg state);
+
+void nvme_dev_full_path(nvme_ns_t n, char *path, size_t len);
+void nvme_generic_full_path(nvme_ns_t n, char *path, size_t len);
+void nvme_show_message(bool error, const char *msg, ...);
+void nvme_show_perror(const char *msg);
+void nvme_show_error_status(int status, const char *msg, ...);
+void nvme_show_init(void);
+void nvme_show_finish(void);
+#endif /* NVME_PRINT_H */
diff --git a/nvme-rpmb.c b/nvme-rpmb.c
new file mode 100644
index 0000000..345e6ea
--- /dev/null
+++ b/nvme-rpmb.c
@@ -0,0 +1,1057 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 Micron Technology 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 <limits.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.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
+
+/*
+ * 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 algorithm name */
+ if (strlen(algo) > sizeof(provider_sa.salg_name)) {
+ fprintf(stderr, "%s: algorithm name overflow", __func__);
+ return hash;
+ }
+ 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_close_infd;
+ }
+
+ /* 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_close_infd;
+ }
+ }
+
+ /* now send data to hash */
+ outfd = accept(infd, NULL, 0);
+ if (outfd < 0) {
+ perror("accept");
+ goto out_close_infd;
+ }
+ error = send(outfd, data, datalen, 0);
+ if (error < 0) {
+ perror("send");
+ goto out_close_outfd;
+ }
+
+ /* read computed hash */
+ hash = (unsigned char *)calloc(hash_size, 1);
+ if (hash == NULL) {
+ perror("calloc");
+ goto out_close_outfd;
+ }
+
+ error = read(outfd, hash, hash_size);
+ if (error != hash_size) {
+ perror("read");
+ free(hash);
+ hash = NULL;
+ }
+out_close_outfd:
+ close(outfd);
+out_close_infd:
+ 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;
+ }
+ *data = buf;
+ *len = err;
+ err = 0;
+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
+
+static int send_rpmb_req(int fd, unsigned char tgt, int size,
+ struct rpmb_data_frame_t *req)
+{
+ struct nvme_security_send_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .nsid = 0,
+ .nssf = tgt,
+ .spsp0 = RPMB_NVME_SPSP,
+ .spsp1 = 0,
+ .secp = RPMB_NVME_SECP,
+ .tl = 0,
+ .data_len = size,
+ .data = (void *)req,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ return nvme_security_send(&args);
+}
+
+static int recv_rpmb_rsp(int fd, int tgt, int size,
+ struct rpmb_data_frame_t *rsp)
+{
+
+ struct nvme_security_receive_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .nsid = 0,
+ .nssf = tgt,
+ .spsp0 = RPMB_NVME_SPSP,
+ .spsp1 = 0,
+ .secp = RPMB_NVME_SECP,
+ .al = 0,
+ .data_len = size,
+ .data = (void *)rsp,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ return nvme_security_receive(&args);
+}
+
+/* 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;
+ int err;
+
+ if (keystr == NULL) {
+ if (keyfile != NULL) {
+ err = read_file(keyfile, &keybuf, keysize);
+ if (err < 0)
+ return NULL;
+ }
+ } 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(fd, 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(fd, 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)
+ return 0;
+ if ((rsp = rpmb_read_request(fd, req, req_size, rsp_size)) == NULL)
+ {
+ free(req);
+ return 0;
+ }
+
+ /* 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);
+ 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(req);
+ break;
+ }
+
+ 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;
+ }
+
+ /* reuse response buffer */
+ memset(rsp, 0, rsp_size);
+ err = recv_rpmb_rsp(fd, req->target, rsp_size, 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(fd, tgt, req_size, 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(fd, tgt, rsp_size, 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(fd, tgt, rsp_size, 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(fd, 0, req_size, 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(fd, 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;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_dev *dev;
+ int err = -1;
+
+ 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 ((err = parse_and_open(&dev, argc, argv, desc, opts)))
+ return err;
+
+ /* before parsing commands, check if controller supports any RPMB targets */
+ err = nvme_identify_ctrl(dev_fd(dev), &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, 0);
+ 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(dev_fd(dev), 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(dev_fd(dev),
+ &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 Partition Protection is %s\n",
+ ((cfg->bp_enable & 0x1) ? "Enabled" : "Disabled"));
+ printf("Boot Partition 1 is %s\n",
+ ((cfg->bp_lock & 0x2) ? "Locked" : "Unlocked"));
+ printf("Boot Partition 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(dev_fd(dev), cfg.target,
+ cfg.address, &msg_buf,
+ cfg.blocks,
+ (regs.access_size + 1));
+ if (err > 0 && msg_buf != NULL) {
+ printf("Writing %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(dev_fd(dev), 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(dev_fd(dev), msg_buf,
+ key_buf, key_size);
+ break;
+
+ case RPMB_REQ_AUTH_KEY_PROGRAM:
+ err = rpmb_program_auth_key(dev_fd(dev), cfg.target,
+ key_buf, key_size);
+ break;
+ default:
+ break;
+ }
+
+out:
+ /* release memory */
+ free(key_buf);
+ free(msg_buf);
+
+ /* close device */
+ dev_close(dev);
+
+ return err;
+}
diff --git a/nvme-wrap.c b/nvme-wrap.c
new file mode 100644
index 0000000..a61b489
--- /dev/null
+++ b/nvme-wrap.c
@@ -0,0 +1,436 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Definitions for the NVM Express interface: libnvme/libnvme-mi device
+ * wrappers.
+ */
+
+#include <errno.h>
+
+#include <libnvme.h>
+#include <libnvme-mi.h>
+
+#include "nvme.h"
+#include "nvme-wrap.h"
+
+/*
+ * Helper for libnvme functions that pass the fd/ep separately. These just
+ * pass the correct handle to the direct/MI function.
+ * @op: the name of the libnvme function, without the nvme_/nvme_mi prefix
+ * @d: device handle: struct nvme_dev
+ */
+#define do_admin_op(op, d, ...) ({ \
+ int __rc; \
+ if (d->type == NVME_DEV_DIRECT) \
+ __rc = nvme_ ## op(d->direct.fd, __VA_ARGS__); \
+ else if (d->type == NVME_DEV_MI) \
+ __rc = nvme_mi_admin_ ## op (d->mi.ctrl, __VA_ARGS__); \
+ else \
+ __rc = -ENODEV; \
+ __rc; })
+
+/*
+ * Helper for libnvme functions use the 'struct _args' pattern. These need
+ * the fd and timeout set for the direct interface, and pass the ep as
+ * an argument for the MI interface
+ * @op: the name of the libnvme function, without the nvme_/nvme_mi prefix
+ * @d: device handle: struct nvme_dev
+ * @args: op-specific args struct
+ */
+#define do_admin_args_op(op, d, args) ({ \
+ int __rc; \
+ if (d->type == NVME_DEV_DIRECT) { \
+ args->fd = d->direct.fd; \
+ __rc = nvme_ ## op(args); \
+ } else if (d->type == NVME_DEV_MI) \
+ __rc = nvme_mi_admin_ ## op (d->mi.ctrl, args); \
+ else \
+ __rc = -ENODEV; \
+ __rc; })
+
+int nvme_cli_identify(struct nvme_dev *dev, struct nvme_identify_args *args)
+{
+ return do_admin_args_op(identify, dev, args);
+}
+
+int nvme_cli_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl *ctrl)
+{
+ return do_admin_op(identify_ctrl, dev, ctrl);
+}
+
+int nvme_cli_identify_ctrl_list(struct nvme_dev *dev, __u16 ctrl_id,
+ struct nvme_ctrl_list *list)
+{
+ return do_admin_op(identify_ctrl_list, dev, ctrl_id, list);
+}
+
+int nvme_cli_identify_nsid_ctrl_list(struct nvme_dev *dev, __u32 nsid,
+ __u16 ctrl_id,
+ struct nvme_ctrl_list *list)
+{
+ return do_admin_op(identify_nsid_ctrl_list, dev, nsid, ctrl_id, list);
+}
+
+int nvme_cli_identify_ns(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_id_ns *ns)
+{
+ return do_admin_op(identify_ns, dev, nsid, ns);
+}
+
+int nvme_cli_identify_ns_descs(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_id_desc *descs)
+{
+ return do_admin_op(identify_ns_descs, dev, nsid, descs);
+}
+
+int nvme_cli_identify_allocated_ns(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_id_ns *ns)
+{
+ return do_admin_op(identify_allocated_ns, dev, nsid, ns);
+}
+
+int nvme_cli_identify_active_ns_list(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_list *list)
+{
+ return do_admin_op(identify_active_ns_list, dev, nsid, list);
+}
+
+int nvme_cli_identify_allocated_ns_list(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_list *list)
+{
+ return do_admin_op(identify_allocated_ns_list, dev, nsid, list);
+}
+
+int nvme_cli_identify_primary_ctrl(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_primary_ctrl_cap *cap)
+{
+ return do_admin_op(identify_primary_ctrl, dev, nsid, cap);
+}
+
+int nvme_cli_identify_secondary_ctrl_list(struct nvme_dev *dev,
+ __u16 ctrl_id,
+ struct nvme_secondary_ctrl_list *sc_list)
+{
+ return do_admin_op(identify_secondary_ctrl_list, dev, ctrl_id,
+ sc_list);
+}
+
+int nvme_cli_get_features(struct nvme_dev *dev,
+ struct nvme_get_features_args *args)
+{
+ return do_admin_args_op(get_features, dev, args);
+}
+
+int nvme_cli_ns_mgmt_delete(struct nvme_dev *dev, __u32 nsid)
+{
+ return do_admin_op(ns_mgmt_delete, dev, nsid);
+}
+
+int nvme_cli_ns_attach(struct nvme_dev *dev, struct nvme_ns_attach_args *args)
+{
+ return do_admin_args_op(ns_attach, dev, args);
+}
+
+int nvme_cli_ns_attach_ctrls(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist)
+{
+ return do_admin_op(ns_attach_ctrls, dev, nsid, ctrlist);
+}
+
+int nvme_cli_ns_detach_ctrls(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist)
+{
+ return do_admin_op(ns_detach_ctrls, dev, nsid, ctrlist);
+}
+
+int nvme_cli_format_nvm(struct nvme_dev *dev, struct nvme_format_nvm_args *args)
+{
+ return do_admin_args_op(format_nvm, dev, args);
+}
+
+int nvme_cli_sanitize_nvm(struct nvme_dev *dev, struct nvme_sanitize_nvm_args *args)
+{
+ return do_admin_args_op(sanitize_nvm, dev, args);
+}
+
+int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args)
+{
+ return do_admin_args_op(get_log, dev, args);
+}
+
+int nvme_cli_get_log_page(struct nvme_dev *dev, __u32 xfer_len,
+ struct nvme_get_log_args *args)
+{
+ return do_admin_op(get_log_page, dev, xfer_len, args);
+}
+
+int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae,
+ enum nvme_cmd_get_log_lid lid,
+ __u32 nsid, __u32 len, void *log)
+{
+ return do_admin_op(get_nsid_log, dev, rae, lid, nsid, len, log);
+}
+
+int nvme_cli_get_log_simple(struct nvme_dev *dev,
+ enum nvme_cmd_get_log_lid lid,
+ __u32 len, void *log)
+{
+ return do_admin_op(get_log_simple, dev, lid, len, log);
+}
+
+int nvme_cli_get_log_supported_log_pages(struct nvme_dev *dev, bool rae,
+ struct nvme_supported_log_pages *log)
+{
+ return do_admin_op(get_log_supported_log_pages, dev, rae, log);
+}
+
+int nvme_cli_get_log_error(struct nvme_dev *dev, unsigned int nr_entries,
+ bool rae, struct nvme_error_log_page *err_log)
+{
+ return do_admin_op(get_log_error, dev, nr_entries, rae, err_log);
+}
+
+int nvme_cli_get_log_smart(struct nvme_dev *dev, __u32 nsid, bool rae,
+ struct nvme_smart_log *smart_log)
+{
+ return do_admin_op(get_log_smart, dev, nsid, rae, smart_log);
+}
+
+int nvme_cli_get_log_fw_slot(struct nvme_dev *dev, bool rae,
+ struct nvme_firmware_slot *fw_log)
+{
+ return do_admin_op(get_log_fw_slot, dev, rae, fw_log);
+}
+
+int nvme_cli_get_log_changed_ns_list(struct nvme_dev *dev, bool rae,
+ struct nvme_ns_list *ns_log)
+{
+ return do_admin_op(get_log_changed_ns_list, dev, rae, ns_log);
+}
+
+int nvme_cli_get_log_cmd_effects(struct nvme_dev *dev, enum nvme_csi csi,
+ struct nvme_cmd_effects_log *effects_log)
+{
+ return do_admin_op(get_log_cmd_effects, dev, csi, effects_log);
+}
+
+int nvme_cli_get_log_device_self_test(struct nvme_dev *dev,
+ struct nvme_self_test_log *log)
+{
+ return do_admin_op(get_log_device_self_test, dev, log);
+}
+
+int nvme_cli_get_log_create_telemetry_host(struct nvme_dev *dev,
+ struct nvme_telemetry_log *log)
+{
+ return do_admin_op(get_log_create_telemetry_host, dev, log);
+}
+
+int nvme_cli_get_log_telemetry_host(struct nvme_dev *dev, __u64 offset,
+ __u32 len, void *log)
+{
+ return do_admin_op(get_log_telemetry_host, dev, offset, len, log);
+}
+
+int nvme_cli_get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae,
+ __u64 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_telemetry_ctrl, dev, rae, offset, len, log);
+}
+
+int nvme_cli_get_log_endurance_group(struct nvme_dev *dev, __u16 endgid,
+ struct nvme_endurance_group_log *log)
+{
+ return do_admin_op(get_log_endurance_group, dev, endgid, log);
+}
+
+int nvme_cli_get_log_predictable_lat_nvmset(struct nvme_dev *dev,
+ __u16 nvmsetid,
+ struct nvme_nvmset_predictable_lat_log *log)
+{
+ return do_admin_op(get_log_predictable_lat_nvmset, dev, nvmsetid, log);
+}
+
+int nvme_cli_get_log_predictable_lat_event(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_predictable_lat_event, dev, rae, offset,
+ len, log);
+}
+
+int nvme_cli_get_log_ana(struct nvme_dev *dev,
+ enum nvme_log_ana_lsp lsp, bool rae,
+ __u64 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_ana, dev, lsp, rae, offset, len, log);
+}
+
+int nvme_cli_get_log_ana_groups(struct nvme_dev *dev, bool rae, __u32 len,
+ struct nvme_ana_group_desc *log)
+{
+ return do_admin_op(get_log_ana_groups, dev, rae, len, log);
+}
+
+int nvme_cli_get_log_lba_status(struct nvme_dev *dev, bool rae,
+ __u64 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_lba_status, dev, rae, offset, len, log);
+}
+
+int nvme_cli_get_log_endurance_grp_evt(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_endurance_grp_evt, dev, rae, offset, len,
+ log);
+}
+
+int nvme_cli_get_log_fid_supported_effects(struct nvme_dev *dev, bool rae,
+ struct nvme_fid_supported_effects_log *log)
+{
+ return do_admin_op(get_log_fid_supported_effects, dev, rae, log);
+}
+
+int nvme_cli_get_log_mi_cmd_supported_effects(struct nvme_dev *dev, bool rae,
+ struct nvme_mi_cmd_supported_effects_log *log)
+{
+ return do_admin_op(get_log_mi_cmd_supported_effects, dev, rae, log);
+}
+
+int nvme_cli_get_log_boot_partition(struct nvme_dev *dev, bool rae, __u8 lsp,
+ __u32 len,
+ struct nvme_boot_partition *part)
+{
+ return do_admin_op(get_log_boot_partition, dev, rae, lsp, len, part);
+}
+
+int nvme_cli_get_log_phy_rx_eom(struct nvme_dev *dev, __u8 lsp, __u16 controller,
+ __u32 len, struct nvme_phy_rx_eom_log *part)
+{
+ return do_admin_op(get_log_phy_rx_eom, dev, lsp, controller, len, part);
+}
+
+int nvme_cli_get_log_discovery(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log)
+{
+ return do_admin_op(get_log_discovery, dev, rae, offset, len, log);
+}
+
+int nvme_cli_get_log_media_unit_stat(struct nvme_dev *dev, __u16 domid,
+ struct nvme_media_unit_stat_log *mus)
+{
+ return do_admin_op(get_log_media_unit_stat, dev, domid, mus);
+}
+
+int nvme_cli_get_log_support_cap_config_list(struct nvme_dev *dev,
+ __u16 domid,
+ struct nvme_supported_cap_config_list_log *cap)
+{
+ return do_admin_op(get_log_support_cap_config_list, dev, domid, cap);
+}
+
+int nvme_cli_get_log_reservation(struct nvme_dev *dev, bool rae,
+ struct nvme_resv_notification_log *log)
+{
+ return do_admin_op(get_log_reservation, dev, rae, log);
+}
+
+int nvme_cli_get_log_sanitize(struct nvme_dev *dev, bool rae,
+ struct nvme_sanitize_log_page *log)
+{
+ return do_admin_op(get_log_sanitize, dev, rae, log);
+}
+
+int nvme_cli_get_log_zns_changed_zones(struct nvme_dev *dev, __u32 nsid,
+ bool rae,
+ struct nvme_zns_changed_zone_log *log)
+{
+ return do_admin_op(get_log_zns_changed_zones, dev, nsid, rae, log);
+}
+
+int nvme_cli_get_log_persistent_event(struct nvme_dev *dev,
+ enum nvme_pevent_log_action action,
+ __u32 size, void *pevent_log)
+{
+ return do_admin_op(get_log_persistent_event, dev, action, size,
+ pevent_log);
+}
+
+int nvme_cli_fw_download(struct nvme_dev *dev,
+ struct nvme_fw_download_args *args)
+{
+ return do_admin_args_op(fw_download, dev, args);
+}
+
+int nvme_cli_fw_commit(struct nvme_dev *dev,
+ struct nvme_fw_commit_args *args)
+{
+ return do_admin_args_op(fw_commit, dev, args);
+}
+
+int nvme_cli_admin_passthru(struct nvme_dev *dev, __u8 opcode, __u8 flags,
+ __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13,
+ __u32 cdw14, __u32 cdw15, __u32 data_len,
+ void *data, __u32 metadata_len, void *metadata,
+ __u32 timeout_ms, __u32 *result)
+{
+ return do_admin_op(admin_passthru, dev, opcode, flags, rsvd, nsid,
+ cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15,
+ data_len, data, metadata_len, metadata, timeout_ms,
+ result);
+}
+
+/* The MI & direct interfaces don't have an exactly-matching API for
+ * ns_mgmt_create, as we don't support a timeout for MI.
+ */
+int nvme_cli_ns_mgmt_create(struct nvme_dev *dev,
+ struct nvme_ns_mgmt_host_sw_specified *data,
+ __u32 *nsid, __u32 timeout, __u8 csi)
+{
+ if (dev->type == NVME_DEV_DIRECT)
+ return nvme_ns_mgmt_create(dev_fd(dev), NULL, nsid, timeout,
+ csi, data);
+ if (dev->type == NVME_DEV_MI)
+ return nvme_mi_admin_ns_mgmt_create(dev->mi.ctrl, NULL,
+ csi, nsid, data);
+
+ return -ENODEV;
+}
+
+int nvme_cli_get_feature_length2(int fid, __u32 cdw11, enum nvme_data_tfr dir,
+ __u32 *len)
+{
+ int err;
+
+ err = nvme_get_feature_length2(fid, cdw11, dir, len);
+ if (err != -EEXIST)
+ return err;
+ return nvme_get_feature_length(fid, cdw11, len);
+}
+
+int nvme_cli_security_send(struct nvme_dev *dev,
+ struct nvme_security_send_args* args)
+{
+ return do_admin_args_op(security_send, dev, args);
+}
+
+int nvme_cli_security_receive(struct nvme_dev *dev,
+ struct nvme_security_receive_args* args)
+{
+ /* Cannot use do_admin_args_op here because the API have different suffix*/
+ if (dev->type == NVME_DEV_DIRECT) {
+ args->fd = dev->direct.fd;
+ args->timeout = NVME_DEFAULT_IOCTL_TIMEOUT;
+ return nvme_security_receive(args);
+ }
+
+ if (dev->type == NVME_DEV_MI)
+ return nvme_mi_admin_security_recv(dev->mi.ctrl, args);
+
+ return -ENODEV;
+}
+
+void nvme_cli_set_debug(struct nvme_dev *dev, bool set)
+{
+ if (dev->type == NVME_DEV_DIRECT)
+ nvme_set_debug(set);
+}
diff --git a/nvme-wrap.h b/nvme-wrap.h
new file mode 100644
index 0000000..c50df14
--- /dev/null
+++ b/nvme-wrap.h
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Definitions for the NVM Express interface: libnvme/libnvme-mi device
+ * wrappers.
+ */
+
+#ifndef _NVME_WRAP_H
+#define _NVME_WRAP_H
+
+#include "nvme.h"
+
+int nvme_cli_identify(struct nvme_dev *dev, struct nvme_identify_args *args);
+int nvme_cli_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl *ctrl);
+int nvme_cli_identify_ctrl_list(struct nvme_dev *dev, __u16 ctrl_id,
+ struct nvme_ctrl_list *list);
+int nvme_cli_identify_nsid_ctrl_list(struct nvme_dev *dev, __u32 nsid,
+ __u16 ctrl_id,
+ struct nvme_ctrl_list *list);
+int nvme_cli_identify_ns(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_id_ns *ns);
+int nvme_cli_identify_ns_descs(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_id_desc *descs);
+int nvme_cli_identify_allocated_ns(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_id_ns *ns);
+int nvme_cli_identify_active_ns_list(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_list *list);
+int nvme_cli_identify_allocated_ns_list(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ns_list *list);
+int nvme_cli_identify_primary_ctrl(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_primary_ctrl_cap *cap);
+int nvme_cli_identify_secondary_ctrl_list(struct nvme_dev *dev,
+ __u16 ctrl_id,
+ struct nvme_secondary_ctrl_list *sc_list);
+int nvme_cli_ns_mgmt_delete(struct nvme_dev *dev, __u32 nsid);
+int nvme_cli_ns_mgmt_create(struct nvme_dev *dev,
+ struct nvme_ns_mgmt_host_sw_specified *data,
+ __u32 *nsid, __u32 timeout, __u8 csi);
+
+int nvme_cli_ns_attach(struct nvme_dev *dev, struct nvme_ns_attach_args *args);
+
+int nvme_cli_ns_attach_ctrls(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist);
+int nvme_cli_ns_detach_ctrls(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_ctrl_list *ctrlist);
+
+int nvme_cli_format_nvm(struct nvme_dev *dev, struct nvme_format_nvm_args *args);
+int nvme_cli_sanitize_nvm(struct nvme_dev *dev,
+ struct nvme_sanitize_nvm_args *args);
+
+int nvme_cli_get_features(struct nvme_dev *dev,
+ struct nvme_get_features_args *args);
+
+
+int nvme_cli_get_log(struct nvme_dev *dev, struct nvme_get_log_args *args);
+int nvme_cli_get_log_page(struct nvme_dev *dev,
+ __u32 xfer_len,
+ struct nvme_get_log_args *args);
+
+int nvme_cli_get_nsid_log(struct nvme_dev *dev, bool rae,
+ enum nvme_cmd_get_log_lid lid,
+ __u32 nsid, __u32 len, void *log);
+int nvme_cli_get_log_simple(struct nvme_dev *dev,
+ enum nvme_cmd_get_log_lid lid,
+ __u32 len, void *log);
+int nvme_cli_get_log_supported_log_pages(struct nvme_dev *dev, bool rae,
+ struct nvme_supported_log_pages *log);
+int nvme_cli_get_log_error(struct nvme_dev *dev, unsigned int nr_entries,
+ bool rae, struct nvme_error_log_page *err_log);
+int nvme_cli_get_log_smart(struct nvme_dev *dev, __u32 nsid, bool rae,
+ struct nvme_smart_log *smart_log);
+int nvme_cli_get_log_fw_slot(struct nvme_dev *dev, bool rae,
+ struct nvme_firmware_slot *fw_log);
+int nvme_cli_get_log_changed_ns_list(struct nvme_dev *dev, bool rae,
+ struct nvme_ns_list *ns_log);
+int nvme_cli_get_log_cmd_effects(struct nvme_dev *dev, enum nvme_csi csi,
+ struct nvme_cmd_effects_log *effects_log);
+int nvme_cli_get_log_device_self_test(struct nvme_dev *dev,
+ struct nvme_self_test_log *log);
+int nvme_cli_get_log_create_telemetry_host(struct nvme_dev *dev,
+ struct nvme_telemetry_log *log);
+int nvme_cli_get_log_telemetry_host(struct nvme_dev *dev, __u64 offset,
+ __u32 len, void *log);
+int nvme_cli_get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae,
+ __u64 offset, __u32 len, void *log);
+int nvme_cli_get_log_endurance_group(struct nvme_dev *dev, __u16 endgid,
+ struct nvme_endurance_group_log *log);
+int nvme_cli_get_log_predictable_lat_nvmset(struct nvme_dev *dev,
+ __u16 nvmsetid,
+ struct nvme_nvmset_predictable_lat_log *log);
+int nvme_cli_get_log_predictable_lat_event(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log);
+int nvme_cli_get_log_ana(struct nvme_dev *dev,
+ enum nvme_log_ana_lsp lsp, bool rae,
+ __u64 offset, __u32 len, void *log);
+int nvme_cli_get_log_ana_groups(struct nvme_dev *dev, bool rae, __u32 len,
+ struct nvme_ana_group_desc *log);
+int nvme_cli_get_log_lba_status(struct nvme_dev *dev, bool rae,
+ __u64 offset, __u32 len, void *log);
+int nvme_cli_get_log_endurance_grp_evt(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log);
+int nvme_cli_get_log_fid_supported_effects(struct nvme_dev *dev, bool rae,
+ struct nvme_fid_supported_effects_log *log);
+int nvme_cli_get_log_mi_cmd_supported_effects(struct nvme_dev *dev, bool rae,
+ struct nvme_mi_cmd_supported_effects_log *log);
+int nvme_cli_get_log_boot_partition(struct nvme_dev *dev, bool rae, __u8 lsp,
+ __u32 len,
+ struct nvme_boot_partition *part);
+int nvme_cli_get_log_phy_rx_eom(struct nvme_dev *dev, __u8 lsp, __u16 controller,
+ __u32 len, struct nvme_phy_rx_eom_log *part);
+int nvme_cli_get_log_discovery(struct nvme_dev *dev, bool rae,
+ __u32 offset, __u32 len, void *log);
+int nvme_cli_get_log_media_unit_stat(struct nvme_dev *dev, __u16 domid,
+ struct nvme_media_unit_stat_log *mus);
+int nvme_cli_get_log_support_cap_config_list(struct nvme_dev *dev,
+ __u16 domid,
+ struct nvme_supported_cap_config_list_log *cap);
+int nvme_cli_get_log_reservation(struct nvme_dev *dev, bool rae,
+ struct nvme_resv_notification_log *log);
+int nvme_cli_get_log_sanitize(struct nvme_dev *dev, bool rae,
+ struct nvme_sanitize_log_page *log);
+int nvme_cli_get_log_zns_changed_zones(struct nvme_dev *dev, __u32 nsid,
+ bool rae,
+ struct nvme_zns_changed_zone_log *log);
+int nvme_cli_get_log_persistent_event(struct nvme_dev *dev,
+ enum nvme_pevent_log_action action,
+ __u32 size, void *pevent_log);
+
+int nvme_cli_fw_download(struct nvme_dev *dev,
+ struct nvme_fw_download_args *args);
+
+int nvme_cli_fw_commit(struct nvme_dev *dev,
+ struct nvme_fw_commit_args *args);
+
+int nvme_cli_admin_passthru(struct nvme_dev *dev, __u8 opcode, __u8 flags,
+ __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12, __u32 cdw13,
+ __u32 cdw14, __u32 cdw15, __u32 data_len,
+ void *data, __u32 metadata_len, void *metadata,
+ __u32 timeout_ms, __u32 *result);
+
+int nvme_cli_get_feature_length2(int fid, __u32 cdw11, enum nvme_data_tfr dir,
+ __u32 *len);
+
+int nvme_cli_security_send(struct nvme_dev *dev,
+ struct nvme_security_send_args* args);
+
+int nvme_cli_security_receive(struct nvme_dev *dev,
+ struct nvme_security_receive_args* args);
+
+void nvme_cli_set_debug(struct nvme_dev *dev, bool set);
+#endif /* _NVME_WRAP_H */
diff --git a/nvme.c b/nvme.c
new file mode 100644
index 0000000..e9aac8f
--- /dev/null
+++ b/nvme.c
@@ -0,0 +1,9105 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * NVM-Express command line utility.
+ *
+ * Copyright (c) 2014-2015, Intel Corporation.
+ *
+ * Written by Keith Busch <kbusch@kernel.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * This program uses NVMe IOCTLs to run native nvme commands to a device.
+ */
+#include "config.h"
+#include "nvme/tree.h"
+#include "nvme/types.h"
+#include "util/cleanup.h"
+#include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <signal.h>
+
+#include <linux/fs.h>
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if HAVE_SYS_RANDOM
+ #include <sys/random.h>
+#endif
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "plugin.h"
+#include "util/base64.h"
+#include "util/crc32.h"
+#include "nvme-wrap.h"
+#include "util/argconfig.h"
+#include "util/suffix.h"
+#include "fabrics.h"
+#define CREATE_CMD
+#include "nvme-builtin.h"
+#include "malloc.h"
+
+struct feat_cfg {
+ enum nvme_features_id feature_id;
+ __u32 namespace_id;
+ enum nvme_get_features_sel sel;
+ __u32 cdw11;
+ __u32 cdw12;
+ __u8 uuid_index;
+ __u32 data_len;
+ bool raw_binary;
+ bool human_readable;
+};
+
+struct passthru_config {
+ __u8 opcode;
+ __u8 flags;
+ __u16 rsvd;
+ __u32 namespace_id;
+ __u32 data_len;
+ __u32 metadata_len;
+ __u32 timeout;
+ __u32 cdw2;
+ __u32 cdw3;
+ __u32 cdw10;
+ __u32 cdw11;
+ __u32 cdw12;
+ __u32 cdw13;
+ __u32 cdw14;
+ __u32 cdw15;
+ char *input_file;
+ char *metadata;
+ bool raw_binary;
+ bool show_command;
+ bool dry_run;
+ bool read;
+ bool write;
+ __u8 prefill;
+ bool latency;
+};
+
+#define NVME_ARGS(n, ...) \
+ struct argconfig_commandline_options n[] = { \
+ OPT_FLAG("verbose", 'v', NULL, verbose), \
+ OPT_FMT("output-format", 'o', &output_format_val, output_format), \
+ ##__VA_ARGS__, \
+ OPT_END() \
+ }
+
+static const char nvme_version_string[] = NVME_VERSION;
+
+static struct plugin builtin = {
+ .commands = commands,
+ .name = NULL,
+ .desc = NULL,
+ .next = NULL,
+ .tail = &builtin,
+};
+
+static struct program nvme = {
+ .name = "nvme",
+ .version = nvme_version_string,
+ .usage = "<command> [<device>] [<args>]",
+ .desc = "The '<device>' may be either an NVMe character "
+ "device (ex: /dev/nvme0), an nvme block device "
+ "(ex: /dev/nvme0n1), or a mctp address in the form "
+ "mctp:<net>,<eid>[:ctrl-id]",
+ .extensions = &builtin,
+};
+
+const char *output_format = "Output format: normal|json|binary";
+static const char *app_tag = "app tag for end-to-end PI";
+static const char *app_tag_mask = "app tag mask for end-to-end PI";
+static const char *block_count = "number of blocks (zeroes based) on device to access";
+static const char *crkey = "current reservation key";
+static const char *csi = "command set identifier";
+static const char *buf_len = "buffer len (if) data is sent or received";
+static const char *domainid = "Domain Identifier";
+static const char *doper = "directive operation";
+static const char *dry = "show command instead of sending";
+static const char *dspec_w_dtype = "directive specification associated with directive type";
+static const char *dtype = "directive type";
+static const char *force_unit_access = "force device to commit data before command completes";
+static const char *human_readable_directive = "show directive in readable format";
+static const char *human_readable_identify = "show identify in readable format";
+static const char *human_readable_info = "show info in readable format";
+static const char *human_readable_log = "show log in readable format";
+static const char *iekey = "ignore existing res. key";
+static const char *latency = "output latency statistics";
+static const char *lba_format_index = "The index into the LBA Format list\n"
+ "identifying the LBA Format capabilities that are to be returned";
+static const char *limited_retry = "limit media access attempts";
+static const char *lsp = "log specific field";
+static const char *mos = "management operation specific";
+static const char *mo = "management operation";
+static const char *namespace_desired = "desired namespace";
+static const char *namespace_id_desired = "identifier of desired namespace";
+static const char *namespace_id_optional = "optional namespace attached to controller";
+static const char *nssf = "NVMe Security Specific Field";
+static const char *prinfo = "PI and check field";
+static const char *rae = "Retain an Asynchronous Event";
+static const char *raw_directive = "show directive in binary format";
+static const char *raw_dump = "dump output in binary format";
+static const char *raw_identify = "show identify in binary format";
+static const char *raw_log = "show log in binary format";
+static const char *raw_output = "output in binary format";
+static const char *ref_tag = "reference tag for end-to-end PI";
+static const char *raw_use = "use binary output";
+static const char *rtype = "reservation type";
+static const char *secp = "security protocol (cf. SPC-4)";
+static const char *spsp = "security-protocol-specific (cf. SPC-4)";
+static const char *start_block = "64-bit LBA of first block to access";
+static const char *storage_tag = "storage tag for end-to-end PI";
+static const char *timeout = "timeout value, in milliseconds";
+static const char *uuid_index = "UUID index";
+static const char *uuid_index_specify = "specify uuid index";
+static const char *verbose = "Increase output verbosity";
+static const char dash[51] = {[0 ... 49] = '=', '\0'};
+static const char space[51] = {[0 ... 49] = ' ', '\0'};
+
+static char *output_format_val = "normal";
+
+static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev);
+
+const char *nvme_strerror(int errnum)
+{
+ if (errnum >= ENVME_CONNECT_RESOLVE)
+ return nvme_errno_to_string(errnum);
+ return strerror(errnum);
+}
+
+int map_log_level(int verbose, bool quiet)
+{
+ int log_level;
+
+ /*
+ * LOG_NOTICE is unused thus the user has to provide two 'v' for getting
+ * any feedback at all. Thus skip this level
+ */
+ verbose++;
+
+ switch (verbose) {
+ case 0:
+ log_level = LOG_WARNING;
+ break;
+ case 1:
+ log_level = LOG_NOTICE;
+ break;
+ case 2:
+ log_level = LOG_INFO;
+ break;
+ default:
+ log_level = LOG_DEBUG;
+ break;
+ }
+ if (quiet)
+ log_level = LOG_ERR;
+
+ return log_level;
+}
+
+static ssize_t getrandom_bytes(void *buf, size_t buflen)
+{
+#if HAVE_SYS_RANDOM
+ return getrandom(buf, buflen, GRND_NONBLOCK);
+#else
+ ssize_t result;
+ int fd, err = 0;
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0)
+ return fd;
+ result = read(fd, buf, buflen);
+ if (result < 0)
+ err = errno;
+ close(fd);
+ errno = err;
+ return result;
+#endif
+}
+
+static bool is_chardev(struct nvme_dev *dev)
+{
+ return S_ISCHR(dev->direct.stat.st_mode);
+}
+
+static bool is_blkdev(struct nvme_dev *dev)
+{
+ return S_ISBLK(dev->direct.stat.st_mode);
+}
+
+static int open_dev_direct(struct nvme_dev **devp, char *devstr, int flags)
+{
+ struct nvme_dev *dev;
+ int err;
+
+ dev = calloc(1, sizeof(*dev));
+ if (!dev)
+ return -1;
+
+ dev->type = NVME_DEV_DIRECT;
+ dev->name = basename(devstr);
+ err = open(devstr, flags);
+ if (err < 0) {
+ nvme_show_perror(devstr);
+ goto err_free;
+ }
+ dev->direct.fd = err;
+
+ err = fstat(dev_fd(dev), &dev->direct.stat);
+ if (err < 0) {
+ nvme_show_perror(devstr);
+ goto err_close;
+ }
+ if (!is_chardev(dev) && !is_blkdev(dev)) {
+ nvme_show_error("%s is not a block or character device", devstr);
+ err = -ENODEV;
+ goto err_close;
+ }
+ *devp = dev;
+ return 0;
+
+err_close:
+ close(dev_fd(dev));
+err_free:
+ free(dev);
+ return err;
+}
+
+static int parse_mi_dev(char *dev, unsigned int *net, uint8_t *eid,
+ unsigned int *ctrl)
+{
+ int rc;
+
+ /* <net>,<eid>:<ctrl-id> form */
+ rc = sscanf(dev, "mctp:%u,%hhu:%u", net, eid, ctrl);
+ if (rc == 3)
+ return 0;
+
+ /* <net>,<eid> form, implicit ctrl-id = 0 */
+ *ctrl = 0;
+ rc = sscanf(dev, "mctp:%u,%hhu", net, eid);
+ if (rc == 2)
+ return 0;
+
+ return -1;
+}
+
+static int open_dev_mi_mctp(struct nvme_dev **devp, char *devstr)
+{
+ unsigned int net, ctrl_id;
+ struct nvme_dev *dev;
+ unsigned char eid;
+ int rc;
+
+ rc = parse_mi_dev(devstr, &net, &eid, &ctrl_id);
+ if (rc) {
+ nvme_show_error("invalid device specifier '%s'", devstr);
+ return rc;
+ }
+
+ dev = calloc(1, sizeof(*dev));
+ if (!dev)
+ return -1;
+
+ dev->type = NVME_DEV_MI;
+ dev->name = devstr;
+
+ /* todo: verbose argument */
+ dev->mi.root = nvme_mi_create_root(stderr, LOG_WARNING);
+ if (!dev->mi.root)
+ goto err_free;
+
+ dev->mi.ep = nvme_mi_open_mctp(dev->mi.root, net, eid);
+ if (!dev->mi.ep)
+ goto err_free_root;
+
+ dev->mi.ctrl = nvme_mi_init_ctrl(dev->mi.ep, ctrl_id);
+ if (!dev->mi.ctrl)
+ goto err_close_ep;
+
+ *devp = dev;
+ return 0;
+
+err_close_ep:
+ nvme_mi_close(dev->mi.ep);
+err_free_root:
+ nvme_mi_free_root(dev->mi.root);
+err_free:
+ free(dev);
+ return -1;
+}
+
+static int check_arg_dev(int argc, char **argv)
+{
+ if (optind >= argc) {
+ errno = EINVAL;
+ nvme_show_perror(argv[0]);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int get_dev(struct nvme_dev **dev, int argc, char **argv, int flags)
+{
+ char *devname;
+ int ret;
+
+ ret = check_arg_dev(argc, argv);
+ if (ret)
+ return ret;
+
+ devname = argv[optind];
+
+ if (!strncmp(devname, "mctp:", strlen("mctp:")))
+ ret = open_dev_mi_mctp(dev, devname);
+ else
+ ret = open_dev_direct(dev, devname, flags);
+
+ return ret != 0 ? -errno : 0;
+}
+
+int parse_and_open(struct nvme_dev **dev, int argc, char **argv,
+ const char *desc,
+ struct argconfig_commandline_options *opts)
+{
+ int ret;
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_dev(dev, argc, argv, O_RDONLY);
+ if (ret < 0)
+ argconfig_print_help(desc, opts);
+ else if (argconfig_parse_seen(opts, "verbose"))
+ nvme_cli_set_debug(*dev, true);
+
+ return ret;
+}
+
+int open_exclusive(struct nvme_dev **dev, int argc, char **argv,
+ int ignore_exclusive)
+{
+ int flags = O_RDONLY;
+
+ if (!ignore_exclusive)
+ flags |= O_EXCL;
+
+ return get_dev(dev, argc, argv, flags);
+}
+
+int validate_output_format(const char *format, enum nvme_print_flags *flags)
+{
+ enum nvme_print_flags f;
+
+ if (!format)
+ return -EINVAL;
+
+ if (!strcmp(format, "normal"))
+ f = NORMAL;
+ else if (!strcmp(format, "json"))
+ f = JSON;
+ else if (!strcmp(format, "binary"))
+ f = BINARY;
+ else
+ return -EINVAL;
+
+ *flags = f;
+
+ return 0;
+}
+
+bool nvme_is_output_format_json(void)
+{
+ enum nvme_print_flags flags;
+
+ if (validate_output_format(output_format_val, &flags))
+ return false;
+
+ return flags == JSON;
+}
+
+void dev_close(struct nvme_dev *dev)
+{
+ switch (dev->type) {
+ case NVME_DEV_DIRECT:
+ close(dev_fd(dev));
+ break;
+ case NVME_DEV_MI:
+ nvme_mi_close(dev->mi.ep);
+ nvme_mi_free_root(dev->mi.root);
+ break;
+ }
+ free(dev);
+}
+
+static int get_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve SMART log for the given device "
+ "(or optionally a namespace) in either decoded format "
+ "(default) or binary.";
+
+ _cleanup_free_ struct nvme_smart_log *smart_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ const char *namespace = "(optional) desired namespace";
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .raw_binary = false,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ smart_log = nvme_alloc(sizeof(*smart_log));
+ if (!smart_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_smart(dev, cfg.namespace_id, false,
+ smart_log);
+ if (!err)
+ nvme_show_smart_log(smart_log, cfg.namespace_id,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("smart log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_ana_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve ANA log for the given device in "
+ "decoded format (default), json or binary.";
+ const char *groups = "Return ANA groups only.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev= NULL;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_free_ void *ana_log = NULL;
+ size_t ana_log_len;
+ enum nvme_print_flags flags;
+ enum nvme_log_ana_lsp lsp;
+ int err = -1;
+
+ struct config {
+ bool groups;
+ };
+
+ struct config cfg = {
+ .groups = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("groups", 'g', &cfg.groups, groups));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err) {
+ nvme_show_error("ERROR : nvme_identify_ctrl() failed: %s",
+ nvme_strerror(errno));
+ return err;
+ }
+
+ ana_log_len = sizeof(struct nvme_ana_log) +
+ le32_to_cpu(ctrl->nanagrpid) * sizeof(struct nvme_ana_group_desc);
+ if (!(ctrl->anacap & (1 << 6)))
+ ana_log_len += le32_to_cpu(ctrl->mnan) * sizeof(__le32);
+
+ ana_log = nvme_alloc(ana_log_len);
+ if (!ana_log)
+ return -ENOMEM;
+
+ lsp = cfg.groups ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY :
+ NVME_LOG_ANA_LSP_RGO_NAMESPACES;
+
+ err = nvme_cli_get_log_ana(dev, lsp, true, 0, ana_log_len, ana_log);
+ if (!err)
+ nvme_show_ana_log(ana_log, dev->name, ana_log_len, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("ana-log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int parse_telemetry_da(struct nvme_dev *dev,
+ enum nvme_telemetry_da da,
+ struct nvme_telemetry_log *telem,
+ size_t *size)
+
+{
+ _cleanup_free_ struct nvme_id_ctrl *id_ctrl = NULL;
+ size_t dalb = 0;
+
+ id_ctrl = nvme_alloc(sizeof(*id_ctrl));
+ if (!id_ctrl)
+ return -ENOMEM;
+
+ switch (da) {
+ case NVME_TELEMETRY_DA_1:
+ dalb = le16_to_cpu(telem->dalb1);
+ break;
+ case NVME_TELEMETRY_DA_2:
+ dalb = le16_to_cpu(telem->dalb2);
+ break;
+ case NVME_TELEMETRY_DA_3:
+ /* dalb3 >= dalb2 >= dalb1 */
+ dalb = le16_to_cpu(telem->dalb3);
+ break;
+ case NVME_TELEMETRY_DA_4:
+ if (nvme_cli_identify_ctrl(dev, id_ctrl)) {
+ perror("identify-ctrl");
+ return -errno;
+ }
+
+ if (id_ctrl->lpa & 0x40) {
+ dalb = le32_to_cpu(telem->dalb4);
+ } else {
+ nvme_show_error(
+ "Data area 4 unsupported, bit 6 of Log Page Attributes not set");
+ return -EINVAL;
+ }
+ break;
+ default:
+ nvme_show_error("Invalid data area parameter - %d", da);
+ return -EINVAL;
+ }
+
+ if (dalb == 0) {
+ nvme_show_error("ERROR: No telemetry data block");
+ return -ENOENT;
+ }
+ *size = (dalb + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
+ return 0;
+}
+
+static int get_log_telemetry_ctrl(struct nvme_dev *dev, bool rae, size_t size,
+ struct nvme_telemetry_log **buf)
+{
+ struct nvme_telemetry_log *log;
+ int err;
+
+ log = nvme_alloc(size);
+ if (!log)
+ return -errno;
+
+ err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0, size, log);
+ if (err) {
+ free(log);
+ return -errno;
+ }
+
+ *buf = log;
+ return 0;
+}
+
+static int get_log_telemetry_host(struct nvme_dev *dev, size_t size,
+ struct nvme_telemetry_log **buf)
+{
+ struct nvme_telemetry_log *log;
+ int err;
+
+ log = nvme_alloc(size);
+ if (!log)
+ return -errno;
+
+ err = nvme_cli_get_log_telemetry_host(dev, 0, size, log);
+ if (err) {
+ free(log);
+ return -errno;
+ }
+
+ *buf = log;
+ return 0;
+}
+
+static int __create_telemetry_log_host(struct nvme_dev *dev,
+ enum nvme_telemetry_da da,
+ size_t *size,
+ struct nvme_telemetry_log **buf)
+{
+ _cleanup_free_ struct nvme_telemetry_log *log = NULL;
+ int err;
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_create_telemetry_host(dev, log);
+ if (err)
+ return -errno;
+
+ err = parse_telemetry_da(dev, da, log, size);
+ if (err)
+ return err;
+
+ return get_log_telemetry_host(dev, *size, buf);
+}
+
+static int __get_telemetry_log_ctrl(struct nvme_dev *dev,
+ bool rae,
+ enum nvme_telemetry_da da,
+ size_t *size,
+ struct nvme_telemetry_log **buf)
+{
+ struct nvme_telemetry_log *log;
+ int err;
+
+ log = nvme_alloc(NVME_LOG_TELEM_BLOCK_SIZE);
+ if (!log)
+ return -errno;
+
+ /*
+ * set rae = true so it won't clear the current telemetry log in
+ * controller
+ */
+ err = nvme_cli_get_log_telemetry_ctrl(dev, true, 0,
+ NVME_LOG_TELEM_BLOCK_SIZE,
+ log);
+ if (err)
+ goto free;
+
+ if (!log->ctrlavail) {
+ if (!rae) {
+ err = nvme_cli_get_log_telemetry_ctrl(dev, rae, 0,
+ NVME_LOG_TELEM_BLOCK_SIZE,
+ log);
+ goto free;
+ }
+
+ *size = NVME_LOG_TELEM_BLOCK_SIZE;
+ *buf = log;
+
+ printf("Warning: Telemetry Controller-Initiated Data Not Available.\n");
+ return 0;
+ }
+
+ err = parse_telemetry_da(dev, da, log, size);
+ if (err)
+ goto free;
+
+ return get_log_telemetry_ctrl(dev, rae, *size, buf);
+
+free:
+ free(log);
+ return err;
+}
+
+static int __get_telemetry_log_host(struct nvme_dev *dev,
+ enum nvme_telemetry_da da,
+ size_t *size,
+ struct nvme_telemetry_log **buf)
+{
+ _cleanup_free_ struct nvme_telemetry_log *log = NULL;
+ int err;
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -errno;
+
+ err = nvme_cli_get_log_telemetry_host(dev, 0,
+ NVME_LOG_TELEM_BLOCK_SIZE,
+ log);
+ if (err)
+ return err;
+
+ err = parse_telemetry_da(dev, da, log, size);
+ if (err)
+ return err;
+
+ return get_log_telemetry_host(dev, *size, buf);
+}
+
+static int get_telemetry_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve telemetry log and write to binary file";
+ const char *fname = "File name to save raw binary, includes header";
+ const char *hgen = "Have the host tell the controller to generate the report";
+ const char *cgen = "Gather report generated by the controller.";
+ const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
+
+ _cleanup_free_ struct nvme_telemetry_log *log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_file_ int output = -1;
+ int err = 0;
+ size_t total_size;
+ __u8 *data_ptr = NULL;
+ int data_written = 0, data_remaining = 0;
+
+ struct config {
+ char *file_name;
+ __u32 host_gen;
+ bool ctrl_init;
+ int data_area;
+ bool rae;
+ };
+ struct config cfg = {
+ .file_name = NULL,
+ .host_gen = 1,
+ .ctrl_init = false,
+ .data_area = 3,
+ .rae = true,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FILE("output-file", 'O', &cfg.file_name, fname),
+ OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen),
+ OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen),
+ OPT_UINT("data-area", 'd', &cfg.data_area, dgen),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.file_name) {
+ nvme_show_error("Please provide an output file!");
+ return -EINVAL;
+ }
+
+ cfg.host_gen = !!cfg.host_gen;
+ output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ nvme_show_error("Failed to open output file %s: %s!",
+ cfg.file_name, strerror(errno));
+ return output;
+ }
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -ENOMEM;
+
+ if (cfg.ctrl_init)
+ err = __get_telemetry_log_ctrl(dev, cfg.rae, cfg.data_area,
+ &total_size, &log);
+ else if (cfg.host_gen)
+ err = __create_telemetry_log_host(dev, cfg.data_area,
+ &total_size, &log);
+ else
+ err = __get_telemetry_log_host(dev, cfg.data_area,
+ &total_size, &log);
+
+ if (err < 0) {
+ nvme_show_error("get-telemetry-log: %s", nvme_strerror(errno));
+ return err;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "Failed to acquire telemetry log %d!\n", err);
+ return err;
+ }
+
+ data_written = 0;
+ data_remaining = total_size;
+ data_ptr = (__u8 *)log;
+
+ while (data_remaining) {
+ data_written = write(output, data_ptr, data_remaining);
+ if (data_written < 0) {
+ data_remaining = data_written;
+ break;
+ } else if (data_written <= data_remaining) {
+ data_remaining -= data_written;
+ data_ptr += data_written;
+ } else {
+ /* Unexpected overwrite */
+ fprintf(stderr, "Failure: Unexpected telemetry log overwrite - data_remaining = 0x%x, data_written = 0x%x\n",
+ data_remaining, data_written);
+ break;
+ }
+ }
+
+ if (fsync(output) < 0) {
+ nvme_show_error("ERROR : %s: : fsync : %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ return err;
+}
+
+static int get_endurance_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieves endurance groups log page and prints the log.";
+ const char *group_id = "The endurance group identifier";
+
+ _cleanup_free_ struct nvme_endurance_group_log *endurance_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 group_id;
+ };
+
+ struct config cfg = {
+ .group_id = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("group-id", 'g', &cfg.group_id, group_id));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ endurance_log = nvme_alloc(sizeof(*endurance_log));
+ if (!endurance_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_endurance_group(dev, cfg.group_id,
+ endurance_log);
+ if (!err)
+ nvme_show_endurance_log(endurance_log, cfg.group_id,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("endurance log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int collect_effects_log(struct nvme_dev *dev, enum nvme_csi csi,
+ struct list_head *list, int flags)
+{
+ nvme_effects_log_node_t *node;
+ int err;
+
+ node = nvme_alloc(sizeof(*node));
+ if (!node)
+ return -ENOMEM;
+
+ node->csi = csi;
+
+ err = nvme_cli_get_log_cmd_effects(dev, csi, &node->effects);
+ if (err) {
+ free(node);
+ return err;
+ }
+ list_add(list, &node->node);
+ return 0;
+}
+
+static int get_effects_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve command effects log page and print the table.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ struct list_head log_pages;
+ nvme_effects_log_node_t *node;
+
+ void *bar = NULL;
+
+ int err = -1;
+ enum nvme_print_flags flags;
+
+ struct config {
+ bool human_readable;
+ bool raw_binary;
+ int csi;
+ };
+
+ struct config cfg = {
+ .human_readable = false,
+ .raw_binary = false,
+ .csi = -1,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log),
+ OPT_INT("csi", 'c', &cfg.csi, csi));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ list_head_init(&log_pages);
+
+ if (cfg.csi < 0) {
+ nvme_root_t r;
+ __u64 cap;
+
+ r = nvme_scan(NULL);
+ bar = mmap_registers(r, dev);
+ nvme_free_tree(r);
+
+ if (bar) {
+ cap = mmio_read64(bar + NVME_REG_CAP);
+ munmap(bar, getpagesize());
+ } else {
+ struct nvme_get_property_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .offset = NVME_REG_CAP,
+ .value = &cap,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+ err = nvme_get_property(&args);
+ if (err)
+ goto cleanup_list;
+ }
+
+ if (NVME_CAP_CSS(cap) & NVME_CAP_CSS_NVM)
+ err = collect_effects_log(dev, NVME_CSI_NVM,
+ &log_pages, flags);
+
+ if (!err && (NVME_CAP_CSS(cap) & NVME_CAP_CSS_CSI))
+ err = collect_effects_log(dev, NVME_CSI_ZNS,
+ &log_pages, flags);
+ } else {
+ err = collect_effects_log(dev, cfg.csi, &log_pages, flags);
+ }
+
+ if (!err)
+ nvme_print_effects_log_pages(&log_pages, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("effects log page");
+
+cleanup_list:
+ while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node)))
+ free(node);
+
+ return err;
+}
+
+static int get_supported_log_pages(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve supported logs and print the table.";
+
+ _cleanup_free_ struct nvme_supported_log_pages *supports = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ supports = nvme_alloc(sizeof(*supports));
+ if (!supports)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_supported_log_pages(dev, false, supports);
+ if (!err)
+ nvme_show_supported_log(supports, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("supported log pages: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve specified number of "
+ "error log entries from a given device "
+ "in either decoded format (default) or binary.";
+ const char *log_entries = "number of entries to retrieve";
+ const char *raw = "dump in binary format";
+
+ _cleanup_free_ struct nvme_error_log_page *err_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u32 log_entries;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 64,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ nvme_show_error("non-zero log-entries is required param");
+ return -1;
+ }
+
+ err = nvme_cli_identify_ctrl(dev, &ctrl);
+ if (err < 0) {
+ nvme_show_perror("identify controller");
+ return err;
+ } else if (err) {
+ nvme_show_error("could not identify controller");
+ return err;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, ctrl.elpe + 1);
+ err_log = nvme_alloc(cfg.log_entries * sizeof(struct nvme_error_log_page));
+ if (!err_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_error(dev, cfg.log_entries, false, err_log);
+ if (!err)
+ nvme_show_error_log(err_log, cfg.log_entries,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("error log");
+
+ return err;
+}
+
+static int get_fw_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve the firmware log for the "
+ "specified device in either decoded format (default) or binary.";
+
+ _cleanup_free_ struct nvme_firmware_slot *fw_log = NULL;;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ fw_log = nvme_alloc(sizeof(*fw_log));
+ if (!fw_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_fw_slot(dev, false, fw_log);
+ if (!err)
+ nvme_show_fw_log(fw_log, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("fw log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Changed Namespaces log for the given device "
+ "in either decoded format (default) or binary.";
+
+ _cleanup_free_ struct nvme_ns_list *changed_ns_list_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_output));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ changed_ns_list_log = nvme_alloc(sizeof(*changed_ns_list_log));
+ if (!changed_ns_list_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_changed_ns_list(dev, true,
+ changed_ns_list_log);
+ if (!err)
+ nvme_show_changed_ns_list_log(changed_ns_list_log,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("changed ns list log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+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";
+
+ _cleanup_free_ struct nvme_nvmset_predictable_lat_log *plpns_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 nvmset_id;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 1,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("nvmset-id", 'i', &cfg.nvmset_id, nvmset_id),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ plpns_log = nvme_alloc(sizeof(*plpns_log));
+ if (!plpns_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_predictable_lat_nvmset(dev, cfg.nvmset_id,
+ plpns_log);
+ if (!err)
+ nvme_show_predictable_latency_per_nvmset(plpns_log, cfg.nvmset_id, dev->name,
+ flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("predictable latency per nvm set: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+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";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_free_ void *pea_log = NULL;
+ enum nvme_print_flags flags;
+ __u32 log_size;
+ int err;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ nvme_show_error("non-zero log-entries is required param");
+ return -EINVAL;
+ }
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err < 0) {
+ nvme_show_error("identify controller: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le32_to_cpu(ctrl->nsetidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+
+ pea_log = nvme_alloc(log_size);
+ if (!pea_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_predictable_lat_event(dev, cfg.rae, 0,
+ log_size, pea_log);
+ if (!err)
+ nvme_show_predictable_latency_event_agg_log(pea_log, cfg.log_entries, log_size,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("predictable latency event aggregate log page: %s",
+ nvme_strerror(errno));
+
+ return err;
+}
+
+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";
+
+ _cleanup_free_ struct nvme_persistent_event_log *pevent_collected = NULL;
+ _cleanup_free_ struct nvme_persistent_event_log *pevent = NULL;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ void *pevent_log_info;
+ int err;
+
+ struct config {
+ __u8 action;
+ __u32 log_len;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .action = 0xff,
+ .log_len = 0,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("action", 'a', &cfg.action, action),
+ OPT_UINT("log_len", 'l', &cfg.log_len, log_len),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ pevent = nvme_alloc(sizeof(*pevent));
+ if (!pevent)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_persistent_event(dev, cfg.action,
+ sizeof(*pevent), pevent);
+ if (err < 0) {
+ nvme_show_error("persistent event log: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ if (cfg.action == NVME_PEVENT_LOG_RELEASE_CTX) {
+ printf("Releasing Persistent Event Log Context\n");
+ return 0;
+ }
+
+ if (!cfg.log_len && cfg.action != NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ cfg.log_len = le64_to_cpu(pevent->tll);
+ } else if (!cfg.log_len && cfg.action == NVME_PEVENT_LOG_EST_CTX_AND_READ) {
+ printf("Establishing Persistent Event Log Context\n");
+ return 0;
+ }
+
+ /*
+ * if header already 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_huge(cfg.log_len, &mh);
+ if (!pevent_log_info)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_persistent_event(dev, cfg.action,
+ cfg.log_len, pevent_log_info);
+ if (!err) {
+ err = nvme_cli_get_log_persistent_event(dev, cfg.action,
+ sizeof(*pevent),
+ pevent);
+ if (err < 0) {
+ nvme_show_error("persistent event log: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+ pevent_collected = pevent_log_info;
+ if (pevent_collected->gen_number != pevent->gen_number) {
+ printf("Collected Persistent Event Log may be invalid,\n"
+ "Re-read the log is required\n");
+ return -EINVAL;
+ }
+
+ nvme_show_persistent_event_log(pevent_log_info, cfg.action,
+ cfg.log_len, dev->name, flags);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("persistent event log: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+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";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_free_ void *endurance_log = NULL;
+ enum nvme_print_flags flags;
+ __u32 log_size;
+ int err;
+
+ struct config {
+ __u64 log_entries;
+ bool rae;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .log_entries = 2044,
+ .rae = false,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ nvme_show_error("non-zero log-entries is required param");
+ return -EINVAL;
+ }
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err < 0) {
+ nvme_show_error("identify controller: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_error("could not identify controller");
+ return -ENODEV;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, le16_to_cpu(ctrl->endgidmax));
+ log_size = sizeof(__u64) + cfg.log_entries * sizeof(__u16);
+
+ endurance_log = nvme_alloc(log_size);
+ if (!endurance_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_endurance_grp_evt(dev, cfg.rae, 0, log_size,
+ endurance_log);
+ if (!err)
+ nvme_show_endurance_group_event_agg_log(endurance_log, cfg.log_entries, log_size,
+ dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("endurance group event aggregate log page: %s",
+ nvme_strerror(errno));
+
+ return err;
+}
+
+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.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *lba_status = NULL;
+ enum nvme_print_flags flags;
+ __u32 lslplen;
+ int err;
+
+ struct config {
+ bool rae;
+ };
+
+ struct config cfg = {
+ .rae = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("rae", 'r', &cfg.rae, rae));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ err = nvme_cli_get_log_lba_status(dev, true, 0, sizeof(__u32),
+ &lslplen);
+ if (err < 0) {
+ nvme_show_error("lba status log page: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ lba_status = nvme_alloc(lslplen);
+ if (!lba_status)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_lba_status(dev, cfg.rae, 0, lslplen, lba_status);
+ if (!err)
+ nvme_show_lba_status_log(lba_status, lslplen, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("lba status log page: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+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.";
+
+ _cleanup_free_ struct nvme_resv_notification_log *resv = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ resv = nvme_alloc(sizeof(*resv));
+ if (!resv)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_reservation(dev, false, resv);
+ if (!err)
+ nvme_show_resv_notif_log(resv, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("resv notifi log: %s", nvme_strerror(errno));
+
+ return err;
+
+}
+
+static int get_boot_part_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve Boot Partition "
+ "log page and prints it, for the given "
+ "device in either decoded format(default), json or binary.";
+ const char *fname = "boot partition data output file name";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_boot_partition *boot = NULL;
+ _cleanup_free_ __u8 *bp_log = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+ _cleanup_file_ int output = -1;
+ __u32 bpsz = 0;
+
+ struct config {
+ __u8 lsp;
+ char *file_name;
+ };
+
+ struct config cfg = {
+ .lsp = 0,
+ .file_name = NULL,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("lsp", 's', &cfg.lsp, lsp),
+ OPT_FILE("output-file", 'f', &cfg.file_name, fname));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (!cfg.file_name) {
+ nvme_show_error("Please provide an output file!");
+ return -1;
+ }
+
+ if (cfg.lsp > 127) {
+ nvme_show_error("invalid lsp param: %u", cfg.lsp);
+ return -1;
+ }
+
+ output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ nvme_show_error("Failed to open output file %s: %s!",
+ cfg.file_name, strerror(errno));
+ return output;
+ }
+
+ boot = nvme_alloc(sizeof(*boot));
+ if (!boot)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_boot_partition(dev, false, cfg.lsp,
+ sizeof(*boot), boot);
+ if (err < 0) {
+ nvme_show_error("boot partition log: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ bpsz = (boot->bpinfo & 0x7fff) * 128 * 1024;
+ bp_log = nvme_alloc(sizeof(*boot) + bpsz);
+ if (!bp_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_boot_partition(dev, false, cfg.lsp,
+ sizeof(*boot) + bpsz,
+ (struct nvme_boot_partition *)bp_log);
+ if (!err)
+ nvme_show_boot_part_log(&bp_log, dev->name, sizeof(*boot) + bpsz, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("boot partition log: %s", nvme_strerror(errno));
+
+ err = write(output, (void *) bp_log + sizeof(*boot), bpsz);
+ if (err != bpsz)
+ fprintf(stderr, "Failed to flush all data to file!\n");
+ else
+ printf("Data flushed into file %s\n", cfg.file_name);
+ err = 0;
+
+ return err;
+}
+
+static int get_phy_rx_eom_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Physical Interface Receiver Eye Opening "
+ "Measurement log for the given device in decoded format "
+ "(default), json or binary.";
+ const char *controller = "Target Controller ID.";
+ _cleanup_free_ struct nvme_phy_rx_eom_log *phy_rx_eom_log = NULL;
+ size_t phy_rx_eom_log_len;
+ enum nvme_print_flags flags;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err = -1;
+ __u8 lsp_tmp;
+
+ struct config {
+ __u8 lsp;
+ __u16 controller;
+ };
+
+ struct config cfg = {
+ .lsp = 0,
+ .controller = NVME_LOG_LSI_NONE,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("lsp", 's', &cfg.lsp, lsp),
+ OPT_SHRT("controller", 'c', &cfg.controller, controller));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.lsp > 127) {
+ nvme_show_error("invalid lsp param: %u", cfg.lsp);
+ return -1;
+ } else if ((cfg.lsp & 3) == 3) {
+ nvme_show_error("invalid measurement quality: %u", cfg.lsp & 3);
+ return -1;
+ } else if ((cfg.lsp & 12) == 12) {
+ nvme_show_error("invalid action: %u", cfg.lsp & 12);
+ return -1;
+ }
+
+ /* Fetching header to calculate total log length */
+ phy_rx_eom_log_len = sizeof(struct nvme_phy_rx_eom_log);
+ phy_rx_eom_log = nvme_alloc(phy_rx_eom_log_len);
+ if (!phy_rx_eom_log)
+ return -ENOMEM;
+
+ /* Just read measurement, take given action when fetching full log */
+ lsp_tmp = cfg.lsp & 0xf3;
+
+ err = nvme_cli_get_log_phy_rx_eom(dev, lsp_tmp, cfg.controller, phy_rx_eom_log_len,
+ phy_rx_eom_log);
+ if (err) {
+ if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("phy-rx-eom-log: %s", nvme_strerror(errno));
+
+ return err;
+ }
+
+ if (phy_rx_eom_log->eomip == NVME_PHY_RX_EOM_COMPLETED)
+ phy_rx_eom_log_len = le16_to_cpu(phy_rx_eom_log->hsize) +
+ le32_to_cpu(phy_rx_eom_log->dsize) *
+ le16_to_cpu(phy_rx_eom_log->nd);
+ else
+ phy_rx_eom_log_len = le16_to_cpu(phy_rx_eom_log->hsize);
+
+ phy_rx_eom_log = nvme_realloc(phy_rx_eom_log, phy_rx_eom_log_len);
+ if (!phy_rx_eom_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_phy_rx_eom(dev, cfg.lsp, cfg.controller, phy_rx_eom_log_len,
+ phy_rx_eom_log);
+ if (!err)
+ nvme_show_phy_rx_eom_log(phy_rx_eom_log, cfg.controller, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("phy-rx-eom-log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_media_unit_stat_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve the configuration and wear of media units and print it";
+
+ _cleanup_free_ struct nvme_media_unit_stat_log *mus = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u16 domainid;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .domainid = 0,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("domain-id", 'd', &cfg.domainid, domainid),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ mus = nvme_alloc(sizeof(*mus));
+ if (!mus)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_media_unit_stat(dev, cfg.domainid, mus);
+ if (!err)
+ nvme_show_media_unit_stat_log(mus, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("media unit status log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_supp_cap_config_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve the list of Supported Capacity Configuration Descriptors";
+
+ _cleanup_free_ struct nvme_supported_cap_config_list_log *cap_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u16 domainid;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .domainid = 0,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("domain-id", 'd', &cfg.domainid, domainid),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_use));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ cap_log = nvme_alloc(sizeof(*cap_log));
+ if (!cap_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_support_cap_config_list(dev, cfg.domainid,
+ cap_log);
+ if (!err)
+ nvme_show_supported_cap_config_log(cap_log, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("supported capacity configuration list log");
+
+ return err;
+}
+
+static int io_mgmt_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "I/O Management Send";
+ const char *data = "optional file for data (default stdin)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ int err = -1;
+ int dfd = STDIN_FILENO;
+
+ struct config {
+ __u16 mos;
+ __u8 mo;
+ __u32 namespace_id;
+ char *file;
+ __u32 data_len;
+ };
+
+ struct config cfg = {
+ .mos = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_SHRT("mos", 's', &cfg.mos, mos),
+ OPT_BYTE("mo", 'm', &cfg.mo, mo),
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_perror("get-namespace-id");
+ return err;
+ }
+ }
+
+ if (cfg.data_len) {
+ buf = nvme_alloc(cfg.data_len);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ if (cfg.file) {
+ dfd = open(cfg.file, O_RDONLY);
+ if (dfd < 0) {
+ nvme_show_perror(cfg.file);
+ return -errno;
+ }
+ }
+
+ err = read(dfd, buf, cfg.data_len);
+ if (err < 0) {
+ nvme_show_perror("read");
+ goto close_fd;
+ }
+
+ struct nvme_io_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .mos = cfg.mos,
+ .mo = cfg.mo,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+
+ err = nvme_io_mgmt_send(&args);
+ if (!err)
+ printf("io-mgmt-send: Success, mos:%u mo:%u nsid:%d\n",
+ cfg.mos, cfg.mo, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("io-mgmt-send");
+
+close_fd:
+ if (cfg.file)
+ close(dfd);
+ return err;
+}
+
+static int io_mgmt_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "I/O Management Receive";
+ const char *data = "optional file for data (default stdout)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ int err = -1;
+ _cleanup_file_ int dfd = -1;
+
+ struct config {
+ __u16 mos;
+ __u8 mo;
+ __u32 namespace_id;
+ char *file;
+ __u32 data_len;
+ };
+
+ struct config cfg = {
+ .mos = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_SHRT("mos", 's', &cfg.mos, mos),
+ OPT_BYTE("mo", 'm', &cfg.mo, mo),
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_perror("get-namespace-id");
+ return err;
+ }
+ }
+
+ if (cfg.data_len) {
+ buf = nvme_alloc(cfg.data_len);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ struct nvme_io_mgmt_recv_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .mos = cfg.mos,
+ .mo = cfg.mo,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+
+ err = nvme_io_mgmt_recv(&args);
+ if (!err) {
+ printf("io-mgmt-recv: Success, mos:%u mo:%u nsid:%d\n",
+ cfg.mos, cfg.mo, cfg.namespace_id);
+
+ if (cfg.file) {
+ dfd = open(cfg.file, O_WRONLY | O_CREAT, 0644);
+ if (dfd < 0) {
+ nvme_show_perror(cfg.file);
+ return -errno;
+ }
+
+ err = write(dfd, buf, cfg.data_len);
+ if (err < 0) {
+ nvme_show_perror("write");
+ return -errno;
+ }
+ } else {
+ d((unsigned char *)buf, cfg.data_len, 16, 1);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_perror("io-mgmt-recv");
+ }
+
+ return err;
+}
+
+static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve desired number of bytes "
+ "from a given log on a specified device in either "
+ "hex-dump (default) or binary format";
+ const char *log_id = "identifier of log to retrieve";
+ const char *log_len = "how many bytes to retrieve";
+ const char *aen = "result of the aen, use to override log id";
+ const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
+ const char *lsi = "log specific identifier specifies an identifier that is required for a particular log page";
+ const char *raw = "output in raw format";
+ const char *offset_type = "offset type";
+ const char *xfer_len = "read chunk size (default 4k)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ unsigned char *log = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u8 log_id;
+ __u32 log_len;
+ __u32 aen;
+ __u64 lpo;
+ __u8 lsp;
+ __u16 lsi;
+ bool rae;
+ __u8 uuid_index;
+ bool raw_binary;
+ __u8 csi;
+ bool ot;
+ __u32 xfer_len;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .log_id = 0xff,
+ .log_len = 0,
+ .aen = 0,
+ .lpo = NVME_LOG_LPO_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = NVME_LOG_LSI_NONE,
+ .rae = false,
+ .uuid_index = NVME_UUID_NONE,
+ .raw_binary = false,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .xfer_len = 4096,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_BYTE("log-id", 'i', &cfg.log_id, log_id),
+ OPT_UINT("log-len", 'l', &cfg.log_len, log_len),
+ OPT_UINT("aen", 'a', &cfg.aen, aen),
+ OPT_SUFFIX("lpo", 'L', &cfg.lpo, lpo),
+ OPT_BYTE("lsp", 's', &cfg.lsp, lsp),
+ OPT_SHRT("lsi", 'S', &cfg.lsi, lsi),
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
+ OPT_FLAG("ot", 'O', &cfg.ot, offset_type),
+ OPT_UINT("xfer-len", 'x', &cfg.xfer_len, xfer_len));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.aen) {
+ cfg.log_len = 4096;
+ cfg.log_id = (cfg.aen >> 16) & 0xff;
+ }
+
+ if (!cfg.log_len || cfg.log_len & 0x3) {
+ nvme_show_error("non-zero or non-dw alignment log-len is required param");
+ return -EINVAL;
+ }
+
+ if (cfg.lsp > 127) {
+ nvme_show_error("invalid lsp param");
+ return -EINVAL;
+ }
+
+ if (cfg.uuid_index > 127) {
+ nvme_show_error("invalid uuid index param");
+ return -EINVAL;
+ }
+
+ if (cfg.xfer_len == 0 || cfg.xfer_len % 4096) {
+ nvme_show_error("xfer-len argument invalid. It needs to be multiple of 4k");
+ return -EINVAL;
+ }
+
+ log = nvme_alloc(cfg.log_len);
+ if (!log)
+ return -ENOMEM;
+
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .lid = cfg.log_id,
+ .nsid = cfg.namespace_id,
+ .lpo = cfg.lpo,
+ .lsp = cfg.lsp,
+ .lsi = cfg.lsi,
+ .rae = cfg.rae,
+ .uuidx = cfg.uuid_index,
+ .csi = cfg.csi,
+ .ot = cfg.ot,
+ .len = cfg.log_len,
+ .log = log,
+ .result = NULL,
+ };
+ err = nvme_cli_get_log_page(dev, cfg.xfer_len, &args);
+ if (!err) {
+ if (!cfg.raw_binary) {
+ printf("Device:%s log-id:%d namespace-id:%#x\n", dev->name, cfg.log_id,
+ cfg.namespace_id);
+ d(log, cfg.log_len, 16, 1);
+ } else {
+ d_raw((unsigned char *)log, cfg.log_len);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("log page: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static int sanitize_log(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Retrieve sanitize log and show it.";
+
+ _cleanup_free_ struct nvme_sanitize_log_page *sanitize_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ bool rae;
+ bool human_readable;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .rae = false,
+ .human_readable = false,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("rae", 'r', &cfg.rae, rae),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_log));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ sanitize_log = nvme_alloc(sizeof(*sanitize_log));
+ if (!sanitize_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_sanitize(dev, cfg.rae, sanitize_log);
+ if (!err)
+ nvme_show_sanitize_log(sanitize_log, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("sanitize status log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_fid_support_effects_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve FID Support and Effects log and show it.";
+
+ _cleanup_free_ struct nvme_fid_supported_effects_log *fid_support_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ fid_support_log = nvme_alloc(sizeof(*fid_support_log));
+ if (!fid_support_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_fid_supported_effects(dev, false, fid_support_log);
+ if (!err)
+ nvme_show_fid_support_effects_log(fid_support_log, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("fid support effects log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_mi_cmd_support_effects_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve NVMe-MI Command Support and Effects log and show it.";
+
+ _cleanup_free_ struct nvme_mi_cmd_supported_effects_log *mi_cmd_support_log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_log));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ mi_cmd_support_log = nvme_alloc(sizeof(*mi_cmd_support_log));
+ if (!mi_cmd_support_log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_mi_cmd_supported_effects(dev, false, mi_cmd_support_log);
+ if (!err)
+ nvme_show_mi_cmd_support_effects_log(mi_cmd_support_log, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("mi command support effects log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int list_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Show controller list information for the subsystem the "
+ "given device is part of, or optionally controllers attached to a specific namespace.";
+ const char *controller = "controller to display";
+
+ _cleanup_free_ struct nvme_ctrl_list *cntlist = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 cntid;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .cntid = 0,
+ .namespace_id = NVME_NSID_NONE,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_optional));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ cntlist = nvme_alloc(sizeof(*cntlist));
+ if (!cntlist)
+ return -ENOMEM;
+
+ if (cfg.namespace_id == NVME_NSID_NONE)
+ err = nvme_cli_identify_ctrl_list(dev, cfg.cntid, cntlist);
+ else
+ err = nvme_cli_identify_nsid_ctrl_list(dev, cfg.namespace_id,
+ cfg.cntid, cntlist);
+ if (!err)
+ nvme_show_list_ctrl(cntlist, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("id controller list: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int list_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ 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";
+
+ _cleanup_free_ struct nvme_ns_list *ns_list = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ int csi;
+ bool all;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .csi = -1,
+ .all = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_INT("csi", 'y', &cfg.csi, csi),
+ OPT_FLAG("all", 'a', &cfg.all, all));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0 || (flags != JSON && flags != NORMAL)) {
+ nvme_show_error("Invalid output format");
+ return -EINVAL;
+ }
+
+ if (!cfg.namespace_id) {
+ nvme_show_error("invalid nsid parameter");
+ return -EINVAL;
+ }
+
+ ns_list = nvme_alloc(sizeof(*ns_list));
+ if (!ns_list)
+ return -ENOMEM;
+
+ struct nvme_identify_args args = {
+ .args_size = sizeof(args),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .data = ns_list,
+ .nsid = cfg.namespace_id - 1.
+ };
+ if (cfg.csi < 0) {
+ args.cns = cfg.all ? NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST :
+ NVME_IDENTIFY_CNS_NS_ACTIVE_LIST;
+ } else {
+ args.cns = cfg.all ? NVME_IDENTIFY_CNS_CSI_ALLOCATED_NS_LIST :
+ NVME_IDENTIFY_CNS_CSI_NS_ACTIVE_LIST;
+ args.csi = cfg.csi;
+ }
+
+ err = nvme_cli_identify(dev, &args);
+ if (!err)
+ nvme_show_list_ns(ns_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("id namespace list: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_ns_lba_format(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Namespace command to the given "
+ "device, returns capability field properties of the specified "
+ "LBA Format index in various formats.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u16 lba_format_index;
+ __u8 uuid_index;
+ };
+
+ struct config cfg = {
+ .lba_format_index = 0,
+ .uuid_index = NVME_UUID_NONE,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_identify_ns_csi_user_data_format(dev_fd(dev),
+ cfg.lba_format_index,
+ cfg.uuid_index, NVME_CSI_NVM, ns);
+ if (!err)
+ nvme_show_id_ns(ns, 0, cfg.lba_format_index, true, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("identify namespace for specific LBA format");
+
+ return err;
+}
+
+static int id_endurance_grp_list(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Show endurance group list information for the given endurance group id";
+ const char *endurance_grp_id = "Endurance Group ID";
+
+ _cleanup_free_ struct nvme_id_endurance_group_list *endgrp_list = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u16 endgrp_id;
+ };
+
+ struct config cfg = {
+ .endgrp_id = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("endgrp-id", 'i', &cfg.endgrp_id, endurance_grp_id));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0 || (flags != JSON && flags != NORMAL)) {
+ nvme_show_error("invalid output format");
+ return -EINVAL;
+ }
+
+ endgrp_list = nvme_alloc(sizeof(*endgrp_list));
+ if (!endgrp_list)
+ return -ENOMEM;
+
+ err = nvme_identify_endurance_group_list(dev_fd(dev), cfg.endgrp_id, endgrp_list);
+ if (!err)
+ nvme_show_endurance_group_list(endgrp_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("Id endurance group list: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int delete_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Delete the given namespace by "
+ "sending a namespace management command to "
+ "the provided device. All controllers should be detached from "
+ "the namespace prior to namespace deletion. A namespace ID "
+ "becomes inactive when that namespace is detached or, if "
+ "the namespace is not already inactive, once deleted.";
+ const char *namespace_id = "namespace to delete";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 timeout;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .timeout = 120000,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ err = nvme_cli_ns_mgmt_delete(dev, cfg.namespace_id);
+ if (!err)
+ printf("%s: Success, deleted nsid:%d\n", cmd->name, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("delete namespace: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd)
+{
+ _cleanup_free_ struct nvme_ctrl_list *cntlist = NULL;
+ _cleanup_free_ __u16 *ctrlist = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err, num, i, list[2048];
+
+ const char *namespace_id = "namespace to attach";
+ const char *cont = "optional comma-sep controller id list";
+
+ struct config {
+ __u32 namespace_id;
+ char *cntlist;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .cntlist = "",
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LIST("controllers", 'c', &cfg.cntlist, cont));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ nvme_show_error("%s: namespace-id parameter required", cmd->name);
+ return -EINVAL;
+ }
+
+ num = argconfig_parse_comma_sep_array(cfg.cntlist, list, 2047);
+ if (!num)
+ fprintf(stderr, "warning: empty controller-id list will result in no actual change in namespace attachment\n");
+
+ if (num == -1) {
+ nvme_show_error("%s: controller id list is malformed", cmd->name);
+ return -EINVAL;
+ }
+
+ cntlist = nvme_alloc(sizeof(*cntlist));
+ if (!cntlist)
+ return -ENOMEM;
+
+ ctrlist = nvme_alloc(sizeof(*ctrlist) * 2048);
+ if (!ctrlist)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++)
+ ctrlist[i] = (__u16)list[i];
+
+ nvme_init_ctrl_list(cntlist, num, ctrlist);
+
+ if (attach)
+ err = nvme_cli_ns_attach_ctrls(dev, cfg.namespace_id,
+ cntlist);
+ else
+ err = nvme_cli_ns_detach_ctrls(dev, cfg.namespace_id,
+ cntlist);
+
+ if (!err)
+ printf("%s: Success, nsid:%d\n", cmd->name, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror(attach ? "attach namespace" : "detach namespace");
+
+ return err;
+}
+
+static int attach_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Attach the given namespace to the "
+ "given controller or comma-sep list of controllers. ID of the "
+ "given namespace becomes active upon attachment to a "
+ "controller. A namespace must be attached to a controller "
+ "before IO commands may be directed to that namespace.";
+
+ return nvme_attach_ns(argc, argv, 1, desc, cmd);
+}
+
+static int detach_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Detach the given namespace from the "
+ "given controller; de-activates the given namespace's ID. A "
+ "namespace must be attached to a controller before IO "
+ "commands may be directed to that namespace.";
+
+ return nvme_attach_ns(argc, argv, 0, desc, cmd);
+}
+
+static int parse_lba_num_si(struct nvme_dev *dev, const char *opt,
+ const char *val, __u8 flbas, __u64 *num, __u32 align)
+{
+ _cleanup_free_ struct nvme_ns_list *ns_list = NULL;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ __u32 nsid = 1;
+ unsigned int remainder;
+ char *endptr;
+ int err = -EINVAL;
+ int i;
+ int lbas;
+
+ struct nvme_identify_args args = {
+ .args_size = sizeof(args),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
+ .nsid = nsid - 1.
+ };
+
+ if (!val)
+ return 0;
+
+ if (*num) {
+ nvme_show_error(
+ "Invalid specification of both %s and its SI argument, please specify only one",
+ opt);
+ return err;
+ }
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err) {
+ if (err < 0)
+ nvme_show_error("identify controller: %s", nvme_strerror(errno));
+ else
+ nvme_show_status(err);
+ return err;
+ }
+
+ ns_list = nvme_alloc(sizeof(*ns_list));
+ if (!ns_list)
+ return -ENOMEM;
+ args.data = ns_list;
+
+ if ((ctrl->oacs & 0x8) >> 3)
+ nsid = NVME_NSID_ALL;
+ else {
+ err = nvme_cli_identify(dev, &args);
+ if (err) {
+ if (err < 0)
+ nvme_show_error("identify namespace list: %s",
+ nvme_strerror(errno));
+ else
+ nvme_show_status(err);
+ return err;
+ }
+ nsid = le32_to_cpu(ns_list->ns[0]);
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, nsid, ns);
+ if (err) {
+ if (err < 0)
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ else
+ nvme_show_status(err);
+ return err;
+ }
+
+ i = flbas & NVME_NS_FLBAS_LOWER_MASK;
+ lbas = (1 << ns->lbaf[i].ds) + ns->lbaf[i].ms;
+
+ if (suffix_si_parse(val, &endptr, (uint64_t *)num)) {
+ nvme_show_error("Expected long suffixed integer argument for '%s-si' but got '%s'!",
+ opt, val);
+ return -errno;
+ }
+
+ if (endptr[0]) {
+ remainder = *num % align;
+ if (remainder)
+ *num += align - remainder;
+ }
+
+ if (endptr[0] != '\0')
+ *num /= lbas;
+
+ return 0;
+}
+
+static int create_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a namespace management command "
+ "to the specified device to create a namespace with the given "
+ "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 (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 *endgid = "Endurance Group Identifier (ENDGID)";
+ const char *csi = "command set identifier (CSI)";
+ const char *lbstm = "logical block storage tag mask (LBSTM)";
+ const char *nphndls = "Number of Placement Handles (NPHNDLS)";
+ const char *bs = "target block size, specify only if \'FLBAS\' value not entered";
+ const char *nsze_si = "size of ns (NSZE) in standard SI units";
+ const char *ncap_si = "capacity of ns (NCAP) in standard SI units";
+ const char *azr = "Allocate ZRWA Resources (AZR) for Zoned Namespace Command Set";
+ const char *rar = "Requested Active Resources (RAR) for Zoned Namespace Command Set";
+ const char *ror = "Requested Open Resources (ROR) for Zoned Namespace Command Set";
+ const char *rnumzrwa =
+ "Requested Number of ZRWA Resources (RNUMZRWA) for Zoned Namespace Command Set";
+ const char *phndls = "Comma separated list of Placement Handle Associated RUH";
+
+ _cleanup_free_ struct nvme_ns_mgmt_host_sw_specified *data = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err = 0, i;
+ __u32 nsid;
+ uint16_t num_phandle;
+ uint16_t phndl[128] = { 0, };
+ _cleanup_free_ struct nvme_id_ctrl *id = NULL;
+ _cleanup_free_ struct nvme_id_ns_granularity_list *gr_list = NULL;
+ __u32 align_nsze = 1 << 20; /* Default 1 MiB */
+ __u32 align_ncap = align_nsze;
+
+ struct config {
+ __u64 nsze;
+ __u64 ncap;
+ __u8 flbas;
+ __u8 dps;
+ __u8 nmic;
+ __u32 anagrpid;
+ __u16 nvmsetid;
+ __u16 endgid;
+ __u64 bs;
+ __u32 timeout;
+ __u8 csi;
+ __u64 lbstm;
+ __u16 nphndls;
+ char *nsze_si;
+ char *ncap_si;
+ bool azr;
+ __u32 rar;
+ __u32 ror;
+ __u32 rnumzrwa;
+ char *phndls;
+ };
+
+ struct config cfg = {
+ .nsze = 0,
+ .ncap = 0,
+ .flbas = 0xff,
+ .dps = 0,
+ .nmic = 0,
+ .anagrpid = 0,
+ .nvmsetid = 0,
+ .endgid = 0,
+ .bs = 0x00,
+ .timeout = 120000,
+ .csi = 0,
+ .lbstm = 0,
+ .nphndls = 0,
+ .nsze_si = NULL,
+ .ncap_si = NULL,
+ .azr = false,
+ .rar = 0,
+ .ror = 0,
+ .rnumzrwa = 0,
+ .phndls = "",
+ };
+
+ NVME_ARGS(opts,
+ OPT_SUFFIX("nsze", 's', &cfg.nsze, nsze),
+ OPT_SUFFIX("ncap", 'c', &cfg.ncap, ncap),
+ OPT_BYTE("flbas", 'f', &cfg.flbas, flbas),
+ OPT_BYTE("dps", 'd', &cfg.dps, dps),
+ OPT_BYTE("nmic", 'm', &cfg.nmic, nmic),
+ OPT_UINT("anagrp-id", 'a', &cfg.anagrpid, anagrpid),
+ OPT_UINT("nvmset-id", 'i', &cfg.nvmsetid, nvmsetid),
+ OPT_UINT("endg-id", 'e', &cfg.endgid, endgid),
+ OPT_SUFFIX("block-size", 'b', &cfg.bs, bs),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_BYTE("csi", 'y', &cfg.csi, csi),
+ OPT_SUFFIX("lbstm", 'l', &cfg.lbstm, lbstm),
+ OPT_SHRT("nphndls", 'n', &cfg.nphndls, nphndls),
+ OPT_STR("nsze-si", 'S', &cfg.nsze_si, nsze_si),
+ OPT_STR("ncap-si", 'C', &cfg.ncap_si, ncap_si),
+ OPT_FLAG("azr", 'z', &cfg.azr, azr),
+ OPT_UINT("rar", 'r', &cfg.rar, rar),
+ OPT_UINT("ror", 'O', &cfg.ror, ror),
+ OPT_UINT("rnumzrwa", 'u', &cfg.rnumzrwa, rnumzrwa),
+ OPT_LIST("phndls", 'p', &cfg.phndls, phndls));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.flbas != 0xff && cfg.bs != 0x00) {
+ nvme_show_error(
+ "Invalid specification of both FLBAS and Block Size, please specify only one");
+ return -EINVAL;
+ }
+ if (cfg.bs) {
+ if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) {
+ nvme_show_error(
+ "Invalid value for block size (%"PRIu64"). Block size must be a power of two",
+ (uint64_t)cfg.bs);
+ return -EINVAL;
+ }
+
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, ns);
+ if (err) {
+ if (err < 0) {
+ nvme_show_error("identify-namespace: %s", nvme_strerror(errno));
+ } else {
+ fprintf(stderr, "identify failed\n");
+ nvme_show_status(err);
+ }
+ return err;
+ }
+ for (i = 0; i <= ns->nlbaf; ++i) {
+ if ((1 << ns->lbaf[i].ds) == cfg.bs && ns->lbaf[i].ms == 0) {
+ cfg.flbas = i;
+ break;
+ }
+ }
+
+ }
+ if (cfg.flbas == 0xff) {
+ fprintf(stderr, "FLBAS corresponding to block size %"PRIu64" not found\n",
+ (uint64_t)cfg.bs);
+ fprintf(stderr, "Please correct block size, or specify FLBAS directly\n");
+
+ return -EINVAL;
+ }
+
+ id = nvme_alloc(sizeof(*id));
+ if (!id)
+ return -ENOMEM;
+
+ err = nvme_identify_ctrl(dev_fd(dev), id);
+ if (err) {
+ if (err < 0) {
+ nvme_show_error("identify-controller: %s", nvme_strerror(errno));
+ } else {
+ fprintf(stderr, "identify controller failed\n");
+ nvme_show_status(err);
+ }
+ return err;
+ }
+
+ if (id->ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) {
+ gr_list = nvme_alloc(sizeof(*gr_list));
+ if (!gr_list)
+ return -ENOMEM;
+
+ if (!nvme_identify_ns_granularity(dev_fd(dev), gr_list)) {
+ struct nvme_id_ns_granularity_desc *desc;
+ int index = cfg.flbas;
+
+ /* FIXME: add a proper bitmask to libnvme */
+ if (!(gr_list->attributes & 1)) {
+ /* Only the first descriptor is valid */
+ index = 0;
+ } else if (index > gr_list->num_descriptors) {
+ /*
+ * The descriptor will contain only zeroes
+ * so we don't need to read it.
+ */
+ goto parse_lba;
+ }
+ desc = &gr_list->entry[index];
+
+ if (desc->nszegran && desc->nszegran < align_nsze)
+ align_nsze = desc->nszegran;
+ if (desc->ncapgran && desc->ncapgran < align_ncap)
+ align_ncap = desc->ncapgran;
+ }
+ }
+
+parse_lba:
+ err = parse_lba_num_si(dev, "nsze", cfg.nsze_si, cfg.flbas, &cfg.nsze, align_nsze);
+ if (err)
+ return err;
+
+ err = parse_lba_num_si(dev, "ncap", cfg.ncap_si, cfg.flbas, &cfg.ncap, align_ncap);
+ if (err)
+ return err;
+
+ if (cfg.csi != NVME_CSI_ZNS && (cfg.azr || cfg.rar || cfg.ror || cfg.rnumzrwa)) {
+ nvme_show_error("Invalid ZNS argument is given (CSI:%#x)", cfg.csi);
+ return -EINVAL;
+ }
+
+ data = nvme_alloc(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
+ data->nsze = cpu_to_le64(cfg.nsze);
+ data->ncap = cpu_to_le64(cfg.ncap);
+ data->flbas = cfg.flbas;
+ data->dps = cfg.dps;
+ data->nmic = cfg.nmic;
+ data->anagrpid = cpu_to_le32(cfg.anagrpid);
+ data->nvmsetid = cpu_to_le16(cfg.nvmsetid);
+ data->endgid = cpu_to_le16(cfg.endgid);
+ data->lbstm = cpu_to_le64(cfg.lbstm);
+ data->zns.znsco = cfg.azr;
+ data->zns.rar = cpu_to_le32(cfg.rar);
+ data->zns.ror = cpu_to_le32(cfg.ror);
+ data->zns.rnumzrwa = cpu_to_le32(cfg.rnumzrwa);
+ data->nphndls = cpu_to_le16(cfg.nphndls);
+
+ num_phandle = argconfig_parse_comma_sep_array_short(cfg.phndls, phndl, ARRAY_SIZE(phndl));
+ if (cfg.nphndls != num_phandle) {
+ nvme_show_error("Invalid Placement handle list");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_phandle; i++)
+ data->phndl[i] = cpu_to_le16(phndl[i]);
+
+ err = nvme_cli_ns_mgmt_create(dev, data, &nsid, cfg.timeout, cfg.csi);
+ if (!err)
+ printf("%s: Success, created nsid:%d\n", cmd->name, nsid);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("create namespace: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static bool nvme_match_device_filter(nvme_subsystem_t s,
+ nvme_ctrl_t c, nvme_ns_t ns, void *f_args)
+{
+ int ret, instance, nsid, s_num;
+ char *devname = f_args;
+
+ if (!devname || !strlen(devname))
+ return true;
+
+ ret = sscanf(devname, "nvme%dn%d", &instance, &nsid);
+ if (ret != 2)
+ return true;
+
+ if (s) {
+ ret = sscanf(nvme_subsystem_get_name(s), "nvme-subsys%d",
+ &s_num);
+ if (ret == 1 && s_num == instance)
+ return true;
+ }
+ if (c) {
+ s = nvme_ctrl_get_subsystem(c);
+
+ ret = sscanf(nvme_subsystem_get_name(s), "nvme-subsys%d",
+ &s_num);
+ if (ret == 1 && s_num == instance)
+ return true;
+ }
+ if (ns) {
+ if (!strcmp(devname, nvme_ns_get_name(ns)))
+ return true;
+ }
+
+ return false;
+}
+
+static int list_subsys(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ nvme_root_t r = NULL;
+ enum nvme_print_flags flags;
+ const char *desc = "Retrieve information for subsystems";
+ nvme_scan_filter_t filter = NULL;
+ char *devname;
+ int err;
+ int nsid = NVME_NSID_ALL;
+
+ NVME_ARGS(opts);
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err < 0)
+ goto ret;
+
+ devname = NULL;
+ if (optind < argc)
+ devname = basename(argv[optind++]);
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0 || (flags != JSON && flags != NORMAL)) {
+ nvme_show_error("Invalid output format");
+ return -EINVAL;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ r = nvme_create_root(stderr, map_log_level(!!(flags & VERBOSE), false));
+ if (!r) {
+ if (devname)
+ nvme_show_error("Failed to scan nvme subsystem for %s", devname);
+ else
+ nvme_show_error("Failed to scan nvme subsystem");
+ err = -errno;
+ goto ret;
+ }
+
+ if (devname) {
+ int subsys_num;
+
+ if (sscanf(devname, "nvme%dn%d", &subsys_num, &nsid) != 2) {
+ nvme_show_error("Invalid device name %s", devname);
+ err = -EINVAL;
+ goto ret;
+ }
+ filter = nvme_match_device_filter;
+ }
+
+ err = nvme_scan_topology(r, filter, (void *)devname);
+ if (err) {
+ nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno));
+ goto ret;
+ }
+
+ nvme_show_subsystem_list(r, nsid != NVME_NSID_ALL, flags);
+
+ret:
+ if (r)
+ nvme_free_tree(r);
+ return err;
+}
+
+static int list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve basic information for all NVMe namespaces";
+ enum nvme_print_flags flags;
+ nvme_root_t r;
+ int err = 0;
+
+ NVME_ARGS(opts);
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err < 0)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0 || (flags != JSON && flags != NORMAL)) {
+ nvme_show_error("Invalid output format");
+ return -EINVAL;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ r = nvme_create_root(stderr, map_log_level(!!(flags & VERBOSE), false));
+ if (!r) {
+ nvme_show_error("Failed to create topology root: %s", nvme_strerror(errno));
+ return -errno;
+ }
+ err = nvme_scan_topology(r, NULL, NULL);
+ if (err < 0) {
+ nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno));
+ nvme_free_tree(r);
+ return err;
+ }
+
+ nvme_show_list_items(r, flags);
+ nvme_free_tree(r);
+
+ return err;
+}
+
+int __id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin,
+ void (*vs)(__u8 *vs, struct json_object *root))
+{
+ const char *desc = "Send an Identify Controller command to "
+ "the given device and report information about the specified "
+ "controller in human-readable or "
+ "binary format. May also return vendor-specific "
+ "controller attributes in hex-dump if requested.";
+ const char *vendor_specific = "dump binary vendor field";
+
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ bool vendor_specific;
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .vendor_specific = false,
+ .raw_binary = false,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("vendor-specific", 'V', &cfg.vendor_specific, vendor_specific),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.vendor_specific)
+ flags |= VS;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (!err)
+ nvme_show_id_ctrl(ctrl, flags, vs);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify controller: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ 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.";
+
+ _cleanup_free_ struct nvme_id_ctrl_nvm *ctrl_nvm = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ ctrl_nvm = nvme_alloc(sizeof(*ctrl_nvm));
+ if (!ctrl_nvm)
+ return -ENOMEM;
+
+ err = nvme_nvm_identify_ctrl(dev_fd(dev), ctrl_nvm);
+ if (!err)
+ nvme_show_id_ctrl_nvm(ctrl_nvm, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("nvm identify controller: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int nvm_id_ns(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Namespace NVM Command Set "
+ "command to the given device and report information about "
+ "the specified namespace in various formats.";
+
+ _cleanup_free_ struct nvme_nvm_id_ns *id_ns = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u32 namespace_id;
+ __u8 uuid_index;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .uuid_index = NVME_UUID_NONE,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_perror("get-namespace-id");
+ return err;
+ }
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+ if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ id_ns = nvme_alloc(sizeof(*id_ns));
+ if (!id_ns)
+ return -ENOMEM;
+
+ err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id,
+ cfg.uuid_index,
+ NVME_CSI_NVM, id_ns);
+ if (!err)
+ nvme_show_nvm_id_ns(id_ns, cfg.namespace_id, ns, 0, false, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("nvm identify namespace");
+
+ return err;
+}
+
+static int nvm_id_ns_lba_format(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an NVM Command Set specific Identify Namespace "
+ "command to the given device, returns capability field properties of "
+ "the specified LBA Format index in the specified namespace in various formats.";
+
+ _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u16 lba_format_index;
+ __u8 uuid_index;
+ };
+
+ struct config cfg = {
+ .lba_format_index = 0,
+ .uuid_index = NVME_UUID_NONE,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("lba-format-index", 'i', &cfg.lba_format_index, lba_format_index),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, NVME_NSID_ALL, ns);
+ if (err) {
+ ns->nlbaf = NVME_FEAT_LBA_RANGE_MAX - 1;
+ ns->nulbaf = 0;
+ }
+
+ nvm_ns = nvme_alloc(sizeof(*nvm_ns));
+ if (!nvm_ns)
+ return -ENOMEM;
+
+ err = nvme_identify_iocs_ns_csi_user_data_format(dev_fd(dev), cfg.lba_format_index,
+ cfg.uuid_index, NVME_CSI_NVM, nvm_ns);
+ if (!err)
+ nvme_show_nvm_id_ns(nvm_ns, 0, ns, cfg.lba_format_index, true, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_perror("NVM identify namespace for specific LBA format");
+
+ return err;
+}
+
+static int ns_descs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send Namespace Identification Descriptors command to the "
+ "given device, returns the namespace identification descriptors "
+ "of the specific namespace in either human-readable or binary format.";
+ const char *raw = "show descriptors in binary format";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *nsdescs = NULL;;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ nsdescs = nvme_alloc(sizeof(*nsdescs));
+ if (!nsdescs)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns_descs(dev, cfg.namespace_id, nsdescs);
+ if (!err)
+ nvme_show_id_ns_descs(nsdescs, cfg.namespace_id, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Namespace command to the "
+ "given device, returns properties of the specified namespace "
+ "in either human-readable or binary format. Can also return "
+ "binary vendor-specific namespace attributes.";
+ const char *force = "Return this namespace, even if not attached (1.2 devices only)";
+ const char *vendor_specific = "dump binary vendor fields";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ bool force;
+ bool vendor_specific;
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .force = false,
+ .vendor_specific = false,
+ .raw_binary = false,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_FLAG("force", 0, &cfg.force, force),
+ OPT_FLAG("vendor-specific", 'V', &cfg.vendor_specific, vendor_specific),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.vendor_specific)
+ flags |= VS;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ if (cfg.force)
+ err = nvme_cli_identify_allocated_ns(dev, cfg.namespace_id, ns);
+ else
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+
+ if (!err)
+ nvme_show_id_ns(ns, cfg.namespace_id, 0, false, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int cmd_set_independent_id_ns(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Send an I/O Command Set Independent Identify "
+ "Namespace command to the given device, returns properties of the "
+ "specified namespace in human-readable or binary or json format.";
+
+ _cleanup_free_ struct nvme_id_independent_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err = -1;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .raw_binary = false,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_identify),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_identify));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = cfg.namespace_id = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_perror("get-namespace-id");
+ return err;
+ }
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_identify_independent_identify_ns(dev_fd(dev), cfg.namespace_id, ns);
+ if (!err)
+ nvme_show_cmd_set_independent_id_ns(ns, cfg.namespace_id, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("I/O command set independent identify namespace: %s",
+ nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_ns_granularity(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Namespace Granularity List command to the "
+ "given device, returns namespace granularity list "
+ "in either human-readable or binary format.";
+
+ _cleanup_free_ struct nvme_id_ns_granularity_list *granularity_list = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ granularity_list = nvme_alloc(NVME_IDENTIFY_DATA_SIZE);
+ if (!granularity_list)
+ return -ENOMEM;
+
+ err = nvme_identify_ns_granularity(dev_fd(dev), granularity_list);
+ if (!err)
+ nvme_show_id_ns_granularity_list(granularity_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify namespace granularity: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_nvmset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify NVM Set List command to the "
+ "given device, returns entries for NVM Set identifiers greater "
+ "than or equal to the value specified CDW11.NVMSETID "
+ "in either binary format or json format";
+ const char *nvmset_id = "NVM Set Identify value";
+
+ _cleanup_free_ struct nvme_id_nvmset_list *nvmset = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 nvmset_id;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ nvmset = nvme_alloc(sizeof(*nvmset));
+ if (!nvmset)
+ return -ENOMEM;
+
+ err = nvme_identify_nvmset_list(dev_fd(dev), cfg.nvmset_id, nvmset);
+ if (!err)
+ nvme_show_id_nvmset(nvmset, cfg.nvmset_id, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify nvm set list: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int id_uuid(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify UUID List command to the "
+ "given device, returns list of supported Vendor Specific UUIDs "
+ "in either human-readable or binary format.";
+ const char *raw = "show uuid in binary format";
+ const char *human_readable = "show uuid in readable format";
+
+ _cleanup_free_ struct nvme_id_uuid_list *uuid_list = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .raw_binary = false,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ uuid_list = nvme_alloc(sizeof(*uuid_list));
+ if (!uuid_list)
+ return -ENOMEM;
+
+ err = nvme_identify_uuid(dev_fd(dev), uuid_list);
+ if (!err)
+ nvme_show_id_uuid_list(uuid_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify UUID list: %s", nvme_strerror(errno));
+
+ 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";
+
+ _cleanup_free_ struct nvme_id_iocs *iocs = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u16 cntid;
+ };
+
+ struct config cfg = {
+ .cntid = 0xffff,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("controller-id", 'c', &cfg.cntid, controller_id));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ iocs = nvme_alloc(sizeof(*iocs));
+ if (!iocs)
+ return -ENOMEM;
+
+ err = nvme_identify_iocs(dev_fd(dev), cfg.cntid, iocs);
+ if (!err) {
+ printf("NVMe Identify I/O Command Set:\n");
+ nvme_show_id_iocs(iocs, 0);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("NVMe Identify I/O Command Set: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static int id_domain(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Domain List command to the "
+ "given device, returns properties of the specified domain "
+ "in either normal|json|binary format.";
+ const char *domain_id = "identifier of desired domain";
+
+ _cleanup_free_ struct nvme_id_domain_list *id_domain = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 dom_id;
+ };
+
+ struct config cfg = {
+ .dom_id = 0xffff,
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("dom-id", 'd', &cfg.dom_id, domain_id));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ id_domain = nvme_alloc(sizeof(*id_domain));
+ if (!id_domain)
+ return -ENOMEM;
+
+ err = nvme_identify_domain_list(dev_fd(dev), cfg.dom_id, id_domain);
+ if (!err) {
+ printf("NVMe Identify command for Domain List is successful:\n");
+ printf("NVMe Identify Domain List:\n");
+ nvme_show_id_domain_list(id_domain, flags);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("NVMe Identify Domain List: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get namespace ID of a the block device.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ unsigned int nsid;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_nsid(dev_fd(dev), &nsid);
+ if (err < 0) {
+ nvme_show_error("get namespace ID: %s", nvme_strerror(errno));
+ return -errno;
+ }
+
+ printf("%s: namespace-id:%d\n", dev->name, nsid);
+
+ return 0;
+}
+
+static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Virtualization Management command is supported by primary controllers "
+ "that support the Virtualization Enhancements capability. This command is used for:\n"
+ " 1. Modifying Flexible Resource allocation for the primary controller\n"
+ " 2. Assigning Flexible Resources for secondary controllers\n"
+ " 3. Setting the Online and Offline state for secondary controllers";
+ const char *cntlid = "Controller Identifier(CNTLID)";
+ const char *rt = "Resource Type(RT): [0,1]\n"
+ "0h: VQ Resources\n"
+ "1h: VI Resources";
+ const char *act = "Action(ACT): [1,7,8,9]\n"
+ "1h: Primary Flexible\n"
+ "7h: Secondary Offline\n"
+ "8h: Secondary Assign\n"
+ "9h: Secondary Online";
+ const char *nr = "Number of Controller Resources(NR)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u16 cntlid;
+ __u8 rt;
+ __u8 act;
+ __u16 nr;
+ };
+
+ struct config cfg = {
+ .cntlid = 0,
+ .rt = 0,
+ .act = 0,
+ .nr = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid),
+ OPT_BYTE("rt", 'r', &cfg.rt, rt),
+ OPT_BYTE("act", 'a', &cfg.act, act),
+ OPT_SHRT("nr", 'n', &cfg.nr, nr));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ struct nvme_virtual_mgmt_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .act = cfg.act,
+ .rt = cfg.rt,
+ .cntlid = cfg.cntlid,
+ .nr = cfg.nr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_virtual_mgmt(&args);
+ if (!err)
+ printf("success, Number of Controller Resources Modified (NRM):%#x\n", result);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("virt-mgmt: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int primary_ctrl_caps(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *cntlid = "Controller ID";
+ 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.";
+
+ _cleanup_free_ struct nvme_primary_ctrl_cap *caps = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 cntlid;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .cntlid = 0,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_info));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ caps = nvme_alloc(sizeof(*caps));
+ if (!caps)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_primary_ctrl(dev, cfg.cntlid, caps);
+ if (!err)
+ nvme_show_primary_ctrl_cap(caps, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify primary controller capabilities: %s",
+ nvme_strerror(errno));
+
+ return err;
+}
+
+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 of the given device.";
+ const char *controller = "lowest controller identifier to display";
+ const char *num_entries = "number of entries to retrieve";
+
+ _cleanup_free_ struct nvme_secondary_ctrl_list *sc_list = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u16 cntid;
+ __u32 num_entries;
+ };
+
+ struct config cfg = {
+ .cntid = 0,
+ .num_entries = ARRAY_SIZE(sc_list->sc_entry),
+ };
+
+ NVME_ARGS(opts,
+ OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
+ OPT_UINT("num-entries", 'e', &cfg.num_entries, num_entries));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (!cfg.num_entries) {
+ nvme_show_error("non-zero num-entries is required param");
+ return -EINVAL;
+ }
+
+ sc_list = nvme_alloc(sizeof(*sc_list));
+ if (!sc_list)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_secondary_ctrl_list(dev, cfg.cntid, sc_list);
+ if (!err)
+ nvme_show_list_secondary_ctrl(sc_list, cfg.num_entries, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("id secondary controller list: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static void intr_self_test(int signum)
+{
+ printf("\nInterrupted device self-test operation by %s\n", strsignal(signum));
+
+ errno = EINTR;
+}
+
+static int sleep_self_test(unsigned int seconds)
+{
+ errno = 0;
+
+ sleep(seconds);
+
+ if (errno)
+ return -errno;
+
+ return 0;
+}
+
+static int wait_self_test(struct nvme_dev *dev)
+{
+ static const char spin[] = {'-', '\\', '|', '/' };
+ _cleanup_free_ struct nvme_self_test_log *log = NULL;
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ int err, i = 0, p = 0, cnt = 0;
+ int wthr;
+
+ signal(SIGINT, intr_self_test);
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err) {
+ nvme_show_error("identify-ctrl: %s", nvme_strerror(errno));
+ return err;
+ }
+
+ wthr = le16_to_cpu(ctrl->edstt) * 60 / 100 + 60;
+
+ printf("Waiting for self test completion...\n");
+ while (true) {
+ printf("\r[%.*s%c%.*s] %3d%%", p / 2, dash, spin[i % 4], 49 - p / 2, space, p);
+ fflush(stdout);
+ err = sleep_self_test(1);
+ if (err)
+ return err;
+
+ err = nvme_cli_get_log_device_self_test(dev, log);
+ if (err) {
+ printf("\n");
+ if (err < 0)
+ perror("self test log\n");
+ else
+ nvme_show_status(err);
+ return err;
+ }
+
+ if (++cnt > wthr) {
+ nvme_show_error("no progress for %d seconds, stop waiting", wthr);
+ return -EIO;
+ }
+
+ if (log->completion == 0 && p > 0) {
+ printf("\r[%.*s] %3d%%\n", 50, dash, 100);
+ break;
+ }
+
+ if (log->completion < p) {
+ printf("\n");
+ nvme_show_error("progress broken");
+ return -EIO;
+ } else if (log->completion != p) {
+ p = log->completion;
+ cnt = 0;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static void abort_self_test(struct nvme_dev_self_test_args *args)
+{
+ int err;
+
+ args->stc = NVME_DST_STC_ABORT;
+
+ err = nvme_dev_self_test(args);
+ if (!err)
+ printf("Aborting device self-test operation\n");
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("Device self-test: %s", nvme_strerror(errno));
+}
+
+static int device_self_test(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Implementing the device self-test feature "
+ "which provides the necessary log to determine the state of the device";
+ const char *namespace_id =
+ "Indicate the namespace in which the device self-test has to be carried out";
+ const char *self_test_code =
+ "This field specifies the action taken by the device self-test command :\n"
+ "0h Show current state of device self-test operation\n"
+ "1h Start a short device self-test operation\n"
+ "2h Start a extended device self-test operation\n"
+ "eh Start a vendor specific device self-test operation\n"
+ "fh Abort the device self-test operation";
+ const char *wait = "Wait for the test to finish";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u8 stc;
+ bool wait;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .stc = NVME_ST_CODE_RESERVED,
+ .wait = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_BYTE("self-test-code", 's', &cfg.stc, self_test_code),
+ OPT_FLAG("wait", 'w', &cfg.wait, wait));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.stc == NVME_ST_CODE_RESERVED) {
+ _cleanup_free_ struct nvme_self_test_log *log = NULL;
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_device_self_test(dev, log);
+ if (err) {
+ printf("\n");
+ if (err < 0)
+ perror("self test log\n");
+ else
+ nvme_show_status(err);
+ }
+
+ if (log->completion == 0) {
+ printf("no self test running\n");
+ } else {
+ if (cfg.wait)
+ err = wait_self_test(dev);
+ else
+ printf("progress %d%%\n", log->completion);
+ }
+
+ goto check_abort;
+ }
+
+ struct nvme_dev_self_test_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .stc = cfg.stc,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_dev_self_test(&args);
+ if (!err) {
+ if (cfg.stc == NVME_ST_CODE_ABORT)
+ printf("Aborting device self-test operation\n");
+ else if (cfg.stc == NVME_ST_CODE_EXTENDED)
+ printf("Extended Device self-test started\n");
+ else if (cfg.stc == NVME_ST_CODE_SHORT)
+ printf("Short Device self-test started\n");
+
+ if (cfg.wait && cfg.stc != NVME_ST_CODE_ABORT)
+ err = wait_self_test(dev);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("Device self-test: %s", nvme_strerror(errno));
+ }
+
+check_abort:
+ if (err == -EINTR)
+ abort_self_test(&args);
+
+ return err;
+}
+
+static int self_test_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ 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 *dst_entries = "Indicate how many DST log entries to be retrieved, "
+ "by default all the 20 entries will be retrieved";
+
+ _cleanup_free_ struct nvme_self_test_log *log = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err;
+
+ struct config {
+ __u8 dst_entries;
+ };
+
+ struct config cfg = {
+ .dst_entries = NVME_LOG_ST_MAX_RESULTS,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("dst-entries", 'e', &cfg.dst_entries, dst_entries));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ log = nvme_alloc(sizeof(*log));
+ if (!log)
+ return -ENOMEM;
+
+ err = nvme_cli_get_log_device_self_test(dev, log);
+ if (!err)
+ nvme_show_self_test_log(log, cfg.dst_entries, 0, dev->name, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("self test log: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int get_feature_id(struct nvme_dev *dev, struct feat_cfg *cfg,
+ void **buf, __u32 *result)
+{
+ if (!cfg->data_len)
+ nvme_get_feature_length(cfg->feature_id, cfg->cdw11,
+ &cfg->data_len);
+
+ /* check for Extended Host Identifier */
+ if (cfg->feature_id == NVME_FEAT_FID_HOST_ID && (cfg->cdw11 & 0x1))
+ cfg->data_len = 16;
+
+ if (cfg->feature_id == NVME_FEAT_FID_FDP_EVENTS) {
+ cfg->data_len = 0xff * sizeof(__u16);
+ cfg->cdw11 |= 0xff << 16;
+ }
+
+ if (cfg->sel == 3)
+ cfg->data_len = 0;
+
+ if (cfg->data_len) {
+ *buf = nvme_alloc(cfg->data_len - 1);
+ if (!*buf)
+ return -1;
+ }
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fid = cfg->feature_id,
+ .nsid = cfg->namespace_id,
+ .sel = cfg->sel,
+ .cdw11 = cfg->cdw11,
+ .uuidx = cfg->uuid_index,
+ .data_len = cfg->data_len,
+ .data = *buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = result,
+ };
+ return nvme_cli_get_features(dev, &args);
+}
+
+static int filter_out_flags(int status)
+{
+ return status & (NVME_GET(NVME_SCT_MASK, SCT) |
+ NVME_GET(NVME_SC_MASK, SC));
+}
+
+static void get_feature_id_print(struct feat_cfg cfg, int err, __u32 result,
+ void *buf)
+{
+ int status = filter_out_flags(err);
+ enum nvme_status_type type = NVME_STATUS_TYPE_NVME;
+
+ if (!err) {
+ if (!cfg.raw_binary || !buf) {
+ nvme_feature_show(cfg.feature_id, cfg.sel, result);
+ if (cfg.sel == 3)
+ nvme_show_select_result(cfg.feature_id, result);
+ else if (cfg.human_readable)
+ nvme_feature_show_fields(cfg.feature_id, result,
+ buf);
+ else if (buf)
+ d(buf, cfg.data_len, 16, 1);
+ } else if (buf) {
+ d_raw(buf, cfg.data_len);
+ }
+ } else if (err > 0) {
+ if (!nvme_status_equals(status, type, NVME_SC_INVALID_FIELD) &&
+ !nvme_status_equals(status, type, NVME_SC_INVALID_NS))
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("get-feature: %s", nvme_strerror(errno));
+ }
+}
+
+static int get_feature_id_changed(struct nvme_dev *dev, struct feat_cfg cfg,
+ bool changed)
+{
+ int err;
+ int err_def = 0;
+ __u32 result;
+ __u32 result_def;
+ void *buf = NULL;
+ void *buf_def = NULL;
+
+ if (changed)
+ cfg.sel = 0;
+
+ err = get_feature_id(dev, &cfg, &buf, &result);
+
+ if (!err && changed) {
+ cfg.sel = 1;
+ err_def = get_feature_id(dev, &cfg, &buf_def, &result_def);
+ }
+
+ if (changed)
+ cfg.sel = 8;
+
+ if (err || !changed || err_def || result != result_def ||
+ (buf && buf_def && !strcmp(buf, buf_def)))
+ get_feature_id_print(cfg, err, result, buf);
+
+ free(buf);
+ free(buf_def);
+
+ return err;
+}
+
+static int get_feature_ids(struct nvme_dev *dev, struct feat_cfg cfg)
+{
+ int err = 0;
+ int i;
+ int feat_max = 0x100;
+ int feat_num = 0;
+ bool changed = false;
+ int status = 0;
+ enum nvme_status_type type = NVME_STATUS_TYPE_NVME;
+
+ if (cfg.sel == 8)
+ changed = true;
+
+ if (cfg.feature_id)
+ feat_max = cfg.feature_id + 1;
+
+ for (i = cfg.feature_id; i < feat_max; i++, feat_num++) {
+ cfg.feature_id = i;
+ err = get_feature_id_changed(dev, cfg, changed);
+ if (!err)
+ continue;
+ status = filter_out_flags(err);
+ if (nvme_status_equals(status, type, NVME_SC_INVALID_FIELD))
+ continue;
+ if (!nvme_status_equals(status, type, NVME_SC_INVALID_NS))
+ break;
+ nvme_show_error_status(err, "get-feature:%#0*x (%s)", cfg.feature_id ? 4 : 2,
+ cfg.feature_id, nvme_feature_to_string(cfg.feature_id));
+ }
+
+ if (feat_num == 1 && nvme_status_equals(status, type, NVME_SC_INVALID_FIELD))
+ nvme_show_status(err);
+
+ return err;
+}
+
+static int get_feature(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 "
+ "behavior 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.";
+ const char *raw = "show feature in binary format";
+ const char *feature_id = "feature identifier";
+ const char *sel = "[0-3,8]: current/default/saved/supported/changed";
+ const char *cdw11 = "feature specific dword 11";
+ const char *human_readable = "show feature in readable format";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct feat_cfg cfg = {
+ .feature_id = 0,
+ .namespace_id = 0,
+ .sel = 0,
+ .data_len = 0,
+ .raw_binary = false,
+ .cdw11 = 0,
+ .uuid_index = 0,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_BYTE("sel", 's', &cfg.sel, sel),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!argconfig_parse_seen(opts, "namespace-id")) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
+ if (cfg.sel > 8) {
+ nvme_show_error("invalid 'select' param:%d", cfg.sel);
+ return -EINVAL;
+ }
+
+ if (cfg.uuid_index > 127) {
+ nvme_show_error("invalid uuid index param: %u", cfg.uuid_index);
+ return -1;
+ }
+
+ nvme_show_init();
+
+ err = get_feature_ids(dev, cfg);
+
+ nvme_show_finish();
+
+ return err;
+}
+
+/*
+ * Transfers one chunk of firmware to the device, and decodes & reports any
+ * errors. Returns -1 on (fatal) error; signifying that the transfer should
+ * be aborted.
+ */
+static int fw_download_single(struct nvme_dev *dev, void *fw_buf,
+ unsigned int fw_len, uint32_t offset,
+ uint32_t len, bool progress, bool ignore_ovr)
+{
+ const unsigned int max_retries = 3;
+ bool retryable, ovr;
+ int err, try;
+
+ if (progress) {
+ printf("Firmware download: transferring 0x%08x/0x%08x bytes: %03d%%\r",
+ offset, fw_len, (int)(100 * offset / fw_len));
+ }
+
+ struct nvme_fw_download_args args = {
+ .args_size = sizeof(args),
+ .offset = offset,
+ .data_len = len,
+ .data = fw_buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ for (try = 0; try < max_retries; try++) {
+ if (try > 0) {
+ fprintf(stderr, "retrying offset %x (%u/%u)\n",
+ offset, try, max_retries);
+ }
+
+ err = nvme_cli_fw_download(dev, &args);
+ if (!err)
+ return 0;
+
+ /*
+ * don't retry if the NVMe-type error indicates Do Not Resend.
+ */
+ retryable = !((err > 0) &&
+ (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) &&
+ (nvme_status_get_value(err) & NVME_SC_DNR));
+
+ /*
+ * detect overwrite errors, which are handled differently
+ * depending on ignore_ovr
+ */
+ ovr = (err > 0) &&
+ (nvme_status_get_type(err) == NVME_STATUS_TYPE_NVME) &&
+ (NVME_GET(err, SCT) == NVME_SCT_CMD_SPECIFIC) &&
+ (NVME_GET(err, SC) == NVME_SC_OVERLAPPING_RANGE);
+
+ if (ovr && ignore_ovr)
+ return 0;
+
+ /*
+ * if we're printing progress, we'll need a newline to separate
+ * error output from the progress data (which doesn't have a
+ * \n), and flush before we write to stderr.
+ */
+ if (progress) {
+ printf("\n");
+ fflush(stdout);
+ }
+
+ fprintf(stderr, "fw-download: error on offset 0x%08x/0x%08x\n",
+ offset, fw_len);
+
+ if (err < 0) {
+ fprintf(stderr, "fw-download: %s\n", nvme_strerror(errno));
+ } else {
+ nvme_show_status(err);
+ if (ovr) {
+ /*
+ * non-ignored ovr error: print a little extra info
+ * about recovering
+ */
+ fprintf(stderr,
+ "Use --ignore-ovr to ignore overwrite errors\n");
+
+ /*
+ * We'll just be attempting more overwrites if
+ * we retry. DNR will likely be set, but force
+ * an exit anyway.
+ */
+ retryable = false;
+ }
+ }
+
+ if (!retryable)
+ break;
+ }
+
+ return -1;
+}
+
+static int fw_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Copy all or part of a firmware image to "
+ "a controller for future update. Optionally, specify how "
+ "many KiB of the firmware to transfer at once. The offset will "
+ "start at 0 and automatically adjust based on xfer size "
+ "unless fw is split across multiple files. May be submitted "
+ "while outstanding commands exist on the Admin and IO "
+ "Submission Queues. Activate downloaded firmware with "
+ "fw-activate, and then reset the device to apply the downloaded firmware.";
+ const char *fw = "firmware file (required)";
+ const char *xfer = "transfer chunksize limit";
+ const char *offset = "starting dword offset, default 0";
+ const char *progress = "display firmware transfer progress";
+ const char *ignore_ovr = "ignore overwrite errors";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ _cleanup_file_ int fw_fd = -1;
+ unsigned int fw_size, pos;
+ int err;
+ struct stat sb;
+ void *fw_buf;
+ struct nvme_id_ctrl ctrl;
+
+ struct config {
+ char *fw;
+ __u32 xfer;
+ __u32 offset;
+ bool progress;
+ bool ignore_ovr;
+ };
+
+ struct config cfg = {
+ .fw = "",
+ .xfer = 4096,
+ .offset = 0,
+ .progress = false,
+ .ignore_ovr = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FILE("fw", 'f', &cfg.fw, fw),
+ OPT_UINT("xfer", 'x', &cfg.xfer, xfer),
+ OPT_UINT("offset", 'O', &cfg.offset, offset),
+ OPT_FLAG("progress", 'p', &cfg.progress, progress),
+ OPT_FLAG("ignore-ovr", 'i', &cfg.ignore_ovr, ignore_ovr));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ cfg.offset <<= 2;
+ if (fw_fd < 0) {
+ nvme_show_error("Failed to open firmware file %s: %s", cfg.fw, strerror(errno));
+ return -EINVAL;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ nvme_show_perror("fstat");
+ return err;
+ }
+
+ fw_size = sb.st_size;
+ if ((fw_size & 0x3) || (fw_size == 0)) {
+ nvme_show_error("Invalid size:%d for f/w image", fw_size);
+ return -EINVAL;
+ }
+
+ if (cfg.xfer == 0) {
+ err = nvme_cli_identify_ctrl(dev, &ctrl);
+ if (err) {
+ nvme_show_error("identify-ctrl: %s", nvme_strerror(errno));
+ return err;
+ }
+ if (ctrl.fwug == 0 || ctrl.fwug == 0xff)
+ cfg.xfer = 4096;
+ else
+ cfg.xfer = ctrl.fwug * 4096;
+ } else if (cfg.xfer % 4096)
+ cfg.xfer = 4096;
+
+ fw_buf = nvme_alloc_huge(fw_size, &mh);
+ if (!fw_buf)
+ return -ENOMEM;
+
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
+ err = -errno;
+ nvme_show_error("read :%s :%s", cfg.fw, strerror(errno));
+ return err;
+ }
+
+ for (pos = 0; pos < fw_size; pos += cfg.xfer) {
+ cfg.xfer = min(cfg.xfer, fw_size - pos);
+
+ err = fw_download_single(dev, fw_buf + pos, fw_size,
+ cfg.offset + pos, cfg.xfer,
+ cfg.progress, cfg.ignore_ovr);
+ if (err)
+ break;
+ }
+
+ if (!err) {
+ /* end the progress output */
+ if (cfg.progress)
+ printf("\n");
+ printf("Firmware download success\n");
+ }
+
+ return err;
+}
+
+static char *nvme_fw_status_reset_type(__u16 status)
+{
+ 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";
+ default:
+ return "unknown";
+ }
+}
+
+static bool fw_commit_support_mud(struct nvme_dev *dev)
+{
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ int err;
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return false;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+
+ if (err)
+ nvme_show_error("identify-ctrl: %s", nvme_strerror(errno));
+ else if (ctrl->frmw >> 5 & 0x1)
+ return true;
+
+ return false;
+}
+
+static void fw_commit_print_mud(struct nvme_dev *dev, __u32 result)
+{
+ if (!fw_commit_support_mud(dev))
+ return;
+
+ printf("Multiple Update Detected (MUD) Value: %u\n", result);
+
+ if (result & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command\n"
+ "sequence due to processing a command from a Management Endpoint");
+
+ if (result >> 1 & 0x1)
+ printf("Detected an overlapping firmware/boot partition image update command\n"
+ "sequence due to processing a command from an Admin SQ on a controller");
+}
+
+static int fw_commit(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Verify downloaded firmware image and "
+ "commit to specific firmware slot. Device is not automatically "
+ "reset following firmware activation. A reset may be issued "
+ "with an 'echo 1 > /sys/class/nvme/nvmeX/reset_controller'. "
+ "Ensure nvmeX is the device you just activated before reset.";
+ const char *slot = "[0-7]: firmware slot for commit action";
+ const char *action = "[0-7]: commit action";
+ const char *bpid = "[0,1]: boot partition identifier, if applicable (default: 0)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u8 slot;
+ __u8 action;
+ __u8 bpid;
+ };
+
+ struct config cfg = {
+ .slot = 0,
+ .action = 0,
+ .bpid = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("slot", 's', &cfg.slot, slot),
+ OPT_BYTE("action", 'a', &cfg.action, action),
+ OPT_BYTE("bpid", 'b', &cfg.bpid, bpid));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.slot > 7) {
+ nvme_show_error("invalid slot:%d", cfg.slot);
+ return -EINVAL;
+ }
+ if (cfg.action > 7 || cfg.action == 4 || cfg.action == 5) {
+ nvme_show_error("invalid action:%d", cfg.action);
+ return -EINVAL;
+ }
+ if (cfg.bpid > 1) {
+ nvme_show_error("invalid boot partition id:%d", cfg.bpid);
+ return -EINVAL;
+ }
+
+ struct nvme_fw_commit_args args = {
+ .args_size = sizeof(args),
+ .slot = cfg.slot,
+ .action = cfg.action,
+ .bpid = cfg.bpid,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_cli_fw_commit(dev, &args);
+
+ if (err < 0) {
+ nvme_show_error("fw-commit: %s", nvme_strerror(errno));
+ } else if (err != 0) {
+ __u32 val = nvme_status_get_value(err);
+ int type = nvme_status_get_type(err);
+
+ if (type == NVME_STATUS_TYPE_NVME) {
+ switch (val & 0x7ff) {
+ case NVME_SC_FW_NEEDS_CONV_RESET:
+ case NVME_SC_FW_NEEDS_SUBSYS_RESET:
+ case NVME_SC_FW_NEEDS_RESET:
+ printf("Success activating firmware action:%d slot:%d",
+ cfg.action, cfg.slot);
+ if (cfg.action == 6 || cfg.action == 7)
+ printf(" bpid:%d", cfg.bpid);
+ printf(", but firmware requires %s reset\n",
+ nvme_fw_status_reset_type(val));
+ break;
+ default:
+ nvme_show_status(err);
+ break;
+ }
+ } else {
+ nvme_show_status(err);
+ }
+ } else {
+ printf("Success committing firmware action:%d slot:%d",
+ cfg.action, cfg.slot);
+ if (cfg.action == 6 || cfg.action == 7)
+ printf(" bpid:%d", cfg.bpid);
+ printf("\n");
+ fw_commit_print_mud(dev, result);
+ }
+
+ return err;
+}
+
+static int subsystem_reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Resets the NVMe subsystem";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_subsystem_reset(dev_fd(dev));
+ if (err < 0) {
+ if (errno == ENOTTY)
+ nvme_show_error("Subsystem-reset: NVM Subsystem Reset not supported.");
+ else
+ nvme_show_error("Subsystem-reset: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static int reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Resets the NVMe controller\n";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_ctrl_reset(dev_fd(dev));
+ if (err < 0)
+ nvme_show_error("Reset: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int ns_rescan(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Rescans the NVMe namespaces\n";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ NVME_ARGS(opts);
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_ns_rescan(dev_fd(dev));
+ if (err < 0)
+ nvme_show_error("Namespace Rescan");
+
+ return err;
+}
+
+static int sanitize_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a sanitize command.";
+ const char *no_dealloc_desc = "No deallocate after sanitize.";
+ const char *oipbp_desc = "Overwrite invert pattern between passes.";
+ const char *owpass_desc = "Overwrite pass count.";
+ const char *ause_desc = "Allow unrestricted sanitize exit.";
+ const char *sanact_desc = "Sanitize action: 1 = Exit failure mode, 2 = Start block erase, 3 = Start overwrite, 4 = Start crypto erase";
+ const char *ovrpat_desc = "Overwrite pattern.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ bool no_dealloc;
+ bool oipbp;
+ __u8 owpass;
+ bool ause;
+ __u8 sanact;
+ __u32 ovrpat;
+ };
+
+ struct config cfg = {
+ .no_dealloc = false,
+ .oipbp = false,
+ .owpass = 0,
+ .ause = false,
+ .sanact = 0,
+ .ovrpat = 0,
+ };
+
+ OPT_VALS(sanact) = {
+ VAL_BYTE("exit-failure", NVME_SANITIZE_SANACT_EXIT_FAILURE),
+ VAL_BYTE("start-block-erase", NVME_SANITIZE_SANACT_START_BLOCK_ERASE),
+ VAL_BYTE("start-overwrite", NVME_SANITIZE_SANACT_START_OVERWRITE),
+ VAL_BYTE("start-crypto-erase", NVME_SANITIZE_SANACT_START_CRYPTO_ERASE),
+ VAL_END()
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("no-dealloc", 'd', &cfg.no_dealloc, no_dealloc_desc),
+ OPT_FLAG("oipbp", 'i', &cfg.oipbp, oipbp_desc),
+ OPT_BYTE("owpass", 'n', &cfg.owpass, owpass_desc),
+ OPT_FLAG("ause", 'u', &cfg.ause, ause_desc),
+ OPT_BYTE("sanact", 'a', &cfg.sanact, sanact_desc, sanact),
+ OPT_UINT("ovrpat", 'p', &cfg.ovrpat, ovrpat_desc));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ switch (cfg.sanact) {
+ case NVME_SANITIZE_SANACT_EXIT_FAILURE:
+ case NVME_SANITIZE_SANACT_START_BLOCK_ERASE:
+ case NVME_SANITIZE_SANACT_START_OVERWRITE:
+ case NVME_SANITIZE_SANACT_START_CRYPTO_ERASE:
+ break;
+ default:
+ nvme_show_error("Invalid Sanitize Action");
+ return -EINVAL;
+ }
+
+ if (cfg.sanact == NVME_SANITIZE_SANACT_EXIT_FAILURE) {
+ if (cfg.ause || cfg.no_dealloc) {
+ nvme_show_error("SANACT is Exit Failure Mode");
+ return -EINVAL;
+ }
+ }
+
+ if (cfg.sanact == NVME_SANITIZE_SANACT_START_OVERWRITE) {
+ if (cfg.owpass > 15) {
+ nvme_show_error("OWPASS out of range [0-15]");
+ return -EINVAL;
+ }
+ } else {
+ if (cfg.owpass || cfg.oipbp || cfg.ovrpat) {
+ nvme_show_error("SANACT is not Overwrite");
+ return -EINVAL;
+ }
+ }
+
+ struct nvme_sanitize_nvm_args args = {
+ .args_size = sizeof(args),
+ .sanact = cfg.sanact,
+ .ause = cfg.ause,
+ .owpass = cfg.owpass,
+ .oipbp = cfg.oipbp,
+ .nodas = cfg.no_dealloc,
+ .ovrpat = cfg.ovrpat,
+ .result = NULL,
+ };
+ err = nvme_cli_sanitize_nvm(dev, &args);
+ if (err < 0)
+ nvme_show_error("sanitize: %s", nvme_strerror(errno));
+ else if (err > 0)
+ nvme_show_status(err);
+
+ return err;
+}
+
+static int nvme_get_properties(int fd, void **pbar)
+{
+ int offset, err, size = getpagesize();
+ __u64 value;
+ void *bar = malloc(size);
+
+ if (!bar) {
+ nvme_show_error("malloc: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(bar, 0xff, size);
+ for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) {
+ struct nvme_get_property_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .offset = offset,
+ .value = &value,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+
+ err = nvme_get_property(&args);
+ if (nvme_status_equals(err, NVME_STATUS_TYPE_NVME, NVME_SC_INVALID_FIELD)) {
+ err = 0;
+ value = -1;
+ } else if (err) {
+ nvme_show_error("get-property: %s", nvme_strerror(errno));
+ break;
+ }
+ if (nvme_is_64bit_reg(offset)) {
+ *(uint64_t *)(bar + offset) = value;
+ offset += 8;
+ } else {
+ *(uint32_t *)(bar + offset) = value;
+ offset += 4;
+ }
+ }
+
+ if (err)
+ free(bar);
+ else
+ *pbar = bar;
+
+ return err;
+}
+
+static void *mmap_registers(nvme_root_t r, struct nvme_dev *dev)
+{
+ nvme_ctrl_t c = NULL;
+ nvme_ns_t n = NULL;
+
+ char path[512];
+ void *membase;
+ int fd;
+
+ c = nvme_scan_ctrl(r, dev->name);
+ if (c) {
+ snprintf(path, sizeof(path), "%s/device/resource0",
+ nvme_ctrl_get_sysfs_dir(c));
+ nvme_free_ctrl(c);
+ } else {
+ n = nvme_scan_namespace(dev->name);
+ if (!n) {
+ nvme_show_error("Unable to find %s", dev->name);
+ return NULL;
+ }
+ snprintf(path, sizeof(path), "%s/device/device/resource0",
+ nvme_ns_get_sysfs_dir(n));
+ nvme_free_ns(n);
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ if (map_log_level(0, false) >= LOG_DEBUG)
+ nvme_show_error("%s did not find a pci resource, open failed %s",
+ dev->name, strerror(errno));
+ return NULL;
+ }
+
+ membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
+ if (membase == MAP_FAILED) {
+ if (map_log_level(0, false) >= LOG_DEBUG) {
+ fprintf(stderr, "%s failed to map. ", dev->name);
+ fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n");
+ }
+ membase = NULL;
+ }
+
+ close(fd);
+ return membase;
+}
+
+static int show_registers(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Reads and shows the defined NVMe controller registers\n"
+ "in binary or human-readable format";
+ const char *human_readable =
+ "show info in readable format in case of output_format == normal";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ bool fabrics = false;
+ nvme_root_t r;
+ void *bar;
+ int err;
+
+ struct config {
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ r = nvme_scan(NULL);
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ goto free_tree;
+ }
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ bar = mmap_registers(r, dev);
+ if (!bar) {
+ err = nvme_get_properties(dev_fd(dev), &bar);
+ if (err)
+ goto free_tree;
+ fabrics = true;
+ }
+
+ nvme_show_ctrl_registers(bar, fabrics, flags);
+ if (fabrics)
+ free(bar);
+ else
+ munmap(bar, getpagesize());
+free_tree:
+ nvme_free_tree(r);
+ return err;
+}
+
+static int get_property(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Reads and shows the defined NVMe controller property\n"
+ "for NVMe over Fabric. Property offset must be one of:\n"
+ "CAP=0x0, VS=0x8, CC=0x14, CSTS=0x1c, NSSR=0x20";
+ const char *offset = "offset of the requested property";
+ const char *human_readable = "show property in readable format";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u64 value;
+ int err;
+
+ struct config {
+ int offset;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .offset = -1,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("offset", 'O', &cfg.offset, offset),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.offset == -1) {
+ nvme_show_error("offset required param");
+ return -EINVAL;
+ }
+
+ struct nvme_get_property_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .offset = cfg.offset,
+ .value = &value,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ };
+ err = nvme_get_property(&args);
+ if (err < 0)
+ nvme_show_error("get-property: %s", nvme_strerror(errno));
+ else if (!err)
+ nvme_show_single_property(cfg.offset, value, cfg.human_readable);
+ else if (err > 0)
+ nvme_show_status(err);
+
+ return err;
+}
+
+static int set_property(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Writes and shows the defined NVMe controller property for NVMe over Fabric";
+ const char *offset = "the offset of the property";
+ const char *value = "the value of the property to be set";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ int offset;
+ int value;
+ };
+
+ struct config cfg = {
+ .offset = -1,
+ .value = -1,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("offset", 'O', &cfg.offset, offset),
+ OPT_UINT("value", 'V', &cfg.value, value));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.offset == -1) {
+ nvme_show_error("offset required param");
+ return -EINVAL;
+ }
+ if (cfg.value == -1) {
+ nvme_show_error("value required param");
+ return -EINVAL;
+ }
+
+ struct nvme_set_property_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .offset = cfg.offset,
+ .value = cfg.value,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_set_property(&args);
+ if (err < 0)
+ nvme_show_error("set-property: %s", nvme_strerror(errno));
+ else if (!err)
+ printf("set-property: %02x (%s), value: %#08x\n", cfg.offset,
+ nvme_register_to_string(cfg.offset), cfg.value);
+ else if (err > 0)
+ nvme_show_status(err);
+
+ return err;
+}
+
+static int format_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Re-format a specified namespace on the\n"
+ "given device. Can erase all data in namespace (user\n"
+ "data erase) or delete data encryption key if specified.\n"
+ "Can also be used to change LBAF to change the namespaces reported physical block format.";
+ const char *lbaf = "LBA format to apply (required)";
+ const char *ses = "[0-2]: secure erase";
+ const char *pil = "[0-1]: protection info location last/first 8 bytes of metadata";
+ const char *pi = "[0-3]: protection info off/Type 1/Type 2/Type 3";
+ const char *ms = "[0-1]: extended format off/on";
+ const char *reset = "Automatically reset the controller after successful format";
+ const char *bs = "target block size";
+ const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
+
+ _cleanup_free_ struct nvme_id_ctrl *ctrl = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u8 prev_lbaf = 0;
+ int block_size;
+ int err, i;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 timeout;
+ __u8 lbaf;
+ __u8 ses;
+ __u8 pi;
+ __u8 pil;
+ __u8 ms;
+ bool reset;
+ bool force;
+ __u64 bs;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .timeout = 600000,
+ .lbaf = 0xff,
+ .ses = 0,
+ .pi = 0,
+ .pil = 0,
+ .ms = 0,
+ .reset = false,
+ .force = false,
+ .bs = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_BYTE("lbaf", 'l', &cfg.lbaf, lbaf),
+ OPT_BYTE("ses", 's', &cfg.ses, ses),
+ OPT_BYTE("pi", 'i', &cfg.pi, pi),
+ OPT_BYTE("pil", 'p', &cfg.pil, pil),
+ OPT_BYTE("ms", 'm', &cfg.ms, ms),
+ OPT_FLAG("reset", 'r', &cfg.reset, reset),
+ OPT_FLAG("force", 0, &cfg.force, force),
+ OPT_SUFFIX("block-size", 'b', &cfg.bs, bs));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = open_exclusive(&dev, argc, argv, cfg.force);
+ if (err) {
+ if (errno == EBUSY) {
+ fprintf(stderr, "Failed to open %s.\n", basename(argv[optind]));
+ fprintf(stderr, "Namespace is currently busy.\n");
+ if (!cfg.force)
+ fprintf(stderr, "Use the force [--force] option to ignore that.\n");
+ } else {
+ argconfig_print_help(desc, opts);
+ }
+ return err;
+ }
+
+ if (cfg.lbaf != 0xff && cfg.bs != 0) {
+ nvme_show_error(
+ "Invalid specification of both LBAF and Block Size, please specify only one");
+ return -EINVAL;
+ }
+ if (cfg.bs) {
+ if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) {
+ nvme_show_error(
+ "Invalid value for block size (%"PRIu64"), must be a power of two",
+ (uint64_t) cfg.bs);
+ return -EINVAL;
+ }
+ }
+
+ ctrl = nvme_alloc(sizeof(*ctrl));
+ if (!ctrl)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ctrl(dev, ctrl);
+ if (err) {
+ nvme_show_error("identify-ctrl: %s", nvme_strerror(errno));
+ return -errno;
+ }
+
+ if ((ctrl->fna & 1) == 1) {
+ /*
+ * FNA bit 0 set to 1: all namespaces ... shall be configured with the same
+ * attributes and a format (excluding secure erase) of any namespace results in a
+ * format of all namespaces.
+ */
+ cfg.namespace_id = NVME_NSID_ALL;
+ } else if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return -errno;
+ }
+ }
+
+ if (cfg.namespace_id == 0) {
+ nvme_show_error(
+ "Invalid namespace ID, specify a namespace to format or use\n"
+ "'-n 0xffffffff' to format all namespaces on this controller.");
+ return -EINVAL;
+ }
+
+ if (cfg.namespace_id != NVME_NSID_ALL) {
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+ if (err) {
+ if (err < 0) {
+ nvme_show_error("identify-namespace: %s", nvme_strerror(errno));
+ } else {
+ fprintf(stderr, "identify failed\n");
+ nvme_show_status(err);
+ }
+ return err;
+ }
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &prev_lbaf);
+
+ if (cfg.bs) {
+ for (i = 0; i <= ns->nlbaf; ++i) {
+ if ((1ULL << ns->lbaf[i].ds) == cfg.bs && ns->lbaf[i].ms == 0) {
+ cfg.lbaf = i;
+ break;
+ }
+ }
+ if (cfg.lbaf == 0xff) {
+ fprintf(stderr,
+ "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");
+ return -EINVAL;
+ }
+ } else if (cfg.lbaf == 0xff) {
+ cfg.lbaf = prev_lbaf;
+ }
+ } else {
+ if (cfg.lbaf == 0xff)
+ cfg.lbaf = 0;
+ }
+
+ /* ses & pi checks set to 7 for forward-compatibility */
+ if (cfg.ses > 7) {
+ nvme_show_error("invalid secure erase settings:%d", cfg.ses);
+ return -EINVAL;
+ }
+ if (cfg.lbaf > 63) {
+ nvme_show_error("invalid lbaf:%d", cfg.lbaf);
+ return -EINVAL;
+ }
+ if (cfg.pi > 7) {
+ nvme_show_error("invalid pi:%d", cfg.pi);
+ return -EINVAL;
+ }
+ if (cfg.pil > 1) {
+ nvme_show_error("invalid pil:%d", cfg.pil);
+ return -EINVAL;
+ }
+ if (cfg.ms > 1) {
+ nvme_show_error("invalid ms:%d", cfg.ms);
+ return -EINVAL;
+ }
+
+ if (!cfg.force) {
+ fprintf(stderr, "You are about to format %s, namespace %#x%s.\n",
+ dev->name, cfg.namespace_id,
+ cfg.namespace_id == NVME_NSID_ALL ? "(ALL namespaces)" : "");
+ nvme_show_relatives(dev->name);
+ fprintf(stderr,
+ "WARNING: Format may irrevocably delete this device's data.\n"
+ "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"
+ "Use the force [--force] option to suppress this warning.\n");
+ sleep(10);
+ fprintf(stderr, "Sending format operation ...\n");
+ }
+
+ struct nvme_format_nvm_args args = {
+ .args_size = sizeof(args),
+ .nsid = cfg.namespace_id,
+ .lbafu = (cfg.lbaf & NVME_NS_FLBAS_HIGHER_MASK) >> 4,
+ .lbaf = cfg.lbaf & NVME_NS_FLBAS_LOWER_MASK,
+ .mset = cfg.ms,
+ .pi = cfg.pi,
+ .pil = cfg.pil,
+ .ses = cfg.ses,
+ .timeout = cfg.timeout,
+ .result = NULL,
+ };
+ err = nvme_cli_format_nvm(dev, &args);
+ if (err < 0) {
+ nvme_show_error("format: %s", nvme_strerror(errno));
+ } else if (err != 0) {
+ nvme_show_status(err);
+ } else {
+ printf("Success formatting namespace:%x\n", cfg.namespace_id);
+ if (dev->type == NVME_DEV_DIRECT && cfg.lbaf != prev_lbaf) {
+ if (is_chardev(dev)) {
+ if (ioctl(dev_fd(dev), NVME_IOCTL_RESCAN) < 0) {
+ nvme_show_error("failed to rescan namespaces");
+ return -errno;
+ }
+ } else if (cfg.namespace_id != NVME_NSID_ALL) {
+ 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(dev_fd(dev), BLKBSZSET, &block_size) < 0) {
+ nvme_show_error("failed to set block size to %d",
+ block_size);
+ return -errno;
+ }
+
+ if (ioctl(dev_fd(dev), BLKRRPART) < 0) {
+ nvme_show_error("failed to re-read partition table");
+ return -errno;
+ }
+ }
+ }
+ if (dev->type == NVME_DEV_DIRECT && cfg.reset && is_chardev(dev))
+ nvme_ctrl_reset(dev_fd(dev));
+ }
+
+ return err;
+}
+
+#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 "
+ "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.";
+ const char *feature_id = "feature identifier (required)";
+ const char *data = "optional file for feature data (default stdin)";
+ const char *value = "new value of feature (required)";
+ const char *cdw12 = "feature cdw12, if used";
+ const char *save = "specifies that the controller shall save the attribute";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ _cleanup_file_ int ffd = STDIN_FILENO;
+ int err;
+ __u32 result;
+
+ struct config {
+ __u32 namespace_id;
+ __u8 feature_id;
+ __u64 value;
+ __u32 cdw12;
+ __u8 uuid_index;
+ __u32 data_len;
+ char *file;
+ bool save;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .feature_id = 0,
+ .value = 0,
+ .uuid_index = 0,
+ .data_len = 0,
+ .file = "",
+ .save = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_BYTE("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_SUFFIX("value", 'V', &cfg.value, value),
+ OPT_UINT("cdw12", 'c', &cfg.cdw12, cdw12),
+ OPT_BYTE("uuid-index", 'U', &cfg.uuid_index, uuid_index_specify),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len),
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_FLAG("save", 's', &cfg.save, save));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!argconfig_parse_seen(opts, "namespace-id")) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return -errno;
+ }
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
+ if (!cfg.feature_id) {
+ nvme_show_error("feature-id required param");
+ return -EINVAL;
+ }
+
+ if (cfg.uuid_index > 127) {
+ nvme_show_error("invalid uuid index param: %u", cfg.uuid_index);
+ return -1;
+ }
+
+ if (!cfg.data_len)
+ nvme_cli_get_feature_length2(cfg.feature_id, cfg.value,
+ NVME_DATA_TFR_HOST_TO_CTRL,
+ &cfg.data_len);
+
+ if (cfg.data_len) {
+ buf = nvme_alloc(cfg.data_len);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ if (buf) {
+ /*
+ * Use the '-v' value for the timestamp feature if provided as
+ * a convenience since it can often fit in 4-bytes. The user
+ * should use the buffer method if the value exceeds this
+ * length.
+ */
+ if (cfg.feature_id == NVME_FEAT_FID_TIMESTAMP && 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) {
+ nvme_show_error("Failed to open file %s: %s",
+ cfg.file, strerror(errno));
+ return -EINVAL;
+ }
+
+ err = read(ffd, buf, cfg.data_len);
+ if (err < 0) {
+ nvme_show_error("failed to read data buffer from input file: %s",
+ strerror(errno));
+ return -errno;
+ }
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = cfg.namespace_id,
+ .cdw11 = cfg.value,
+ .cdw12 = cfg.cdw12,
+ .save = cfg.save,
+ .uuidx = cfg.uuid_index,
+ .cdw15 = 0,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (err < 0) {
+ nvme_show_error("set-feature: %s", nvme_strerror(errno));
+ } else if (!err) {
+ printf("set-feature:%#0*x (%s), value:%#0*"PRIx64", cdw12:%#0*x, save:%#x\n",
+ cfg.feature_id ? 4 : 2, cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id),
+ cfg.value ? 10 : 8, (uint64_t)cfg.value,
+ cfg.cdw12 ? 10 : 8, cfg.cdw12, cfg.save);
+ if (cfg.feature_id == NVME_FEAT_FID_LBA_STS_INTERVAL)
+ nvme_show_lba_status_info(result);
+ if (buf) {
+ if (cfg.feature_id == NVME_FEAT_FID_LBA_RANGE)
+ nvme_show_lba_range((struct nvme_lba_range_type *)buf, result, 0);
+ else
+ d(buf, cfg.data_len, 16, 1);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ return err;
+}
+
+static int sec_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct stat sb;
+ const char *desc = "Transfer security protocol data to\n"
+ "a controller. Security Receives for the same protocol should be\n"
+ "performed after Security Sends. The security protocol field\n"
+ "associates Security Sends (security-send) and Security Receives (security-recv).";
+ const char *file = "transfer payload";
+ const char *tl = "transfer length (cf. SPC-4)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *sec_buf = NULL;
+ _cleanup_file_ int sec_fd = -1;
+ unsigned int sec_size;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ char *file;
+ __u8 nssf;
+ __u8 secp;
+ __u16 spsp;
+ __u32 tl;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .file = "",
+ .nssf = 0,
+ .secp = 0,
+ .spsp = 0,
+ .tl = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_FILE("file", 'f', &cfg.file, file),
+ OPT_BYTE("nssf", 'N', &cfg.nssf, nssf),
+ OPT_BYTE("secp", 'p', &cfg.secp, secp),
+ OPT_SHRT("spsp", 's', &cfg.spsp, spsp),
+ OPT_UINT("tl", 't', &cfg.tl, tl));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.tl == 0) {
+ nvme_show_error("--tl unspecified or zero");
+ return -EINVAL;
+ }
+ if ((cfg.tl & 3) != 0)
+ nvme_show_error(
+ "WARNING: --tl not dword aligned; unaligned bytes may be truncated");
+
+ if (strlen(cfg.file) == 0) {
+ sec_fd = STDIN_FILENO;
+ sec_size = cfg.tl;
+ } else {
+ sec_fd = open(cfg.file, O_RDONLY);
+ if (sec_fd < 0) {
+ nvme_show_error("Failed to open %s: %s", cfg.file, strerror(errno));
+ return -EINVAL;
+ }
+
+ err = fstat(sec_fd, &sb);
+ if (err < 0) {
+ nvme_show_perror("fstat");
+ return err;
+ }
+
+ sec_size = cfg.tl > sb.st_size ? cfg.tl : sb.st_size;
+ }
+
+ sec_buf = nvme_alloc(cfg.tl);
+ if (!sec_buf)
+ return -ENOMEM;
+
+ err = read(sec_fd, sec_buf, sec_size);
+ if (err < 0) {
+ nvme_show_error("Failed to read data from security file %s with %s", cfg.file,
+ strerror(errno));
+ return -errno;
+ }
+
+ struct nvme_security_send_args args = {
+ .args_size = sizeof(args),
+ .nsid = cfg.namespace_id,
+ .nssf = cfg.nssf,
+ .spsp0 = cfg.spsp & 0xff,
+ .spsp1 = cfg.spsp >> 8,
+ .secp = cfg.secp,
+ .tl = cfg.tl,
+ .data_len = cfg.tl,
+ .data = sec_buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ err = nvme_cli_security_send(dev, &args);
+
+ if (err < 0)
+ nvme_show_error("security-send: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Security Send Command Success\n");
+
+ return err;
+}
+
+static int dir_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Set directive parameters of the specified directive type.";
+ const char *endir = "directive enable";
+ const char *ttype = "target directive type to be enabled/disabled";
+ const char *input = "write/send file (default stdin)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ __u32 result;
+ __u32 dw12 = 0;
+ _cleanup_file_ int ffd = STDIN_FILENO;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 data_len;
+ __u8 dtype;
+ __u8 ttype;
+ __u16 dspec;
+ __u8 doper;
+ __u16 endir;
+ bool human_readable;
+ bool raw_binary;
+ char *file;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .data_len = 0,
+ .dtype = 0,
+ .ttype = 0,
+ .dspec = 0,
+ .doper = 0,
+ .endir = 1,
+ .human_readable = false,
+ .raw_binary = false,
+ .file = "",
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len),
+ OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype),
+ OPT_BYTE("target-dir", 'T', &cfg.ttype, ttype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype),
+ OPT_BYTE("dir-oper", 'O', &cfg.doper, doper),
+ OPT_SHRT("endir", 'e', &cfg.endir, endir),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_directive),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive),
+ OPT_FILE("input-file", 'i', &cfg.file, input));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ switch (cfg.dtype) {
+ case NVME_DIRECTIVE_DTYPE_IDENTIFY:
+ switch (cfg.doper) {
+ case NVME_DIRECTIVE_SEND_IDENTIFY_DOPER_ENDIR:
+ if (!cfg.ttype) {
+ nvme_show_error("target-dir required param\n");
+ return -EINVAL;
+ }
+ dw12 = cfg.ttype << 8 | cfg.endir;
+ break;
+ default:
+ nvme_show_error("invalid directive operations for Identify Directives");
+ return -EINVAL;
+ }
+ break;
+ case NVME_DIRECTIVE_DTYPE_STREAMS:
+ switch (cfg.doper) {
+ case NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_IDENTIFIER:
+ case NVME_DIRECTIVE_SEND_STREAMS_DOPER_RELEASE_RESOURCE:
+ break;
+ default:
+ nvme_show_error("invalid directive operations for Streams Directives");
+ return -EINVAL;
+ }
+ break;
+ default:
+ nvme_show_error("invalid directive type");
+ return -EINVAL;
+ }
+
+ if (cfg.data_len) {
+ buf = nvme_alloc(cfg.data_len);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ if (buf) {
+ if (strlen(cfg.file)) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd <= 0) {
+ nvme_show_error("Failed to open file %s: %s",
+ cfg.file, strerror(errno));
+ return -EINVAL;
+ }
+ }
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ nvme_show_error("failed to read data buffer from input file %s",
+ strerror(errno));
+ return -errno;
+ }
+ }
+
+ struct nvme_directive_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .dspec = cfg.dspec,
+ .doper = cfg.doper,
+ .dtype = cfg.dtype,
+ .cdw12 = dw12,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_directive_send(&args);
+ if (err < 0) {
+ nvme_show_error("dir-send: %s", nvme_strerror(errno));
+ return err;
+ }
+ if (!err) {
+ printf("dir-send: type %#x, operation %#x, spec_val %#x, nsid %#x, result %#x\n",
+ cfg.dtype, cfg.doper, cfg.dspec, cfg.namespace_id, result);
+ if (buf) {
+ if (!cfg.raw_binary)
+ d(buf, cfg.data_len, 16, 1);
+ else
+ d_raw(buf, cfg.data_len);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ return err;
+}
+
+static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "The Write Uncorrectable command is used to set a range of logical blocks to invalid.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 start_block;
+ __u16 block_count;
+ __u8 dtype;
+ __u16 dspec;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .dtype = 0,
+ .dspec = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ if (cfg.dtype > 0xf) {
+ nvme_show_error("Invalid directive type, %x", cfg.dtype);
+ return -EINVAL;
+ }
+
+ struct nvme_io_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.start_block,
+ .nlb = cfg.block_count,
+ .control = cfg.dtype << 4,
+ .dspec = cfg.dspec,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_write_uncorrectable(&args);
+ if (err < 0)
+ nvme_show_error("write uncorrectable: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Write Uncorrectable Success\n");
+
+ return err;
+}
+
+static int invalid_tags(__u64 storage_tag, __u64 ref_tag, __u8 sts, __u8 pif)
+{
+ int result = 0;
+
+ if (sts < 64 && storage_tag >= (1LL << sts)) {
+ nvme_show_error("Storage tag larger than storage tag size");
+ return 1;
+ }
+
+ switch (pif) {
+ case 0:
+ if (ref_tag >= (1LL << (32 - sts)))
+ result = 1;
+ break;
+ case 1:
+ if (sts > 16 && ref_tag >= (1LL << (80 - sts)))
+ result = 1;
+ break;
+ case 2:
+ if (sts > 0 && ref_tag >= (1LL << (48 - sts)))
+ result = 1;
+ break;
+ default:
+ nvme_show_error("Invalid PIF");
+ result = 1;
+ break;
+ }
+
+ if (result)
+ nvme_show_error("Reference tag larger than allowed by PIF");
+
+ return result;
+}
+
+static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u8 lba_index, sts = 0, pif = 0;
+ __u16 control = 0;
+ int err;
+
+ const char *desc =
+ "The Write Zeroes command is used to set a range of logical blocks to zero.";
+ const char *deac =
+ "Set DEAC bit, requesting controller to deallocate specified logical blocks";
+ const char *storage_tag_check =
+ "This bit specifies the Storage Tag field shall be checked as\n"
+ "part of end-to-end data protection processing";
+
+ struct config {
+ __u32 namespace_id;
+ __u64 start_block;
+ __u16 block_count;
+ __u8 dtype;
+ bool deac;
+ bool limited_retry;
+ bool force_unit_access;
+ __u8 prinfo;
+ __u64 ref_tag;
+ __u16 app_tag_mask;
+ __u16 app_tag;
+ __u64 storage_tag;
+ bool storage_tag_check;
+ __u16 dspec;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .dtype = 0,
+ .deac = false,
+ .limited_retry = false,
+ .force_unit_access = false,
+ .prinfo = 0,
+ .ref_tag = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ .storage_tag = 0,
+ .storage_tag_check = false,
+ .dspec = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype),
+ OPT_FLAG("deac", 'd', &cfg.deac, deac),
+ OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
+ OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask),
+ OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag),
+ OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check),
+ OPT_SHRT("dir-spec", 'D', &cfg.dspec, dspec_w_dtype));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.prinfo > 0xf)
+ return -EINVAL;
+
+ if (cfg.dtype > 0xf) {
+ nvme_show_error("Invalid directive type, %x", cfg.dtype);
+ return -EINVAL;
+ }
+
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_IO_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_IO_FUA;
+ if (cfg.deac)
+ control |= NVME_IO_DEAC;
+ if (cfg.storage_tag_check)
+ control |= NVME_IO_STC;
+ control |= (cfg.dtype << 4);
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+ if (err < 0) {
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ nvm_ns = nvme_alloc(sizeof(*nvm_ns));
+ if (!nvm_ns)
+ return -ENOMEM;
+
+ err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0, NVME_CSI_NVM, nvm_ns);
+ if (!err) {
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
+ sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK;
+ pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7;
+ }
+
+ if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif))
+ return -EINVAL;
+
+ struct nvme_io_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.start_block,
+ .nlb = cfg.block_count,
+ .control = control,
+ .reftag_u64 = cfg.ref_tag,
+ .apptag = cfg.app_tag,
+ .appmask = cfg.app_tag_mask,
+ .sts = sts,
+ .pif = pif,
+ .storage_tag = cfg.storage_tag,
+ .dspec = cfg.dspec,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_write_zeros(&args);
+ if (err < 0)
+ nvme_show_error("write-zeroes: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Write Zeroes Success\n");
+
+ return err;
+}
+
+static int dsm(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Dataset Management command is used by the host to\n"
+ "indicate attributes for ranges of logical blocks. This includes attributes\n"
+ "for discarding unused blocks, data read and write frequency, access size, and other\n"
+ "information that may be used to optimize performance and reliability.";
+ const char *blocks = "Comma separated list of the number of blocks in each range";
+ const char *starting_blocks = "Comma separated list of the starting block in each range";
+ const char *context_attrs = "Comma separated list of the context attributes in each range";
+ const char *ad = "Attribute Deallocate";
+ const char *idw = "Attribute Integral Dataset for Write";
+ const char *idr = "Attribute Integral Dataset for Read";
+ const char *cdw11 = "All the command DWORD 11 attributes. Use instead of specifying individual attributes";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_dsm_range *dsm = NULL;
+ uint16_t nr, nc, nb, ns;
+ __u32 ctx_attrs[256] = {0,};
+ __u32 nlbs[256] = {0,};
+ __u64 slbas[256] = {0,};
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ char *ctx_attrs;
+ char *blocks;
+ char *slbas;
+ bool ad;
+ bool idw;
+ bool idr;
+ __u32 cdw11;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .ctx_attrs = "",
+ .blocks = "",
+ .slbas = "",
+ .ad = false,
+ .idw = false,
+ .idr = false,
+ .cdw11 = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_LIST("ctx-attrs", 'a', &cfg.ctx_attrs, context_attrs),
+ OPT_LIST("blocks", 'b', &cfg.blocks, blocks),
+ OPT_LIST("slbs", 's', &cfg.slbas, starting_blocks),
+ OPT_FLAG("ad", 'd', &cfg.ad, ad),
+ OPT_FLAG("idw", 'w', &cfg.idw, idw),
+ OPT_FLAG("idr", 'r', &cfg.idr, idr),
+ OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ nc = argconfig_parse_comma_sep_array_u32(cfg.ctx_attrs, ctx_attrs, ARRAY_SIZE(ctx_attrs));
+ nb = argconfig_parse_comma_sep_array_u32(cfg.blocks, nlbs, ARRAY_SIZE(nlbs));
+ ns = argconfig_parse_comma_sep_array_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas));
+ nr = max(nc, max(nb, ns));
+ if (!nr || nr > 256) {
+ nvme_show_error("No range definition provided");
+ return -EINVAL;
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+ if (!cfg.cdw11)
+ cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0);
+
+ dsm = nvme_alloc(sizeof(*dsm) * 256);
+ if (!dsm)
+ return -ENOMEM;
+
+ nvme_init_dsm_range(dsm, ctx_attrs, nlbs, slbas, nr);
+ struct nvme_dsm_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .attrs = cfg.cdw11,
+ .nr_ranges = nr,
+ .dsm = dsm,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_dsm(&args);
+ if (err < 0)
+ nvme_show_error("data-set management: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe DSM: success\n");
+
+ return err;
+}
+
+static int copy_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Copy command is used by the host to copy data\n"
+ "from one or more source logical block ranges to a\n"
+ "single consecutive destination logical block range.";
+ 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_snsids = "source namespace identifier per range (comma-separated list)";
+ const char *d_sopts = "source options per range (comma-separated list)";
+ 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";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u16 nr, nb, ns, nrts, natms, nats, nids;
+ __u16 nlbs[256] = { 0 };
+ __u64 slbas[256] = { 0 };
+ __u32 snsids[256] = { 0 };
+ __u16 sopts[256] = { 0 };
+ int err;
+
+ union {
+ __u32 short_pi[256];
+ __u64 long_pi[256];
+ } eilbrts;
+
+ __u32 elbatms[256] = { 0 };
+ __u32 elbats[256] = { 0 };
+
+ union {
+ struct nvme_copy_range f0[256];
+ struct nvme_copy_range_f1 f1[256];
+ struct nvme_copy_range_f2 f2[256];
+ struct nvme_copy_range_f3 f3[256];
+ } *copy;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 sdlba;
+ char *slbas;
+ char *nlbs;
+ char *snsids;
+ char *sopts;
+ bool lr;
+ bool fua;
+ __u8 prinfow;
+ __u8 prinfor;
+ __u64 ilbrt;
+ char *eilbrts;
+ __u16 lbat;
+ char *elbats;
+ __u16 lbatm;
+ char *elbatms;
+ __u8 dtype;
+ __u16 dspec;
+ __u8 format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .sdlba = 0,
+ .slbas = "",
+ .nlbs = "",
+ .snsids = "",
+ .sopts = "",
+ .lr = false,
+ .fua = false,
+ .prinfow = 0,
+ .prinfor = 0,
+ .ilbrt = 0,
+ .eilbrts = "",
+ .lbat = 0,
+ .elbats = "",
+ .lbatm = 0,
+ .elbatms = "",
+ .dtype = 0,
+ .dspec = 0,
+ .format = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ 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_LIST("snsids", 'N', &cfg.snsids, d_snsids),
+ OPT_LIST("sopts", 'O', &cfg.sopts, d_sopts),
+ 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_SUFFIX("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));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ nb = argconfig_parse_comma_sep_array_u16(cfg.nlbs, nlbs, ARRAY_SIZE(nlbs));
+ ns = argconfig_parse_comma_sep_array_u64(cfg.slbas, slbas, ARRAY_SIZE(slbas));
+ nids = argconfig_parse_comma_sep_array_u32(cfg.snsids, snsids, ARRAY_SIZE(snsids));
+ argconfig_parse_comma_sep_array_u16(cfg.sopts, sopts, ARRAY_SIZE(sopts));
+
+ if (cfg.format == 0 || cfg.format == 2) {
+ nrts = argconfig_parse_comma_sep_array_u32(cfg.eilbrts, eilbrts.short_pi,
+ ARRAY_SIZE(eilbrts.short_pi));
+ } else if (cfg.format == 1 || cfg.format == 3) {
+ nrts = argconfig_parse_comma_sep_array_u64(cfg.eilbrts, eilbrts.long_pi,
+ ARRAY_SIZE(eilbrts.long_pi));
+ } else {
+ nvme_show_error("invalid format");
+ return -EINVAL;
+ }
+
+ natms = argconfig_parse_comma_sep_array_u32(cfg.elbatms, elbatms, ARRAY_SIZE(elbatms));
+ nats = argconfig_parse_comma_sep_array_u32(cfg.elbats, elbats, ARRAY_SIZE(elbats));
+
+ nr = max(nb, max(ns, max(nrts, max(natms, nats))));
+ if (cfg.format == 2 || cfg.format == 3) {
+ if (nr != nids) {
+ nvme_show_error("formats 2 and 3 require source namespace ids for each source range");
+ return -EINVAL;
+ }
+ } else if (nids) {
+ nvme_show_error("formats 0 and 1 do not support cross-namespace copy");
+ return -EINVAL;
+ }
+ if (!nr || nr > 256) {
+ nvme_show_error("invalid range");
+ return -EINVAL;
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ copy = nvme_alloc(sizeof(*copy));
+ if (!copy)
+ return -ENOMEM;
+
+ if (cfg.format == 0)
+ nvme_init_copy_range(copy->f0, nlbs, slbas, eilbrts.short_pi, elbatms, elbats, nr);
+ else if (cfg.format == 1)
+ nvme_init_copy_range_f1(copy->f1, nlbs, slbas, eilbrts.long_pi, elbatms, elbats, nr);
+ else if (cfg.format == 2)
+ nvme_init_copy_range_f2(copy->f2, snsids, nlbs, slbas, sopts, eilbrts.short_pi, elbatms,
+ elbats, nr);
+ else if (cfg.format == 3)
+ nvme_init_copy_range_f3(copy->f3, snsids, nlbs, slbas, sopts, eilbrts.long_pi, elbatms,
+ elbats, nr);
+
+ struct nvme_copy_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .copy = copy->f0,
+ .sdlba = cfg.sdlba,
+ .nr = nr,
+ .prinfor = cfg.prinfor,
+ .prinfow = cfg.prinfow,
+ .dtype = cfg.dtype,
+ .dspec = cfg.dspec,
+ .format = cfg.format,
+ .lr = cfg.lr,
+ .fua = cfg.fua,
+ .ilbrt_u64 = cfg.ilbrt,
+ .lbatm = cfg.lbatm,
+ .lbat = cfg.lbat,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_copy(&args);
+ if (err < 0)
+ nvme_show_error("NVMe Copy: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe Copy: success\n");
+
+ return err;
+}
+
+static int flush_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Commit data and metadata associated with\n"
+ "given namespaces to nonvolatile media. Applies to all commands\n"
+ "finished before the flush was submitted. Additional data may also be\n"
+ "flushed by the controller, from any namespace, depending on controller and\n"
+ "associated namespace status.";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ err = nvme_flush(dev_fd(dev), cfg.namespace_id);
+ if (err < 0)
+ nvme_show_error("flush: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe Flush: success\n");
+
+ return err;
+}
+
+static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Obtain a reservation on a given\n"
+ "namespace. Only one reservation is allowed at a time on a\n"
+ "given namespace, though multiple controllers may register\n"
+ "with that namespace. Namespace reservation will abort with\n"
+ "status Reservation Conflict if the given namespace is already reserved.";
+ const char *prkey = "pre-empt reservation key";
+ const char *racqa = "reservation acquire action";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 crkey;
+ __u64 prkey;
+ __u8 rtype;
+ __u8 racqa;
+ bool iekey;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .crkey = 0,
+ .prkey = 0,
+ .rtype = 0,
+ .racqa = 0,
+ .iekey = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
+ OPT_SUFFIX("prkey", 'p', &cfg.prkey, prkey),
+ OPT_BYTE("rtype", 't', &cfg.rtype, rtype),
+ OPT_BYTE("racqa", 'a', &cfg.racqa, racqa),
+ OPT_FLAG("iekey", 'i', &cfg.iekey, iekey));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+ if (cfg.racqa > 7) {
+ nvme_show_error("invalid racqa:%d", cfg.racqa);
+ return -EINVAL;
+ }
+
+ struct nvme_resv_acquire_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .rtype = cfg.rtype,
+ .racqa = cfg.racqa,
+ .iekey = !!cfg.iekey,
+ .crkey = cfg.crkey,
+ .nrkey = cfg.prkey,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_resv_acquire(&args);
+ if (err < 0)
+ nvme_show_error("reservation acquire: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation Acquire success\n");
+
+ return err;
+}
+
+static int resv_register(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Register, de-register, or\n"
+ "replace a controller's reservation on a given namespace.\n"
+ "Only one reservation at a time is allowed on any namespace.";
+ const char *nrkey = "new reservation key";
+ const char *rrega = "reservation registration action";
+ const char *cptpl = "change persistence through power loss setting";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 crkey;
+ __u64 nrkey;
+ __u8 rrega;
+ __u8 cptpl;
+ bool iekey;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .crkey = 0,
+ .nrkey = 0,
+ .rrega = 0,
+ .cptpl = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
+ OPT_SUFFIX("nrkey", 'k', &cfg.nrkey, nrkey),
+ OPT_BYTE("rrega", 'r', &cfg.rrega, rrega),
+ OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl),
+ OPT_FLAG("iekey", 'i', &cfg.iekey, iekey));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+ if (cfg.cptpl > 3) {
+ nvme_show_error("invalid cptpl:%d", cfg.cptpl);
+ return -EINVAL;
+ }
+
+ if (cfg.rrega > 7) {
+ nvme_show_error("invalid rrega:%d", cfg.rrega);
+ return -EINVAL;
+ }
+
+ struct nvme_resv_register_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .rrega = cfg.rrega,
+ .cptpl = cfg.cptpl,
+ .iekey = !!cfg.iekey,
+ .crkey = cfg.crkey,
+ .nrkey = cfg.nrkey,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_resv_register(&args);
+ if (err < 0)
+ nvme_show_error("reservation register: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation success\n");
+
+ return err;
+}
+
+static int resv_release(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Releases reservation held on a\n"
+ "namespace by the given controller. If rtype != current reservation\n"
+ "type, release will fails. If the given controller holds no\n"
+ "reservation on the namespace or is not the namespace's current\n"
+ "reservation holder, the release command completes with no\n"
+ "effect. If the reservation type is not Write Exclusive or\n"
+ "Exclusive Access, all registrants on the namespace except\n"
+ "the issuing controller are notified.";
+ const char *rrela = "reservation release action";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 crkey;
+ __u8 rtype;
+ __u8 rrela;
+ __u8 iekey;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .crkey = 0,
+ .rtype = 0,
+ .rrela = 0,
+ .iekey = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_SUFFIX("crkey", 'c', &cfg.crkey, crkey),
+ OPT_BYTE("rtype", 't', &cfg.rtype, rtype),
+ OPT_BYTE("rrela", 'a', &cfg.rrela, rrela),
+ OPT_FLAG("iekey", 'i', &cfg.iekey, iekey));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+ if (cfg.rrela > 7) {
+ nvme_show_error("invalid rrela:%d", cfg.rrela);
+ return -EINVAL;
+ }
+
+ struct nvme_resv_release_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .rtype = cfg.rtype,
+ .rrela = cfg.rrela,
+ .iekey = !!cfg.iekey,
+ .crkey = cfg.crkey,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_resv_release(&args);
+ if (err < 0)
+ nvme_show_error("reservation release: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation Release success\n");
+
+ return err;
+}
+
+static int resv_report(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Returns Reservation Status data\n"
+ "structure describing any existing reservations on and the\n"
+ "status of a given namespace. Namespace Reservation Status\n"
+ "depends on the number of controllers registered for that namespace.";
+ const char *numd = "number of dwords to transfer";
+ const char *eds = "request extended data structure";
+
+ _cleanup_free_ struct nvme_resv_status *status = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ enum nvme_print_flags flags;
+ int err, size;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 numd;
+ __u8 eds;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .numd = 0,
+ .eds = false,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_UINT("numd", 'd', &cfg.numd, numd),
+ OPT_FLAG("eds", 'e', &cfg.eds, eds),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ if (!cfg.numd || cfg.numd >= (0x1000 >> 2))
+ cfg.numd = (0x1000 >> 2) - 1;
+ if (cfg.numd < 3)
+ cfg.numd = 3;
+
+ size = (cfg.numd + 1) << 2;
+
+ status = nvme_alloc(size);
+ if (!status)
+ return -ENOMEM;
+
+ struct nvme_resv_report_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .eds = cfg.eds,
+ .len = size,
+ .report = status,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_resv_report(&args);
+ if (!err)
+ nvme_show_resv_report(status, size, cfg.eds, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("reservation report: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+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 +
+ (end_time.tv_usec - start_time.tv_usec);
+ return err;
+}
+
+static int submit_io(int opcode, char *command, const char *desc, int argc, char **argv)
+{
+ struct timeval start_time, end_time;
+ void *buffer;
+ _cleanup_free_ void *mbuffer = NULL;
+ int err = 0;
+ _cleanup_file_ int dfd = -1, mfd = -1;
+ int flags;
+ int mode = 0644;
+ __u16 control = 0, nblocks = 0;
+ __u32 dsmgmt = 0;
+ unsigned int logical_block_size = 0;
+ unsigned long long buffer_size = 0, mbuffer_size = 0;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ __u8 lba_index, ms = 0, sts = 0, pif = 0;
+
+ const char *start_block_addr = "64-bit addr of first block to access";
+ const char *data_size = "size of data in bytes";
+ const char *metadata_size = "size of metadata in bytes";
+ const char *data = "data file";
+ const char *metadata = "metadata file";
+ const char *limited_retry_num = "limit num. media access attempts";
+ const char *show = "show command before sending";
+ const char *dtype_for_write = "directive type (for write-only)";
+ const char *dspec = "directive specific (for write-only)";
+ const char *dsm = "dataset management attributes (lower 8 bits)";
+ const char *storage_tag_check = "This bit specifies the Storage Tag field shall be\n"
+ "checked as part of end-to-end data protection processing";
+ const char *force = "The \"I know what I'm doing\" flag, do not enforce exclusive access for write";
+
+ struct config {
+ __u32 namespace_id;
+ __u64 start_block;
+ __u16 block_count;
+ __u64 data_size;
+ __u64 metadata_size;
+ __u64 ref_tag;
+ char *data;
+ char *metadata;
+ __u8 prinfo;
+ __u16 app_tag_mask;
+ __u16 app_tag;
+ __u64 storage_tag;
+ bool limited_retry;
+ bool force_unit_access;
+ bool storage_tag_check;
+ __u8 dtype;
+ __u16 dspec;
+ __u8 dsmgmt;
+ bool show;
+ bool dry_run;
+ bool latency;
+ bool force;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .data_size = 0,
+ .metadata_size = 0,
+ .ref_tag = 0,
+ .data = "",
+ .metadata = "",
+ .prinfo = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ .storage_tag = 0,
+ .limited_retry = false,
+ .force_unit_access = false,
+ .storage_tag_check = false,
+ .dtype = 0,
+ .dspec = 0,
+ .dsmgmt = 0,
+ .show = false,
+ .dry_run = false,
+ .latency = false,
+ .force = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block_addr),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size),
+ OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size),
+ OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_FILE("data", 'd', &cfg.data, data),
+ OPT_FILE("metadata", 'M', &cfg.metadata, metadata),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask),
+ OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag),
+ OPT_SUFFIX("storage-tag", 'g', &cfg.storage_tag, storage_tag),
+ OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry_num),
+ OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype_for_write),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec),
+ OPT_BYTE("dsm", 'D', &cfg.dsmgmt, dsm),
+ OPT_FLAG("show-command", 'V', &cfg.show, show),
+ OPT_FLAG("dry-run", 'w', &cfg.dry_run, dry),
+ OPT_FLAG("latency", 't', &cfg.latency, latency),
+ OPT_FLAG("force", 0, &cfg.force, force));
+
+ if (opcode != nvme_cmd_write) {
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+ } else {
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+ err = open_exclusive(&dev, argc, argv, cfg.force);
+ if (err) {
+ if (errno == EBUSY) {
+ fprintf(stderr, "Failed to open %s.\n", basename(argv[optind]));
+ fprintf(stderr, "Namespace is currently busy.\n");
+ if (!cfg.force)
+ fprintf(stderr,
+ "Use the force [--force] option to ignore that.\n");
+ } else {
+ argconfig_print_help(desc, opts);
+ }
+ return err;
+ }
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ if (cfg.prinfo > 0xf)
+ return err;
+
+ dsmgmt = cfg.dsmgmt;
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_IO_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_IO_FUA;
+ if (cfg.storage_tag_check)
+ control |= NVME_IO_STC;
+ if (cfg.dtype) {
+ if (cfg.dtype > 0xf) {
+ nvme_show_error("Invalid directive type, %x", cfg.dtype);
+ return -EINVAL;
+ }
+ control |= cfg.dtype << 4;
+ dsmgmt |= ((__u32)cfg.dspec) << 16;
+ }
+
+ if (opcode & 1) {
+ dfd = mfd = STDIN_FILENO;
+ flags = O_RDONLY;
+ } else {
+ dfd = mfd = STDOUT_FILENO;
+ flags = O_WRONLY | O_CREAT;
+ }
+
+ if (strlen(cfg.data)) {
+ dfd = open(cfg.data, flags, mode);
+ if (dfd < 0) {
+ nvme_show_perror(cfg.data);
+ return -EINVAL;
+ }
+ }
+
+ if (strlen(cfg.metadata)) {
+ mfd = open(cfg.metadata, flags, mode);
+ if (mfd < 0) {
+ nvme_show_perror(cfg.metadata);
+ return -EINVAL;
+ }
+ }
+
+ if (!cfg.data_size) {
+ nvme_show_error("data size not provided");
+ return -EINVAL;
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+ if (err > 0) {
+ nvme_show_status(err);
+ return err;
+ } else if (err < 0) {
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ return err;
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
+ logical_block_size = 1 << ns->lbaf[lba_index].ds;
+ ms = ns->lbaf[lba_index].ms;
+ if (NVME_FLBAS_META_EXT(ns->flbas)) {
+ /*
+ * No meta data is transferred for PRACT=1 and MD=8:
+ * 5.2.2.1 Protection Information and Write Commands
+ * 5.2.2.2 Protection Information and Read Commands
+ */
+ if (!((cfg.prinfo & 0x8) != 0 && ms == 8))
+ logical_block_size += ms;
+ }
+
+ buffer_size = ((long long)cfg.block_count + 1) * logical_block_size;
+ if (cfg.data_size < buffer_size)
+ nvme_show_error("Rounding data size to fit block count (%lld bytes)", buffer_size);
+ else
+ buffer_size = cfg.data_size;
+
+ if (argconfig_parse_seen(opts, "block-count")) {
+ /* Use the value provided */
+ nblocks = cfg.block_count;
+ } else {
+ /* Get the required block count. Note this is a zeroes based value. */
+ nblocks = ((buffer_size + (logical_block_size - 1)) / logical_block_size) - 1;
+
+ /* Update the data size based on the required block count */
+ buffer_size = ((unsigned long long)nblocks + 1) * logical_block_size;
+ }
+
+ buffer = nvme_alloc_huge(buffer_size, &mh);
+ if (!buffer)
+ return -ENOMEM;
+
+ nvm_ns = nvme_alloc(sizeof(*nvm_ns));
+ if (!nvm_ns)
+ return -ENOMEM;
+
+ if (cfg.metadata_size) {
+ err = nvme_identify_ns_csi(dev_fd(dev), 1, 0, NVME_CSI_NVM, nvm_ns);
+ if (!err) {
+ sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK;
+ pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7;
+ }
+
+ mbuffer_size = ((unsigned long long)cfg.block_count + 1) * ms;
+ if (ms && cfg.metadata_size < mbuffer_size)
+ nvme_show_error("Rounding metadata size to fit block count (%lld bytes)",
+ mbuffer_size);
+ else
+ mbuffer_size = cfg.metadata_size;
+
+ mbuffer = malloc(mbuffer_size);
+ if (!mbuffer)
+ return -ENOMEM;
+ memset(mbuffer, 0, mbuffer_size);
+ }
+
+ if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif))
+ return -EINVAL;
+
+ if (opcode & 1) {
+ err = read(dfd, (void *)buffer, cfg.data_size);
+ if (err < 0) {
+ err = -errno;
+ nvme_show_error("failed to read data buffer from input file %s", strerror(errno));
+ return err;
+ }
+ }
+
+ if ((opcode & 1) && cfg.metadata_size) {
+ err = read(mfd, (void *)mbuffer, mbuffer_size);
+ if (err < 0) {
+ err = -errno;
+ nvme_show_error("failed to read meta-data buffer from input file %s", strerror(errno));
+ return err;
+ }
+ }
+
+ if (cfg.show || cfg.dry_run) {
+ printf("opcode : %02x\n", opcode);
+ printf("nsid : %02x\n", cfg.namespace_id);
+ printf("flags : %02x\n", 0);
+ printf("control : %04x\n", control);
+ printf("nblocks : %04x\n", nblocks);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer);
+ printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer);
+ printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block);
+ printf("dsmgmt : %08x\n", dsmgmt);
+ printf("reftag : %"PRIx64"\n", (uint64_t)cfg.ref_tag);
+ printf("apptag : %04x\n", cfg.app_tag);
+ printf("appmask : %04x\n", cfg.app_tag_mask);
+ printf("storagetagcheck : %04x\n", cfg.storage_tag_check);
+ printf("storagetag : %"PRIx64"\n", (uint64_t)cfg.storage_tag);
+ printf("pif : %02x\n", pif);
+ printf("sts : %02x\n", sts);
+ }
+ if (cfg.dry_run)
+ return 0;
+
+ struct nvme_io_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.start_block,
+ .nlb = nblocks,
+ .control = control,
+ .dsm = cfg.dsmgmt,
+ .sts = sts,
+ .pif = pif,
+ .dspec = cfg.dspec,
+ .reftag_u64 = cfg.ref_tag,
+ .apptag = cfg.app_tag,
+ .appmask = cfg.app_tag_mask,
+ .storage_tag = cfg.storage_tag,
+ .data_len = buffer_size,
+ .data = buffer,
+ .metadata_len = mbuffer_size,
+ .metadata = mbuffer,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ gettimeofday(&start_time, NULL);
+ err = nvme_io(&args, opcode);
+ gettimeofday(&end_time, NULL);
+ if (cfg.latency)
+ printf(" latency: %s: %llu us\n", command, elapsed_utime(start_time, end_time));
+ if (err < 0) {
+ nvme_show_error("submit-io: %s", nvme_strerror(errno));
+ } else if (err) {
+ nvme_show_status(err);
+ } else {
+ if (!(opcode & 1) && write(dfd, (void *)buffer, buffer_size) < 0) {
+ nvme_show_error("write: %s: failed to write buffer to output file",
+ strerror(errno));
+ err = -EINVAL;
+ } else if (!(opcode & 1) && cfg.metadata_size &&
+ write(mfd, (void *)mbuffer, mbuffer_size) < 0) {
+ nvme_show_error(
+ "write: %s: failed to write meta-data buffer to output file",
+ strerror(errno));
+ err = -EINVAL;
+ } else {
+ fprintf(stderr, "%s: Success\n", command);
+ }
+ }
+
+ return err;
+}
+
+static int compare(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Compare specified logical blocks on\n"
+ "device with specified data buffer; return failure if buffer\n"
+ "and block(s) are dissimilar";
+
+ return submit_io(nvme_cmd_compare, "compare", desc, argc, argv);
+}
+
+static int read_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Copy specified logical blocks on the given\n"
+ "device to specified data buffer (default buffer is stdout).";
+
+ return submit_io(nvme_cmd_read, "read", desc, argc, argv);
+}
+
+static int write_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Copy from provided data buffer (default\n"
+ "buffer is stdin) to specified logical blocks on the given device.";
+
+ return submit_io(nvme_cmd_write, "write", desc, argc, argv);
+}
+
+static int verify_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ __u16 control = 0;
+ __u8 lba_index, sts = 0, pif = 0;
+ _cleanup_free_ struct nvme_nvm_id_ns *nvm_ns = NULL;
+ _cleanup_free_ struct nvme_id_ns *ns = NULL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err;
+
+ const char *desc = "Verify specified logical blocks on the given device.";
+ const char *force_unit_access_verify =
+ "force device to commit cached data before performing the verify operation";
+ const char *storage_tag_check =
+ "This bit specifies the Storage Tag field shall be checked as part of Verify operation";
+
+ struct config {
+ __u32 namespace_id;
+ __u64 start_block;
+ __u16 block_count;
+ bool limited_retry;
+ bool force_unit_access;
+ __u8 prinfo;
+ __u32 ref_tag;
+ __u16 app_tag;
+ __u16 app_tag_mask;
+ __u64 storage_tag;
+ bool storage_tag_check;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .limited_retry = false,
+ .force_unit_access = false,
+ .prinfo = 0,
+ .ref_tag = 0,
+ .app_tag = 0,
+ .app_tag_mask = 0,
+ .storage_tag = 0,
+ .storage_tag_check = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
+ OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force_unit_access_verify),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_SUFFIX("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask),
+ OPT_SUFFIX("storage-tag", 'S', &cfg.storage_tag, storage_tag),
+ OPT_FLAG("storage-tag-check", 'C', &cfg.storage_tag_check, storage_tag_check));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.prinfo > 0xf)
+ return -EINVAL;
+
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_IO_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_IO_FUA;
+ if (cfg.storage_tag_check)
+ control |= NVME_IO_STC;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ nvme_show_error("get-namespace-id: %s", nvme_strerror(errno));
+ return err;
+ }
+ }
+
+ ns = nvme_alloc(sizeof(*ns));
+ if (!ns)
+ return -ENOMEM;
+
+ err = nvme_cli_identify_ns(dev, cfg.namespace_id, ns);
+ if (err < 0) {
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ return err;
+ } else if (err) {
+ nvme_show_status(err);
+ return err;
+ }
+
+ nvm_ns = nvme_alloc(sizeof(*nvm_ns));
+ if (!nvm_ns)
+ return -ENOMEM;
+
+ err = nvme_identify_ns_csi(dev_fd(dev), cfg.namespace_id, 0,
+ NVME_CSI_NVM, nvm_ns);
+ if (!err) {
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
+ sts = nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_STS_MASK;
+ pif = (nvm_ns->elbaf[lba_index] & NVME_NVM_ELBAF_PIF_MASK) >> 7;
+ }
+
+ if (invalid_tags(cfg.storage_tag, cfg.ref_tag, sts, pif))
+ return -EINVAL;
+
+ struct nvme_io_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.start_block,
+ .nlb = cfg.block_count,
+ .control = control,
+ .reftag_u64 = cfg.ref_tag,
+ .apptag = cfg.app_tag,
+ .appmask = cfg.app_tag_mask,
+ .sts = sts,
+ .pif = pif,
+ .storage_tag = cfg.storage_tag,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_verify(&args);
+ if (err < 0)
+ nvme_show_error("verify: %s", nvme_strerror(errno));
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Verify Success\n");
+
+ return err;
+}
+
+static int sec_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Obtain results of one or more\n"
+ "previously submitted security-sends. Results, and association\n"
+ "between Security Send and Receive, depend on the security\n"
+ "protocol field as they are defined by the security protocol\n"
+ "used. A Security Receive must follow a Security Send made with\n"
+ "the same security protocol.";
+ const char *size = "size of buffer (prints to stdout on success)";
+ const char *al = "allocation length (cf. SPC-4)";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *sec_buf = NULL;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 size;
+ __u8 nssf;
+ __u8 secp;
+ __u16 spsp;
+ __u32 al;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .size = 0,
+ .nssf = 0,
+ .secp = 0,
+ .spsp = 0,
+ .al = 0,
+ .raw_binary = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_UINT("size", 'x', &cfg.size, size),
+ OPT_BYTE("nssf", 'N', &cfg.nssf, nssf),
+ OPT_BYTE("secp", 'p', &cfg.secp, secp),
+ OPT_SHRT("spsp", 's', &cfg.spsp, spsp),
+ OPT_UINT("al", 't', &cfg.al, al),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.size) {
+ sec_buf = nvme_alloc(sizeof(*sec_buf));
+ if (!sec_buf)
+ return -ENOMEM;
+ }
+
+ struct nvme_security_receive_args args = {
+ .args_size = sizeof(args),
+ .nsid = cfg.namespace_id,
+ .nssf = cfg.nssf,
+ .spsp0 = cfg.spsp & 0xff,
+ .spsp1 = cfg.spsp >> 8,
+ .secp = cfg.secp,
+ .al = cfg.al,
+ .data_len = cfg.size,
+ .data = sec_buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ err = nvme_cli_security_receive(dev, &args);
+ if (err < 0) {
+ nvme_show_error("security receive: %s", nvme_strerror(errno));
+ } else if (err != 0) {
+ nvme_show_status(err);
+ } else {
+ printf("NVME Security Receive Command Success\n");
+ if (!cfg.raw_binary)
+ d(sec_buf, cfg.size, 16, 1);
+ else if (cfg.size)
+ d_raw((unsigned char *)sec_buf, cfg.size);
+ }
+
+ return err;
+}
+
+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 *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 number of dwords to return";
+ const char *atype = "Action Type(ATYPE) specifies the mechanism\n"
+ "the controller uses in determining the LBA Status Descriptors to return.";
+ const char *rl =
+ "Range Length(RL) specifies the length of the range of contiguous LBAs beginning at SLBA";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ enum nvme_print_flags flags;
+ unsigned long buf_len;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 slba;
+ __u32 mndw;
+ __u8 atype;
+ __u16 rl;
+ __u32 timeout;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .slba = 0,
+ .mndw = 0,
+ .atype = 0,
+ .rl = 0,
+ .timeout = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ 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));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (!cfg.atype) {
+ nvme_show_error("action type (--action) has to be given");
+ return -EINVAL;
+ }
+
+ buf_len = (cfg.mndw + 1) * 4;
+ buf = nvme_alloc(buf_len);
+ if (!buf)
+ return -ENOMEM;
+
+ struct nvme_get_lba_status_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.slba,
+ .mndw = cfg.mndw,
+ .rl = cfg.rl,
+ .atype = cfg.atype,
+ .lbas = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_get_lba_status(&args);
+ if (!err)
+ nvme_show_lba_status(buf, buf_len, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("get lba status: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+static int capacity_mgmt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Host software uses the Capacity Management command to\n"
+ "configure Endurance Groups and NVM Sets in an NVM subsystem by either\n"
+ "selecting one of a set of supported configurations or by specifying the\n"
+ "capacity of the Endurance Group or NVM Set to be created";
+ const char *operation = "Operation to be performed by the controller";
+ const char *element_id = "Value specific to the value of the Operation field.";
+ const char *cap_lower =
+ "Least significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created";
+ const char *cap_upper =
+ "Most significant 32 bits of the capacity in bytes of the Endurance Group or NVM Set to be created";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err = -1;
+ __u32 result;
+
+ struct config {
+ __u8 operation;
+ __u16 element_id;
+ __u32 dw11;
+ __u32 dw12;
+ };
+
+ struct config cfg = {
+ .operation = 0xff,
+ .element_id = 0xffff,
+ .dw11 = 0,
+ .dw12 = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("operation", 'O', &cfg.operation, operation),
+ OPT_SHRT("element-id", 'i', &cfg.element_id, element_id),
+ OPT_UINT("cap-lower", 'l', &cfg.dw11, cap_lower),
+ OPT_UINT("cap-upper", 'u', &cfg.dw12, cap_upper));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.operation > 0xf) {
+ nvme_show_error("invalid operation field: %u", cfg.operation);
+ return -1;
+ }
+
+ struct nvme_capacity_mgmt_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .op = cfg.operation,
+ .element_id = cfg.element_id,
+ .cdw11 = cfg.dw11,
+ .cdw12 = cfg.dw12,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_capacity_mgmt(&args);
+ if (!err) {
+ printf("Capacity Management Command is Success\n");
+ if (cfg.operation == 1)
+ printf("Created Element Identifier for Endurance Group is: %u\n", result);
+ else if (cfg.operation == 3)
+ printf("Created Element Identifier for NVM Set is: %u\n", result);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_error("capacity management: %s", nvme_strerror(errno));
+ }
+
+ return err;
+}
+
+static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Read directive parameters of the specified directive type.";
+ const char *nsr = "namespace stream requested";
+
+ enum nvme_print_flags flags = NORMAL;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_free_ void *buf = NULL;
+ __u32 result;
+ __u32 dw12 = 0;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 data_len;
+ bool raw_binary;
+ __u8 dtype;
+ __u16 dspec;
+ __u8 doper;
+ __u16 nsr; /* dw12 for NVME_DIR_ST_RCVOP_STATUS */
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .data_len = 0,
+ .raw_binary = false,
+ .dtype = 0,
+ .dspec = 0,
+ .doper = 0,
+ .nsr = 0,
+ .human_readable = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id_desired),
+ OPT_UINT("data-len", 'l', &cfg.data_len, buf_len),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_directive),
+ OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec_w_dtype),
+ OPT_BYTE("dir-oper", 'O', &cfg.doper, doper),
+ OPT_SHRT("req-resource", 'r', &cfg.nsr, nsr),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable_directive));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ switch (cfg.dtype) {
+ case NVME_DIRECTIVE_DTYPE_IDENTIFY:
+ switch (cfg.doper) {
+ case NVME_DIRECTIVE_RECEIVE_IDENTIFY_DOPER_PARAM:
+ if (!cfg.data_len)
+ cfg.data_len = 4096;
+ break;
+ default:
+ nvme_show_error("invalid directive operations for Identify Directives");
+ return -EINVAL;
+ }
+ break;
+ case NVME_DIRECTIVE_DTYPE_STREAMS:
+ switch (cfg.doper) {
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_PARAM:
+ if (!cfg.data_len)
+ cfg.data_len = 32;
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_STATUS:
+ if (!cfg.data_len)
+ cfg.data_len = 128 * 1024;
+ break;
+ case NVME_DIRECTIVE_RECEIVE_STREAMS_DOPER_RESOURCE:
+ dw12 = cfg.nsr;
+ break;
+ default:
+ nvme_show_error("invalid directive operations for Streams Directives");
+ return -EINVAL;
+ }
+ break;
+ default:
+ nvme_show_error("invalid directive type");
+ return -EINVAL;
+ }
+
+ if (cfg.data_len) {
+ buf = nvme_alloc(cfg.data_len);
+ if (!buf)
+ return -ENOMEM;
+ }
+
+ struct nvme_directive_recv_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .dspec = cfg.dspec,
+ .doper = cfg.doper,
+ .dtype = cfg.dtype,
+ .cdw12 = dw12,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_directive_recv(&args);
+ if (!err)
+ nvme_directive_show(cfg.dtype, cfg.doper, cfg.dspec, cfg.namespace_id,
+ result, buf, cfg.data_len, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else if (err < 0)
+ nvme_show_error("dir-receive: %s", nvme_strerror(errno));
+
+ return err;
+}
+
+/* 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 lockdown_cmd(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "The Lockdown command is used to control the\n"
+ "Command and Feature Lockdown capability which configures the\n"
+ "prohibition or allowance of execution of the specified command\n"
+ "or Set Features command targeting a specific Feature Identifier.";
+ const char *ofi_desc = "Opcode or Feature Identifier (OFI)\n"
+ "specifies the command opcode or Set Features Feature Identifier\n"
+ "identified by the Scope field.";
+ const char *ifc_desc =
+ "[0-3] Interface (INF) field identifies the interfaces affected by this command.";
+ const char *prhbt_desc = "[0-1]Prohibit(PRHBT) bit specifies whether\n"
+ "to prohibit or allow the command opcode or Set Features Feature\n"
+ "Identifier specified by this command.";
+ const char *scp_desc =
+ "[0-15]Scope(SCP) field specifies the contents of the Opcode or Feature Identifier field.";
+ const char *uuid_desc = "UUID Index - If this field is set to a non-zero\n"
+ "value, then the value of this field is the index of a UUID in the UUID\n"
+ "List that is used by the command.If this field is cleared to 0h,\n"
+ "then no UUID index is specified";
+
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ int err = -1;
+
+ struct config {
+ __u8 ofi;
+ __u8 ifc;
+ __u8 prhbt;
+ __u8 scp;
+ __u8 uuid;
+ };
+
+ struct config cfg = {
+ .ofi = 0,
+ .ifc = 0,
+ .prhbt = 0,
+ .scp = 0,
+ .uuid = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("ofi", 'O', &cfg.ofi, ofi_desc),
+ OPT_BYTE("ifc", 'f', &cfg.ifc, ifc_desc),
+ OPT_BYTE("prhbt", 'p', &cfg.prhbt, prhbt_desc),
+ OPT_BYTE("scp", 's', &cfg.scp, scp_desc),
+ OPT_BYTE("uuid", 'U', &cfg.uuid, uuid_desc));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ /* check for input argument limit */
+ if (cfg.ifc > 3) {
+ nvme_show_error("invalid interface settings:%d", cfg.ifc);
+ return -1;
+ }
+ if (cfg.prhbt > 1) {
+ nvme_show_error("invalid prohibit settings:%d", cfg.prhbt);
+ return -1;
+ }
+ if (cfg.scp > 15) {
+ nvme_show_error("invalid scope settings:%d", cfg.scp);
+ return -1;
+ }
+ if (cfg.uuid > 127) {
+ nvme_show_error("invalid UUID index settings:%d", cfg.uuid);
+ return -1;
+ }
+
+ struct nvme_lockdown_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .scp = cfg.scp,
+ .prhbt = cfg.prhbt,
+ .ifc = cfg.ifc,
+ .ofi = cfg.ofi,
+ .uuidx = cfg.uuid,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_lockdown(&args);
+ if (err < 0)
+ nvme_show_error("lockdown: %s", nvme_strerror(errno));
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ printf("Lockdown Command is Successful\n");
+
+ return err;
+}
+
+static void passthru_print_read_output(struct passthru_config cfg, void *data, int dfd, void *mdata,
+ int mfd, int err)
+{
+ if (strlen(cfg.input_file)) {
+ if (write(dfd, (void *)data, cfg.data_len) < 0)
+ perror("failed to write data buffer");
+ } else if (data) {
+ if (cfg.raw_binary)
+ d_raw((unsigned char *)data, cfg.data_len);
+ else if (!err)
+ d((unsigned char *)data, cfg.data_len, 16, 1);
+ }
+ if (cfg.metadata_len && cfg.metadata) {
+ if (strlen(cfg.metadata)) {
+ if (write(mfd, (void *)mdata, cfg.metadata_len) < 0)
+ perror("failed to write metadata buffer");
+ } else {
+ if (cfg.raw_binary)
+ d_raw((unsigned char *)mdata, cfg.metadata_len);
+ else if (!err)
+ d((unsigned char *)mdata, cfg.metadata_len, 16, 1);
+ }
+ }
+}
+
+static int passthru(int argc, char **argv, bool admin,
+ const char *desc, struct command *cmd)
+{
+ const char *opcode = "opcode (required)";
+ const char *cflags = "command flags";
+ const char *rsvd = "value for reserved field";
+ const char *data_len = "data I/O length (bytes)";
+ const char *metadata_len = "metadata seg. length (bytes)";
+ const char *metadata = "metadata input or output file";
+ 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 = "data input or output file";
+ const char *show = "print command before 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";
+
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ _cleanup_file_ int dfd = -1, mfd = -1;
+ int flags;
+ int mode = 0644;
+ void *data = NULL;
+ _cleanup_free_ void *mdata = NULL;
+ int err = 0;
+ __u32 result;
+ const char *cmd_name = NULL;
+ struct timeval start_time, end_time;
+
+ struct passthru_config cfg = {
+ .opcode = 0,
+ .flags = 0,
+ .prefill = 0,
+ .rsvd = 0,
+ .namespace_id = 0,
+ .data_len = 0,
+ .metadata_len = 0,
+ .timeout = 0,
+ .cdw2 = 0,
+ .cdw3 = 0,
+ .cdw10 = 0,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw14 = 0,
+ .cdw15 = 0,
+ .input_file = "",
+ .metadata = "",
+ .raw_binary = false,
+ .show_command = false,
+ .dry_run = false,
+ .read = false,
+ .write = false,
+ .latency = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("opcode", 'O', &cfg.opcode, opcode),
+ OPT_BYTE("flags", 'f', &cfg.flags, cflags),
+ OPT_BYTE("prefill", 'p', &cfg.prefill, prefill),
+ OPT_SHRT("rsvd", 'R', &cfg.rsvd, rsvd),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_UINT("metadata-len", 'm', &cfg.metadata_len, metadata_len),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_UINT("cdw2", '2', &cfg.cdw2, cdw2),
+ OPT_UINT("cdw3", '3', &cfg.cdw3, cdw3),
+ OPT_UINT("cdw10", '4', &cfg.cdw10, cdw10),
+ OPT_UINT("cdw11", '5', &cfg.cdw11, cdw11),
+ OPT_UINT("cdw12", '6', &cfg.cdw12, cdw12),
+ OPT_UINT("cdw13", '7', &cfg.cdw13, cdw13),
+ OPT_UINT("cdw14", '8', &cfg.cdw14, cdw14),
+ OPT_UINT("cdw15", '9', &cfg.cdw15, cdw15),
+ OPT_FILE("input-file", 'i', &cfg.input_file, input),
+ OPT_FILE("metadata", 'M', &cfg.metadata, metadata),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_dump),
+ OPT_FLAG("show-command", 's', &cfg.show_command, show),
+ OPT_FLAG("dry-run", 'd', &cfg.dry_run, dry),
+ OPT_FLAG("read", 'r', &cfg.read, re),
+ OPT_FLAG("write", 'w', &cfg.write, wr),
+ OPT_FLAG("latency", 'T', &cfg.latency, latency));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.opcode & 0x01) {
+ cfg.write = true;
+ flags = O_RDONLY;
+ dfd = mfd = STDIN_FILENO;
+ }
+
+ if (cfg.opcode & 0x02) {
+ cfg.read = true;
+ flags = O_WRONLY | O_CREAT;
+ dfd = mfd = STDOUT_FILENO;
+ }
+
+ if (strlen(cfg.input_file)) {
+ dfd = open(cfg.input_file, flags, mode);
+ if (dfd < 0) {
+ nvme_show_perror(cfg.input_file);
+ return -EINVAL;
+ }
+ }
+
+ if (cfg.metadata && strlen(cfg.metadata)) {
+ mfd = open(cfg.metadata, flags, mode);
+ if (mfd < 0) {
+ nvme_show_perror(cfg.metadata);
+ return -EINVAL;
+ }
+ }
+
+ if (cfg.metadata_len) {
+ mdata = malloc(cfg.metadata_len);
+ if (!mdata)
+ return -ENOMEM;
+
+ if (cfg.write) {
+ if (read(mfd, mdata, cfg.metadata_len) < 0) {
+ err = -errno;
+ nvme_show_perror("failed to read metadata write buffer");
+ return err;
+ }
+ } else {
+ memset(mdata, cfg.prefill, cfg.metadata_len);
+ }
+ }
+
+ if (cfg.data_len) {
+ data = nvme_alloc_huge(cfg.data_len, &mh);
+ if (!data)
+ return -ENOMEM;
+
+ memset(data, cfg.prefill, cfg.data_len);
+ if (!cfg.read && !cfg.write) {
+ nvme_show_error("data direction not given");
+ return -EINVAL;
+ } else if (cfg.write) {
+ if (read(dfd, data, cfg.data_len) < 0) {
+ err = -errno;
+ nvme_show_error("failed to read write buffer %s", strerror(errno));
+ return err;
+ }
+ }
+ }
+
+ if (cfg.show_command || cfg.dry_run) {
+ printf("opcode : %02x\n", cfg.opcode);
+ printf("flags : %02x\n", cfg.flags);
+ printf("rsvd1 : %04x\n", cfg.rsvd);
+ printf("nsid : %08x\n", cfg.namespace_id);
+ printf("cdw2 : %08x\n", cfg.cdw2);
+ printf("cdw3 : %08x\n", cfg.cdw3);
+ printf("data_len : %08x\n", cfg.data_len);
+ printf("metadata_len : %08x\n", cfg.metadata_len);
+ printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)data);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mdata);
+ printf("cdw10 : %08x\n", cfg.cdw10);
+ printf("cdw11 : %08x\n", cfg.cdw11);
+ printf("cdw12 : %08x\n", cfg.cdw12);
+ printf("cdw13 : %08x\n", cfg.cdw13);
+ printf("cdw14 : %08x\n", cfg.cdw14);
+ printf("cdw15 : %08x\n", cfg.cdw15);
+ printf("timeout_ms : %08x\n", cfg.timeout);
+ }
+ if (cfg.dry_run)
+ return 0;
+
+ gettimeofday(&start_time, NULL);
+
+ if (admin)
+ err = nvme_cli_admin_passthru(dev, cfg.opcode, cfg.flags,
+ cfg.rsvd,
+ cfg.namespace_id, cfg.cdw2,
+ cfg.cdw3, cfg.cdw10,
+ cfg.cdw11, cfg.cdw12, cfg.cdw13,
+ cfg.cdw14,
+ cfg.cdw15, cfg.data_len, data,
+ cfg.metadata_len,
+ mdata, cfg.timeout, &result);
+ else
+ err = nvme_io_passthru(dev_fd(dev), cfg.opcode, cfg.flags,
+ cfg.rsvd,
+ cfg.namespace_id, cfg.cdw2, cfg.cdw3,
+ cfg.cdw10,
+ cfg.cdw11, cfg.cdw12, cfg.cdw13,
+ cfg.cdw14,
+ cfg.cdw15, cfg.data_len, data,
+ cfg.metadata_len,
+ mdata, cfg.timeout, &result);
+
+ gettimeofday(&end_time, NULL);
+ cmd_name = nvme_cmd_to_string(admin, cfg.opcode);
+ if (cfg.latency)
+ printf("%s Command %s latency: %llu us\n", admin ? "Admin" : "IO",
+ strcmp(cmd_name, "Unknown") ? cmd_name : "Vendor Specific",
+ elapsed_utime(start_time, end_time));
+
+ if (err < 0) {
+ nvme_show_error("%s: %s", __func__, nvme_strerror(errno));
+ } else if (err) {
+ nvme_show_status(err);
+ } else {
+ fprintf(stderr, "%s Command %s is Success and result: 0x%08x\n", admin ? "Admin" : "IO",
+ strcmp(cmd_name, "Unknown") ? cmd_name : "Vendor Specific", result);
+ if (cfg.read)
+ passthru_print_read_output(cfg, data, dfd, mdata, mfd, err);
+ }
+
+ return err;
+}
+
+static int io_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Send a user-defined IO command to the specified device via IOCTL passthrough, return results.";
+
+ return passthru(argc, argv, false, 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, true, desc, cmd);
+}
+
+static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ char *hostnqn;
+
+ hostnqn = nvmf_hostnqn_generate();
+ if (!hostnqn) {
+ nvme_show_error("\"%s\" not supported. Install lib uuid and rebuild.",
+ command->name);
+ return -ENOTSUP;
+ }
+ printf("%s\n", hostnqn);
+ free(hostnqn);
+ return 0;
+}
+
+static int show_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ char *hostnqn;
+
+ hostnqn = nvmf_hostnqn_from_file();
+ if (!hostnqn)
+ hostnqn = nvmf_hostnqn_generate();
+
+ if (!hostnqn) {
+ nvme_show_error("hostnqn is not available -- use nvme gen-hostnqn");
+ return -ENOENT;
+ }
+
+ fprintf(stdout, "%s\n", hostnqn);
+ free(hostnqn);
+
+ return 0;
+}
+
+
+static int gen_dhchap_key(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc =
+ "Generate a DH-HMAC-CHAP host key usable for NVMe In-Band Authentication.";
+ const char *secret =
+ "Optional secret (in hexadecimal characters) to be used to initialize the host key.";
+ const char *key_len = "Length of the resulting key (32, 48, or 64 bytes).";
+ const char *hmac =
+ "HMAC function to use for key transformation (0 = none, 1 = SHA-256, 2 = SHA-384, 3 = SHA-512).";
+ const char *nqn = "Host NQN to use for key transformation.";
+
+ unsigned char *raw_secret;
+ unsigned char key[68];
+ char encoded_key[128];
+ unsigned long crc = crc32(0L, NULL, 0);
+ int err = 0;
+
+ struct config {
+ char *secret;
+ unsigned int key_len;
+ char *nqn;
+ unsigned int hmac;
+ };
+
+ struct config cfg = {
+ .secret = NULL,
+ .key_len = 0,
+ .nqn = NULL,
+ .hmac = 0,
+ };
+
+ NVME_ARGS(opts,
+ OPT_STR("secret", 's', &cfg.secret, secret),
+ OPT_UINT("key-length", 'l', &cfg.key_len, key_len),
+ OPT_STR("nqn", 'n', &cfg.nqn, nqn),
+ OPT_UINT("hmac", 'm', &cfg.hmac, hmac));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.hmac > 3) {
+ nvme_show_error("Invalid HMAC identifier %u", cfg.hmac);
+ return -EINVAL;
+ }
+ if (cfg.hmac > 0) {
+ switch (cfg.hmac) {
+ case 1:
+ if (!cfg.key_len) {
+ cfg.key_len = 32;
+ } else if (cfg.key_len != 32) {
+ nvme_show_error("Invalid key length %d for SHA(256)", cfg.key_len);
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ if (!cfg.key_len) {
+ cfg.key_len = 48;
+ } else if (cfg.key_len != 48) {
+ nvme_show_error("Invalid key length %d for SHA(384)", cfg.key_len);
+ return -EINVAL;
+ }
+ break;
+ case 3:
+ if (!cfg.key_len) {
+ cfg.key_len = 64;
+ } else if (cfg.key_len != 64) {
+ nvme_show_error("Invalid key length %d for SHA(512)", cfg.key_len);
+ return -EINVAL;
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (!cfg.key_len) {
+ cfg.key_len = 32;
+ }
+
+ if (cfg.key_len != 32 && cfg.key_len != 48 && cfg.key_len != 64) {
+ nvme_show_error("Invalid key length %u", cfg.key_len);
+ return -EINVAL;
+ }
+ raw_secret = malloc(cfg.key_len);
+ if (!raw_secret)
+ return -ENOMEM;
+ if (!cfg.secret) {
+ if (getrandom_bytes(raw_secret, cfg.key_len) < 0)
+ return -errno;
+ } else {
+ int secret_len = 0, i;
+ unsigned int c;
+
+ for (i = 0; i < strlen(cfg.secret); i += 2) {
+ if (sscanf(&cfg.secret[i], "%02x", &c) != 1) {
+ nvme_show_error("Invalid secret '%s'", cfg.secret);
+ return -EINVAL;
+ }
+ raw_secret[secret_len++] = (unsigned char)c;
+ }
+ if (secret_len != cfg.key_len) {
+ nvme_show_error("Invalid key length (%d bytes)", secret_len);
+ return -EINVAL;
+ }
+ }
+
+ if (!cfg.nqn) {
+ cfg.nqn = nvmf_hostnqn_from_file();
+ if (!cfg.nqn) {
+ nvme_show_error("Could not read host NQN");
+ return -ENOENT;
+ }
+ }
+
+ if (nvme_gen_dhchap_key(cfg.nqn, cfg.hmac, cfg.key_len, raw_secret, key) < 0)
+ return -errno;
+
+ crc = crc32(crc, key, cfg.key_len);
+ key[cfg.key_len++] = crc & 0xff;
+ key[cfg.key_len++] = (crc >> 8) & 0xff;
+ key[cfg.key_len++] = (crc >> 16) & 0xff;
+ key[cfg.key_len++] = (crc >> 24) & 0xff;
+
+ memset(encoded_key, 0, sizeof(encoded_key));
+ base64_encode(key, cfg.key_len, encoded_key);
+
+ printf("DHHC-1:%02x:%s:\n", cfg.hmac, encoded_key);
+ return 0;
+}
+
+static int check_dhchap_key(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc =
+ "Check a DH-HMAC-CHAP host key for usability for NVMe In-Band Authentication.";
+ const char *key = "DH-HMAC-CHAP key (in hexadecimal characters) to be validated.";
+
+ unsigned char decoded_key[128];
+ unsigned int decoded_len;
+ u_int32_t crc = crc32(0L, NULL, 0);
+ u_int32_t key_crc;
+ int err = 0, hmac;
+ struct config {
+ char *key;
+ };
+
+ struct config cfg = {
+ .key = NULL,
+ };
+
+ NVME_ARGS(opts,
+ OPT_STR("key", 'k', &cfg.key, key));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.key) {
+ nvme_show_error("Key not specified");
+ return -EINVAL;
+ }
+
+ if (sscanf(cfg.key, "DHHC-1:%02x:*s", &hmac) != 1) {
+ nvme_show_error("Invalid key header '%s'", cfg.key);
+ return -EINVAL;
+ }
+ switch (hmac) {
+ case 0:
+ break;
+ case 1:
+ if (strlen(cfg.key) != 59) {
+ nvme_show_error("Invalid key length for SHA(256)");
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ if (strlen(cfg.key) != 83) {
+ nvme_show_error("Invalid key length for SHA(384)");
+ return -EINVAL;
+ }
+ break;
+ case 3:
+ if (strlen(cfg.key) != 103) {
+ nvme_show_error("Invalid key length for SHA(512)");
+ return -EINVAL;
+ }
+ break;
+ default:
+ nvme_show_error("Invalid HMAC identifier %d", hmac);
+ return -EINVAL;
+ }
+
+ err = base64_decode(cfg.key + 10, strlen(cfg.key) - 11, decoded_key);
+ if (err < 0) {
+ nvme_show_error("Base64 decoding failed, error %d", err);
+ return err;
+ }
+ decoded_len = err;
+ if (decoded_len < 32) {
+ nvme_show_error("Base64 decoding failed (%s, size %u)", cfg.key + 10, decoded_len);
+ return -EINVAL;
+ }
+ decoded_len -= 4;
+ if (decoded_len != 32 && decoded_len != 48 && decoded_len != 64) {
+ nvme_show_error("Invalid key length %d", decoded_len);
+ return -EINVAL;
+ }
+ crc = crc32(crc, decoded_key, decoded_len);
+ key_crc = ((u_int32_t)decoded_key[decoded_len]) |
+ ((u_int32_t)decoded_key[decoded_len + 1] << 8) |
+ ((u_int32_t)decoded_key[decoded_len + 2] << 16) |
+ ((u_int32_t)decoded_key[decoded_len + 3] << 24);
+ if (key_crc != crc) {
+ nvme_show_error("CRC mismatch (key %08x, crc %08x)", key_crc, crc);
+ return -EINVAL;
+ }
+ printf("Key is valid (HMAC %d, length %d, CRC %08x)\n", hmac, decoded_len, crc);
+ return 0;
+}
+
+static int gen_tls_key(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Generate a TLS key in NVMe PSK Interchange format.";
+ const char *secret =
+ "Optional secret (in hexadecimal characters) to be used for the TLS key.";
+ const char *hmac = "HMAC function to use for the retained key (1 = SHA-256, 2 = SHA-384).";
+ const char *identity = "TLS identity version to use (0 = NVMe TCP 1.0c, 1 = NVMe TCP 2.0";
+ const char *hostnqn = "Host NQN for the retained key.";
+ const char *subsysnqn = "Subsystem NQN for the retained key.";
+ const char *keyring = "Keyring for the retained key.";
+ const char *keytype = "Key type of the retained key.";
+ const char *insert = "Insert only, do not print the retained key.";
+
+ unsigned char *raw_secret;
+ char encoded_key[128];
+ int key_len = 32;
+ unsigned long crc = crc32(0L, NULL, 0);
+ int err;
+ long tls_key;
+
+ struct config {
+ char *keyring;
+ char *keytype;
+ char *hostnqn;
+ char *subsysnqn;
+ char *secret;
+ unsigned int hmac;
+ unsigned int identity;
+ bool insert;
+ };
+
+ struct config cfg = {
+ .keyring = ".nvme",
+ .keytype = "psk",
+ .hostnqn = NULL,
+ .subsysnqn = NULL,
+ .secret = NULL,
+ .hmac = 1,
+ .identity = 0,
+ .insert = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_STR("keyring", 'k', &cfg.keyring, keyring),
+ OPT_STR("keytype", 't', &cfg.keytype, keytype),
+ OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),
+ OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),
+ OPT_STR("secret", 's', &cfg.secret, secret),
+ OPT_UINT("hmac", 'm', &cfg.hmac, hmac),
+ OPT_UINT("identity", 'I', &cfg.identity, identity),
+ OPT_FLAG("insert", 'i', &cfg.insert, insert));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+ if (cfg.hmac < 1 || cfg.hmac > 2) {
+ nvme_show_error("Invalid HMAC identifier %u", cfg.hmac);
+ return -EINVAL;
+ }
+ if (cfg.identity > 1) {
+ nvme_show_error("Invalid TLS identity version %u",
+ cfg.identity);
+ return -EINVAL;
+ }
+ if (cfg.insert) {
+ if (!cfg.subsysnqn) {
+ nvme_show_error("No subsystem NQN specified");
+ return -EINVAL;
+ }
+ if (!cfg.hostnqn) {
+ cfg.hostnqn = nvmf_hostnqn_from_file();
+ if (!cfg.hostnqn) {
+ nvme_show_error("Failed to read host NQN");
+ return -EINVAL;
+ }
+ }
+ }
+ if (cfg.hmac == 2)
+ key_len = 48;
+
+ raw_secret = malloc(key_len + 4);
+ if (!raw_secret)
+ return -ENOMEM;
+ if (!cfg.secret) {
+ if (getrandom_bytes(raw_secret, key_len) < 0)
+ return -errno;
+ } else {
+ int secret_len = 0, i;
+ unsigned int c;
+
+ for (i = 0; i < strlen(cfg.secret); i += 2) {
+ if (sscanf(&cfg.secret[i], "%02x", &c) != 1) {
+ nvme_show_error("Invalid secret '%s'", cfg.secret);
+ return -EINVAL;
+ }
+ if (i >= key_len * 2) {
+ fprintf(stderr, "Skipping excess secret bytes\n");
+ break;
+ }
+ raw_secret[secret_len++] = (unsigned char)c;
+ }
+ if (secret_len != key_len) {
+ nvme_show_error("Invalid key length (%d bytes)", secret_len);
+ return -EINVAL;
+ }
+ }
+
+ if (cfg.insert) {
+ tls_key = nvme_insert_tls_key_versioned(cfg.keyring,
+ cfg.keytype, cfg.hostnqn,
+ cfg.subsysnqn, cfg.identity,
+ cfg.hmac, raw_secret, key_len);
+ if (tls_key < 0) {
+ nvme_show_error("Failed to insert key, error %d", errno);
+ return -errno;
+ }
+
+ printf("Inserted TLS key %08x\n", (unsigned int)tls_key);
+ return 0;
+ }
+ crc = crc32(crc, raw_secret, key_len);
+ raw_secret[key_len++] = crc & 0xff;
+ raw_secret[key_len++] = (crc >> 8) & 0xff;
+ raw_secret[key_len++] = (crc >> 16) & 0xff;
+ raw_secret[key_len++] = (crc >> 24) & 0xff;
+
+ memset(encoded_key, 0, sizeof(encoded_key));
+ base64_encode(raw_secret, key_len, encoded_key);
+
+ printf("NVMeTLSkey-1:%02x:%s:\n", cfg.hmac, encoded_key);
+ return 0;
+}
+
+static int check_tls_key(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Check a TLS key for NVMe PSK Interchange format.\n";
+ const char *keydata = "TLS key (in PSK Interchange format) to be validated.";
+ const char *identity = "TLS identity version to use (0 = NVMe TCP 1.0c, 1 = NVMe TCP 2.0)";
+ const char *hostnqn = "Host NQN for the retained key.";
+ const char *subsysnqn = "Subsystem NQN for the retained key.";
+ const char *keyring = "Keyring for the retained key.";
+ const char *keytype = "Key type of the retained key.";
+ const char *insert = "Insert retained key into the keyring.";
+
+ unsigned char decoded_key[128];
+ unsigned int decoded_len;
+ u_int32_t crc = crc32(0L, NULL, 0);
+ u_int32_t key_crc;
+ int err = 0, hmac;
+ long tls_key;
+ struct config {
+ char *keyring;
+ char *keytype;
+ char *hostnqn;
+ char *subsysnqn;
+ char *keydata;
+ unsigned int identity;
+ bool insert;
+ };
+
+ struct config cfg = {
+ .keyring = ".nvme",
+ .keytype = "psk",
+ .hostnqn = NULL,
+ .subsysnqn = NULL,
+ .keydata = NULL,
+ .identity = 0,
+ .insert = false,
+ };
+
+ NVME_ARGS(opts,
+ OPT_STR("keyring", 'k', &cfg.keyring, keyring),
+ OPT_STR("keytype", 't', &cfg.keytype, keytype),
+ OPT_STR("hostnqn", 'n', &cfg.hostnqn, hostnqn),
+ OPT_STR("subsysnqn", 'c', &cfg.subsysnqn, subsysnqn),
+ OPT_STR("keydata", 'd', &cfg.keydata, keydata),
+ OPT_UINT("identity", 'I', &cfg.identity, identity),
+ OPT_FLAG("insert", 'i', &cfg.insert, insert));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.keydata) {
+ nvme_show_error("No key data");
+ return -EINVAL;
+ }
+ if (cfg.identity > 1) {
+ nvme_show_error("Invalid TLS identity version %u",
+ cfg.identity);
+ return -EINVAL;
+ }
+
+ if (sscanf(cfg.keydata, "NVMeTLSkey-1:%02x:*s", &hmac) != 1) {
+ nvme_show_error("Invalid key '%s'", cfg.keydata);
+ return -EINVAL;
+ }
+ switch (hmac) {
+ case 1:
+ if (strlen(cfg.keydata) != 65) {
+ nvme_show_error("Invalid key length %zu for SHA(256)", strlen(cfg.keydata));
+ return -EINVAL;
+ }
+ break;
+ case 2:
+ if (strlen(cfg.keydata) != 89) {
+ nvme_show_error("Invalid key length %zu for SHA(384)", strlen(cfg.keydata));
+ return -EINVAL;
+ }
+ break;
+ default:
+ nvme_show_error("Invalid HMAC identifier %d", hmac);
+ return -EINVAL;
+ }
+
+ if (cfg.subsysnqn) {
+ if (cfg.insert && !cfg.hostnqn) {
+ cfg.hostnqn = nvmf_hostnqn_from_file();
+ if (!cfg.hostnqn) {
+ nvme_show_error("Failed to read host NQN");
+ return -EINVAL;
+ }
+ }
+ } else if (cfg.insert || cfg.identity == 1) {
+ nvme_show_error("Need to specify a subsystem NQN");
+ return -EINVAL;
+ }
+ err = base64_decode(cfg.keydata + 16, strlen(cfg.keydata) - 17, decoded_key);
+ if (err < 0) {
+ nvme_show_error("Base64 decoding failed (%s, error %d)", cfg.keydata + 16, err);
+ return err;
+ }
+ decoded_len = err;
+ decoded_len -= 4;
+ if (decoded_len != 32 && decoded_len != 48) {
+ nvme_show_error("Invalid key length %d", decoded_len);
+ return -EINVAL;
+ }
+ crc = crc32(crc, decoded_key, decoded_len);
+ key_crc = ((u_int32_t)decoded_key[decoded_len]) |
+ ((u_int32_t)decoded_key[decoded_len + 1] << 8) |
+ ((u_int32_t)decoded_key[decoded_len + 2] << 16) |
+ ((u_int32_t)decoded_key[decoded_len + 3] << 24);
+ if (key_crc != crc) {
+ nvme_show_error("CRC mismatch (key %08x, crc %08x)", key_crc, crc);
+ return -EINVAL;
+ }
+ if (cfg.insert) {
+ tls_key = nvme_insert_tls_key_versioned(cfg.keyring,
+ cfg.keytype, cfg.hostnqn,
+ cfg.subsysnqn, cfg.identity,
+ hmac, decoded_key, decoded_len);
+ if (tls_key < 0) {
+ nvme_show_error("Failed to insert key, error %d", errno);
+ return -errno;
+ }
+ printf("Inserted TLS key %08x\n", (unsigned int)tls_key);
+ } else {
+ char *tls_id;
+
+ tls_id = nvme_generate_tls_key_identity(cfg.hostnqn,
+ cfg.subsysnqn, cfg.identity,
+ hmac, decoded_key, decoded_len);
+ if (!tls_id) {
+ nvme_show_error("Failed to generate identity, error %d",
+ errno);
+ return -errno;
+ }
+ printf("%s\n", tls_id);
+ free(tls_id);
+ }
+ return 0;
+}
+
+static int show_topology_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Show the topology\n";
+ const char *ranking = "Ranking order: namespace|ctrl";
+ enum nvme_print_flags flags;
+ nvme_root_t r;
+ enum nvme_cli_topo_ranking rank;
+ int err;
+
+ struct config {
+ char *ranking;
+ };
+
+ struct config cfg = {
+ .ranking = "namespace",
+ };
+
+ NVME_ARGS(opts,
+ OPT_FMT("ranking", 'r', &cfg.ranking, ranking));
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format_val, &flags);
+ if (err < 0) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ if (argconfig_parse_seen(opts, "verbose"))
+ flags |= VERBOSE;
+
+ if (!strcmp(cfg.ranking, "namespace")) {
+ rank = NVME_CLI_TOPO_NAMESPACE;
+ } else if (!strcmp(cfg.ranking, "ctrl")) {
+ rank = NVME_CLI_TOPO_CTRL;
+ } else {
+ nvme_show_error("Invalid ranking argument: %s", cfg.ranking);
+ return -EINVAL;
+ }
+
+ r = nvme_create_root(stderr, map_log_level(!!(flags & VERBOSE), false));
+ if (!r) {
+ nvme_show_error("Failed to create topology root: %s", nvme_strerror(errno));
+ return -errno;
+ }
+
+ err = nvme_scan_topology(r, NULL, NULL);
+ if (err < 0) {
+ nvme_show_error("Failed to scan topology: %s", nvme_strerror(errno));
+ nvme_free_tree(r);
+ return err;
+ }
+
+ nvme_show_topology(r, rank, flags);
+ nvme_free_tree(r);
+
+ return err;
+}
+
+static int discover_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send Get Log Page request to Discovery Controller.";
+
+ return nvmf_discover(desc, argc, argv, false);
+}
+
+static int connect_all_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Discover NVMeoF subsystems and connect to them";
+
+ return nvmf_discover(desc, argc, argv, true);
+}
+
+static int connect_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Connect to NVMeoF subsystem";
+
+ return nvmf_connect(desc, argc, argv);
+}
+
+static int disconnect_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Disconnect from NVMeoF subsystem";
+
+ return nvmf_disconnect(desc, argc, argv);
+}
+
+int disconnect_all_cmd(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Disconnect from all connected NVMeoF subsystems";
+
+ return nvmf_disconnect_all(desc, argc, argv);
+}
+
+static int config_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Configuration of NVMeoF subsystems";
+
+ return nvmf_config(desc, argc, argv);
+}
+
+static int dim_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc =
+ "Send Discovery Information Management command to a Discovery Controller (DC)";
+
+ return nvmf_dim(desc, argc, argv);
+}
+
+static int nvme_mi(int argc, char **argv, __u8 admin_opcode, const char *desc)
+{
+ const char *opcode = "opcode (required)";
+ const char *data_len = "data I/O length (bytes)";
+ const char *nmimt = "nvme-mi message type";
+ const char *nmd0 = "nvme management dword 0 value";
+ const char *nmd1 = "nvme management dword 1 value";
+ const char *input = "data input or output file";
+
+ int mode = 0644;
+ void *data = NULL;
+ int err = 0;
+ bool send;
+ _cleanup_file_ int fd = -1;
+ int flags;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ __u32 result;
+
+ struct config {
+ __u8 opcode;
+ __u32 namespace_id;
+ __u32 data_len;
+ __u32 nmimt;
+ __u32 nmd0;
+ __u32 nmd1;
+ char *input_file;
+ };
+
+ struct config cfg = {
+ .opcode = 0,
+ .namespace_id = 0,
+ .data_len = 0,
+ .nmimt = 0,
+ .nmd0 = 0,
+ .nmd1 = 0,
+ .input_file = "",
+ };
+
+ NVME_ARGS(opts,
+ OPT_BYTE("opcode", 'O', &cfg.opcode, opcode),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_desired),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_UINT("nmimt", 'm', &cfg.nmimt, nmimt),
+ OPT_UINT("nmd0", '0', &cfg.nmd0, nmd0),
+ OPT_UINT("nmd1", '1', &cfg.nmd1, nmd1),
+ OPT_FILE("input-file", 'i', &cfg.input_file, input));
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (admin_opcode == nvme_admin_nvme_mi_send) {
+ flags = O_RDONLY;
+ fd = STDIN_FILENO;
+ send = true;
+ } else {
+ flags = O_WRONLY | O_CREAT;
+ fd = STDOUT_FILENO;
+ send = false;
+ }
+
+ if (strlen(cfg.input_file)) {
+ fd = open(cfg.input_file, flags, mode);
+ if (fd < 0) {
+ nvme_show_perror(cfg.input_file);
+ return -EINVAL;
+ }
+ }
+
+ if (cfg.data_len) {
+ data = nvme_alloc_huge(cfg.data_len, &mh);
+ if (!data)
+ return -ENOMEM;
+
+ if (send) {
+ if (read(fd, data, cfg.data_len) < 0) {
+ err = -errno;
+ nvme_show_error("failed to read write buffer %s", strerror(errno));
+ return err;
+ }
+ }
+ }
+
+ err = nvme_cli_admin_passthru(dev, admin_opcode, 0, 0, cfg.namespace_id, 0, 0,
+ cfg.nmimt << 11 | 4, cfg.opcode, cfg.nmd0, cfg.nmd1, 0, 0,
+ cfg.data_len, data, 0, NULL, 0, &result);
+ if (err < 0) {
+ nvme_show_error("nmi_recv: %s", nvme_strerror(errno));
+ } else if (err) {
+ nvme_show_status(err);
+ } else {
+ printf(
+ "%s Command is Success and result: 0x%08x (status: 0x%02x, response: 0x%06x)\n",
+ nvme_cmd_to_string(true, admin_opcode), result, result & 0xff, result >> 8);
+ if (result & 0xff)
+ printf("status: %s\n", nvme_mi_status_to_string(result & 0xff));
+ if (!send && strlen(cfg.input_file)) {
+ if (write(fd, (void *)data, cfg.data_len) < 0)
+ perror("failed to write data buffer");
+ } else if (data && !send && !err) {
+ d((unsigned char *)data, cfg.data_len, 16, 1);
+ }
+ }
+
+ return err;
+}
+
+static int nmi_recv(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Send a NVMe-MI Receive command to the specified device, return results.";
+
+ return nvme_mi(argc, argv, nvme_admin_nvme_mi_recv, desc);
+}
+
+static int nmi_send(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a NVMe-MI Send command to the specified device, return results.";
+
+ return nvme_mi(argc, argv, nvme_admin_nvme_mi_send, desc);
+}
+
+void register_extension(struct plugin *plugin)
+{
+ plugin->parent = &nvme;
+ nvme.extensions->tail->next = plugin;
+ nvme.extensions->tail = plugin;
+}
+
+int main(int argc, char **argv)
+{
+ int err;
+
+ nvme.extensions->parent = &nvme;
+ if (argc < 2) {
+ general_help(&builtin);
+ return 0;
+ }
+ setlocale(LC_ALL, "");
+
+ err = handle_plugin(argc - 1, &argv[1], nvme.extensions);
+ if (err == -ENOTTY)
+ general_help(&builtin);
+
+ return err ? 1 : 0;
+}
diff --git a/nvme.control.in b/nvme.control.in
new file mode 100644
index 0000000..74d36aa
--- /dev/null
+++ b/nvme.control.in
@@ -0,0 +1,9 @@
+Package: nvme
+Version: @VERSION@
+Section: base
+Priority: optional
+Architecture: amd64
+Depends: @DEPENDS@
+Maintainer: Keith Busch <kbusch@kernel.org>
+Description: NVM-Express Command Line Interface
+ The nvme management tool
diff --git a/nvme.h b/nvme.h
new file mode 100644
index 0000000..3915698
--- /dev/null
+++ b/nvme.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Definitions for the NVM Express interface
+ * Copyright (c) 2011-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+
+#ifndef _NVME_H
+#define _NVME_H
+
+#include <dirent.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <endian.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <libnvme-mi.h>
+
+#include "plugin.h"
+#include "util/json.h"
+#include "util/mem.h"
+#include "util/argconfig.h"
+#include "util/cleanup.h"
+
+enum nvme_print_flags {
+ NORMAL = 0,
+ VERBOSE = 1 << 0, /* verbosely decode complex values for humans */
+ JSON = 1 << 1, /* display in json format */
+ VS = 1 << 2, /* hex dump vendor specific data areas */
+ BINARY = 1 << 3, /* binary dump raw bytes */
+};
+
+enum nvme_cli_topo_ranking {
+ NVME_CLI_TOPO_NAMESPACE,
+ NVME_CLI_TOPO_CTRL,
+};
+
+#define SYS_NVME "/sys/class/nvme"
+
+enum nvme_dev_type {
+ NVME_DEV_DIRECT,
+ NVME_DEV_MI,
+};
+
+struct nvme_dev {
+ enum nvme_dev_type type;
+ union {
+ struct {
+ int fd;
+ struct stat stat;
+ } direct;
+ struct {
+ nvme_root_t root;
+ nvme_mi_ep_t ep;
+ nvme_mi_ctrl_t ctrl;
+ } mi;
+ };
+
+ const char *name;
+};
+
+#define dev_fd(d) __dev_fd(d, __func__, __LINE__)
+
+static inline int __dev_fd(struct nvme_dev *dev, const char *func, int line)
+{
+ if (dev->type != NVME_DEV_DIRECT) {
+ fprintf(stderr,
+ "warning: %s:%d not a direct transport!\n",
+ func, line);
+ return -1;
+ }
+ return dev->direct.fd;
+}
+
+static inline nvme_mi_ep_t dev_mi_ep(struct nvme_dev *dev)
+{
+ if (dev->type != NVME_DEV_MI) {
+ fprintf(stderr,
+ "warning: not a MI transport!\n");
+ return NULL;
+ }
+ return dev->mi.ep;
+}
+
+void register_extension(struct plugin *plugin);
+
+/*
+ * parse_and_open - parses arguments and opens the NVMe device, populating @dev
+ */
+int parse_and_open(struct nvme_dev **dev, int argc, char **argv, const char *desc,
+ struct argconfig_commandline_options *clo);
+
+void dev_close(struct nvme_dev *dev);
+
+static inline DEFINE_CLEANUP_FUNC(
+ cleanup_nvme_dev, struct nvme_dev *, dev_close)
+#define _cleanup_nvme_dev_ __cleanup__(cleanup_nvme_dev)
+
+extern const char *output_format;
+
+int validate_output_format(const char *format, enum nvme_print_flags *flags);
+bool nvme_is_output_format_json(void);
+int __id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin, void (*vs)(uint8_t *vs, struct json_object *root));
+
+extern int current_index;
+
+const char *nvme_strerror(int errnum);
+
+unsigned long long elapsed_utime(struct timeval start_time,
+ struct timeval end_time);
+
+/* nvme-print.c */
+const char *nvme_select_to_string(int sel);
+
+void d(unsigned char *buf, int len, int width, int group);
+void d_raw(unsigned char *buf, unsigned len);
+uint64_t int48_to_long(uint8_t *data);
+
+int map_log_level(int verbose, bool quiet);
+#endif /* _NVME_H */
diff --git a/nvme.spec.in b/nvme.spec.in
new file mode 100644
index 0000000..3eab9ff
--- /dev/null
+++ b/nvme.spec.in
@@ -0,0 +1,66 @@
+Name: nvme
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: Core nvme tools
+License: GPL-2.0-only
+Group: Development/Tools
+URL: https://github.com/linux-nvme/nvme-cli/
+Provides: nvme
+Requires(post): util-linux systemd systemd-udev
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+@REQUIRES@
+
+%description
+NVMe is a fast, scalable, direct attached storage interface. The nvme
+cli rpm installs core management tools with minimal dependencies.
+
+%install
+meson install --destdir %{buildroot} --skip-subprojects
+touch %{buildroot}@SYSCONFDIR@/nvme/hostnqn
+touch %{buildroot}@SYSCONFDIR@/nvme/hostid
+
+%files
+%defattr(-,root,root)
+@SBINDIR@/nvme
+@MANDIR@/man1/nvme*.1*
+@DATADIR@/bash-completion/completions/nvme
+@DATADIR@/zsh/site-functions/_nvme
+%dir @SYSCONFDIR@/nvme
+@SYSCONFDIR@/nvme/hostnqn
+@SYSCONFDIR@/nvme/hostid
+@SYSCONFDIR@/nvme/discovery.conf
+%ghost @SYSCONFDIR@/nvme/config.json
+@UDEVRULESDIR@/70-nvmf-autoconnect.rules
+@UDEVRULESDIR@/71-nvmf-netapp.rules
+@DRACUTRILESDIR@/70-nvmf-autoconnect.conf
+@SYSTEMDDIR@/nvmf-connect@.service
+@SYSTEMDDIR@/nvmefc-boot-connections.service
+@SYSTEMDDIR@/nvmf-connect.target
+@SYSTEMDDIR@/nvmf-autoconnect.service
+
+%clean
+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 $(@SBINDIR@/nvme gen-hostnqn) > @SYSCONFDIR@/nvme/hostnqn
+ fi
+ if [ ! -s @SYSCONFDIR@/nvme/hostid ]; then
+ uuidgen > @SYSCONFDIR@/nvme/hostid
+ fi
+
+ # apply udev and systemd changes that we did
+ systemctl daemon-reload
+ udevadm control --reload-rules && udevadm trigger
+fi
+
+%changelog
+* Tue Dec 17 2019 Simon Schricker <sschricker@suse.de>
+ - Add new udev rules to set iopolicy for NetApp devices
+
+* Mon Oct 15 2018 Eyal Ben-David <eyalbe@il.ibm.com> - 1.6.81.g899a-2
+- bash-completion check
+
+* Thu Oct 15 2015 Keith Busch <keith.busch@intel.com>
+- Initial RPM spec
diff --git a/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in b/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
new file mode 100644
index 0000000..ba96116
--- /dev/null
+++ b/nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
@@ -0,0 +1 @@
+install_items+=" @UDEVRULESDIR@/70-nvmf-autoconnect.rules "
diff --git a/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in
new file mode 100644
index 0000000..7036625
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Auto-connect to subsystems on FC-NVME devices found during boot
+ConditionPathExists=/sys/class/fc/fc_udev_device/nvme_discovery
+DefaultDependencies=no
+After=systemd-udevd.service
+Before=local-fs-pre.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "echo add > /sys/class/fc/fc_udev_device/nvme_discovery"
+
+[Install]
+WantedBy=default.target
diff --git a/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in b/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in
new file mode 100644
index 0000000..92960cd
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-autoconnect.service.in
@@ -0,0 +1,15 @@
+[Unit]
+Description=Connect NVMe-oF subsystems automatically during boot
+ConditionPathExists=|@SYSCONFDIR@/nvme/config.json
+ConditionPathExists=|@SYSCONFDIR@/nvme/discovery.conf
+Wants=modprobe@nvme_fabrics.service
+After=modprobe@nvme_fabrics.service
+After=network-online.target
+Before=remote-fs-pre.target
+
+[Service]
+Type=oneshot
+ExecStart=@SBINDIR@/nvme connect-all --context=autoconnect
+
+[Install]
+WantedBy=default.target
diff --git a/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in b/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in
new file mode 100644
index 0000000..820e6ce
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-connect-nbft.service.in
@@ -0,0 +1,14 @@
+# This unit is meant to be started by network management software
+# after a network interface defined in the NBFT gets set up
+[Unit]
+Description=Connect NBFT-defined NVMe-oF subsystems automatically
+ConditionPathExists=|/sys/firmware/acpi/tables/NBFT
+ConditionPathExists=|/sys/firmware/acpi/tables/NBFT1
+Wants=modprobe@nvme_fabrics.service
+After=modprobe@nvme_fabrics.service
+After=network-online.target
+Before=remote-fs-pre.target
+
+[Service]
+Type=oneshot
+ExecStart=@SBINDIR@/nvme connect-all --nbft
diff --git a/nvmf-autoconnect/systemd/nvmf-connect.target.in b/nvmf-autoconnect/systemd/nvmf-connect.target.in
new file mode 100644
index 0000000..f64a37c
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-connect.target.in
@@ -0,0 +1,2 @@
+[Unit]
+Description=All instances of nvmf-autoconnect daemon
diff --git a/nvmf-autoconnect/systemd/nvmf-connect@.service.in b/nvmf-autoconnect/systemd/nvmf-connect@.service.in
new file mode 100644
index 0000000..5ba7086
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-connect@.service.in
@@ -0,0 +1,16 @@
+#
+# Unit file used by 70-nvmf-autoconnect.rules.
+#
+
+[Unit]
+Description=NVMf auto-connect scan upon nvme discovery controller Events
+DefaultDependencies=no
+After=systemd-udevd.service
+Before=local-fs-pre.target
+PartOf=nvmf-connect.target
+Requires=nvmf-connect.target
+
+[Service]
+Type=simple
+Environment="CONNECT_ARGS=%i"
+ExecStart=/bin/sh -c "@SBINDIR@/nvme connect-all --context=autoconnect --quiet `/bin/echo -e '${CONNECT_ARGS}'`"
diff --git a/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in b/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in
new file mode 100644
index 0000000..344942b
--- /dev/null
+++ b/nvmf-autoconnect/udev-rules/65-persistent-net-nbft.rules.in
@@ -0,0 +1,2 @@
+# Avoid renaming nbft$X interfaces
+SUBSYSTEM=="net", ACTION!="remove", ENV{INTERFACE}=="nbft*", NAME:="%E{INTERFACE}"
diff --git a/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in
new file mode 100644
index 0000000..9235a5c
--- /dev/null
+++ b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules.in
@@ -0,0 +1,32 @@
+#
+# nvmf-autoconnect.rules:
+# Handles udev events which invoke automatically scan via discovery
+# controller and connect to elements in the discovery log.
+#
+#
+ACTION!="change", GOTO="autoconnect_end"
+
+# For backwards compatibility. Make sure HOST_IFACE is not an empty string.
+ENV{NVME_HOST_IFACE}=="", ENV{NVME_HOST_IFACE}="none"
+
+# Events from persistent discovery controllers or nvme-fc transport events
+# NVME_AEN:
+# type 0x2 (NOTICE) info 0xf0 (DISCOVERY_LOG_CHANGE) log-page-id 0x70 (DISCOVERY_LOG_PAGE)
+ACTION=="change", SUBSYSTEM=="nvme", ENV{NVME_AEN}=="0x70f002", \
+ ENV{NVME_TRTYPE}=="*", ENV{NVME_TRADDR}=="*", \
+ ENV{NVME_TRSVCID}=="*", ENV{NVME_HOST_TRADDR}=="*", ENV{NVME_HOST_IFACE}=="*", \
+ RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=$kernel\t--transport=$env{NVME_TRTYPE}\t--traddr=$env{NVME_TRADDR}\t--trsvcid=$env{NVME_TRSVCID}\t--host-traddr=$env{NVME_HOST_TRADDR}\t--host-iface=$env{NVME_HOST_IFACE}.service"
+
+# nvme-fc transport generated events (old-style for compatibility)
+ACTION=="change", SUBSYSTEM=="fc", ENV{FC_EVENT}=="nvmediscovery", \
+ ENV{NVMEFC_HOST_TRADDR}=="*", ENV{NVMEFC_TRADDR}=="*", \
+ RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=none\t--transport=fc\t--traddr=$env{NVMEFC_TRADDR}\t--trsvcid=none\t--host-traddr=$env{NVMEFC_HOST_TRADDR}.service"
+
+# A discovery controller just (re)connected, re-read the discovery log change to
+# check if there were any changes since it was last connected.
+ACTION=="change", SUBSYSTEM=="nvme", ENV{NVME_EVENT}=="rediscover", ATTR{cntrltype}=="discovery", \
+ ENV{NVME_TRTYPE}=="*", ENV{NVME_TRADDR}=="*", \
+ ENV{NVME_TRSVCID}=="*", ENV{NVME_HOST_TRADDR}=="*", ENV{NVME_HOST_IFACE}=="*", \
+ RUN+="@SYSTEMCTL@ --no-block restart nvmf-connect@--device=$kernel\t--transport=$env{NVME_TRTYPE}\t--traddr=$env{NVME_TRADDR}\t--trsvcid=$env{NVME_TRSVCID}\t--host-traddr=$env{NVME_HOST_TRADDR}\t--host-iface=$env{NVME_HOST_IFACE}.service"
+
+LABEL="autoconnect_end"
diff --git a/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in b/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in
new file mode 100644
index 0000000..99b6a8b
--- /dev/null
+++ b/nvmf-autoconnect/udev-rules/71-nvmf-netapp.rules.in
@@ -0,0 +1,6 @@
+# Enable round-robin for NetApp ONTAP and NetApp E-Series
+ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp ONTAP Controller", ATTR{iopolicy}="round-robin"
+ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{subsystype}=="nvm", ATTR{model}=="NetApp E-Series", ATTR{iopolicy}="round-robin"
+
+# Set ctrl_loss_tmo to -1 for NetApp ONTAP NVMe/TCP
+ACTION!="remove", SUBSYSTEM=="nvme", KERNEL=="nvme*", ATTR{transport}=="tcp", ATTR{model}=="NetApp ONTAP Controller", ATTR{ctrl_loss_tmo}="-1"
diff --git a/plugin.c b/plugin.c
new file mode 100644
index 0000000..a5cb4f9
--- /dev/null
+++ b/plugin.c
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "plugin.h"
+#include "util/argconfig.h"
+
+#include <libnvme.h>
+
+static int version_cmd(struct plugin *plugin)
+{
+ struct program *prog = plugin->parent;
+
+ if (plugin->name) {
+ printf("%s %s version %s (git %s)\n",
+ prog->name, plugin->name, plugin->version, GIT_VERSION);
+ } else {
+ printf("%s version %s (git %s)\n",
+ prog->name, prog->version, GIT_VERSION);
+ }
+ printf("libnvme version %s (git %s)\n",
+ nvme_get_version(NVME_VERSION_PROJECT),
+ nvme_get_version(NVME_VERSION_GIT));
+ return 0;
+}
+
+static int help(int argc, char **argv, struct plugin *plugin)
+{
+ char man[0x100];
+ struct program *prog = plugin->parent;
+ char *str = argv[1];
+ int i;
+
+ if (argc == 1) {
+ general_help(plugin);
+ return 0;
+ }
+
+ for (i = 0; plugin->commands[i]; i++) {
+ struct command *cmd = plugin->commands[i];
+
+ if (strcmp(str, cmd->name))
+ if (!cmd->alias || (cmd->alias && strcmp(str, cmd->alias)))
+ continue;
+
+ if (plugin->name)
+ sprintf(man, "%s-%s-%s", prog->name, plugin->name, cmd->name);
+ else
+ sprintf(man, "%s-%s", prog->name, cmd->name);
+ if (execlp("man", "man", man, (char *)NULL))
+ perror(argv[1]);
+ }
+ return 0;
+}
+
+static void usage_cmd(struct plugin *plugin)
+{
+ struct program *prog = plugin->parent;
+
+ if (plugin->name)
+ printf("usage: %s %s %s\n", prog->name, plugin->name, prog->usage);
+ else
+ printf("usage: %s %s\n", prog->name, prog->usage);
+}
+
+void general_help(struct plugin *plugin)
+{
+ struct program *prog = plugin->parent;
+ struct plugin *extension;
+ unsigned int i = 0;
+ unsigned int padding = 15;
+ unsigned int curr_length = 0;
+
+ printf("%s-%s\n", prog->name, prog->version);
+
+ usage_cmd(plugin);
+
+ printf("\n");
+ print_word_wrapped(prog->desc, 0, 0, stdout);
+ printf("\n");
+
+ if (plugin->desc) {
+ printf("\n");
+ print_word_wrapped(plugin->desc, 0, 0, stdout);
+ printf("\n");
+ }
+
+ printf("\nThe following are all implemented sub-commands:\n");
+
+ /*
+ * iterate through all commands to get maximum length
+ * Still need to handle the case of ultra long strings, help messages, etc
+ */
+ for (; plugin->commands[i]; i++) {
+ curr_length = 2 + strlen(plugin->commands[i]->name);
+ if (padding < curr_length)
+ padding = curr_length;
+ }
+
+ i = 0;
+ for (; plugin->commands[i]; i++)
+ printf(" %-*s %s\n", padding, plugin->commands[i]->name,
+ plugin->commands[i]->help);
+
+ printf(" %-*s %s\n", padding, "version", "Shows the program version");
+ printf(" %-*s %s\n", padding, "help", "Display this help");
+ printf("\n");
+
+ if (plugin->name)
+ printf("See '%s %s help <command>' for more information on a specific command\n",
+ prog->name, plugin->name);
+ else
+ printf("See '%s help <command>' for more information on a specific command\n",
+ prog->name);
+
+ /*
+ * The first plugin is the built-in. If we're not showing help for the
+ * built-in, don't show the program's other extensions
+ */
+ if (plugin->name)
+ return;
+
+ extension = prog->extensions->next;
+ if (!extension)
+ return;
+
+ printf("\nThe following are all installed plugin extensions:\n");
+ while (extension) {
+ printf(" %-*s %s\n", 15, extension->name, extension->desc);
+ extension = extension->next;
+ }
+ printf("\nSee '%s <plugin> help' for more information on a plugin\n",
+ prog->name);
+}
+
+int handle_plugin(int argc, char **argv, struct plugin *plugin)
+{
+ char *str = argv[0];
+ char use[0x100];
+ struct plugin *extension;
+ struct program *prog = plugin->parent;
+ struct command **cmd = plugin->commands;
+ struct command *cr = NULL;
+ bool cr_valid = false;
+
+ if (!argc) {
+ general_help(plugin);
+ return 0;
+ }
+
+ if (!plugin->name)
+ sprintf(use, "%s %s <device> [OPTIONS]", prog->name, str);
+ else
+ sprintf(use, "%s %s %s <device> [OPTIONS]", prog->name, plugin->name, str);
+ argconfig_append_usage(use);
+
+ /* translate --help and --version into commands */
+ while (*str == '-')
+ str++;
+
+ if (!strcmp(str, "help"))
+ return help(argc, argv, plugin);
+ if (!strcmp(str, "version"))
+ return version_cmd(plugin);
+
+ while (*cmd) {
+ if (!strcmp(str, (*cmd)->name) ||
+ ((*cmd)->alias && !strcmp(str, (*cmd)->alias)))
+ return (*cmd)->fn(argc, argv, *cmd, plugin);
+ if (!strncmp(str, (*cmd)->name, strlen(str))) {
+ if (cr) {
+ cr_valid = false;
+ } else {
+ cr = *cmd;
+ cr_valid = true;
+ }
+ }
+ cmd++;
+ }
+
+ if (cr && cr_valid) {
+ sprintf(use, "%s %s <device> [OPTIONS]", prog->name, cr->name);
+ argconfig_append_usage(use);
+ return cr->fn(argc, argv, cr, plugin);
+ }
+
+ /* Check extensions only if this is running the built-in plugin */
+ if (plugin->name) {
+ printf("ERROR: Invalid sub-command '%s' for plugin %s\n", str, plugin->name);
+ return -ENOTTY;
+ }
+
+ extension = plugin->next;
+ while (extension) {
+ if (!strcmp(str, extension->name))
+ return handle_plugin(argc - 1, &argv[1], extension);
+ extension = extension->next;
+ }
+
+ /*
+ * If the command is executed with the extension name and
+ * command together ("plugin-command"), run the plug in
+ */
+ extension = plugin->next;
+ while (extension) {
+ if (!strncmp(str, extension->name, strlen(extension->name))) {
+ argv[0] += strlen(extension->name);
+ while (*argv[0] == '-')
+ argv[0]++;
+ return handle_plugin(argc, &argv[0], extension);
+ }
+ extension = extension->next;
+ }
+ printf("ERROR: Invalid sub-command '%s'\n", str);
+ return -ENOTTY;
+}
diff --git a/plugin.h b/plugin.h
new file mode 100644
index 0000000..03bd95a
--- /dev/null
+++ b/plugin.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef PLUGIN_H
+#define PLUGIN_H
+
+#include <stdbool.h>
+
+struct program {
+ const char *name;
+ const char *version;
+ const char *usage;
+ const char *desc;
+ const char *more;
+ struct command **commands;
+ struct plugin *extensions;
+};
+
+struct plugin {
+ const char *name;
+ const char *desc;
+ const char *version;
+ struct command **commands;
+ struct program *parent;
+ struct plugin *next;
+ struct plugin *tail;
+};
+
+struct command {
+ char *name;
+ char *help;
+ int (*fn)(int argc, char **argv, struct command *command, struct plugin *plugin);
+ char *alias;
+};
+
+void general_help(struct plugin *plugin);
+int handle_plugin(int argc, char **argv, struct plugin *plugin);
+
+#endif
diff --git a/plugins/amzn/amzn-nvme.c b/plugins/amzn/amzn-nvme.c
new file mode 100644
index 0000000..d359cc3
--- /dev/null
+++ b/plugins/amzn/amzn-nvme.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.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..f6c4f8b
--- /dev/null
+++ b/plugins/amzn/amzn-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/dell/dell-nvme.c b/plugins/dell/dell-nvme.c
new file mode 100644
index 0000000..8ed10e7
--- /dev/null
+++ b/plugins/dell/dell-nvme.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+// Copyright © 2022 Dell Inc. or its subsidiaries. All Rights Reserved.
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+
+#define CREATE_CMD
+#include "dell-nvme.h"
+
+#define ARRAY_NAME_LEN 80
+
+struct nvme_vu_id_ctrl_field {
+ __u16 dell_mjr;
+ __u16 dell_mnr;
+ __u16 dell_ter;
+ __u8 reserved0[1018];
+};
+
+static void dell_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
+ char array_ver[16] = { 0 };
+ char array_name[ARRAY_NAME_LEN + 1] = {0};
+
+ snprintf(array_ver, sizeof(array_ver), "0x%04x%04x%04x",
+ le16_to_cpu(id->dell_mjr),
+ le16_to_cpu(id->dell_mnr),
+ le16_to_cpu(id->dell_ter));
+
+ memcpy(array_name, vs + sizeof(array_ver), ARRAY_NAME_LEN);
+
+ if (root) {
+ json_object_add_value_string(root, "array_name", strlen(array_name) > 1 ? array_name : "NULL");
+ json_object_add_value_string(root, "array_ver", array_ver);
+ return;
+ }
+
+ printf("array_name : %s\n", strlen(array_name) > 1 ? array_name : "NULL");
+ printf("array_ver : %s\n", array_ver);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, dell_id_ctrl);
+}
diff --git a/plugins/dell/dell-nvme.h b/plugins/dell/dell-nvme.h
new file mode 100644
index 0000000..aaf0de1
--- /dev/null
+++ b/plugins/dell/dell-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/dell/dell-nvme
+
+#if !defined(DELL_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define DELL_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("dell", "DELL vendor specific extensions", NVME_VERSION),
+ 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
new file mode 100644
index 0000000..ca4b53d
--- /dev/null
+++ b/plugins/dera/dera-nvme.c
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "dera-nvme.h"
+
+static int char4_to_int(__u8 *data)
+{
+ int i;
+ int result = 0;
+
+ for (i = 0; i < 4; i++) {
+ result = result << 8;
+ result += data[3 - i];
+ }
+ return result;
+}
+
+struct nvme_dera_smart_info_log
+{
+ __u8 quick_rebuild_cnt0[4];
+ __u8 quick_rebuild_cnt1[4];
+ __u8 full_rebuild_cnt0[4];
+ __u8 full_rebuild_cnt1[4];
+ __u8 raw_rebuild_cnt0[4];
+ __u8 raw_rebuild_cnt1[4];
+ __u8 cap_aged;
+ __u8 cap_aged_ratio;
+ __u8 cap_status;
+ __u8 cap_voltage[4];
+ __u8 cap_charge_ctrl_en;
+ __u8 cap_charge_ctrl_val[2];
+ __u8 cap_charge_max_thr[2];
+ __u8 cap_charge_min_thr[2];
+ __u8 dev_status;
+ __u8 dev_status_up;
+ __u8 nand_erase_err_cnt[4];
+ __u8 nand_program_err_cnt[4];
+ __u8 ddra_1bit_err[2];
+ __u8 ddra_2bit_err[2];
+ __u8 ddrb_1bit_err[2];
+ __u8 ddrb_2bit_err[2];
+ __u8 ddr_err_bit;
+ __u8 pcie_corr_err[2];
+ __u8 pcie_uncorr_err[2];
+ __u8 pcie_fatal_err[2];
+ __u8 pcie_err_bit;
+ __u8 power_level;
+ __u8 current_power[2];
+ __u8 nand_init_fail[2];
+ __u8 fw_loader_version[8];
+ __u8 uefi_driver_version[8];
+ __u8 gpio0_err[2];
+ __u8 gpio5_err[2];
+ __u8 gpio_err_bit[2];
+ __u8 rebuild_percent;
+ __u8 pcie_volt_status;
+ __u8 current_pcie_volt[2];
+ __u8 init_pcie_volt_thr[2];
+ __u8 rt_pcie_volt_thr[2];
+ __u8 init_pcie_volt_low[2];
+ __u8 rt_pcie_volt_low[2];
+ __u8 temp_sensor_abnormal[2];
+ __u8 nand_read_retry_fail_cnt[4];
+ __u8 fw_slot_version[8];
+ __u8 rsved[395];
+};
+
+enum dera_device_status
+{
+ DEVICE_STATUS_READY = 0x00,
+ DEVICE_STATUS_QUICK_REBUILDING = 0x01,
+ DEVICE_STATUS_FULL_REBUILDING = 0x02,
+ DEVICE_STATUS_RAW_REBUILDING = 0x03,
+ DEVICE_STATUS_CARD_READ_ONLY = 0x04,
+ DEVICE_STATUS_FATAL_ERROR = 0x05,
+ DEVICE_STATUS_BUSY = 0x06,
+ DEVICE_STAUTS_LOW_LEVEL_FORMAT = 0x07,
+ DEVICE_STAUTS_FW_COMMITING = 0x08,
+ DEVICE_STAUTS__OVER_TEMPRATURE = 0x09,
+};
+
+static int nvme_dera_get_device_status(int fd, enum dera_device_status *result)
+{
+ int err = 0;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = 0xc0,
+ .addr = (__u64)(uintptr_t)NULL,
+ .data_len = 0,
+ .cdw10 = 0,
+ .cdw12 = 0x104,
+ };
+
+ err = nvme_submit_admin_passthru(fd, &cmd, NULL);
+ if (!err && result)
+ *result = cmd.result;
+
+ return err;
+}
+
+static int get_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_dera_smart_info_log log;
+ enum dera_device_status state = DEVICE_STATUS_FATAL_ERROR;
+ char *desc = "Get the Dera device status";
+ struct nvme_dev *dev;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xc0, sizeof(log), &log);
+ if (err)
+ goto exit;
+
+ static const char *dev_status[] = {
+ "Normal",
+ "Quick Rebuilding",
+ "Full Rebuilding",
+ "Raw Rebuilding",
+ "Card Read Only",
+ "Fatal Error",
+ "Busy",
+ "Low Level Format",
+ "Firmware Committing",
+ "Over Temperature" };
+
+ static const char *volt_status[] = {
+ "Normal",
+ "Initial Low",
+ "Runtime Low",
+ };
+
+ err = nvme_dera_get_device_status(dev_fd(dev), &state);
+ if (!err) {
+ if (state > 0 && state < 4)
+ printf("device_status : %s %d%% completed\n", dev_status[state], log.rebuild_percent);
+ else
+ printf("device_status : %s\n", dev_status[state]);
+ } else {
+ goto exit;
+ }
+
+ printf("dev_status_up : %s\n", dev_status[log.dev_status_up]);
+ printf("cap_aged : %s\n", log.cap_aged == 1 ? "True" : "False");
+ printf("cap_aged_ratio : %d%%\n", log.cap_aged_ratio < 100 ? log.cap_aged_ratio : 100);
+ printf("cap_status : %s\n", log.cap_status == 0 ? "Normal" : (log.cap_status == 1 ? "Warning" : "Critical"));
+ printf("cap_voltage : %d mV\n", char4_to_int(log.cap_voltage));
+ printf("nand_erase_err_cnt : %d\n", char4_to_int(log.nand_erase_err_cnt));
+ printf("nand_program_err_cnt : %d\n", char4_to_int(log.nand_program_err_cnt));
+ printf("ddra_1bit_err : %d\n", log.ddra_1bit_err[1] << 8 | log.ddra_1bit_err[0]);
+ printf("ddra_2bit_err : %d\n", log.ddra_2bit_err[1] << 8 | log.ddra_2bit_err[0]);
+ printf("ddrb_1bit_err : %d\n", log.ddrb_1bit_err[1] << 8 | log.ddrb_1bit_err[0]);
+ printf("ddrb_2bit_err : %d\n", log.ddrb_2bit_err[1] << 8 | log.ddrb_2bit_err[0]);
+ printf("ddr_err_bit : %d\n", log.ddr_err_bit);
+ printf("pcie_corr_err : %d\n", log.pcie_corr_err[1] << 8 | log.pcie_corr_err[0]);
+ printf("pcie_uncorr_err : %d\n", log.pcie_uncorr_err[1] << 8 | log.pcie_uncorr_err[0]);
+ printf("pcie_fatal_err : %d\n", log.pcie_fatal_err[1] << 8 | log.pcie_fatal_err[0]);
+ printf("power_level : %d W\n", log.power_level);
+ printf("current_power : %d mW\n", log.current_power[1] << 8 | log.current_power[0]);
+ printf("nand_init_fail : %d\n", log.nand_init_fail[1] << 8 | log.nand_init_fail[0]);
+ printf("fw_loader_version : %.*s\n", 8, log.fw_loader_version);
+ printf("uefi_driver_version : %.*s\n", 8, log.uefi_driver_version);
+
+ if (log.pcie_volt_status < sizeof(volt_status) / sizeof(const char *))
+ printf("pcie_volt_status : %s\n", volt_status[log.pcie_volt_status]);
+ else
+ printf("pcie_volt_status : Unknown\n");
+
+ printf("current_pcie_volt : %d mV\n", log.current_pcie_volt[1] << 8 | log.current_pcie_volt[0]);
+ printf("init_pcie_volt_low_cnt : %d\n", log.init_pcie_volt_low[1] << 8 | log.init_pcie_volt_low[0]);
+ printf("rt_pcie_volt_low_cnt : %d\n", log.rt_pcie_volt_low[1] << 8 | log.rt_pcie_volt_low[0]);
+ printf("temp_sensor_abnormal_cnt : %d\n", log.temp_sensor_abnormal[1] << 8 | log.temp_sensor_abnormal[0]);
+ printf("nand_read_retry_fail_cnt : %d\n", char4_to_int(log.nand_read_retry_fail_cnt));
+ printf("fw_slot_version : %.*s\n", 8, log.fw_slot_version);
+
+exit:
+ if (err > 0)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
diff --git a/plugins/dera/dera-nvme.h b/plugins/dera/dera-nvme.h
new file mode 100644
index 0000000..a5bb0ae
--- /dev/null
+++ b/plugins/dera/dera-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/dera/dera-nvme
+
+#if !defined(DERA_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define DERA_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("dera", "Dera vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Dera SMART Log, show it", get_status, "stat")
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/fdp/fdp.c b/plugins/fdp/fdp.c
new file mode 100644
index 0000000..2a221f8
--- /dev/null
+++ b/plugins/fdp/fdp.c
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#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 "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "fdp.h"
+
+static int fdp_configs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Get Flexible Data Placement Configurations";
+ const char *egid = "Endurance group identifier";
+ const char *human_readable = "show log in readable format";
+ const char *raw = "use binary output";
+
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ struct nvme_fdp_config_log hdr;
+ void *log = NULL;
+ int err;
+
+ struct config {
+ __u16 egid;
+ char *output_format;
+ bool human_readable;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .egid = 0,
+ .output_format = "normal",
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (flags < 0)
+ goto out;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.egid) {
+ fprintf(stderr, "endurance group identifier required\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
+ sizeof(hdr), &hdr);
+ if (err) {
+ nvme_show_status(errno);
+ goto out;
+ }
+
+ log = malloc(hdr.size);
+ if (!log) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = nvme_get_log_fdp_configurations(dev->direct.fd, cfg.egid, 0,
+ hdr.size, log);
+ if (err) {
+ nvme_show_status(errno);
+ goto out;
+ }
+
+ nvme_show_fdp_configs(log, hdr.size, flags);
+
+out:
+ dev_close(dev);
+ free(log);
+
+ return err;
+}
+
+static int fdp_usage(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Flexible Data Placement Reclaim Unit Handle Usage";
+ const char *egid = "Endurance group identifier";
+ const char *raw = "use binary output";
+
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ struct nvme_fdp_ruhu_log hdr;
+ size_t len;
+ void *log = NULL;
+ int err;
+
+ struct config {
+ __u16 egid;
+ char *output_format;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .egid = 0,
+ .output_format = "normal",
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (flags < 0)
+ goto out;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
+ 0, sizeof(hdr), &hdr);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ len = sizeof(hdr) + le16_to_cpu(hdr.nruh) * sizeof(struct nvme_fdp_ruhu_desc);
+ log = malloc(len);
+ if (!log) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = nvme_get_log_reclaim_unit_handle_usage(dev->direct.fd, cfg.egid,
+ 0, len, log);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ nvme_show_fdp_usage(log, len, flags);
+
+out:
+ dev_close(dev);
+ free(log);
+
+ return err;
+}
+
+static int fdp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Flexible Data Placement Statistics";
+ const char *egid = "Endurance group identifier";
+ const char *raw = "use binary output";
+
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ struct nvme_fdp_stats_log stats;
+ int err;
+
+ struct config {
+ __u16 egid;
+ char *output_format;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .egid = 0,
+ .output_format = "normal",
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (flags < 0)
+ goto out;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ memset(&stats, 0x0, sizeof(stats));
+
+ err = nvme_get_log_fdp_stats(dev->direct.fd, cfg.egid, 0, sizeof(stats), &stats);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ nvme_show_fdp_stats(&stats, flags);
+
+out:
+ dev_close(dev);
+
+ return err;
+}
+
+static int fdp_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Flexible Data Placement Events";
+ const char *egid = "Endurance group identifier";
+ const char *host_events = "Get host events";
+ const char *raw = "use binary output";
+
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ struct nvme_fdp_events_log events;
+ int err;
+
+ struct config {
+ __u16 egid;
+ bool host_events;
+ char *output_format;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .egid = 0,
+ .host_events = false,
+ .output_format = "normal",
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("endgrp-id", 'e', &cfg.egid, egid),
+ OPT_FLAG("host-events", 'E', &cfg.host_events, host_events),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (flags < 0)
+ goto out;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ memset(&events, 0x0, sizeof(events));
+
+ err = nvme_get_log_fdp_events(dev->direct.fd, cfg.egid,
+ cfg.host_events, 0, sizeof(events), &events);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ nvme_show_fdp_events(&events, flags);
+
+out:
+ dev_close(dev);
+
+ return err;
+}
+
+static int fdp_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Reclaim Unit Handle Status";
+ const char *namespace_id = "Namespace identifier";
+ const char *raw = "use binary output";
+
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ struct nvme_fdp_ruh_status hdr;
+ size_t len;
+ void *buf = NULL;
+ int err = -1;
+
+ struct config {
+ __u32 namespace_id;
+ char *output_format;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .raw_binary = false,
+ };
+
+ 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("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (flags < 0)
+ goto out;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto out;
+ }
+ }
+
+ err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
+ cfg.namespace_id, sizeof(hdr), &hdr);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ len = sizeof(struct nvme_fdp_ruh_status) +
+ le16_to_cpu(hdr.nruhsd) * sizeof(struct nvme_fdp_ruh_status_desc);
+ buf = malloc(len);
+ if (!buf) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = nvme_fdp_reclaim_unit_handle_status(dev_fd(dev),
+ cfg.namespace_id, len, buf);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ nvme_show_fdp_ruh_status(buf, len, flags);
+
+out:
+ free(buf);
+ dev_close(dev);
+
+ return err;
+}
+
+static int fdp_update(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Reclaim Unit Handle Update";
+ const char *namespace_id = "Namespace identifier";
+ const char *_pids = "Comma-separated list of placement identifiers to update";
+
+ struct nvme_dev *dev;
+ unsigned short pids[256];
+ __u16 buf[256];
+ int npids;
+ int err = -1;
+
+ struct config {
+ __u32 namespace_id;
+ char *pids;
+ };
+
+ struct config cfg = {
+ .pids = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LIST("pids", 'p', &cfg.pids, _pids),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ npids = argconfig_parse_comma_sep_array_short(cfg.pids, pids, ARRAY_SIZE(pids));
+ if (npids < 0) {
+ perror("could not parse pids");
+ err = -EINVAL;
+ goto out;
+ } else if (npids == 0) {
+ fprintf(stderr, "no placement identifiers set\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto out;
+ }
+ }
+
+ for (unsigned int i = 0; i < npids; i++)
+ buf[i] = cpu_to_le16(pids[i]);
+
+ err = nvme_fdp_reclaim_unit_handle_update(dev_fd(dev), cfg.namespace_id, npids, buf);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ printf("update: Success\n");
+
+out:
+ dev_close(dev);
+
+ return err;
+}
+
+static int fdp_set_events(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Enable or disable FDP events";
+ const char *namespace_id = "Namespace identifier";
+ const char *enable = "Enable/disable event";
+ const char *event_types = "Comma-separated list of event types";
+ const char *ph = "Placement Handle";
+ const char *save = "specifies that the controller shall save the attribute";
+
+ struct nvme_dev *dev;
+ int err = -1;
+ unsigned short evts[255];
+ int nev;
+ __u8 buf[255];
+
+ struct config {
+ __u32 namespace_id;
+ __u16 ph;
+ char *event_types;
+ bool enable;
+ bool save;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SHRT("placement-handle", 'p', &cfg.ph, ph),
+ OPT_FLAG("enable", 'e', &cfg.enable, enable),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_LIST("event-types", 't', &cfg.event_types, event_types),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ nev = argconfig_parse_comma_sep_array_short(cfg.event_types, evts, ARRAY_SIZE(evts));
+ if (nev < 0) {
+ perror("could not parse event types");
+ err = -EINVAL;
+ goto out;
+ } else if (nev == 0) {
+ fprintf(stderr, "no event types set\n");
+ err = -EINVAL;
+ goto out;
+ } else if (nev > 255) {
+ fprintf(stderr, "too many event types (max 255)\n");
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ if (errno != ENOTTY) {
+ fprintf(stderr, "get-namespace-id: %s\n", nvme_strerror(errno));
+ goto out;
+ }
+
+ cfg.namespace_id = NVME_NSID_ALL;
+ }
+ }
+
+ for (unsigned int i = 0; i < nev; i++)
+ buf[i] = (__u8)evts[i];
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = NVME_FEAT_FID_FDP_EVENTS,
+ .save = cfg.save,
+ .nsid = cfg.namespace_id,
+ .cdw11 = (nev << 16) | cfg.ph,
+ .cdw12 = cfg.enable ? 0x1 : 0x0,
+ .data_len = sizeof(buf),
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ err = nvme_set_features(&args);
+ if (err) {
+ nvme_show_status(err);
+ goto out;
+ }
+
+ printf("set-events: Success\n");
+
+out:
+ dev_close(dev);
+
+ return err;
+}
diff --git a/plugins/fdp/fdp.h b/plugins/fdp/fdp.h
new file mode 100644
index 0000000..f162b32
--- /dev/null
+++ b/plugins/fdp/fdp.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/fdp/fdp
+
+#if !defined(FDP_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define FDP_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("fdp", "Manage Flexible Data Placement enabled devices", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("configs", "List configurations", fdp_configs)
+ ENTRY("usage", "Show reclaim unit handle usage", fdp_usage)
+ ENTRY("stats", "Show statistics", fdp_stats)
+ ENTRY("events", "List events affecting reclaim units and media usage", fdp_events)
+ ENTRY("status", "Show reclaim unit handle status", fdp_status)
+ ENTRY("update", "Update a reclaim unit handle", fdp_update)
+ ENTRY("set-events", "Enabled or disable events", fdp_set_events)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/huawei/huawei-nvme.c b/plugins/huawei/huawei-nvme.c
new file mode 100644
index 0000000..0272dea
--- /dev/null
+++ b/plugins/huawei/huawei-nvme.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2019 Huawei Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * Author: Zou Ming<zouming.zouming@huawei.com>,
+ * Yang Feng <philip.yang@huawei.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+
+#include "util/suffix.h"
+
+#define CREATE_CMD
+#include "huawei-nvme.h"
+
+#define HW_SSD_PCI_VENDOR_ID 0x19E5
+#define ARRAY_NAME_LEN 80
+#define NS_NAME_LEN 40
+
+#define MIN_ARRAY_NAME_LEN 16
+#define MIN_NS_NAME_LEN 16
+
+struct huawei_list_item {
+ char node[1024];
+ struct nvme_id_ctrl ctrl;
+ unsigned int nsid;
+ struct nvme_id_ns ns;
+ unsigned int block;
+ char ns_name[NS_NAME_LEN];
+ char array_name[ARRAY_NAME_LEN];
+ bool huawei_device;
+};
+
+struct huawei_list_element_len {
+ unsigned int node;
+ unsigned int ns_name;
+ unsigned int nguid;
+ unsigned int ns_id;
+ unsigned int usage;
+ unsigned int array_name;
+};
+
+static int huawei_get_nvme_info(int fd, struct huawei_list_item *item, const char *node)
+{
+ int err;
+ int len;
+ struct stat nvme_stat_info;
+
+ memset(item, 0, sizeof(*item));
+
+ err = nvme_identify_ctrl(fd, &item->ctrl);
+ if (err)
+ return err;
+
+ /*identify huawei device*/
+ if (strstr(item->ctrl.mn, "Huawei") == NULL &&
+ le16_to_cpu(item->ctrl.vid) != HW_SSD_PCI_VENDOR_ID) {
+ item->huawei_device = false;
+ return 0;
+ }
+
+ item->huawei_device = true;
+ err = nvme_get_nsid(fd, &item->nsid);
+ err = nvme_identify_ns(fd, item->nsid, &item->ns);
+ if (err)
+ return err;
+
+ err = fstat(fd, &nvme_stat_info);
+ if (err < 0)
+ return err;
+
+ strncpy(item->node, node, sizeof(item->node));
+ item->node[sizeof(item->node) - 1] = '\0';
+ item->block = S_ISBLK(nvme_stat_info.st_mode);
+
+ if (item->ns.vs[0] == 0) {
+ len = snprintf(item->ns_name, NS_NAME_LEN, "%s", "----");
+ if (len < 0)
+ return -EINVAL;
+ } else {
+ memcpy(item->ns_name, item->ns.vs, NS_NAME_LEN);
+ item->ns_name[NS_NAME_LEN - 1] = '\0';
+ }
+
+ if (item->ctrl.vs[0] == 0) {
+ len = snprintf(item->array_name, ARRAY_NAME_LEN, "%s", "----");
+ if (len < 0)
+ return -EINVAL;
+ } else {
+ memcpy(item->array_name, item->ctrl.vs, ARRAY_NAME_LEN);
+ item->array_name[ARRAY_NAME_LEN - 1] = '\0';
+ }
+ return 0;
+}
+
+static void format(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--;
+ }
+}
+
+static void huawei_json_print_list_items(struct huawei_list_item *list_items,
+ unsigned int len)
+{
+ struct json_object *root;
+ struct json_object *devices;
+ struct json_object *device_attrs;
+ char formatter[128] = { 0 };
+ int index, i = 0;
+
+ root = json_create_object();
+ devices = json_create_array();
+ for (i = 0; i < len; i++) {
+ device_attrs = json_create_object();
+
+ json_object_add_value_string(device_attrs,
+ "DevicePath",
+ list_items[i].node);
+
+ if (sscanf(list_items[i].node, "/dev/nvme%d", &index) == 1)
+ json_object_add_value_int(device_attrs,
+ "Index",
+ index);
+
+ format(formatter, sizeof(formatter),
+ list_items[i].ns_name,
+ sizeof(list_items[i].ns_name));
+
+ json_object_add_value_string(device_attrs,
+ "NS Name",
+ formatter);
+
+ format(formatter, sizeof(formatter),
+ list_items[i].array_name,
+ sizeof(list_items[i].array_name));
+
+ json_object_add_value_string(device_attrs,
+ "Array Name",
+ formatter);
+
+ json_array_add_value_object(devices, device_attrs);
+ }
+ json_object_add_value_array(root, "Devices", devices);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void huawei_print_list_head(struct huawei_list_element_len element_len)
+{
+ char dash[128];
+ int i;
+
+ for (i = 0; i < 128; i++)
+ dash[i] = '-';
+ dash[127] = '\0';
+
+ printf("%-*.*s %-*.*s %-*.*s %-*.*s %-*.*s %-*.*s\n",
+ element_len.node, element_len.node, "Node",
+ element_len.ns_name, element_len.ns_name, "NS Name",
+ element_len.nguid, element_len.nguid, "Nguid",
+ element_len.ns_id, element_len.ns_id, "NS ID",
+ element_len.usage, element_len.usage, "Usage",
+ element_len.array_name, element_len.array_name, "Array Name");
+
+ printf("%-.*s %-.*s %-.*s %-.*s %-.*s %-.*s\n",
+ element_len.node, dash, element_len.ns_name, dash,
+ element_len.nguid, dash, element_len.ns_id, dash,
+ element_len.usage, dash, element_len.array_name, dash);
+}
+
+static void huawei_print_list_item(struct huawei_list_item *list_item,
+ struct huawei_list_element_len element_len)
+{
+ __u8 lba_index;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(list_item->ns.flbas, &lba_index);
+ unsigned long long lba = 1ULL << list_item->ns.lbaf[lba_index].ds;
+ double nsze = le64_to_cpu(list_item->ns.nsze) * lba;
+ double nuse = le64_to_cpu(list_item->ns.nuse) * lba;
+
+ const char *s_suffix = suffix_si_get(&nsze);
+ const char *u_suffix = suffix_si_get(&nuse);
+
+ char usage[128];
+ char nguid_buf[2 * sizeof(list_item->ns.nguid) + 1];
+ char *nguid = nguid_buf;
+ int i;
+
+ sprintf(usage, "%6.2f %2sB / %6.2f %2sB", nuse, u_suffix, nsze, s_suffix);
+
+ memset(nguid, 0, sizeof(nguid_buf));
+ for (i = 0; i < sizeof(list_item->ns.nguid); i++)
+ nguid += sprintf(nguid, "%02x", list_item->ns.nguid[i]);
+
+ printf("%-*.*s %-*.*s %-*.*s %-*d %-*.*s %-*.*s\n",
+ element_len.node, element_len.node, list_item->node,
+ element_len.ns_name, element_len.ns_name, list_item->ns_name,
+ element_len.nguid, element_len.nguid, nguid_buf,
+ element_len.ns_id, list_item->nsid,
+ element_len.usage, element_len.usage, usage,
+ element_len.array_name, element_len.array_name,
+ list_item->array_name);
+
+}
+
+static unsigned int choose_len(unsigned int old_len, unsigned int cur_len, unsigned int default_len)
+{
+ unsigned int temp_len;
+
+ temp_len = (cur_len > default_len) ? cur_len : default_len;
+ if (temp_len > old_len)
+ return temp_len;
+ return old_len;
+}
+
+static unsigned int huawei_get_ns_len(struct huawei_list_item *list_items, unsigned int len,
+ unsigned int default_len)
+{
+ int i;
+ unsigned int min_len = default_len;
+
+ for (i = 0 ; i < len ; i++)
+ min_len = choose_len(min_len, strlen(list_items->ns_name), default_len);
+
+ return min_len;
+}
+
+static int huawei_get_array_len(struct huawei_list_item *list_items, unsigned int len,
+ unsigned int default_len)
+{
+ int i;
+ int min_len = default_len;
+
+ for (i = 0 ; i < len ; i++)
+ min_len = choose_len(min_len, strlen(list_items->array_name), default_len);
+
+ return min_len;
+}
+
+static void huawei_print_list_items(struct huawei_list_item *list_items, unsigned int len)
+{
+ unsigned int i;
+ struct huawei_list_element_len element_len;
+
+ element_len.node = 16;
+ element_len.nguid = 2 * sizeof(list_items->ns.nguid) + 1;
+ element_len.ns_id = 9;
+ element_len.usage = 26;
+ element_len.ns_name = huawei_get_ns_len(list_items, len, MIN_NS_NAME_LEN);
+ element_len.array_name = huawei_get_array_len(list_items, len, MIN_ARRAY_NAME_LEN);
+
+ huawei_print_list_head(element_len);
+
+ for (i = 0 ; i < len ; i++)
+ huawei_print_list_item(&list_items[i], element_len);
+}
+
+static int huawei_list(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char path[264];
+ struct dirent **devices;
+ struct huawei_list_item *list_items;
+ unsigned int i, n, ret;
+ unsigned int huawei_num = 0;
+ enum nvme_print_flags fmt;
+ const char *desc = "Retrieve basic information for the given huawei device";
+ 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()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0 || (fmt != JSON && fmt != NORMAL))
+ return ret;
+
+ n = scandir("/dev", &devices, nvme_namespace_filter, alphasort);
+ if (n <= 0)
+ return n;
+
+ list_items = calloc(n, sizeof(*list_items));
+ if (!list_items) {
+ fprintf(stderr, "can not allocate controller list payload\n");
+ ret = ENOMEM;
+ goto out_free_devices;
+ }
+
+ for (i = 0; i < n; i++) {
+ int fd;
+
+ snprintf(path, sizeof(path), "/dev/%s", devices[i]->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Cannot open device %s: %s\n",
+ path, strerror(errno));
+ continue;
+ }
+ ret = huawei_get_nvme_info(fd, &list_items[huawei_num], path);
+ if (ret) {
+ close(fd);
+ goto out_free_list_items;
+ }
+ if (list_items[huawei_num].huawei_device == true)
+ huawei_num++;
+ close(fd);
+ }
+
+ if (huawei_num > 0) {
+ if (fmt == JSON)
+ huawei_json_print_list_items(list_items, huawei_num);
+ else
+ huawei_print_list_items(list_items, huawei_num);
+ }
+out_free_list_items:
+ free(list_items);
+out_free_devices:
+ for (i = 0; i < n; i++)
+ free(devices[i]);
+ free(devices);
+
+ return ret;
+}
+
+static void huawei_do_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ char array_name[ARRAY_NAME_LEN + 1] = {0};
+
+ memcpy(array_name, vs, ARRAY_NAME_LEN);
+ if (root)
+ json_object_add_value_string(root, "array name", strlen(array_name) > 1 ? array_name : "NULL");
+ else
+ printf("array name : %s\n", strlen(array_name) > 1 ? array_name : "NULL");
+}
+
+static int huawei_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, huawei_do_id_ctrl);
+}
diff --git a/plugins/huawei/huawei-nvme.h b/plugins/huawei/huawei-nvme.h
new file mode 100644
index 0000000..f49e6fd
--- /dev/null
+++ b/plugins/huawei/huawei-nvme.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/huawei/huawei-nvme
+
+#if !defined(HUAWEI_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define HUAWEI_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("huawei", "Huawei vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("list", "List all Huawei NVMe devices and namespaces on machine", huawei_list)
+ ENTRY("id-ctrl", "Huawei identify controller", huawei_id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/innogrit/innogrit-nvme.c b/plugins/innogrit/innogrit-nvme.c
new file mode 100644
index 0000000..cd47efa
--- /dev/null
+++ b/plugins/innogrit/innogrit-nvme.c
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "typedef.h"
+
+#define CREATE_CMD
+#include "innogrit-nvme.h"
+
+static int innogrit_smart_log_additional(int argc, char **argv,
+ struct command *command,
+ struct plugin *plugin)
+{
+ struct nvme_smart_log smart_log = { 0 };
+ struct vsc_smart_log *pvsc_smart = (struct vsc_smart_log *)smart_log.rsvd232;
+ const char *desc = "Retrieve additional SMART log for the given device ";
+ const char *namespace = "(optional) desired namespace";
+ struct nvme_dev *dev;
+ int err, i, iindex;
+
+ struct config {
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ nvme_get_log_smart(dev_fd(dev), cfg.namespace_id, false, &smart_log);
+ nvme_show_smart_log(&smart_log, cfg.namespace_id, dev->name, NORMAL);
+
+ printf("DW0[0-1] Defect Cnt : %u\n", pvsc_smart->defect_cnt);
+ printf("DW0[2-3] Slc Spb Cnt : %u\n", pvsc_smart->slc_spb_cnt);
+ printf("DW1 Slc Total Ec Cnt : %u\n", pvsc_smart->slc_total_ec_cnt);
+ printf("DW2 Slc Max Ec Cnt : %u\n", pvsc_smart->slc_max_ec_cnt);
+ printf("DW3 Slc Min Ec Cnt : %u\n", pvsc_smart->slc_min_ec_cnt);
+ printf("DW4 Slc Avg Ec Cnt : %u\n", pvsc_smart->slc_avg_ec_cnt);
+ printf("DW5 Total Ec Cnt : %u\n", pvsc_smart->total_ec_cnt);
+ printf("DW6 Max Ec Cnt : %u\n", pvsc_smart->max_ec_cnt);
+ printf("DW7 Min Ec Cnt : %u\n", pvsc_smart->min_ec_cnt);
+ printf("DW8 Avg Ec Cnt : %u\n", pvsc_smart->avg_ec_cnt);
+ printf("DW9 Mrd Rr Good Cnt : %u\n", pvsc_smart->mrd_rr_good_cnt);
+ printf("DW10 Ard Rr Good Cnt : %u\n", pvsc_smart->ard_rr_good_cnt);
+ printf("DW11 Preset Cnt : %u\n", pvsc_smart->preset_cnt);
+ printf("DW12 Nvme Reset Cnt : %u\n", pvsc_smart->nvme_reset_cnt);
+ printf("DW13 Low Pwr Cnt : %u\n", pvsc_smart->low_pwr_cnt);
+ printf("DW14 Wa : %u\n", pvsc_smart->wa);
+ printf("DW15 Ps3 Entry Cnt : %u\n", pvsc_smart->ps3_entry_cnt);
+ printf("DW16[0] highest_temp[0] : %u\n", pvsc_smart->highest_temp[0]);
+ printf("DW16[1] highest_temp[1] : %u\n", pvsc_smart->highest_temp[1]);
+ printf("DW16[2] highest_temp[2] : %u\n", pvsc_smart->highest_temp[2]);
+ printf("DW16[3] highest_temp[3] : %u\n", pvsc_smart->highest_temp[3]);
+ printf("DW17 weight_ec : %u\n", pvsc_smart->weight_ec);
+ printf("DW18 slc_cap_mb : %u\n", pvsc_smart->slc_cap_mb);
+ printf("DW19-20 nand_page_write_cnt : %llu\n", pvsc_smart->nand_page_write_cnt);
+ printf("DW21 program_error_cnt : %u\n", pvsc_smart->program_error_cnt);
+ printf("DW22 erase_error_cnt : %u\n", pvsc_smart->erase_error_cnt);
+ printf("DW23[0] flash_type : %u\n", pvsc_smart->flash_type);
+ printf("DW24 hs_crc_err_cnt : %u\n", pvsc_smart->hs_crc_err_cnt);
+ printf("DW25 ddr_ecc_err_cnt : %u\n", pvsc_smart->ddr_ecc_err_cnt);
+ iindex = 26;
+ for (i = 0; i < (sizeof(pvsc_smart->reserved3)/4); i++) {
+ if (pvsc_smart->reserved3[i] != 0)
+ printf("DW%-37d : %u\n", iindex, pvsc_smart->reserved3[i]);
+ iindex++;
+ }
+
+ return 0;
+}
+
+static int sort_eventlog_fn(const void *a, const void *b)
+{
+ const struct eventlog_addindex *l = a;
+ const struct eventlog_addindex *r = b;
+ int rc;
+
+ if (l->ms > r->ms) {
+ rc = 1;
+ } else if (l->ms < r->ms) {
+ rc = -1;
+ } else {
+ if (l->iindex < r->iindex)
+ rc = -1;
+ else
+ rc = 1;
+ }
+
+ return rc;
+}
+
+static void sort_eventlog(struct eventlog *data16ksrc, unsigned int icount)
+{
+ struct eventlog_addindex peventlogadd[512];
+ unsigned int i;
+
+ for (i = 0; i < icount; i++) {
+ memcpy(&peventlogadd[i], &data16ksrc[i], sizeof(struct eventlog));
+ peventlogadd[i].iindex = i;
+ }
+
+ qsort(peventlogadd, icount, sizeof(struct eventlog_addindex), sort_eventlog_fn);
+
+ for (i = 0; i < icount; i++)
+ memcpy(&data16ksrc[i], &peventlogadd[i], sizeof(struct eventlog));
+}
+
+static unsigned char setfilecontent(char *filenamea, unsigned char *buffer,
+ unsigned int buffersize)
+{
+ FILE *fp = NULL;
+ int rc;
+
+ if (buffersize == 0)
+ return true;
+ fp = fopen(filenamea, "a+");
+ rc = fwrite(buffer, 1, buffersize, fp);
+ fclose(fp);
+ if (rc != buffersize)
+ return false;
+ return true;
+}
+
+static int nvme_vucmd(int fd, unsigned char opcode, unsigned int cdw12,
+ unsigned int cdw13, unsigned int cdw14,
+ unsigned int cdw15, char *data, int data_len)
+{
+ struct nvme_passthru_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = opcode;
+ cmd.cdw2 = IGVSC_SIG;
+ cmd.cdw10 = data_len / 4;
+ cmd.cdw12 = cdw12;
+ cmd.cdw13 = cdw13;
+ cmd.cdw14 = cdw14;
+ cmd.cdw15 = cdw15;
+ cmd.nsid = 0xffffffff;
+ cmd.addr = (__u64)(__u64)(uintptr_t)data;
+ cmd.data_len = data_len;
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+static int innogrit_vsc_geteventlog(int argc, char **argv,
+ struct command *command,
+ struct plugin *plugin)
+{
+ time_t timep;
+ struct tm *logtime;
+ int icount, ioffset16k, iblock, ivsctype;
+ char currentdir[128], filename[512];
+ unsigned char data[4096], data16k[SIZE_16K], zerob[32];
+ unsigned int *pcheckdata;
+ unsigned int isize, icheck_stopvalue, iend;
+ unsigned char bSortLog = false, bget_nextlog = true;
+ struct evlg_flush_hdr *pevlog = (struct evlg_flush_hdr *)data;
+ const char *desc = "Recrieve event log for the given device ";
+ const char *clean_opt = "(optional) 1 for clean event log";
+ struct nvme_dev *dev;
+ int ret = -1;
+
+ struct config {
+ __u32 clean_flg;
+ };
+
+ struct config cfg = {
+ .clean_flg = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("clean_flg", 'c', &cfg.clean_flg, clean_opt),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+
+ if (getcwd(currentdir, 128) == NULL)
+ return -1;
+
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096);
+ if (ret == -1)
+ return ret;
+
+ if (data[0] == 0x5A)
+ ivsctype = 1;
+ else
+ ivsctype = 0;
+
+ time(&timep);
+ logtime = localtime(&timep);
+ sprintf(filename, "%s/eventlog_%02d%02d-%02d%02d%02d.elog", currentdir, logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec);
+
+ iblock = 0;
+ ioffset16k = 0;
+ memset(data16k, 0, SIZE_16K);
+ memset(zerob, 0, 32);
+
+ icount = 0;
+ while (bget_nextlog) {
+ if (icount % 100 == 0) {
+ printf("\rWait for Dump EventLog " XCLEAN_LINE);
+ fflush(stdout);
+ icount = 0;
+ } else if (icount % 5 == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+ icount++;
+
+ memset(data, 0, 4096);
+ if (ivsctype == 1)
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x60, 0x00, 0x00, 0x00, (char *)data,
+ 4096);
+ else
+ ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET_EVENT_LOG, 0, 0,
+ (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF),
+ (char *)data, 4096);
+ if (ret == -1)
+ return ret;
+
+ pcheckdata = (unsigned int *)&data[4096 - 32];
+ icheck_stopvalue = pcheckdata[1];
+
+ if (icheck_stopvalue == 0xFFFFFFFF) {
+ isize = pcheckdata[0];
+ if (isize == 0) {
+ /* Finish Log */
+ bget_nextlog = false;
+ } else if (bSortLog) {
+ /* No Full 4K Package */
+ for (iend = 0; iend < isize - 32; iend += sizeof(struct eventlog)) {
+ if (memcmp(&data[iend], zerob, sizeof(struct eventlog)) != 0) {
+ memcpy(&data16k[ioffset16k], &data[iend], sizeof(struct eventlog));
+ ioffset16k += sizeof(struct eventlog);
+ }
+ }
+ } else {
+ setfilecontent(filename, data, isize);
+ }
+ } else {
+ /* Full 4K Package */
+ if ((pevlog->signature == EVLOG_SIG) && (pevlog->log_type == 1))
+ bSortLog = true;
+
+ if (bSortLog) {
+ for (iend = 0; iend < SIZE_4K; iend += sizeof(struct eventlog)) {
+ if (memcmp(&data[iend], zerob, sizeof(struct eventlog)) != 0) {
+ memcpy(&data16k[ioffset16k], &data[iend], sizeof(struct eventlog));
+ ioffset16k += sizeof(struct eventlog);
+ }
+ }
+
+ iblock++;
+ if (iblock == 4) {
+ sort_eventlog((struct eventlog *)(data16k + sizeof(struct evlg_flush_hdr)),
+ (ioffset16k - sizeof(struct evlg_flush_hdr))/sizeof(struct eventlog));
+ setfilecontent(filename, data16k, ioffset16k);
+ ioffset16k = 0;
+ iblock = 0;
+ memset(data16k, 0, SIZE_16K);
+ }
+ } else {
+ setfilecontent(filename, data, SIZE_4K);
+ }
+
+ }
+ }
+
+ if (bSortLog) {
+ if (ioffset16k > 0) {
+ sort_eventlog((struct eventlog *)(data16k + sizeof(struct evlg_flush_hdr)),
+ (ioffset16k - sizeof(struct evlg_flush_hdr))/sizeof(struct eventlog));
+ setfilecontent(filename, data16k, ioffset16k);
+ }
+ }
+
+ printf("\r" XCLEAN_LINE "Dump eventLog finish to %s\n", filename);
+ chmod(filename, 0666);
+
+ if (cfg.clean_flg == 1) {
+ printf("Clean eventlog\n");
+ nvme_vucmd(dev_fd(dev), NVME_VSC_CLEAN_EVENT_LOG, 0, 0,
+ (SRB_SIGNATURE >> 32),
+ (SRB_SIGNATURE & 0xFFFFFFFF), (char *)NULL, 0);
+ }
+
+ dev_close(dev);
+
+ return ret;
+}
+
+static int innogrit_vsc_getcdump(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ time_t timep;
+ struct tm *logtime;
+ char currentdir[128], filename[512], fname[128];
+ unsigned int itotal, icur, ivsctype;
+ unsigned char data[4096];
+ struct cdumpinfo cdumpinfo;
+ unsigned char busevsc = false;
+ unsigned int ipackcount, ipackindex;
+ char fwvera[32];
+ const char *desc = "Recrieve cdump data for the given device ";
+ struct nvme_dev *dev;
+ int ret = -1;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ if (getcwd(currentdir, 128) == NULL)
+ return -1;
+
+ time(&timep);
+ logtime = localtime(&timep);
+
+ ivsctype = 0;
+ ipackindex = 0;
+ memset(data, 0, 4096);
+
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x03, 0x00, 0x00, (char *)data, 4096);
+ if (ret == -1)
+ return ret;
+
+ if (data[0] == 0x5A) {
+ ivsctype = 1;
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00, (char *)data, 4096);
+ } else {
+ ivsctype = 0;
+ ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
+ (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF),
+ (char *)data, 4096);
+ }
+ if (ret == -1)
+ return ret;
+
+ memcpy(&cdumpinfo, &data[3072], sizeof(cdumpinfo));
+ if (cdumpinfo.sig == 0x5a5b5c5d) {
+ busevsc = true;
+ ipackcount = cdumpinfo.ipackcount;
+ if (ipackcount == 0) {
+ itotal = 0;
+ } else {
+ itotal = cdumpinfo.cdumppack[ipackindex].ilenth;
+ memset(fwvera, 0, sizeof(fwvera));
+ memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec,
+ ipackindex, fwvera);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+ }
+
+
+ if (busevsc == false) {
+ memset(data, 0, 4096);
+ ret = nvme_get_nsid_log(dev_fd(dev), true, 0x07,
+ NVME_NSID_ALL,
+ 4096, data);
+ if (ret != 0)
+ return ret;
+
+ ipackcount = 1;
+ memcpy(&itotal, &data[4092], 4);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d.cdp", logtime->tm_mon+1, logtime->tm_mday,
+ logtime->tm_hour, logtime->tm_min, logtime->tm_sec);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+
+ if (itotal == 0) {
+ printf("no cdump data\n");
+ return 0;
+ }
+
+ while (ipackindex < ipackcount) {
+ memset(data, 0, 4096);
+ strcpy((char *)data, "cdumpstart");
+ setfilecontent(filename, data, strlen((char *)data));
+ for (icur = 0; icur < itotal; icur += 4096) {
+ memset(data, 0, 4096);
+ if (busevsc) {
+ if (ivsctype == 1)
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,
+ (char *)data, 4096);
+ else
+ ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
+ (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF),
+ (char *)data, 4096);
+ } else {
+ ret = nvme_get_nsid_log(dev_fd(dev), true,
+ 0x07,
+ NVME_NSID_ALL, 4096, data);
+ }
+ if (ret != 0)
+ return ret;
+
+ setfilecontent(filename, data, 4096);
+
+ printf("\rWait for dump data %d%%" XCLEAN_LINE, ((icur+4096) * 100/itotal));
+ }
+ memset(data, 0, 4096);
+ strcpy((char *)data, "cdumpend");
+ setfilecontent(filename, data, strlen((char *)data));
+ printf("\r%s\n", fname);
+ ipackindex++;
+ if (ipackindex != ipackcount) {
+ memset(data, 0, 4096);
+ if (busevsc) {
+ if (ivsctype == 1)
+ ret = nvme_vucmd(dev_fd(dev), 0xFE, 0x82, 0x08, 0x00, 0x00,
+ (char *)data, 4096);
+ else
+ ret = nvme_vucmd(dev_fd(dev), NVME_VSC_GET, VSC_FN_GET_CDUMP, 0x00,
+ (SRB_SIGNATURE >> 32), (SRB_SIGNATURE & 0xFFFFFFFF),
+ (char *)data, 4096);
+ } else {
+ ret = nvme_get_nsid_log(dev_fd(dev), true,
+ 0x07,
+ NVME_NSID_ALL, 4096,
+ data);
+ }
+ if (ret != 0)
+ return ret;
+
+ itotal = cdumpinfo.cdumppack[ipackindex].ilenth;
+ memset(fwvera, 0, sizeof(fwvera));
+ memcpy(fwvera, cdumpinfo.cdumppack[ipackindex].fwver, 8);
+ sprintf(fname, "cdump_%02d%02d-%02d%02d%02d_%d_%s.cdp", logtime->tm_mon+1,
+ logtime->tm_mday, logtime->tm_hour, logtime->tm_min, logtime->tm_sec,
+ ipackindex, fwvera);
+ sprintf(filename, "%s/%s", currentdir, fname);
+ }
+
+ }
+
+ printf("\n");
+ dev_close(dev);
+ return ret;
+}
diff --git a/plugins/innogrit/innogrit-nvme.h b/plugins/innogrit/innogrit-nvme.h
new file mode 100644
index 0000000..2de0502
--- /dev/null
+++ b/plugins/innogrit/innogrit-nvme.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/innogrit/innogrit-nvme
+
+#if !defined(INNOGRIT_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define INNOGRIT_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("innogrit", "innogrit vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve innogrit SMART Log, show it", innogrit_smart_log_additional)
+ ENTRY("get-eventlog", "get event log", innogrit_vsc_geteventlog)
+ ENTRY("get-cdump", "get cdump data", innogrit_vsc_getcdump)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/innogrit/typedef.h b/plugins/innogrit/typedef.h
new file mode 100644
index 0000000..f2a59b4
--- /dev/null
+++ b/plugins/innogrit/typedef.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#define SIZE_4K 4096
+#define SIZE_16K 16384
+
+#define NVME_VSC_GET_EVENT_LOG 0xC2
+#define NVME_VSC_CLEAN_EVENT_LOG 0xD8
+#define NVME_VSC_GET 0xE6
+#define VSC_FN_GET_CDUMP 0x08
+#define EVLOG_SIG 0x65766C67
+#define IGVSC_SIG 0x69677673
+#define SRB_SIGNATURE 0x544952474F4E4E49ULL
+#define XCLEAN_LINE "\033[K"
+
+struct evlg_flush_hdr {
+ unsigned int signature;
+ unsigned int fw_ver[2];
+ unsigned int fw_type : 8;
+ unsigned int log_type : 8;
+ unsigned int project : 16;
+ unsigned int trace_cnt;
+ unsigned int sout_crc;
+ unsigned int reserved[2];
+};
+
+struct eventlog {
+ unsigned int ms;
+ unsigned int param[7];
+};
+
+struct eventlog_addindex {
+ unsigned int ms;
+ unsigned int param[7];
+ unsigned int iindex;
+};
+
+#pragma pack(push)
+#pragma pack(1)
+struct vsc_smart_log {
+ unsigned short defect_cnt;
+ unsigned short slc_spb_cnt;
+ unsigned int slc_total_ec_cnt;
+ unsigned int slc_max_ec_cnt;
+ unsigned int slc_min_ec_cnt;
+ unsigned int slc_avg_ec_cnt;
+ unsigned int total_ec_cnt;
+ unsigned int max_ec_cnt;
+ unsigned int min_ec_cnt;
+ unsigned int avg_ec_cnt;
+ unsigned int mrd_rr_good_cnt;
+ unsigned int ard_rr_good_cnt;
+ unsigned int preset_cnt;
+ unsigned int nvme_reset_cnt;
+ unsigned int low_pwr_cnt;
+ unsigned int wa;
+ unsigned int ps3_entry_cnt;
+ u_char highest_temp[4];
+ unsigned int weight_ec;
+ unsigned int slc_cap_mb;
+ unsigned long long nand_page_write_cnt;
+ unsigned int program_error_cnt;
+ unsigned int erase_error_cnt;
+ u_char flash_type;
+ u_char reserved2[3];
+ unsigned int hs_crc_err_cnt;
+ unsigned int ddr_ecc_err_cnt;
+ unsigned int reserved3[44];
+};
+#pragma pack(pop)
+
+struct cdump_pack {
+ unsigned int ilenth;
+ char fwver[8];
+};
+
+struct cdumpinfo {
+ unsigned int sig;
+ unsigned int ipackcount;
+ struct cdump_pack cdumppack[32];
+};
diff --git a/plugins/inspur/inspur-nvme.c b/plugins/inspur/inspur-nvme.c
new file mode 100644
index 0000000..cda3507
--- /dev/null
+++ b/plugins/inspur/inspur-nvme.c
@@ -0,0 +1,233 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "nvme-print.h"
+#include "util/suffix.h"
+
+#define CREATE_CMD
+#include "inspur-nvme.h"
+#include "inspur-utils.h"
+
+void show_r1_vendor_log(r1_cli_vendor_log_t *vendorlog)
+{
+ int i = 0;
+
+ if (vendorlog->device_state == 0)
+ printf("device_state : [healthy]\n");
+ else
+ printf("device_state : [warning]\n");
+
+ printf("commit id : %s\n", vendorlog->commit_id);
+ printf("mcu data id(mcu) : 0x%x\n", le32_to_cpu(vendorlog->mcu_data_id));
+ printf("power_info(mcu) : %u mW\n", le32_to_cpu(vendorlog->power_info));
+ printf("voltage_info(mcu) : %u mV\n", le32_to_cpu(vendorlog->voltage_info));
+ printf("current_info(mcu) : %u mA\n", le32_to_cpu(vendorlog->current_info));
+ printf("history max_power(mcu) : %u mW\n", le32_to_cpu(vendorlog->max_power));
+ printf("disk_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->disk_max_temper) - 273);
+ printf("disk_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->disk_overtemper_cout));
+ printf("ctrl_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->ctrl_max_temper) - 273);
+ printf("ctrl_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->ctrl_overtemper_cout));
+ printf("nand_max_temper(mcu) : %d C\n", le32_to_cpu(vendorlog->nand_max_temper) - 273);
+ printf("nand_overtemper_cout(mcu) : %u\n", le32_to_cpu(vendorlog->nand_overtemper_cout));
+
+ for (i = 0; i < 4; i++)
+ printf("temperature[%d](mcu) : %d C\n", i, le32_to_cpu(vendorlog->current_temp[i]) - 273);
+
+ printf("CAP Time from 32v to 27v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time1));
+ printf("CAP Time from 27v to 10v(mcu) : %u ms\n", le32_to_cpu(vendorlog->cap_transtime.cap_trans_time2));
+ printf("cap_health_state(mcu) : %u\n", le32_to_cpu(vendorlog->cap_health_state));
+ printf("warning bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning[1]),
+ le32_to_cpu(vendorlog->detail_warning[0]));
+ printf("-->high_format_fail : %x\n", vendorlog->detail_warning_bit.high_format_fail);
+ printf("-->low_format_fail : %x\n", vendorlog->detail_warning_bit.low_format_fail);
+ printf("-->current sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail1);
+ printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail2);
+ printf("-->board temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail3);
+ printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_bit.self_test_fail4);
+ printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_bit.capacitance_test_fail);
+ printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_bit.readOnly_after_rebuild);
+ printf("-->firmware_loss : %x\n", vendorlog->detail_warning_bit.firmware_loss);
+ printf("-->cap_self_test : %x\n", vendorlog->detail_warning_bit.cap_unsupply);
+ printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_bit.spare_space_warning);
+ printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_bit.lifetime_warning);
+ printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_bit.temp_high_warning);
+ printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_bit.temp_low_warning);
+ printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_bit.mcu_disable);
+ printf("warning history bit(mcu) : 0x%x%08x\n", le32_to_cpu(vendorlog->detail_warning_his[1]),
+ le32_to_cpu(vendorlog->detail_warning_his[0]));
+ printf("-->high_format_fail : %x\n", vendorlog->detail_warning_his_bit.high_format_fail);
+ printf("-->low_format_fail : %x\n", vendorlog->detail_warning_his_bit.low_format_fail);
+ printf("-->current sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail1);
+ printf("-->nand temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail2);
+ printf("-->board temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail3);
+ printf("-->cntl temp sensor : %x\n", vendorlog->detail_warning_his_bit.self_test_fail4);
+ printf("-->cap_timer_test_fail : %x\n", vendorlog->detail_warning_his_bit.capacitance_test_fail);
+ printf("-->readOnly_after_rebuild : %x\n", vendorlog->detail_warning_his_bit.readOnly_after_rebuild);
+ printf("-->firmware_loss : %x\n", vendorlog->detail_warning_his_bit.firmware_loss);
+ printf("-->cap_self_test : %x\n", vendorlog->detail_warning_his_bit.cap_unsupply);
+ printf("-->spare_space_warning : %x\n", vendorlog->detail_warning_his_bit.spare_space_warning);
+ printf("-->lifetime_warning : %x\n", vendorlog->detail_warning_his_bit.lifetime_warning);
+ printf("-->temp_high_warning : %x\n", vendorlog->detail_warning_his_bit.temp_high_warning);
+ printf("-->temp_low_warning : %x\n", vendorlog->detail_warning_his_bit.temp_low_warning);
+ printf("-->mcu_disable(mcu) : %x\n", vendorlog->detail_warning_his_bit.mcu_disable);
+
+ for (i = 0; i < 4; i++)
+ printf("[%d]nand_bytes_written : %" PRIu64 " GB\n", i, le64_to_cpu(vendorlog->nand_bytes_written[i]));
+
+ for (i = 0; i < 4; i++) {
+ printf("[%d]io_apptag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_apptag_err));
+ printf("[%d]io_guard_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_guard_err));
+ printf("[%d]io_reftag_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_reftag_err));
+ printf("[%d]io_read_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_read_fail_cout));
+ printf("[%d]io_write_fail_cout : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_write_fail_cout));
+ printf("[%d]io_dma_disable_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_disable_err));
+ printf("[%d]io_dma_fatal_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_fatal_err));
+ printf("[%d]io_dma_linkdown_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_linkdown_err));
+ printf("[%d]io_dma_timeout_err : %u\n", i, le32_to_cpu(vendorlog->io_err[i].io_dma_timeout_err));
+ printf("[%d]lba_err[0] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[0]));
+ printf("[%d]lba_err[1] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[1]));
+ printf("[%d]lba_err[2] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[2]));
+ printf("[%d]lba_err[3] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[3]));
+ printf("[%d]lba_err[4] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[4]));
+ printf("[%d]lba_err[5] : %u\n", i, le32_to_cpu(vendorlog->io_err[i].lba_err[5]));
+ }
+
+ printf("temp_throttle_per : %u\n", le32_to_cpu(vendorlog->temp_throttle_per));
+ printf("port0_flreset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_fundamental_reset_cnt));
+ printf("port0_hot_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_hot_reset_cnt));
+ printf("port0_func_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_func_reset_cnt));
+ printf("port0_linkdown_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_linkdown_cnt));
+ printf("port0_ctrl_reset_cnt : %" PRIu64 "\n", le64_to_cpu(vendorlog->port0_ctrl_reset_cnt));
+ printf("ces_RcvErr_cnt : %u\n", le32_to_cpu(vendorlog->ces_RcvErr_cnt));
+ printf("ces_BadTlp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadTlp_cnt));
+ printf("ces_BadDllp_cnt : %u\n", le32_to_cpu(vendorlog->ces_BadDllp_cnt));
+ printf("ces_Rplyover_cnt : %u\n", le32_to_cpu(vendorlog->ces_Rplyover_cnt));
+ printf("ces_RplyTo_cnt : %u\n", le32_to_cpu(vendorlog->ces_RplyTo_cnt));
+ printf("ces_Hlo_cnt : %u\n", le32_to_cpu(vendorlog->ces_Hlo_cnt));
+ printf("scan doorbell err cnt : %u\n", le32_to_cpu(vendorlog->scan_db_err_cnt));
+ printf("doorbell interrupt err cnt : %u\n", le32_to_cpu(vendorlog->db_int_err_cnt));
+
+ printf("------------ncm-----------------------\n");
+ for (i = 0; i < 4; i++) {
+ printf("------------part%d-----------------------\n", i);
+ printf("[%d]nand_rd_unc_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_unc_cnt));
+ printf("[%d]nand_rd_srr_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_srr_cnt));
+ printf("[%d]nand_rd_sdecode_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_soft_decode_cnt));
+ printf("[%d]nand_rd_rb_fail_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_rebuild_fail_cnt));
+ printf("[%d]nand_prg_fail_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_fail_cnt));
+ printf("[%d]nand_eras_fail_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_fail_cnt));
+ printf("[%d]nand_rd_count : %" PRIu64 "\n", i,
+ le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_rd_cnt));
+ printf("[%d]nand_prg_count : %" PRIu64 "\n", i,
+ le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_prg_cnt));
+ printf("[%d]nand_eras_count : %" PRIu64 "\n", i,
+ le64_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].nand_eras_cnt));
+ printf("[%d]BE_scan_unc_count : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].BE_scan_unc_cnt));
+ printf("[%d]rebuild_req_cnt : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].rebuild_req_cnt));
+ printf("[%d]retry_req_cnt : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_req_cnt));
+ printf("[%d]retry_success_cnt : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].retry_success_cnt));
+ printf("[%d]prg_badblk_num : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].prg_badblk_num));
+ printf("[%d]eras_badblk_num : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].eras_badblk_num));
+ printf("[%d]read_badblk_num : %u\n", i,
+ le32_to_cpu(vendorlog->vendor_log_nandctl_cnt[i].unc_badblk_num));
+ }
+
+ printf("[%d]temp_ctrl_limit_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_limit_cnt));
+ printf("[%d]temp_ctrl_stop_count : %u\n", i, le32_to_cpu(vendorlog->temp_ctrl_stop_cnt));
+ printf("------------wlm-----------------------\n");
+ for (i = 0; i < 4; i++) {
+ printf("------------part%d-----------------------\n", i);
+ printf("[%d]fbb_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].fbb_count));
+ printf("[%d]ebb_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].ebb_count));
+ printf("[%d]lbb_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].lbb_count));
+ printf("[%d]gc_read_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_read_count));
+ printf("[%d]gc_write_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_count));
+ printf("[%d]gc_write_fail_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].gc_write_fail_count));
+ printf("[%d]force_gc_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].force_gc_count));
+ printf("[%d]avg_pe_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].avg_pe_count));
+ printf("[%d]max_pe_count : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].max_pe_count));
+ printf("[%d]free_blk_num1 : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num1));
+ printf("[%d]free_blk_num2 : %u\n", i,
+ le32_to_cpu(vendorlog->wearlvl_vendor_log_count[i].free_blk_num2));
+ }
+
+ printf("------------lkm-----------------------\n");
+ printf("[%d]e2e_check_err_count1 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt1));
+ printf("[%d]e2e_check_err_count2 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt2));
+ printf("[%d]e2e_check_err_count3 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt3));
+ printf("[%d]e2e_check_err_count4 : %u\n", i, le32_to_cpu(vendorlog->e2e_check_err_cnt4));
+}
+
+void show_r1_media_err_log(r1_cli_vendor_log_t *vendorlog)
+{
+ int i, j;
+
+ for (i = 0; i < 4; i++) {
+ printf("DM%d read err lba:\n", i);
+ for (j = 0; j < 10; j++)
+ printf("[%d]lba : %" PRIu64 "\n", j, le64_to_cpu(vendorlog->media_err[i].lba_err[j]));
+ }
+}
+
+static int nvme_get_vendor_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ __u8 local_mem[BYTE_OF_4K];
+ char *desc = "Get the Inspur vendor log";
+ struct nvme_dev *dev;
+ int err;
+
+ OPT_ARGS(opts) = { OPT_END() };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ memset(local_mem, 0, BYTE_OF_4K);
+ err = nvme_get_log_simple(dev_fd(dev),
+ (enum nvme_cmd_get_log_lid)VENDOR_SMART_LOG_PAGE,
+ sizeof(r1_cli_vendor_log_t), local_mem);
+ if (!err) {
+ show_r1_vendor_log((r1_cli_vendor_log_t *)local_mem);
+ show_r1_media_err_log((r1_cli_vendor_log_t *)local_mem);
+ } else {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/inspur/inspur-nvme.h b/plugins/inspur/inspur-nvme.h
new file mode 100644
index 0000000..14a5e76
--- /dev/null
+++ b/plugins/inspur/inspur-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/inspur/inspur-nvme
+
+#if !defined(INSPUR_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define INSPUR_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("inspur", "Inspur vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("nvme-vendor-log", "Retrieve Inspur Vendor Log, show it", nvme_get_vendor_log)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/inspur/inspur-utils.h b/plugins/inspur/inspur-utils.h
new file mode 100644
index 0000000..d411bf0
--- /dev/null
+++ b/plugins/inspur/inspur-utils.h
@@ -0,0 +1,175 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __INSPUR_UTILS_H__
+#define __INSPUR_UTILS_H__
+
+#define BYTE_OF_64K 65536UL
+#define BYTE_OF_32K 32768UL
+#define BYTE_OF_16K 16384UL
+#define BYTE_OF_4K 4096UL
+#define BYTE_OF_512 512UL
+#define BYTE_OF_256 256UL
+#define BYTE_OF_128 128UL
+
+/* Inspur specific LOG_PAGE_ID */
+typedef enum {
+ VENDOR_SMART_LOG_PAGE = 0xc0,
+} vendor_sepc_log_page_id_e;
+
+#pragma pack(push, 1)
+typedef struct r1_am_cap_transtime {
+ __u32 cap_trans_time1 : 16;
+ __u32 cap_trans_time2 : 16;
+} r1_cap_transtime_t;
+
+typedef struct vendor_warning_bit {
+ __u32 high_format_fail : 1;
+ __u32 low_format_fail : 1;
+ __u32 rebuild_fail1 : 1;
+ __u32 rebuild_fail2 : 1;
+ __u32 rebuild_fail3 : 1;
+ __u32 rebuild_fail4 : 1;
+ __u32 rebuild_fail5 : 1;
+ __u32 rebuild_fail6 : 1;
+ __u32 self_test_fail1 : 1;
+ __u32 self_test_fail2 : 1;
+ __u32 self_test_fail3 : 1;
+ __u32 self_test_fail4 : 1;
+ __u32 internal_err1 : 1;
+ __u32 internal_err2 : 1;
+ __u32 internal_err3 : 1;
+ __u32 internal_err4 : 1;
+ __u32 internal_err5 : 1;
+ __u32 internal_err6 : 1;
+ __u32 internal_err7 : 1;
+ __u32 internal_err8 : 1;
+ __u32 internal_err9 : 1;
+ __u32 internal_err10 : 1;
+ __u32 internal_err11 : 1;
+ __u32 internal_err12 : 1;
+ __u32 internal_err13 : 1;
+ __u32 internal_err14 : 1;
+ __u32 internal_err15 : 1;
+ __u32 internal_err16 : 1;
+ __u32 capacitance_test_fail : 1;
+ __u32 IO_read_fail : 1;
+ __u32 IO_write_fail : 1;
+ __u32 readOnly_after_rebuild : 1;
+ __u32 firmware_loss : 1;
+ __u32 cap_unsupply : 1;
+ __u32 spare_space_warning : 1;
+ __u32 lifetime_warning : 1;
+ __u32 temp_high_warning : 1;
+ __u32 temp_low_warning : 1;
+ __u32 mcu_disable : 1;
+ __u32 rsv : 25;
+} vendor_warning_str;
+
+typedef struct r1_vendor_log_ncm_cout {
+ __u32 nand_rd_unc_cnt;
+ __u32 nand_rd_srr_cnt;
+ __u32 nand_rd_soft_decode_cnt;
+ __u32 nand_rd_rebuild_fail_cnt;
+ __u32 nand_prg_fail_cnt;
+ __u32 nand_eras_fail_cnt;
+ __u64 nand_rd_cnt;
+ __u64 nand_prg_cnt;
+ __u64 nand_eras_cnt;
+ __u32 BE_scan_unc_cnt;
+ __u32 rebuild_req_cnt;
+ __u16 retry_req_cnt;
+ __u16 retry_success_cnt;
+ __u32 prg_badblk_num;
+ __u32 eras_badblk_num;
+ __u32 unc_badblk_num;
+} r1_vendor_log_nandctl_count_t;
+
+typedef struct r1_wearlvl_vendor_log_count {
+ __u32 fbb_count;
+ __u32 ebb_count;
+ __u32 lbb_count;
+ __u32 gc_read_count;
+ __u32 gc_write_count;
+ __u32 gc_write_fail_count;
+ __u32 force_gc_count;
+ __u32 avg_pe_count;
+ __u32 max_pe_count;
+ __u32 free_blk_num1;
+ __u32 free_blk_num2;
+} r1_wearlvl_vendor_log_count_t;
+
+typedef struct vendor_media_err {
+ __u64 lba_err[10];
+} vendor_media_err_t;
+
+typedef struct r1_vendor_log_io_err {
+ __u32 io_guard_err;
+ __u32 io_apptag_err;
+ __u32 io_reftag_err;
+ __u32 io_dma_linkdown_err;
+ __u32 io_dma_disable_err;
+ __u32 io_dma_timeout_err;
+ __u32 io_dma_fatal_err;
+ __u32 io_write_fail_cout;
+ __u32 io_read_fail_cout;
+ __u32 lba_err[6];
+} r1_vendor_log_io_err_t;
+
+typedef struct r1_vendor_log_s {
+ __u32 max_power;
+ __u32 disk_max_temper;
+ __u32 disk_overtemper_cout;
+ __u32 ctrl_max_temper;
+ __u32 ctrl_overtemper_cout;
+ r1_cap_transtime_t cap_transtime;
+ __u32 cap_health_state;
+ __u32 device_state;
+ r1_vendor_log_io_err_t io_err[4];
+ union {
+ vendor_warning_str detail_warning_bit;
+ __u32 detail_warning[2];
+ };
+ union {
+ vendor_warning_str detail_warning_his_bit;
+ __u32 detail_warning_his[2];
+ };
+ __u32 ddr_bit_err_cout;
+ __u32 temp_throttle_per;
+ __u64 port0_fundamental_reset_cnt;
+ __u64 port0_hot_reset_cnt;
+ __u64 port0_func_reset_cnt;
+ __u64 port0_linkdown_cnt;
+ __u64 port0_ctrl_reset_cnt;
+ __u64 nand_bytes_written[4];
+ __u32 power_info;
+ __u32 voltage_info;
+ __u32 current_info;
+ __u32 current_temp[4];
+ __u32 nand_max_temper;
+ __u32 nand_overtemper_cout;
+ __u32 mcu_data_id;
+ __u8 commit_id[16];
+ __u32 ces_RcvErr_cnt;
+ __u32 ces_BadTlp_cnt;
+ __u32 ces_BadDllp_cnt;
+ __u32 ces_Rplyover_cnt;
+ __u32 ces_RplyTo_cnt;
+ __u32 ces_Hlo_cnt;
+ __u32 scan_db_err_cnt;
+ __u32 db_int_err_cnt;
+ __u8 rsvFE[56];
+ r1_vendor_log_nandctl_count_t vendor_log_nandctl_cnt[4];
+ __u32 temp_ctrl_limit_cnt;
+ __u32 temp_ctrl_stop_cnt;
+ __u8 rsvncm[216];
+ r1_wearlvl_vendor_log_count_t wearlvl_vendor_log_count[4];
+ __u8 rsvwlm[512 - sizeof(r1_wearlvl_vendor_log_count_t) * 4 % 512];
+ __u32 e2e_check_err_cnt1;
+ __u32 e2e_check_err_cnt2;
+ __u32 e2e_check_err_cnt3;
+ __u32 e2e_check_err_cnt4;
+ vendor_media_err_t media_err[4];
+ __u8 rsvlkm[176];
+} r1_cli_vendor_log_t;
+#pragma pack(pop)
+
+#endif // __INSPUR_UTILS_H__
diff --git a/plugins/intel/intel-nvme.c b/plugins/intel/intel-nvme.c
new file mode 100644
index 0000000..378ecc0
--- /dev/null
+++ b/plugins/intel/intel-nvme.c
@@ -0,0 +1,1738 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "intel-nvme.h"
+
+struct __packed nvme_additional_smart_log_item {
+ __u8 key;
+ __u8 _kp[2];
+ __u8 norm;
+ __u8 _np;
+ union __packed {
+ __u8 raw[6];
+ struct __packed wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __packed thermal_throttle {
+ __u8 pct;
+ __u32 count;
+ } thermal_throttle;
+ };
+ __u8 _rp;
+};
+
+struct nvme_additional_smart_log {
+ struct nvme_additional_smart_log_item program_fail_cnt;
+ struct nvme_additional_smart_log_item erase_fail_cnt;
+ struct nvme_additional_smart_log_item wear_leveling_cnt;
+ struct nvme_additional_smart_log_item e2e_err_cnt;
+ struct nvme_additional_smart_log_item crc_err_cnt;
+ struct nvme_additional_smart_log_item timed_workload_media_wear;
+ struct nvme_additional_smart_log_item timed_workload_host_reads;
+ struct nvme_additional_smart_log_item timed_workload_timer;
+ struct nvme_additional_smart_log_item thermal_throttle_status;
+ struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
+ 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 */
+ __u8 rsvd1[3];
+ __u8 ss;
+ __u8 health[20];
+ __u8 cls;
+ __u8 nlw;
+ __u8 scap;
+ __u8 sstat;
+ __u8 bl[8];
+ __u8 rsvd2[38];
+ __u8 ww[8]; /* little endian */
+ __u8 mic_bl[4];
+ __u8 mic_fw[4];
+};
+
+static void json_intel_id_ctrl(struct nvme_vu_id_ctrl_field *id,
+ char *health, char *bl, char *ww, char *mic_bl, char *mic_fw,
+ struct json_object *root)
+{
+ json_object_add_value_int(root, "ss", id->ss);
+ json_object_add_value_string(root, "health", health);
+ json_object_add_value_int(root, "cls", id->cls);
+ json_object_add_value_int(root, "nlw", id->nlw);
+ json_object_add_value_int(root, "scap", id->scap);
+ json_object_add_value_int(root, "sstat", id->sstat);
+ json_object_add_value_string(root, "bl", bl);
+ json_object_add_value_string(root, "ww", ww);
+ json_object_add_value_string(root, "mic_bl", mic_bl);
+ json_object_add_value_string(root, "mic_fw", mic_fw);
+}
+
+static void intel_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
+
+ char health[21] = { 0 };
+ char bl[9] = { 0 };
+ char ww[19] = { 0 };
+ char mic_bl[5] = { 0 };
+ char mic_fw[5] = { 0 };
+
+ if (id->health[0] == 0)
+ snprintf(health, 21, "%s", "healthy");
+ else
+ snprintf(health, 21, "%s", id->health);
+
+ snprintf(bl, 9, "%s", id->bl);
+ snprintf(ww, 19, "%02X%02X%02X%02X%02X%02X%02X%02X", id->ww[7],
+ id->ww[6], id->ww[5], id->ww[4], id->ww[3], id->ww[2],
+ id->ww[1], id->ww[0]);
+ snprintf(mic_bl, 5, "%s", id->mic_bl);
+ snprintf(mic_fw, 5, "%s", id->mic_fw);
+
+ if (root) {
+ json_intel_id_ctrl(id, health, bl, ww, mic_bl, mic_fw, root);
+ return;
+ }
+
+ printf("ss : %d\n", id->ss);
+ printf("health : %s\n", health);
+ printf("cls : %d\n", id->cls);
+ printf("nlw : %d\n", id->nlw);
+ printf("scap : %d\n", id->scap);
+ printf("sstat : %d\n", id->sstat);
+ printf("bl : %s\n", bl);
+ printf("ww : %s\n", ww);
+ printf("mic_bl : %s\n", mic_bl);
+ printf("mic_fw : %s\n", mic_fw);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, intel_id_ctrl);
+}
+
+static void show_intel_smart_log_jsn(struct nvme_additional_smart_log *smart,
+ unsigned int nsid, const char *devname)
+{
+ struct json_object *root, *entry_stats, *dev_stats, *multi;
+
+ root = json_create_object();
+ json_object_add_value_string(root, "Intel Smart log", devname);
+
+ dev_stats = json_create_object();
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->program_fail_cnt.raw));
+ json_object_add_value_object(dev_stats, "program_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_fail_cnt.raw));
+ json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm);
+ multi = json_create_object();
+ json_object_add_value_int(multi, "min", le16_to_cpu(smart->wear_leveling_cnt.wear_level.min));
+ json_object_add_value_int(multi, "max", le16_to_cpu(smart->wear_leveling_cnt.wear_level.max));
+ json_object_add_value_int(multi, "avg", le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "wear_leveling", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->e2e_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "end_to_end_error_detection_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->crc_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "crc_error_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_media_wear.norm);
+ json_object_add_value_double(entry_stats, "raw", ((long double)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
+ json_object_add_value_object(dev_stats, "timed_workload_media_wear", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_host_reads.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_host_reads.raw));
+ json_object_add_value_object(dev_stats, "timed_workload_host_reads", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_timer.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_timer.raw));
+ json_object_add_value_object(dev_stats, "timed_workload_timer", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->thermal_throttle_status.norm);
+ multi = json_create_object();
+ json_object_add_value_int(multi, "pct", smart->thermal_throttle_status.thermal_throttle.pct);
+ json_object_add_value_int(multi, "cnt", smart->thermal_throttle_status.thermal_throttle.count);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "thermal_throttle_status", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->retry_buffer_overflow_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw));
+ json_object_add_value_object(dev_stats, "retry_buffer_overflow_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->pll_lock_loss_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw));
+ json_object_add_value_object(dev_stats, "pll_lock_loss_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw));
+ json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm);
+ 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("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)
+{
+ const char *desc =
+ "Get Intel 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";
+ const char *json = "Dump output in json format";
+
+ struct nvme_additional_smart_log smart_log;
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ bool json;
+ };
+
+ 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_FLAG("json", 'j', &cfg.json, json),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xca, sizeof(smart_log),
+ &smart_log);
+ if (!err) {
+ if (cfg.json)
+ show_intel_smart_log_jsn(&smart_log, cfg.namespace_id,
+ dev->name);
+ else if (!cfg.raw_binary)
+ show_intel_smart_log(&smart_log, cfg.namespace_id,
+ dev->name);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ dev_close(dev);
+ return err;
+}
+
+static int get_market_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Intel Marketing Name log and show it.";
+ const char *raw = "dump output in binary format";
+ struct nvme_dev *dev;
+ char log[512];
+ int err;
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xdd, sizeof(log), log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ printf("Intel Marketing Name Log:\n%s\n", log);
+ else
+ d_raw((unsigned char *)&log, sizeof(log));
+ } else if (err > 0)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
+
+struct intel_temp_stats {
+ __le64 curr;
+ __le64 last_overtemp;
+ __le64 life_overtemp;
+ __le64 highest_temp;
+ __le64 lowest_temp;
+ __u8 rsvd[40];
+ __le64 max_operating_temp;
+ __le64 min_operating_temp;
+ __le64 est_offset;
+};
+
+static void show_temp_stats(struct intel_temp_stats *stats)
+{
+ printf(" Intel Temperature Statistics\n");
+ printf("--------------------------------\n");
+ printf("Current temperature : %"PRIu64"\n", le64_to_cpu(stats->curr));
+ printf("Last critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->last_overtemp));
+ printf("Life critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->life_overtemp));
+ printf("Highest temperature : %"PRIu64"\n", le64_to_cpu(stats->highest_temp));
+ printf("Lowest temperature : %"PRIu64"\n", le64_to_cpu(stats->lowest_temp));
+ printf("Max operating temperature : %"PRIu64"\n", le64_to_cpu(stats->max_operating_temp));
+ printf("Min operating temperature : %"PRIu64"\n", le64_to_cpu(stats->min_operating_temp));
+ printf("Estimated offset : %"PRIu64"\n", le64_to_cpu(stats->est_offset));
+}
+
+static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct intel_temp_stats stats;
+ struct nvme_dev *dev;
+ int err;
+
+ const char *desc = "Get Temperature Statistics log and show it.";
+ const char *raw = "dump output in binary format";
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xc5, sizeof(stats), &stats);
+ if (!err) {
+ if (!cfg.raw_binary)
+ show_temp_stats(&stats);
+ else
+ d_raw((unsigned char *)&stats, sizeof(stats));
+ } else if (err > 0)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
+
+struct intel_lat_stats {
+ __u16 maj;
+ __u16 min;
+ __u32 data[1216];
+};
+
+struct __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
+#define OPTANE_V1000_BUCKET_LEN 8
+#define NAND_LAT_STATS_LEN 4868
+
+
+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,
+ S
+};
+
+/*
+ * COL_WIDTH controls width of columns in human-readable output.
+ * BUFSIZE is for local temp char[]
+ * US_IN_S and US_IN_MS are for unit conversions when printing.
+ */
+#define COL_WIDTH 12
+#define BUFSIZE 10
+#define US_IN_S 1000000
+#define US_IN_MS 1000
+
+static enum FormatUnit get_seconds_magnitude(__u32 microseconds)
+{
+ if (microseconds > US_IN_S)
+ return S;
+ else if (microseconds > US_IN_MS)
+ return MS;
+ else
+ return US;
+}
+
+static float convert_seconds(__u32 microseconds)
+{
+ float divisor = 1.0;
+
+ if (microseconds > US_IN_S)
+ divisor = US_IN_S;
+ else if (microseconds > US_IN_MS)
+ divisor = US_IN_MS;
+ return microseconds / divisor;
+}
+
+/*
+ * For control over whether a string will format to +/-INF or
+ * print out ####.##US normally.
+ */
+enum inf_bound_type {
+ NEGINF,
+ POSINF,
+ NOINF
+};
+
+/*
+ * Edge buckets may have range [#s, inf) or (-inf, #US] in some
+ * latency statistics formats.
+ * Passing in NEGINF to POSINF to bound_type overrides the string to
+ * either of "-INF" or "+INF", respectively.
+ */
+static void set_unit_string(char *buffer, __u32 microseconds,
+ enum FormatUnit unit,
+ enum inf_bound_type bound_type)
+{
+ char *string;
+
+ if (bound_type != NOINF) {
+ snprintf(buffer, BUFSIZE, "%s", bound_type ? "+INF" : "-INF");
+ return;
+ }
+
+ switch (unit) {
+ case US:
+ string = "us";
+ break;
+ case MS:
+ string = "ms";
+ break;
+ case S:
+ string = "s";
+ break;
+ default:
+ string = "_s";
+ break;
+ }
+
+ snprintf(buffer, BUFSIZE, "%4.2f%s", convert_seconds(microseconds),
+ string);
+}
+
+static void init_buffer(char *buffer, size_t size)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ buffer[i] = i + '0';
+}
+
+static void show_lat_stats_bucket(struct intel_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("%-*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, (unsigned long)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)
+{
+ for (int i = (start_offset / bytes_per) - 1;
+ i < end_offset / bytes_per; i++) {
+ if (nonzero_print && stats->data[i] == 0)
+ continue;
+ show_lat_stats_bucket(stats, us_step * i, NOINF,
+ us_step * (i + 1), NOINF, i);
+ }
+}
+
+/*
+ * For 4.0-4.5 revision.
+ */
+#define LATENCY_STATS_V4_BASE_BITS 6
+#define LATENCY_STATS_V4_BASE_VAL (1 << LATENCY_STATS_V4_BASE_BITS)
+
+static int lat_stats_log_scale(int i)
+{
+ // if (i < 128)
+ if (i < (LATENCY_STATS_V4_BASE_VAL << 1))
+ return i;
+
+ int error_bits = (i >> LATENCY_STATS_V4_BASE_BITS) - 1;
+ int base = 1 << (error_bits + LATENCY_STATS_V4_BASE_BITS);
+ int k = i % LATENCY_STATS_V4_BASE_VAL;
+
+ return base + ((k + 0.5) * (1 << error_bits));
+}
+
+/*
+ * Creates a subroot in the following manner:
+ * {
+ * "latstats" : {
+ * "type" : "write" or "read",
+ * "values" : {
+ */
+static void lat_stats_make_json_root(
+ struct json_object *root, struct json_object *bucket_list,
+ int write)
+{
+ struct json_object *subroot = json_create_object();
+
+ json_object_add_value_object(root, "latstats", subroot);
+ json_object_add_value_string(subroot, "type", write ? "write" : "read");
+ json_object_add_value_object(subroot, "values", bucket_list);
+}
+
+/*
+ * Creates a bucket under the "values" json_object. Format is:
+ * "values" : {
+ * "bucket" : {
+ * "id" : #,
+ * "start" : string,
+ * "end" : string,
+ * "value" : 0,
+ * },
+ */
+static void json_add_bucket(struct intel_lat_stats *stats,
+ 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_array_add(bucket_list, 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_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_array_add(bucket_list, 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,
+ __u32 us_step, bool nonzero_print)
+{
+ for (int i = (start_offset / bytes_per) - 1;
+ i < end_offset / bytes_per; i++) {
+ if (nonzero_print && stats->data[i] == 0)
+ continue;
+
+ json_add_bucket(stats, bucket_list,
+ i, us_step * i, NOINF, us_step * (i + 1),
+ NOINF, stats->data[i]);
+ }
+}
+
+static void json_lat_stats_3_0(struct intel_lat_stats *stats,
+ int write)
+{
+ struct json_object *root = json_create_object();
+ struct json_object *bucket_list = json_object_new_array();
+
+ lat_stats_make_json_root(root, bucket_list, write);
+
+ json_lat_stats_linear(stats, bucket_list, 4, 131, 4, 32, false);
+ json_lat_stats_linear(stats, bucket_list, 132, 255, 4, 1024, false);
+ json_lat_stats_linear(stats, bucket_list, 256, 379, 4, 32768, false);
+ json_lat_stats_linear(stats, bucket_list, 380, 383, 4, 32, true);
+ json_lat_stats_linear(stats, bucket_list, 384, 387, 4, 32, true);
+ json_lat_stats_linear(stats, bucket_list, 388, 391, 4, 32, true);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static void json_lat_stats_4_0(struct intel_lat_stats *stats,
+ int write)
+{
+ struct json_object *root = json_create_object();
+ struct json_object *bucket_list = json_object_new_array();
+
+ lat_stats_make_json_root(root, bucket_list, write);
+
+ __u32 lower_us = 0;
+ __u32 upper_us = 1;
+ bool end = false;
+ int max = 1216;
+
+ for (int i = 0; i < max; i++) {
+ lower_us = lat_stats_log_scale(i);
+ if (i >= max - 1)
+ end = true;
+ else
+ upper_us = lat_stats_log_scale(i + 1);
+
+ json_add_bucket(stats, bucket_list, i,
+ lower_us, NOINF, upper_us,
+ end ? POSINF : NOINF, stats->data[i]);
+ }
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static void show_lat_stats_3_0(struct intel_lat_stats *stats)
+{
+ show_lat_stats_linear(stats, 4, 131, 4, 32, false);
+ show_lat_stats_linear(stats, 132, 255, 4, 1024, false);
+ show_lat_stats_linear(stats, 256, 379, 4, 32768, false);
+ show_lat_stats_linear(stats, 380, 383, 4, 32, true);
+ show_lat_stats_linear(stats, 384, 387, 4, 32, true);
+ show_lat_stats_linear(stats, 388, 391, 4, 32, true);
+}
+
+static void show_lat_stats_4_0(struct intel_lat_stats *stats)
+{
+ int lower_us = 0;
+ int upper_us = 1;
+ bool end = false;
+ int max = 1216;
+
+ for (int i = 0; i < max; i++) {
+ lower_us = lat_stats_log_scale(i);
+ if (i >= max - 1)
+ end = true;
+ else
+ upper_us = lat_stats_log_scale(i + 1);
+
+ show_lat_stats_bucket(stats, lower_us, NOINF,
+ upper_us, end ? POSINF : NOINF, i);
+ }
+}
+
+static void json_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_object_new_array();
+
+ 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", (unsigned long)stats->data[8]);
+
+}
+
+static void json_lat_stats(int write)
+{
+ switch (media_version[MEDIA_MAJOR_IDX]) {
+ case 3:
+ json_lat_stats_3_0(&stats, write);
+ break;
+ case 4:
+ 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);
+ break;
+ default:
+ printf("Unsupported minor revision (%u.%u)\n",
+ stats.maj, stats.min);
+ break;
+ }
+ break;
+ case 1000:
+ switch (media_version[MEDIA_MINOR_IDX]) {
+ case 0:
+ json_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);
+ break;
+ }
+ printf("\n");
+}
+
+static void print_dash_separator(int count)
+{
+ for (int i = 0; i < count; i++)
+ putchar('-');
+ putchar('\n');
+}
+
+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",
+ 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 (media_version[MEDIA_MAJOR_IDX]) {
+ case 3:
+ show_lat_stats_3_0(&stats);
+ break;
+ case 4:
+ switch (media_version[MEDIA_MINOR_IDX]) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ show_lat_stats_4_0(&stats);
+ break;
+ default:
+ 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);
+ break;
+ }
+}
+
+static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ __u8 data[NAND_LAT_STATS_LEN];
+ struct nvme_dev *dev;
+ int err;
+
+ const char *desc = "Get Intel Latency Statistics log and show it.";
+ 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 {
+ bool raw_binary;
+ bool json;
+ bool write;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ /* For optate, latency stats are deleted every time their LID is pulled.
+ * Therefore, we query the longest lat_stats log page first.
+ */
+ err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1,
+ sizeof(data), &data);
+
+ media_version[0] = (data[1] << 8) | data[0];
+ media_version[1] = (data[3] << 8) | data[2];
+
+ if (err)
+ goto close_dev;
+
+ if (media_version[0] == 1000) {
+ __u32 thresholds[OPTANE_V1000_BUCKET_LEN] = {0};
+ __u32 result;
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = 0xf7,
+ .nsid = 0,
+ .sel = 0,
+ .cdw11 = cfg.write ? 0x1 : 0x0,
+ .uuidx = 0,
+ .data_len = sizeof(thresholds),
+ .data = thresholds,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_get_features(&args);
+ if (err) {
+ fprintf(stderr, "Querying thresholds failed. ");
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ /* 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];
+
+ }
+
+ /* Move counter values to optate stats struct which has a
+ * smaller size
+ */
+ memcpy(&v1000_stats, (struct optane_lat_stats *)data,
+ sizeof(struct optane_lat_stats));
+ } else {
+ memcpy(&stats, (struct intel_lat_stats *)data,
+ sizeof(struct intel_lat_stats));
+ }
+
+ if (cfg.json)
+ json_lat_stats(cfg.write);
+ else if (!cfg.raw_binary)
+ show_lat_stats(cfg.write);
+ else {
+ if (media_version[0] == 1000)
+ d_raw((unsigned char *)&v1000_stats,
+ sizeof(v1000_stats));
+ else
+ d_raw((unsigned char *)&stats,
+ sizeof(stats));
+ }
+
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
+struct intel_assert_dump {
+ __u32 coreoffset;
+ __u32 assertsize;
+ __u8 assertdumptype;
+ __u8 assertvalid;
+ __u8 reserved[2];
+};
+
+struct intel_event_dump {
+ __u32 numeventdumps;
+ __u32 coresize;
+ __u32 coreoffset;
+ __u32 eventidoffset[16];
+ __u8 eventIdValidity[16];
+};
+
+struct intel_vu_version {
+ __u16 major;
+ __u16 minor;
+};
+
+struct intel_event_header {
+ __u32 eventidsize;
+ struct intel_event_dump edumps[0];
+};
+
+struct intel_vu_log {
+ struct intel_vu_version ver;
+ __u32 header;
+ __u32 size;
+ __u32 numcores;
+ __u8 reserved[4080];
+};
+
+struct intel_vu_nlog {
+ struct intel_vu_version ver;
+ __u32 logselect;
+ __u32 totalnlogs;
+ __u32 nlognum;
+ __u32 nlogname;
+ __u32 nlogbytesize;
+ __u32 nlogprimarybuffsize;
+ __u32 tickspersecond;
+ __u32 corecount;
+ __u32 nlogpausestatus;
+ __u32 selectoffsetref;
+ __u32 selectnlogpause;
+ __u32 selectaddedoffset;
+ __u32 nlogbufnum;
+ __u32 nlogbufnummax;
+ __u32 coreselected;
+ __u32 reserved[3];
+};
+
+struct intel_cd_log {
+ union {
+ struct {
+ __u32 selectLog : 3;
+ __u32 selectCore : 2;
+ __u32 selectNlog : 8;
+ __u8 selectOffsetRef : 1;
+ __u32 selectNlogPause : 2;
+ __u32 reserved2 : 16;
+ } fields;
+ __u32 entireDword;
+ } u;
+};
+
+static void print_intel_nlog(struct intel_vu_nlog *intel_nlog)
+{
+ printf("Version Major %u\n"
+ "Version Minor %u\n"
+ "Log_select %u\n"
+ "totalnlogs %u\n"
+ "nlognum %u\n"
+ "nlogname %u\n"
+ "nlogbytesze %u\n"
+ "nlogprimarybuffsize %u\n"
+ "tickspersecond %u\n"
+ "corecount %u\n"
+ "nlogpausestatus %u\n"
+ "selectoffsetref %u\n"
+ "selectnlogpause %u\n"
+ "selectaddedoffset %u\n"
+ "nlogbufnum %u\n"
+ "nlogbufnummax %u\n"
+ "coreselected %u\n",
+ intel_nlog->ver.major, intel_nlog->ver.minor,
+ intel_nlog->logselect, intel_nlog->totalnlogs, intel_nlog->nlognum,
+ intel_nlog->nlogname, intel_nlog->nlogbytesize,
+ intel_nlog->nlogprimarybuffsize, intel_nlog->tickspersecond,
+ intel_nlog->corecount, intel_nlog->nlogpausestatus,
+ intel_nlog->selectoffsetref, intel_nlog->selectnlogpause,
+ intel_nlog->selectaddedoffset, intel_nlog->nlogbufnum,
+ intel_nlog->nlogbufnummax, intel_nlog->coreselected);
+}
+
+static int read_entire_cmd(struct nvme_passthru_cmd *cmd, int total_size,
+ const size_t max_tfer, int out_fd, int ioctl_fd,
+ __u8 *buf)
+{
+ int err = 0;
+ size_t dword_tfer = 0;
+
+ dword_tfer = min(max_tfer, total_size);
+ while (total_size > 0) {
+ err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL);
+ if (err) {
+ fprintf(stderr,
+ "failed on cmd.data_len %u cmd.cdw13 %u cmd.cdw12 %x cmd.cdw10 %u err %x remaining size %d\n",
+ cmd->data_len, cmd->cdw13, cmd->cdw12,
+ cmd->cdw10, err, total_size);
+ goto out;
+ }
+
+ if (out_fd > 0) {
+ err = write(out_fd, buf, cmd->data_len);
+ if (err < 0) {
+ perror("write failure");
+ goto out;
+ }
+ err = 0;
+ }
+ total_size -= dword_tfer;
+ cmd->cdw13 += dword_tfer;
+ cmd->cdw10 = dword_tfer = min(max_tfer, total_size);
+ cmd->data_len = (min(max_tfer, total_size)) * 4;
+ }
+
+ out:
+ return err;
+}
+
+static int write_header(__u8 *buf, int fd, size_t amnt)
+{
+ if (write(fd, buf, amnt) < 0)
+ return 1;
+ return 0;
+}
+
+static int read_header(struct nvme_passthru_cmd *cmd, __u8 *buf, int ioctl_fd,
+ __u32 dw12, int nsid)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ memset(buf, 0, 4096);
+ cmd->opcode = 0xd2;
+ cmd->nsid = nsid;
+ cmd->cdw10 = 0x400;
+ cmd->cdw12 = dw12;
+ cmd->data_len = 0x1000;
+ cmd->addr = (unsigned long)(void *)buf;
+ return read_entire_cmd(cmd, 0x400, 0x400, -1, ioctl_fd, buf);
+}
+
+static int setup_file(char *f, char *file, int fd, int type)
+{
+ struct nvme_id_ctrl ctrl;
+ int err = 0, i = sizeof(ctrl.sn) - 1;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ return err;
+
+ /* Remove trailing spaces from the name */
+ while (i && ctrl.sn[i] == ' ') {
+ ctrl.sn[i] = '\0';
+ i--;
+ }
+
+ sprintf(f, "%s_%-.*s.bin", type == 0 ? "Nlog" :
+ type == 1 ? "EventLog" : "AssertLog",
+ (int)sizeof(ctrl.sn), ctrl.sn);
+ return err;
+}
+
+static int get_internal_log_old(__u8 *buf, int output, int fd,
+ struct nvme_passthru_cmd *cmd)
+{
+ struct intel_vu_log *intel;
+ int err = 0;
+ const int dwmax = 0x400;
+ const int dmamax = 0x1000;
+
+ intel = (struct intel_vu_log *)buf;
+
+ printf("Log major:%d minor:%d header:%d size:%d\n",
+ intel->ver.major, intel->ver.minor, intel->header, intel->size);
+
+ err = write(output, buf, 0x1000);
+ if (err < 0) {
+ perror("write failure");
+ goto out;
+ }
+ intel->size -= 0x400;
+ cmd->opcode = 0xd2;
+ cmd->cdw10 = min(dwmax, intel->size);
+ cmd->data_len = min(dmamax, intel->size);
+ err = read_entire_cmd(cmd, intel->size, dwmax, output, fd, buf);
+ if (err)
+ goto out;
+
+ err = 0;
+ out:
+ return err;
+}
+
+static int get_internal_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ __u8 buf[0x2000];
+ char f[0x100];
+ int err, output, i, j, count = 0, core_num = 1;
+ struct nvme_passthru_cmd cmd;
+ struct intel_cd_log cdlog;
+ struct intel_vu_log *intel = malloc(sizeof(struct intel_vu_log));
+ struct intel_vu_nlog *intel_nlog = (struct intel_vu_nlog *)buf;
+ struct intel_assert_dump *ad = (struct intel_assert_dump *) intel->reserved;
+ struct intel_event_header *ehdr = (struct intel_event_header *)intel->reserved;
+ struct nvme_dev *dev;
+
+ const char *desc = "Get Intel Firmware Log and save it.";
+ const char *log = "Log type: 0, 1, or 2 for nlog, event log, and assert log, respectively.";
+ const char *core = "Select which region log should come from. -1 for all";
+ const char *nlognum = "Select which nlog to read. -1 for all nlogs";
+ const char *file = "Output file; defaults to device name provided";
+ const char *verbose = "To print out verbose nlog info";
+ const char *namespace_id = "Namespace to get logs from";
+
+ struct config {
+ __u32 namespace_id;
+ __u32 log;
+ int core;
+ int lnum;
+ char *file;
+ bool verbose;
+ };
+
+ struct config cfg = {
+ .namespace_id = -1,
+ .file = NULL,
+ .lnum = -1,
+ .core = -1
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log", 'l', &cfg.log, log),
+ OPT_INT("region", 'r', &cfg.core, core),
+ OPT_INT("nlognum", 'm', &cfg.lnum, nlognum),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_FLAG("verbose-nlog", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ free(intel);
+ return err;
+ }
+
+ if (cfg.log > 2 || cfg.core > 4 || cfg.lnum > 255) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ if (!cfg.file) {
+ err = setup_file(f, cfg.file, dev_fd(dev), cfg.log);
+ if (err)
+ goto out_free;
+ cfg.file = f;
+ }
+
+ cdlog.u.entireDword = 0;
+
+ cdlog.u.fields.selectLog = cfg.log;
+ cdlog.u.fields.selectCore = cfg.core < 0 ? 0 : cfg.core;
+ cdlog.u.fields.selectNlog = cfg.lnum < 0 ? 0 : cfg.lnum;
+
+ output = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ err = output;
+ goto out_free;
+ }
+
+ err = read_header(&cmd, buf, dev_fd(dev), cdlog.u.entireDword,
+ cfg.namespace_id);
+ if (err)
+ goto out;
+ memcpy(intel, buf, sizeof(*intel));
+
+ /* for 1.1 Fultondales will use old nlog, but current assert/event */
+ if ((intel->ver.major < 1 && intel->ver.minor < 1) ||
+ (intel->ver.major <= 1 && intel->ver.minor <= 1 && cfg.log == 0)) {
+ cmd.addr = (unsigned long)(void *)buf;
+ err = get_internal_log_old(buf, output, dev_fd(dev), &cmd);
+ goto out;
+ }
+
+ if (cfg.log == 2) {
+ if (cfg.verbose)
+ printf("Log major:%d minor:%d header:%d size:%d numcores:%d\n",
+ intel->ver.major, intel->ver.minor,
+ intel->header, intel->size, intel->numcores);
+
+ err = write_header(buf, output, 0x1000);
+ if (err) {
+ perror("write failure");
+ goto out;
+ }
+
+ count = intel->numcores;
+ } else if (cfg.log == 0) {
+ if (cfg.lnum < 0)
+ count = intel_nlog->totalnlogs;
+ else
+ count = 1;
+ if (cfg.core < 0)
+ core_num = intel_nlog->corecount;
+ } else if (cfg.log == 1) {
+ core_num = intel->numcores;
+ count = 1;
+ err = write_header(buf, output, sizeof(*intel));
+ if (err)
+ goto out;
+ }
+
+ for (j = (cfg.core < 0 ? 0 : cfg.core);
+ j < (cfg.core < 0 ? core_num : cfg.core + 1);
+ j++) {
+ cdlog.u.fields.selectCore = j;
+ for (i = 0; i < count; i++) {
+ if (cfg.log == 2) {
+ if (!ad[i].assertvalid)
+ continue;
+ cmd.cdw13 = ad[i].coreoffset;
+ cmd.cdw10 = 0x400;
+ cmd.data_len = min(0x400, ad[i].assertsize) * 4;
+ err = read_entire_cmd(&cmd, ad[i].assertsize,
+ 0x400, output,
+ dev_fd(dev),
+ buf);
+ if (err)
+ goto out;
+
+ } else if (cfg.log == 0) {
+ /* If the user selected to read the entire nlog */
+ if (count > 1)
+ cdlog.u.fields.selectNlog = i;
+
+ err = read_header(&cmd, buf, dev_fd(dev),
+ cdlog.u.entireDword,
+ cfg.namespace_id);
+ if (err)
+ goto out;
+ err = write_header(buf, output, sizeof(*intel_nlog));
+ if (err)
+ goto out;
+ if (cfg.verbose)
+ print_intel_nlog(intel_nlog);
+ cmd.cdw13 = 0x400;
+ cmd.cdw10 = 0x400;
+ cmd.data_len = min(0x1000, intel_nlog->nlogbytesize);
+ err = read_entire_cmd(&cmd, intel_nlog->nlogbytesize / 4,
+ 0x400, output,
+ dev_fd(dev),
+ buf);
+ if (err)
+ goto out;
+ } else if (cfg.log == 1) {
+ cmd.cdw13 = ehdr->edumps[j].coreoffset;
+ cmd.cdw10 = 0x400;
+ cmd.data_len = 0x400;
+ err = read_entire_cmd(&cmd, ehdr->edumps[j].coresize,
+ 0x400, output,
+ dev_fd(dev),
+ buf);
+ if (err)
+ goto out;
+ }
+ }
+ }
+ err = 0;
+out:
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ perror("intel log");
+ err = EIO;
+ } else
+ printf("Successfully wrote log to %s\n", cfg.file);
+ close(output);
+out_free:
+ free(intel);
+ dev_close(dev);
+ return err;
+}
+
+static int enable_lat_stats_tracking(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = (
+ "Enable/Disable Intel 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;
+ struct nvme_dev *dev;
+ void *buf = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ bool enable, disable;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .disable = false,
+ };
+
+ struct argconfig_commandline_options command_line_options[] = {
+ {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc},
+ {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc},
+ {NULL}
+ };
+
+ err = parse_and_open(&dev, 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 (err)
+ return err;
+
+ struct nvme_get_features_args args_get = {
+ .args_size = sizeof(args_get),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = sel,
+ .cdw11 = cdw11,
+ .uuidx = 0,
+ .data_len = data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ struct nvme_set_features_args args_set = {
+ .args_size = sizeof(args_set),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = option,
+ .cdw12 = cdw12,
+ .save = save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ switch (option) {
+ case None:
+ err = nvme_get_features(&args_get);
+ if (!err) {
+ printf(
+ "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
+ fid, result);
+ } else {
+ printf("Could not read feature id 0xE2.\n");
+ dev_close(dev);
+ return err;
+ }
+ break;
+ case True:
+ case False:
+ err = nvme_set_features(&args_set);
+ if (err > 0) {
+ nvme_show_status(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;
+ }
+ dev_close(dev);
+ return err;
+}
+
+static int set_lat_stats_thresholds(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ 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;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err, num;
+
+ struct config {
+ bool write;
+ char *bucket_thresholds;
+ };
+
+ struct config cfg = {
+ .write = false,
+ .bucket_thresholds = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_LIST("bucket-thresholds", 't', &cfg.bucket_thresholds,
+ bucket_thresholds),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+
+ if (err)
+ return err;
+
+ /* 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_simple(dev_fd(dev), 0xc2,
+ sizeof(media_version), media_version);
+ if (err) {
+ fprintf(stderr, "Querying media version failed. ");
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ 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_dev;
+
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = cfg.write ? 0x1 : 0x0,
+ .cdw12 = cdw12,
+ .save = save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = sizeof(thresholds),
+ .data = thresholds,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ }
+ } else {
+ fprintf(stderr, "Unsupported command\n");
+ }
+
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h
new file mode 100644
index 0000000..165048a
--- /dev/null
+++ b/plugins/intel/intel-nvme.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/intel/intel-nvme
+
+#if !defined(INTEL_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define INTEL_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("intel", "Intel vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ ENTRY("internal-log", "Retrieve Intel internal firmware log, save it", get_internal_log)
+ 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)
+ ENTRY("temp-stats", "Retrieve Intel Temperature Statistics log, show it", get_temp_stats_log)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/memblaze/memblaze-nvme.c b/plugins/memblaze/memblaze-nvme.c
new file mode 100644
index 0000000..b215125
--- /dev/null
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -0,0 +1,1842 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "nvme.h"
+#include "common.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "memblaze-nvme.h"
+#include "memblaze-utils.h"
+
+enum {
+ /* 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
+ * Return 1 if @fw1 > @fw2
+ */
+static int compare_fw_version(const char *fw1, const char *fw2)
+{
+ while (*fw1 != '\0') {
+ if (*fw2 == '\0' || *fw1 > *fw2)
+ return 1;
+ if (*fw1 < *fw2)
+ return -1;
+ fw1++;
+ fw2++;
+ }
+
+ if (*fw2 != '\0')
+ return -1;
+
+ return 0;
+}
+
+/**********************************************************
+ * input: firmware version string
+ * output:
+ * 1: new intel format
+ * 0: old memblaze format
+ * *******************************************************/
+#define MEMBLAZE_FORMAT (0)
+#define INTEL_FORMAT (1)
+
+/* 2.13 = papaya */
+#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
+/* 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 *model_name)
+{
+ int logpage_format_type = INTEL_FORMAT;
+ const char *boundary_model_name1 = "P"; /* MEMBLAZE P7936DT0640M00 */
+ const char *boundary_model_name2 = "P5920"; /* Use INTEL_FORMAT from Raisin P5920. */
+
+ if (!strncmp(model_name, boundary_model_name1, strlen(boundary_model_name1))) {
+ if (strncmp(model_name, boundary_model_name2, strlen(boundary_model_name2)) < 0)
+ logpage_format_type = MEMBLAZE_FORMAT;
+ }
+ return logpage_format_type;
+}
+
+static __u32 item_id_2_u32(struct nvme_memblaze_smart_log_item *item)
+{
+ __le32 __id = 0;
+
+ memcpy(&__id, item->id, 3);
+ return le32_to_cpu(__id);
+}
+
+static __u64 raw_2_u64(const __u8 *buf, size_t len)
+{
+ __le64 val = 0;
+
+ memcpy(&val, buf, len);
+ return le64_to_cpu(val);
+}
+
+static void get_memblaze_new_smart_info(struct nvme_p4_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 void show_memblaze_smart_log_new(struct nvme_memblaze_smart_log *s,
+ unsigned int nsid, const char *devname)
+{
+ struct nvme_p4_smart_log *smart = (struct nvme_p4_smart_log *)s;
+ __u8 *nm = malloc(NM_SIZE * sizeof(__u8));
+ __u8 *raw = malloc(RAW_SIZE * sizeof(__u8));
+
+ if (!nm) {
+ if (raw)
+ free(raw);
+ return;
+ }
+ if (!raw) {
+ free(nm);
+ return;
+ }
+
+ printf("%s:%s %s:%x\n", "Additional Smart Log for NVME device", devname, "namespace-id", nsid);
+ printf("%-34s%-11s%s\n", "key", "normalized", "raw");
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PROGRAM_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "program_fail_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_ERASE_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "erase_fail_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_WEARLEVELING_COUNT, nm, raw);
+ printf("%-31s : %3d%% %s%u%s%u%s%u\n", "wear_leveling", *nm,
+ "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_E2E_DECTECTION_COUNT, nm, raw);
+ printf("%-31s: %3d%% %"PRIu64"\n", "end_to_end_error_detection_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PCIE_CRC_ERR_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "crc_error_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR, nm, raw);
+ printf("%-32s: %3d%% %.3f%%\n", "timed_workload_media_wear", *nm, ((float)int48_to_long(raw))/1000);
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"%%\n", "timed_workload_host_reads", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_TIMER, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"%s\n", "timed_workload_timer", *nm, int48_to_long(raw), " min");
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
+ printf("%-32s: %3d%% %u%%%s%"PRIu64"\n", "thermal_throttle_status", *nm,
+ *raw, ", cnt: ", int48_to_long(raw+1));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "retry_buffer_overflow_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "pll_lock_loss_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_WRITE, nm, raw);
+ printf("%-32s: %3d%% %s%"PRIu64"\n", "nand_bytes_written", *nm, "sectors: ", int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_HOST_WRITE, nm, raw);
+ printf("%-32s: %3d%% %s%"PRIu64"\n", "host_bytes_written", *nm, "sectors: ", int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "system_area_life_left", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_READ, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "total_read", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BORN, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_born", *nm,
+ "max: ", *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_POWER_CONSUMPTION, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", "power_consumption", *nm,
+ "max: ", *(__u16 *)raw, ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BOOTUP, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", "tempt_since_bootup", *nm, "max: ", *(__u16 *)raw,
+ ", min: ", *(__u16 *)(raw+2), ", curr: ", *(__u16 *)(raw+4));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_READ_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "read_fail_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_TIME, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "thermal_throttle_time", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_FLASH_MEDIA_ERROR, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", "flash_media_error", *nm, int48_to_long(raw));
+
+ free(nm);
+ free(raw);
+}
+
+static void show_memblaze_smart_log_old(struct nvme_memblaze_smart_log *smart,
+ unsigned int nsid, const char *devname, const char *fw_ver)
+{
+ char fw_ver_local[STR_VER_SIZE + 1];
+ struct nvme_memblaze_smart_log_item *item;
+
+ strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
+ *(fw_ver_local + STR_VER_SIZE) = '\0';
+
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
+
+ printf("Total write in GB since last factory reset : %"PRIu64"\n",
+ int48_to_long(smart->items[TOTAL_WRITE].rawval));
+ printf("Total read in GB since last factory reset : %"PRIu64"\n",
+ int48_to_long(smart->items[TOTAL_READ].rawval));
+
+ printf("Thermal throttling status[1:HTP in progress] : %u\n",
+ smart->items[THERMAL_THROTTLE].thermal_throttle.on);
+ printf("Total thermal throttling minutes since power on : %u\n",
+ smart->items[THERMAL_THROTTLE].thermal_throttle.count);
+
+ printf("Maximum temperature in kelvins since last factory reset : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.max));
+ printf("Minimum temperature in kelvins since last factory reset : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.min));
+ if (compare_fw_version(fw_ver, "0.09.0300") != 0) {
+ printf("Maximum temperature in kelvins since power on : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.max));
+ printf("Minimum temperature in kelvins since power on : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.min));
+ }
+ printf("Current temperature in kelvins : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.curr));
+
+ printf("Maximum power in watt since power on : %u\n",
+ le16_to_cpu(smart->items[POWER_CONSUMPTION].power.max));
+ printf("Minimum power in watt since power on : %u\n",
+ le16_to_cpu(smart->items[POWER_CONSUMPTION].power.min));
+ printf("Current power in watt : %u\n",
+ le16_to_cpu(smart->items[POWER_CONSUMPTION].power.curr));
+
+ item = &smart->items[POWER_LOSS_PROTECTION];
+ if (item_id_2_u32(item) == 0xEC)
+ printf("Power loss protection normalized value : %u\n",
+ item->power_loss_protection.curr);
+
+ item = &smart->items[WEARLEVELING_COUNT];
+ if (item_id_2_u32(item) == 0xAD) {
+ printf("Percentage of wearleveling count left : %u\n",
+ le16_to_cpu(item->nmval));
+ printf("Wearleveling count min erase cycle : %u\n",
+ le16_to_cpu(item->wearleveling_count.min));
+ printf("Wearleveling count max erase cycle : %u\n",
+ le16_to_cpu(item->wearleveling_count.max));
+ printf("Wearleveling count avg erase cycle : %u\n",
+ le16_to_cpu(item->wearleveling_count.avg));
+ }
+
+ item = &smart->items[HOST_WRITE];
+ if (item_id_2_u32(item) == 0xF5)
+ printf("Total host write in GiB since device born : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[THERMAL_THROTTLE_CNT];
+ if (item_id_2_u32(item) == 0xEB)
+ printf("Thermal throttling count since device born : %u\n",
+ item->thermal_throttle_cnt.cnt);
+
+ item = &smart->items[CORRECT_PCIE_PORT0];
+ if (item_id_2_u32(item) == 0xED)
+ printf("PCIE Correctable Error Count of Port0 : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[CORRECT_PCIE_PORT1];
+ if (item_id_2_u32(item) == 0xEE)
+ printf("PCIE Correctable Error Count of Port1 : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[REBUILD_FAIL];
+ if (item_id_2_u32(item) == 0xEF)
+ printf("End-to-End Error Detection Count : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[ERASE_FAIL];
+ if (item_id_2_u32(item) == 0xF0)
+ printf("Erase Fail Count : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[PROGRAM_FAIL];
+ if (item_id_2_u32(item) == 0xF1)
+ printf("Program Fail Count : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ item = &smart->items[READ_FAIL];
+ if (item_id_2_u32(item) == 0xF2)
+ printf("Read Fail Count : %llu\n",
+ (unsigned long long)raw_2_u64(item->rawval, sizeof(item->rawval)));
+
+ if (IS_PAPAYA(fw_ver_local)) {
+ struct nvme_p4_smart_log *s = (struct nvme_p4_smart_log *)smart;
+ __u8 *nm = malloc(NM_SIZE * sizeof(__u8));
+ __u8 *raw = malloc(RAW_SIZE * sizeof(__u8));
+
+ if (!nm) {
+ if (raw)
+ free(raw);
+ return;
+ }
+ if (!raw) {
+ free(nm);
+ return;
+ }
+ get_memblaze_new_smart_info(s, PROGRAM_FAIL, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ "program_fail_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(s, ERASE_FAIL, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ "erase_fail_count", *nm, int48_to_long(raw));
+
+ get_memblaze_new_smart_info(s, WEARLEVELING_COUNT, nm, raw);
+ printf("%-31s : %3d%% %s%u%s%u%s%u\n",
+ "wear_leveling", *nm, "min: ", *(__u16 *)raw, ", max: ", *(__u16 *)(raw+2), ", avg: ", *(__u16 *)(raw+4));
+
+ get_memblaze_new_smart_info(s, TOTAL_WRITE, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ "nand_bytes_written", *nm, 32*int48_to_long(raw));
+
+ get_memblaze_new_smart_info(s, HOST_WRITE, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ "host_bytes_written", *nm, 32*int48_to_long(raw));
+
+ free(nm);
+ free(raw);
+ }
+}
+
+static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname,
+ struct nvme_memblaze_smart_log *smart)
+{
+ struct nvme_id_ctrl ctrl;
+ char fw_ver[10];
+ int err = 0;
+
+ 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]);
+
+ if (getlogpage_format_type(ctrl.mn)) /* Intel Format & new format */
+ show_memblaze_smart_log_new(smart, nsid, devname);
+ else /* Memblaze Format & old format */
+ show_memblaze_smart_log_old(smart, nsid, devname, fw_ver);
+ return err;
+}
+
+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) {
+ printf("No enough parameters. abort...\n");
+ va_end(argp);
+ return 1;
+ }
+
+ if (!isalnum((int)*c)) {
+ printf("%s is not a valid number\n", c);
+ va_end(argp);
+ 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;
+ char *desc =
+ "Get Memblaze 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 nvme_dev *dev;
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ };
+ int err;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ err = show_memblaze_smart_log(dev_fd(dev), cfg.namespace_id, dev->name,
+ &smart_log);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ if (err > 0)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+static char *mb_feature_to_string(int feature)
+{
+ 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 mb_get_powermanager_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get Memblaze power management ststus\n (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ __u32 result;
+ __u32 feature_id = MB_FEAT_POWER_MGMT;
+ struct nvme_dev *dev;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = feature_id,
+ .nsid = 0,
+ .sel = 0,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_get_features(&args);
+ 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)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
+
+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";
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u32 feature_id;
+ __u32 value;
+ bool 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = 0,
+ .cdw11 = cfg.value,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ 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)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+#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 = "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 param1 = 0, param2 = 0;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (parse_params(cfg.param, 2, &param1, &param2)) {
+ printf("setfeature: invalid formats %s\n", cfg.param);
+ dev_close(dev);
+ return -EINVAL;
+ }
+ if ((param1 == 1) && (param2 < P2MIN || param2 > P2MAX)) {
+ printf("setfeature: invalid high io latency threshold %d\n", param2);
+ dev_close(dev);
+ return -EINVAL;
+ }
+ cfg.value = (param1 << MB_FEAT_HIGH_LATENCY_VALUE_SHIFT) | param2;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = 0,
+ .cdw11 = cfg.value,
+ .cdw12 = 0,
+ .save = false,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ 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)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+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;
+}
+
+/*
+ * High latency log page definition
+ * Total 32 bytes
+ */
+struct log_page_high_latency {
+ __u8 port;
+ __u8 revision;
+ __u16 rsvd;
+ __u8 opcode;
+ __u8 sqe;
+ __u16 cid;
+ __u32 nsid;
+ __u32 latency;
+ __u64 sLBA;
+ __u16 numLBA;
+ __u16 timestampH;
+ __u32 timestampL;
+}; /* 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;
+}
+
+#define TIME_STR_SIZE (44)
+static int glp_high_latency(FILE *fdi, char *buf, int buflen, int print)
+{
+ struct log_page_high_latency *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(struct log_page_high_latency);
+ for (i = 0; i < buflen; i += entrySize) {
+ logEntry = (struct log_page_high_latency *)(buf + i);
+
+ if (logEntry->latency == 0 && logEntry->revision == 0)
+ return 1;
+
+ if (!logEntry->timestampH) { /* generate host time string */
+ snprintf(string, sizeof(string), "%d", logEntry->timestampL);
+ } else { /* sort */
+ timestamp = logEntry->timestampH;
+ 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);
+ }
+
+ if (fdi)
+ 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;
+}
+
+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";
+ char buf[LOG_PAGE_SIZE];
+ struct nvme_dev *dev;
+ FILE *fdi = NULL;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ fdi = fopen(FID_C3_LOG_FILENAME, "w+");
+
+ glp_high_latency_show_bar(fdi, DO_PRINT_FLAG);
+ err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG,
+ sizeof(buf), &buf);
+
+ while (1) {
+ if (!glp_high_latency(fdi, buf, LOG_PAGE_SIZE, DO_PRINT_FLAG))
+ break;
+ err = nvme_get_log_simple(dev_fd(dev), GLP_ID_VU_GET_HIGH_LATENCY_LOG,
+ sizeof(buf), &buf);
+ if (err) {
+ nvme_show_status(err);
+ break;
+ }
+ }
+
+ if (fdi)
+ fclose(fdi);
+ dev_close(dev);
+ return err;
+}
+
+static int memblaze_fw_commit(int fd, int select)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_fw_commit,
+ .cdw10 = 8,
+ .cdw12 = select,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+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\n"
+ "select which firmware binary to update for 9200 devices. This requires a power cycle once the\n"
+ "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=OOB, EEP, ALL)";
+ int xfer = 4096;
+ void *fw_buf;
+ int selectNo, fw_fd, fw_size, err, offset = 0;
+ struct nvme_dev *dev;
+ struct stat sb;
+ int i;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (strlen(cfg.select) != 3) {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < 3; i++)
+ cfg.select[i] = toupper(cfg.select[i]);
+
+ if (!strncmp(cfg.select, "OOB", 3)) {
+ selectNo = 18;
+ } else if (!strncmp(cfg.select, "EEP", 3)) {
+ selectNo = 10;
+ } else if (!strncmp(cfg.select, "ALL", 3)) {
+ 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;
+ goto out_close;
+ }
+
+ 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_close;
+ }
+
+ if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
+ fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ err = ENOMEM;
+ goto out_close;
+ }
+
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
+ err = errno;
+ goto out_free;
+ }
+
+ while (fw_size > 0) {
+ xfer = min(xfer, fw_size);
+
+ struct nvme_fw_download_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .offset = offset,
+ .data_len = xfer,
+ .data = fw_buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_fw_download(&args);
+ if (err < 0) {
+ perror("fw-download");
+ goto out_free;
+ } else if (err != 0) {
+ nvme_show_status(err);
+ goto out_free;
+ }
+ fw_buf += xfer;
+ fw_size -= xfer;
+ offset += xfer;
+ }
+
+ err = memblaze_fw_commit(dev_fd(dev), selectNo);
+
+ if (err == 0x10B || err == 0x20B) {
+ err = 0;
+ fprintf(stderr, "Update successful! Please power cycle for changes to take effect\n");
+ }
+
+out_free:
+ free(fw_buf);
+out_close:
+ close(fw_fd);
+out:
+ dev_close(dev);
+ 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];
+
+ snprintf(subString0, sizeof(subString0), "%d%s", start, unit0);
+ if (end != 0x7FFFFFFF)
+ snprintf(subString1, sizeof(subString1), "%d%s", end, unit1);
+ else
+ 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");
+ }
+
+ if (fdi)
+ 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];
+ char f1[] = FID_C1_LOG_FILENAME;
+ char f2[] = FID_C2_LOG_FILENAME;
+ struct nvme_dev *dev;
+ int err;
+
+ const char *desc = "Get Latency Statistics log and show it.";
+ const char *write = "Get write statistics (read default)";
+
+ struct config {
+ bool write;
+ };
+ struct config cfg = {
+ .write = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc2 : 0xc1,
+ 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
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+static int memblaze_clear_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "Clear Memblaze devices error log.";
+ struct nvme_dev *dev;
+ int err;
+
+ __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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = 0,
+ .cdw11 = cfg.value,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ 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)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+static int mb_set_lat_stats(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ 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;
+ struct nvme_dev *dev;
+ void *buf = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ bool enable, disable;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .disable = false,
+ };
+
+ struct argconfig_commandline_options command_line_options[] = {
+ {"enable", 'e', "", CFG_FLAG, &cfg.enable, no_argument, enable_desc},
+ {"disable", 'd', "", CFG_FLAG, &cfg.disable, no_argument, disable_desc},
+ {NULL}
+ };
+
+ err = parse_and_open(&dev, 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;
+
+ struct nvme_get_features_args args_get = {
+ .args_size = sizeof(args_get),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = sel,
+ .cdw11 = cdw11,
+ .uuidx = 0,
+ .data_len = data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ struct nvme_set_features_args args_set = {
+ .args_size = sizeof(args_set),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = option,
+ .cdw12 = cdw12,
+ .save = save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ if (err)
+ return err;
+ switch (option) {
+ case None:
+ err = nvme_get_features(&args_get);
+ if (!err) {
+ printf(
+ "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
+ fid, result);
+ } else {
+ printf("Could not read feature id 0xE2.\n");
+ dev_close(dev);
+ return err;
+ }
+ break;
+ case True:
+ case False:
+ err = nvme_set_features(&args_set);
+ if (err > 0) {
+ nvme_show_status(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",
+ 0xe2, option);
+ }
+ break;
+ default:
+ printf("%d not supported.\n", option);
+ err = EINVAL;
+ }
+ dev_close(dev);
+ return err;
+}
+
+// Global definitions
+
+static inline int K2C(int k) // KELVINS_2_CELSIUS
+{
+ return (k - 273);
+};
+
+// Global ID definitions
+
+enum {
+ // feature ids
+ FID_LATENCY_FEATURE = 0xd0,
+
+ // log ids
+ LID_SMART_LOG_ADD = 0xca,
+ LID_LATENCY_STATISTICS = 0xd0,
+ LID_HIGH_LATENCY_LOG = 0xd1,
+ LID_PERFORMANCE_STATISTICS = 0xd2,
+};
+
+// smart-log-add
+
+struct smart_log_add_item {
+ uint32_t index;
+ char *attr;
+};
+
+struct __packed wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+};
+
+struct __packed smart_log_add_item_12 {
+ uint8_t id;
+ uint8_t rsvd[2];
+ uint8_t norm;
+ uint8_t rsvd1;
+ union {
+ struct wear_level wear_level; // 0xad
+ struct temp_since_born { // 0xe7
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } temp_since_born;
+ struct power_consumption { // 0xe8
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } power_consumption;
+ struct temp_since_power_on { // 0xaf
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } temp_since_power_on;
+ uint8_t raw[6];
+ };
+ uint8_t rsvd2;
+};
+
+struct __packed smart_log_add_item_10 {
+ uint8_t id;
+ uint8_t norm;
+ union {
+ struct wear_level wear_level; // 0xad
+ uint8_t raw[6];
+ };
+ uint8_t rsvd[2];
+};
+
+struct smart_log_add {
+ union {
+ union {
+ struct smart_log_add_v0 {
+ struct smart_log_add_item_12 program_fail_count;
+ struct smart_log_add_item_12 erase_fail_count;
+ struct smart_log_add_item_12 wear_leveling_count;
+ struct smart_log_add_item_12 end_to_end_error_count;
+ struct smart_log_add_item_12 crc_error_count;
+ struct smart_log_add_item_12 timed_workload_media_wear;
+ struct smart_log_add_item_12 timed_workload_host_reads;
+ struct smart_log_add_item_12 timed_workload_timer;
+ struct smart_log_add_item_12 thermal_throttle_status;
+ struct smart_log_add_item_12 retry_buffer_overflow_counter;
+ struct smart_log_add_item_12 pll_lock_loss_count;
+ struct smart_log_add_item_12 nand_bytes_written;
+ struct smart_log_add_item_12 host_bytes_written;
+ struct smart_log_add_item_12 system_area_life_remaining;
+ struct smart_log_add_item_12 nand_bytes_read;
+ struct smart_log_add_item_12 temperature;
+ struct smart_log_add_item_12 power_consumption;
+ struct smart_log_add_item_12 power_on_temperature;
+ struct smart_log_add_item_12 power_loss_protection;
+ struct smart_log_add_item_12 read_fail_count;
+ struct smart_log_add_item_12 thermal_throttle_time;
+ struct smart_log_add_item_12 flash_error_media_count;
+ } v0;
+
+ struct smart_log_add_item_12 v0_raw[22];
+ };
+
+ union {
+ struct smart_log_add_v2 {
+ struct smart_log_add_item_12 program_fail_count;
+ struct smart_log_add_item_12 erase_fail_count;
+ struct smart_log_add_item_12 wear_leveling_count;
+ struct smart_log_add_item_12 end_to_end_error_count;
+ struct smart_log_add_item_12 crc_error_count;
+ struct smart_log_add_item_12 timed_workload_media_wear;
+ struct smart_log_add_item_12 timed_workload_host_reads;
+ struct smart_log_add_item_12 timed_workload_timer;
+ struct smart_log_add_item_12 thermal_throttle_status;
+ struct smart_log_add_item_12 lifetime_write_amplification;
+ struct smart_log_add_item_12 pll_lock_loss_count;
+ struct smart_log_add_item_12 nand_bytes_written;
+ struct smart_log_add_item_12 host_bytes_written;
+ struct smart_log_add_item_12 system_area_life_remaining;
+ struct smart_log_add_item_12 firmware_update_count;
+ struct smart_log_add_item_12 dram_cecc_count;
+ struct smart_log_add_item_12 dram_uecc_count;
+ struct smart_log_add_item_12 xor_pass_count;
+ struct smart_log_add_item_12 xor_fail_count;
+ struct smart_log_add_item_12 xor_invoked_count;
+ struct smart_log_add_item_12 inflight_read_io_cmd;
+ struct smart_log_add_item_12 flash_error_media_count;
+ struct smart_log_add_item_12 nand_bytes_read;
+ struct smart_log_add_item_12 temp_since_born;
+ struct smart_log_add_item_12 power_consumption;
+ struct smart_log_add_item_12 temp_since_bootup;
+ struct smart_log_add_item_12 thermal_throttle_time;
+ } v2;
+
+ struct smart_log_add_item_12 v2_raw[27];
+ };
+
+ union {
+ struct smart_log_add_v3 {
+ struct smart_log_add_item_10 program_fail_count;
+ struct smart_log_add_item_10 erase_fail_count;
+ struct smart_log_add_item_10 wear_leveling_count;
+ struct smart_log_add_item_10 ext_e2e_err_count;
+ struct smart_log_add_item_10 crc_err_count;
+ struct smart_log_add_item_10 nand_bytes_written;
+ struct smart_log_add_item_10 host_bytes_written;
+ struct smart_log_add_item_10 reallocated_sector_count;
+ struct smart_log_add_item_10 uncorrectable_sector_count;
+ struct smart_log_add_item_10 nand_uecc_detection;
+ struct smart_log_add_item_10 nand_xor_correction;
+ struct smart_log_add_item_10 gc_count;
+ struct smart_log_add_item_10 dram_uecc_detection_count;
+ struct smart_log_add_item_10 sram_uecc_detection_count;
+ struct smart_log_add_item_10 internal_raid_recovery_fail_count;
+ struct smart_log_add_item_10 inflight_cmds;
+ struct smart_log_add_item_10 internal_e2e_err_count;
+ struct smart_log_add_item_10 die_fail_count;
+ struct smart_log_add_item_10 wear_leveling_execution_count;
+ struct smart_log_add_item_10 read_disturb_count;
+ struct smart_log_add_item_10 data_retention_count;
+ struct smart_log_add_item_10 capacitor_health;
+ } v3;
+
+ struct smart_log_add_item_10 v3_raw[24];
+ };
+
+ uint8_t raw[512];
+ };
+};
+
+static void smart_log_add_v0_print(struct smart_log_add_item_12 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "end_to_end_error_count" },
+ [0xc7] = {4, "crc_error_count" },
+ [0xe2] = {5, "timed_workload_media_wear" },
+ [0xe3] = {6, "timed_workload_host_reads" },
+ [0xe4] = {7, "timed_workload_timer" },
+ [0xea] = {8, "thermal_throttle_status" },
+ [0xf0] = {9, "retry_buffer_overflow_counter"},
+ [0xf3] = {10, "pll_lock_loss_count" },
+ [0xf4] = {11, "nand_bytes_written" },
+ [0xf5] = {12, "host_bytes_written" },
+ [0xf6] = {13, "system_area_life_remaining" },
+ [0xfa] = {14, "nand_bytes_read" },
+ [0xe7] = {15, "temperature" },
+ [0xe8] = {16, "power_consumption" },
+ [0xaf] = {17, "power_on_temperature" },
+ [0xec] = {18, "power_loss_protection" },
+ [0xf2] = {19, "read_fail_count" },
+ [0xeb] = {20, "thermal_throttle_time" },
+ [0xed] = {21, "flash_error_media_count" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xe7:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
+ break;
+ case 0xe8:
+ printf("max: %d, min: %d, curr: %d\n",
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
+ break;
+ case 0xaf:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_v2_print(struct smart_log_add_item_12 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "end_to_end_error_count" },
+ [0xc7] = {4, "crc_error_count" },
+ [0xe2] = {5, "timed_workload_media_wear" },
+ [0xe3] = {6, "timed_workload_host_reads" },
+ [0xe4] = {7, "timed_workload_timer" },
+ [0xea] = {8, "thermal_throttle_status" },
+ [0xf0] = {9, "lifetime_write_amplification"},
+ [0xf3] = {10, "pll_lock_loss_count" },
+ [0xf4] = {11, "nand_bytes_written" },
+ [0xf5] = {12, "host_bytes_written" },
+ [0xf6] = {13, "system_area_life_remaining" },
+ [0xf9] = {14, "firmware_update_count" },
+ [0xfa] = {15, "dram_cecc_count" },
+ [0xfb] = {16, "dram_uecc_count" },
+ [0xfc] = {17, "xor_pass_count" },
+ [0xfd] = {18, "xor_fail_count" },
+ [0xfe] = {19, "xor_invoked_count" },
+ [0xe5] = {20, "inflight_read_io_cmd" },
+ [0xe6] = {21, "flash_error_media_count" },
+ [0xf8] = {22, "nand_bytes_read" },
+ [0xe7] = {23, "temp_since_born" },
+ [0xe8] = {24, "power_consumption" },
+ [0xaf] = {25, "temp_since_bootup" },
+ [0xeb] = {26, "thermal_throttle_time" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xe7:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_born.max)),
+ le16_to_cpu(item->temp_since_born.max),
+ K2C(le16_to_cpu(item->temp_since_born.min)),
+ le16_to_cpu(item->temp_since_born.min),
+ K2C(le16_to_cpu(item->temp_since_born.curr)),
+ le16_to_cpu(item->temp_since_born.curr));
+ break;
+ case 0xe8:
+ printf("max: %d, min: %d, curr: %d\n",
+ le16_to_cpu(item->power_consumption.max),
+ le16_to_cpu(item->power_consumption.min),
+ le16_to_cpu(item->power_consumption.curr));
+ break;
+ case 0xaf:
+ printf("max: %d °C (%d K), min: %d °C (%d K), curr: %d °C (%d K)\n",
+ K2C(le16_to_cpu(item->temp_since_power_on.max)),
+ le16_to_cpu(item->temp_since_power_on.max),
+ K2C(le16_to_cpu(item->temp_since_power_on.min)),
+ le16_to_cpu(item->temp_since_power_on.min),
+ K2C(le16_to_cpu(item->temp_since_power_on.curr)),
+ le16_to_cpu(item->temp_since_power_on.curr));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_v3_print(struct smart_log_add_item_10 *item, int item_count)
+{
+ static const struct smart_log_add_item items[0xff] = {
+ [0xab] = {0, "program_fail_count" },
+ [0xac] = {1, "erase_fail_count" },
+ [0xad] = {2, "wear_leveling_count" },
+ [0xb8] = {3, "ext_e2e_err_count" },
+ [0xc7] = {4, "crc_err_count" },
+ [0xf4] = {5, "nand_bytes_written" },
+ [0xf5] = {6, "host_bytes_written" },
+ [0xd0] = {7, "reallocated_sector_count" },
+ [0xd1] = {8, "uncorrectable_sector_count" },
+ [0xd2] = {9, "nand_uecc_detection" },
+ [0xd3] = {10, "nand_xor_correction" },
+ [0xd4] = {12, "gc_count" }, // 11 is reserved
+ [0xd5] = {13, "dram_uecc_detection_count" },
+ [0xd6] = {14, "sram_uecc_detection_count" },
+ [0xd7] = {15, "internal_raid_recovery_fail_count"},
+ [0xd8] = {16, "inflight_cmds" },
+ [0xd9] = {17, "internal_e2e_err_count" },
+ [0xda] = {19, "die_fail_count" }, // 18 is reserved
+ [0xdb] = {20, "wear_leveling_execution_count" },
+ [0xdc] = {21, "read_disturb_count" },
+ [0xdd] = {22, "data_retention_count" },
+ [0xde] = {23, "capacitor_health" },
+ };
+
+ for (int i = 0; i < item_count; i++, item++) {
+ if (item->id == 0)
+ continue;
+
+ printf("%#-12" PRIx8 "%-36s%-12d", item->id, items[item->id].attr, item->norm);
+ switch (item->id) {
+ case 0xad:
+ printf("min: %d, max: %d, avg: %d\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ break;
+ default:
+ printf("%" PRIu64 "\n", int48_to_long(item->raw));
+ break;
+ }
+ }
+}
+
+static void smart_log_add_print(struct smart_log_add *log, const char *devname)
+{
+ uint8_t version = log->raw[511];
+
+ printf("Version: %u\n", version);
+ printf("\n");
+ printf("Additional Smart Log for NVMe device: %s\n", devname);
+ printf("\n");
+
+ printf("%-12s%-36s%-12s%s\n", "Id", "Key", "Normalized", "Raw");
+
+ switch (version) {
+ case 0:
+ return smart_log_add_v0_print(&log->v0_raw[0],
+ sizeof(struct smart_log_add_v0) / sizeof(struct smart_log_add_item_12));
+ case 2:
+ return smart_log_add_v2_print(&log->v2_raw[0],
+ sizeof(struct smart_log_add_v2) / sizeof(struct smart_log_add_item_12));
+ case 3:
+ return smart_log_add_v3_print(&log->v3_raw[0],
+ sizeof(struct smart_log_add_v3) / sizeof(struct smart_log_add_item_10));
+
+ case 1:
+ fprintf(stderr, "Version %d: N/A\n", version);
+ break;
+ default:
+ fprintf(stderr, "Version %d: Not supported yet\n", version);
+ break;
+ }
+}
+
+static int mb_get_smart_log_add(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, "dump the whole log buffer in binary format"),
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+ // Get log
+
+ struct smart_log_add log = {0};
+
+ err = nvme_get_log_simple(dev_fd(dev), LID_SMART_LOG_ADD, sizeof(struct smart_log_add), &log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ smart_log_add_print(&log, dev->name);
+ else
+ d_raw((unsigned char *)&log, sizeof(struct smart_log_add));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
+
+// performance-monitor
+
+struct latency_stats_bucket {
+ char *start_threshold;
+ char *end_threshold;
+};
+
+struct __packed latency_stats {
+ union {
+ struct latency_stats_v2_0 {
+ uint32_t minor_version;
+ uint32_t major_version;
+ uint32_t bucket_read_data[32];
+ uint32_t rsvd[32];
+ uint32_t bucket_write_data[32];
+ uint32_t rsvd1[32];
+ uint32_t bucket_trim_data[32];
+ uint32_t rsvd2[32];
+ uint8_t rsvd3[248];
+ } v2_0;
+ uint8_t raw[1024];
+ };
+};
+
+struct __packed high_latency_log {
+ union {
+ struct high_latency_log_v1 {
+ uint32_t version;
+ struct high_latency_log_entry {
+ uint64_t timestamp; // ms
+ uint32_t latency;
+ uint32_t qid;
+ uint32_t opcode : 8;
+ uint32_t fuse : 2;
+ uint32_t psdt : 2;
+ uint32_t cid : 16;
+ uint32_t rsvd : 4;
+ uint32_t nsid;
+ uint64_t slba;
+ uint32_t nlb : 16;
+ uint32_t dtype : 8;
+ uint32_t pinfo : 4;
+ uint32_t fua : 1;
+ uint32_t lr : 1;
+ uint32_t rsvd1 : 2;
+ uint8_t rsvd2[28];
+ } entries[1024];
+ } v1;
+ uint8_t raw[4 + 1024 * 64];
+ };
+};
+
+struct __packed performance_stats {
+ union {
+ struct performance_stats_v1 {
+ uint8_t version;
+ uint8_t rsvd[3];
+ struct performance_stats_timestamp {
+ uint8_t timestamp[6];
+ struct performance_stats_entry {
+ uint16_t read_iops; // K IOPS
+ uint16_t read_bandwidth; // MiB
+ uint32_t read_latency; // us
+ uint32_t read_latency_max; // us
+ uint16_t write_iops; // K IOPS
+ uint16_t write_bandwidth; // MiB
+ uint32_t write_latency; // us
+ uint32_t write_latency_max; // us
+ } entries[3600];
+ } timestamps[24];
+ } v1;
+ uint8_t raw[4 + 24 * (6 + 3600 * 24)];
+ };
+};
+
+static int mb_set_latency_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ struct config {
+ uint32_t perf_monitor;
+ uint32_t cmd_mask;
+ uint32_t read_threshold;
+ uint32_t write_threshold;
+ uint32_t de_allocate_trim_threshold;
+ };
+
+ struct config cfg = {0};
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("sel-perf-log", 's', &cfg.perf_monitor,
+ "Select features to turn on, default: Disable\n"
+ " bit 0: latency statistics\n"
+ " bit 1: high latency log\n"
+ " bit 2: Performance stat"),
+ OPT_UINT("set-commands-mask", 'm', &cfg.cmd_mask,
+ "Set Enable, default: Disable\n"
+ " bit 0: Read commands\n"
+ " bit 1: high Write commands\n"
+ " bit 2: De-allocate/TRIM (this bit is not worked for Performance stat.)"),
+ OPT_UINT("set-read-threshold", 'r', &cfg.read_threshold,
+ "set read high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_UINT("set-write-threshold", 'w', &cfg.write_threshold,
+ "set write high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_UINT("set-trim-threshold", 't', &cfg.de_allocate_trim_threshold,
+ "set trim high latency log threshold, it's a 0-based value and unit is 10ms"),
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+
+ // Set feature
+
+ uint32_t result = 0;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = FID_LATENCY_FEATURE,
+ .nsid = 0,
+ .cdw11 = 0 | cfg.perf_monitor,
+ .cdw12 = 0 | cfg.cmd_mask,
+ .cdw13 = 0 |
+ (cfg.read_threshold & 0xff) |
+ ((cfg.write_threshold & 0xff) << 8) |
+ ((cfg.de_allocate_trim_threshold & 0xff) << 16),
+ .cdw15 = 0,
+ .save = 0,
+ .uuidx = 0,
+ .data = NULL,
+ .data_len = 0,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (!err)
+ printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
+
+static int mb_get_latency_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+
+ // Get the configuration
+
+ OPT_ARGS(opts) = {
+ OPT_END()};
+
+ // Open device
+
+ struct nvme_dev *dev = NULL;
+
+ err = parse_and_open(&dev, argc, argv, cmd->help, opts);
+ if (err)
+ return err;
+
+ // Get feature
+
+ uint32_t result = 0;
+
+ err = nvme_get_features_simple(dev_fd(dev), FID_LATENCY_FEATURE, 0, &result);
+ if (!err) {
+ printf("%s have done successfully. result = %#" PRIx32 ".\n", cmd->name, result);
+
+ printf("latency statistics enable status = %d\n", (result & (0x01 << 0)) >> 0);
+ printf("high latency enable status = %d\n", (result & (0x01 << 1)) >> 1);
+ printf("performance stat enable status = %d\n", (result & (0x01 << 2)) >> 2);
+
+ printf("Monitor Read command = %d\n", (result & (0x01 << 4)) >> 4);
+ printf("Monitor Write command = %d\n", (result & (0x01 << 5)) >> 5);
+ printf("Monitor Trim command = %d\n", (result & (0x01 << 6)) >> 6);
+
+ printf("Threshold for Read = %dms\n", (((result & (0xff << 8)) >> 8) + 1) * 10);
+ printf("Threshold for Write = %dms\n", (((result & (0xff << 16)) >> 16) + 1) * 10);
+ printf("Threshold for Trim = %dms\n", (((result & (0xff << 24)) >> 24) + 1) * 10);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ nvme_show_error("%s: %s", cmd->name, nvme_strerror(errno));
+ }
+
+ // Close device
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
new file mode 100644
index 0000000..e25267b
--- /dev/null
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/memblaze/memblaze-nvme
+
+#if !defined(MEMBLAZE_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define MEMBLAZE_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", mb_get_additional_smart_log)
+ ENTRY("get-pm-status", "Get Memblaze Power Manager Status", mb_get_powermanager_status)
+ 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)
+ ENTRY("smart-log-add-x", "Retrieve Memblaze SMART Log, show it", mb_get_smart_log_add)
+ ENTRY("lat-set-feature-x", "Set Enable/Disable for Latency Monitor feature", mb_set_latency_feature)
+ ENTRY("lat-get-feature-x", "Get Enabled/Disabled of Latency Monitor feature", mb_get_latency_feature)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/memblaze/memblaze-utils.h b/plugins/memblaze/memblaze-utils.h
new file mode 100644
index 0000000..8914f95
--- /dev/null
+++ b/plugins/memblaze/memblaze-utils.h
@@ -0,0 +1,217 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __MEMBLAZE_UTILS_H__
+#define __MEMBLAZE_UTILS_H__
+
+#define SMART_INFO_OLD_SIZE 512
+#define SMART_INFO_NEW_SIZE 4096
+
+#define ID_SIZE 3
+#define NM_SIZE 2
+#define RAW_SIZE 7
+
+// Intel Format & new format
+/* Raisin Additional smart external ID */
+#define RAISIN_SI_VD_PROGRAM_FAIL_ID 0xAB
+#define RAISIN_SI_VD_ERASE_FAIL_ID 0xAC
+#define RAISIN_SI_VD_WEARLEVELING_COUNT_ID 0xAD
+#define RAISIN_SI_VD_E2E_DECTECTION_COUNT_ID 0xB8
+#define RAISIN_SI_VD_PCIE_CRC_ERR_COUNT_ID 0xC7
+#define RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR_ID 0xE2
+#define RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ_ID 0xE3
+#define RAISIN_SI_VD_TIMED_WORKLOAD_TIMER_ID 0xE4
+#define RAISIN_SI_VD_THERMAL_THROTTLE_STATUS_ID 0xEA
+#define RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT_ID 0xF0
+#define RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT_ID 0xF3
+#define RAISIN_SI_VD_TOTAL_WRITE_ID 0xF4
+#define RAISIN_SI_VD_HOST_WRITE_ID 0xF5
+#define RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT_ID 0xF6
+#define RAISIN_SI_VD_TOTAL_READ_ID 0xFA
+#define RAISIN_SI_VD_TEMPT_SINCE_BORN_ID 0xE7
+#define RAISIN_SI_VD_POWER_CONSUMPTION_ID 0xE8
+#define RAISIN_SI_VD_TEMPT_SINCE_BOOTUP_ID 0xAF
+#define RAISIN_SI_VD_POWER_LOSS_PROTECTION_ID 0xEC
+#define RAISIN_SI_VD_READ_FAIL_ID 0xF2
+#define RAISIN_SI_VD_THERMAL_THROTTLE_TIME_ID 0xEB
+#define RAISIN_SI_VD_FLASH_MEDIA_ERROR_ID 0xED
+
+/* Raisin Additional smart internal ID */
+typedef enum
+{
+ /* smart attr following intel */
+ RAISIN_SI_VD_PROGRAM_FAIL = 0, /* 0xAB */
+ RAISIN_SI_VD_ERASE_FAIL = 1, /* 0xAC */
+ RAISIN_SI_VD_WEARLEVELING_COUNT = 2,/* 0xAD */
+ RAISIN_SI_VD_E2E_DECTECTION_COUNT = 3, /* 0xB8 */
+ RAISIN_SI_VD_PCIE_CRC_ERR_COUNT = 4, /* 0xC7, 2 port data in one attribute */
+ RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR = 5, /* 0xE2 , unknown definition*/
+ RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ = 6, /* 0xE3 , unknown definition */
+ RAISIN_SI_VD_TIMED_WORKLOAD_TIMER = 7, /* 0xE4 , unknown definition */
+ RAISIN_SI_VD_THERMAL_THROTTLE_STATUS = 8, /* 0xEA */
+ RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT = 9, /* 0xF0, unknown definition*/
+ RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT = 10, /* 0xF3, unknown definition*/
+ RAISIN_SI_VD_TOTAL_WRITE = 11, /* 0xF4, unit is 32MiB */
+ RAISIN_SI_VD_HOST_WRITE = 12, /* 0xF5, unit is 32MiB */
+ RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT = 13, /* 0xF6, unknown definition*/
+ RAISIN_SI_VD_TOTAL_READ = 14, /* 0xFA, unit is 32MiB */
+
+ /* smart attr self defined */
+ RAISIN_SI_VD_TEMPT_SINCE_BORN = 15, /* 0xE7 */
+ RAISIN_SI_VD_POWER_CONSUMPTION = 16, /* 0xE8 */
+ RAISIN_SI_VD_TEMPT_SINCE_BOOTUP = 17, /* 0xAF */
+ RAISIN_SI_VD_POWER_LOSS_PROTECTION = 18, /* 0xEC */
+ RAISIN_SI_VD_READ_FAIL = 19, /* 0xF2 */
+ RAISIN_SI_VD_THERMAL_THROTTLE_TIME = 20, /* 0xEB */
+ RAISIN_SI_VD_FLASH_MEDIA_ERROR = 21, /* 0xED */
+ RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
+} RAISIN_si_vendor_smart_item_e;
+
+// Memblaze Format & old format
+enum {
+ /*0*/TOTAL_WRITE = 0,
+ /*1*/TOTAL_READ,
+ /*2*/THERMAL_THROTTLE,
+ /*3*/TEMPT_SINCE_RESET,
+ /*4*/POWER_CONSUMPTION,
+ /*5*/TEMPT_SINCE_BOOTUP,
+ /*6*/POWER_LOSS_PROTECTION,
+ /*7*/WEARLEVELING_COUNT,
+ /*8*/HOST_WRITE,
+ /*9*/THERMAL_THROTTLE_CNT,
+ /*10*/CORRECT_PCIE_PORT0,
+ /*11*/CORRECT_PCIE_PORT1,
+ /*12*/REBUILD_FAIL,
+ /*13*/ERASE_FAIL,
+ /*14*/PROGRAM_FAIL,
+ /*15*/READ_FAIL,
+ /*16*/NR_SMART_ITEMS = RAISIN_SI_VD_SMART_INFO_ITEMS_MAX,
+};
+
+// Memblaze Format & old format
+#pragma pack(push, 1)
+struct nvme_memblaze_smart_log_item {
+ __u8 id[3];
+ union {
+ __u8 __nmval[2];
+ __le16 nmval;
+ };
+ union {
+ __u8 rawval[6];
+ struct temperature {
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } temperature;
+ struct power {
+ __le16 max;
+ __le16 min;
+ __le16 curr;
+ } power;
+ struct thermal_throttle_mb {
+ __u8 on;
+ __u32 count;
+ } thermal_throttle;
+ struct temperature_p {
+ __le16 max;
+ __le16 min;
+ } temperature_p;
+ struct power_loss_protection {
+ __u8 curr;
+ } power_loss_protection;
+ struct wearleveling_count {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wearleveling_count;
+ struct thermal_throttle_cnt {
+ __u8 active;
+ __le32 cnt;
+ } thermal_throttle_cnt;
+ };
+ __u8 resv;
+};
+#pragma pack(pop)
+
+struct nvme_memblaze_smart_log {
+ struct nvme_memblaze_smart_log_item items[NR_SMART_ITEMS];
+ __u8 resv[SMART_INFO_OLD_SIZE - sizeof(struct nvme_memblaze_smart_log_item) * NR_SMART_ITEMS];
+};
+
+// Intel Format & new format
+struct nvme_p4_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_p4_smart_log
+{
+ struct nvme_p4_smart_log_item itemArr[NR_SMART_ITEMS];
+
+ /**
+ * change 512 to 4096.
+ * because micron's getlogpage request,the size of many commands have changed to 4k.
+ * request size > user malloc size,casuing parameters that are closed in memery are dirty.
+ */
+ __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 { \
+ if (fdi) \
+ fprintf(fdi, format); \
+ if (print) \
+ printf(format); \
+ } while (0)
+
+#define fPRINT_PARAM2(format, value) \
+ do { \
+ if (fdi) \
+ fprintf(fdi, format, value); \
+ if (print) \
+ printf(format, value); \
+ } while (0)
+
+#endif // __MEMBLAZE_UTILS_H__
diff --git a/plugins/meson.build b/plugins/meson.build
new file mode 100644
index 0000000..bb4c9ad
--- /dev/null
+++ b/plugins/meson.build
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+if json_c_dep.found()
+ sources += [
+ 'plugins/amzn/amzn-nvme.c',
+ 'plugins/dell/dell-nvme.c',
+ 'plugins/dera/dera-nvme.c',
+ 'plugins/fdp/fdp.c',
+ 'plugins/huawei/huawei-nvme.c',
+ 'plugins/innogrit/innogrit-nvme.c',
+ 'plugins/inspur/inspur-nvme.c',
+ 'plugins/intel/intel-nvme.c',
+ 'plugins/memblaze/memblaze-nvme.c',
+ 'plugins/micron/micron-nvme.c',
+ 'plugins/nbft/nbft-plugin.c',
+ 'plugins/netapp/netapp-nvme.c',
+ 'plugins/nvidia/nvidia-nvme.c',
+ 'plugins/scaleflux/sfx-nvme.c',
+ 'plugins/seagate/seagate-nvme.c',
+ 'plugins/shannon/shannon-nvme.c',
+ 'plugins/solidigm/solidigm-nvme.c',
+ 'plugins/toshiba/toshiba-nvme.c',
+ 'plugins/transcend/transcend-nvme.c',
+ 'plugins/virtium/virtium-nvme.c',
+ 'plugins/wdc/wdc-nvme.c',
+ 'plugins/wdc/wdc-utils.c',
+ 'plugins/ymtc/ymtc-nvme.c',
+ 'plugins/zns/zns.c',
+ ]
+ subdir('solidigm')
+ subdir('ocp')
+ if conf.has('HAVE_SED_OPAL')
+ subdir('sed')
+ endif
+endif
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
new file mode 100644
index 0000000..63a7a79
--- /dev/null
+++ b/plugins/micron/micron-nvme.c
@@ -0,0 +1,3390 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include <limits.h>
+#include "linux/types.h"
+#include "nvme-print.h"
+#include "util/cleanup.h"
+
+#define CREATE_CMD
+#include "micron-nvme.h"
+
+/* Supported Vendor specific feature ids */
+#define MICRON_FEATURE_CLEAR_PCI_CORRECTABLE_ERRORS 0xC3
+#define MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY 0xC1
+#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 C0_log_size 512
+#define C2_log_size 4096
+#define D0_log_size 512
+#define FB_log_size 512
+#define E1_log_size 256
+#define MaxLogChunk (16 * 1024)
+#define CommonChunkSize (16 * 4096)
+
+#define min(x, y) ((x) > (y) ? (y) : (x))
+#define SensorCount 8
+
+/* Plugin version major_number.minor_number.patch */
+static const char *__version_major = "1";
+static const char *__version_minor = "0";
+static const char *__version_patch = "14";
+
+/*
+ * supported models of micron plugin; new models should be added at the end
+ * before UNKNOWN_MODEL. Make sure M5410 is first in the list !
+ */
+enum eDriveModel {
+ M5410 = 0,
+ M51AX,
+ M51BX,
+ M51CX,
+ M5407,
+ M5411,
+ UNKNOWN_MODEL
+};
+
+#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;
+
+struct LogPageHeader_t {
+ unsigned char numDwordsInLogPageHeaderLo;
+ unsigned char logPageHeaderFormatVersion;
+ unsigned char logPageId;
+ unsigned char numDwordsInLogPageHeaderHi;
+ unsigned int numValidDwordsInPayload;
+ unsigned int numDwordsInEntireLogPage;
+};
+
+static void WriteData(__u8 *data, __u32 len, const char *dir, const char *file, const char *msg)
+{
+ char tempFolder[8192] = { 0 };
+ FILE *fpOutFile = NULL;
+
+ sprintf(tempFolder, "%s/%s", dir, file);
+ fpOutFile = fopen(tempFolder, "ab+");
+ if (fpOutFile) {
+ 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 ReadSysFile(const char *file, unsigned short *id)
+{
+ int ret = 0;
+ char idstr[32] = { '\0' };
+ int fd = open(file, O_RDONLY);
+
+ if (fd < 0) {
+ perror(file);
+ return fd;
+ }
+
+ ret = read(fd, idstr, sizeof(idstr));
+ close(fd);
+ if (ret < 0)
+ perror("read");
+ else
+ *id = strtol(idstr, NULL, 16);
+
+ return ret;
+}
+
+static enum eDriveModel GetDriveModel(int idx)
+{
+ enum 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 0x5196:
+ fallthrough;
+ case 0x51A0:
+ fallthrough;
+ case 0x51A1:
+ fallthrough;
+ case 0x51A2:
+ eModel = M51AX;
+ break;
+ case 0x51B0:
+ fallthrough;
+ case 0x51B1:
+ fallthrough;
+ case 0x51B2:
+ eModel = M51BX;
+ break;
+ case 0x51C0:
+ fallthrough;
+ case 0x51C1:
+ fallthrough;
+ case 0x51C2:
+ fallthrough;
+ case 0x51C3:
+ eModel = M51CX;
+ break;
+ case 0x5405:
+ fallthrough;
+ case 0x5406:
+ fallthrough;
+ 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;
+ 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)
+{
+ 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, '/')) {
+ fileName = strrchr(strFilePath, '\\');
+ if (!fileName)
+ fileName = strrchr(strFilePath, '/');
+
+ if (fileName) {
+ 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);
+ if (!fileLocation)
+ 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]) {
+ strTemp = (char *)malloc(length + 2);
+ if (!strTemp) {
+ free(fileLocation);
+ goto exit_status;
+ }
+ strcpy(strTemp, fileLocation);
+ strcat(strTemp, "/");
+ free(fileLocation);
+
+ length = (int)strlen(strTemp);
+ fileLocation = (char *)malloc(length + 1);
+ if (!fileLocation) {
+ free(strTemp);
+ goto exit_status;
+ }
+
+ memcpy(fileLocation, strTemp, length + 1);
+ free(strTemp);
+ }
+
+ if (stat(fileLocation, &st)) {
+ 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)) {
+ strMainDirName[nIndex] = '\0';
+ sprintf(strAppend, "-%d", j);
+ strcat(strMainDirName, strAppend);
+ j++;
+ }
+
+ if (mkdir(strMainDirName, 0777) < 0) {
+ err = -1;
+ goto exit_status;
+ }
+
+ if (strOSDirName) {
+ sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
+ if (mkdir(strOSDirName, 0777) < 0) {
+ rmdir(strMainDirName);
+ err = -1;
+ goto exit_status;
+ }
+ }
+ if (strCtrlDirName) {
+ sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller");
+ if (mkdir(strCtrlDirName, 0777) < 0) {
+ if (strOSDirName)
+ rmdir(strOSDirName);
+ rmdir(strMainDirName);
+ err = -1;
+ }
+ }
+
+exit_status:
+ return err;
+}
+
+static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize)
+{
+ int err = 0;
+ unsigned char pTmpBuf[CommonChunkSize] = { 0 };
+ struct LogPageHeader_t *pLogHeader = NULL;
+
+ if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) {
+ err = nvme_get_log_simple(nFD, ucLogID, CommonChunkSize, pTmpBuf);
+ if (!err) {
+ pLogHeader = (struct LogPageHeader_t *) pTmpBuf;
+ struct LogPageHeader_t *pLogHeader1 = (struct LogPageHeader_t *) pLogHeader;
+ *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4;
+ if (!pLogHeader1->logPageHeaderFormatVersion) {
+ 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 (ignored)!\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_passthru_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 && (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 && (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_admin_passthru(nFD, &cmd, NULL);
+ ullBytesRead += uiXferDwords * 4;
+ pTempPtr = pBuffer + ullBytesRead;
+ }
+
+ return err;
+}
+
+static int NVMEResetLog(int nFD, unsigned char ucLogID, int nBufferSize,
+ long long llMaxSize)
+{
+ unsigned int *pBuffer = NULL;
+ int err = 0;
+
+ pBuffer = (unsigned int *)calloc(1, nBufferSize);
+ if (!pBuffer)
+ return err;
+
+ while (!err && llMaxSize > 0) {
+ err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize);
+ if (err) {
+ free(pBuffer);
+ return err;
+ }
+
+ if (pBuffer[0] == 0xdeadbeef)
+ break;
+
+ llMaxSize = llMaxSize - nBufferSize;
+ }
+
+ free(pBuffer);
+ return err;
+}
+
+static int GetCommonLogPage(int nFD, unsigned char ucLogID,
+ unsigned char **pBuffer, int nBuffSize)
+{
+ 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_simple(nFD, ucLogID, nBuffSize, pTempPtr);
+ *pBuffer = pTempPtr;
+
+exit_status:
+ return err;
+}
+
+/*
+ * Plugin Commands
+ */
+static int micron_parse_options(struct nvme_dev **dev, int argc, char **argv,
+ const char *desc,
+ struct argconfig_commandline_options *opts,
+ enum eDriveModel *modelp)
+{
+ int idx;
+ int err = parse_and_open(dev, argc, argv, desc, opts);
+
+ if (err) {
+ perror("open");
+ return -1;
+ }
+
+ if (modelp) {
+ if (sscanf(argv[optind], "/dev/nvme%d", &idx) != 1)
+ idx = 0;
+ *modelp = GetDriveModel(idx);
+ }
+
+ return 0;
+}
+
+static int micron_fw_commit(int fd, int select)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_fw_commit,
+ .cdw10 = 8,
+ .cdw12 = select,
+ };
+ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+}
+
+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\n"
+ "select which firmware binary to update for 9200 devices. This requires\n"
+ "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 selectNo, fw_fd, fw_size, err, offset = 0;
+ struct nvme_dev *dev;
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (strlen(cfg.select) != 3) {
+ fprintf(stderr, "Invalid select flag\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < 3; i++)
+ cfg.select[i] = toupper(cfg.select[i]);
+
+ if (!strncmp(cfg.select, "OOB", 3)) {
+ selectNo = 18;
+ } else if (!strncmp(cfg.select, "EEP", 3)) {
+ selectNo = 10;
+ } else if (!strncmp(cfg.select, "ALL", 3)) {
+ selectNo = 26;
+ } else {
+ fprintf(stderr, "Invalid select flag\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ if (fw_fd < 0) {
+ fprintf(stderr, "no firmware file provided\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ err = errno;
+ goto out;
+ }
+
+ 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))) {
+ err = errno;
+ goto out_free;
+ }
+
+ while (fw_size > 0) {
+ xfer = min(xfer, fw_size);
+
+ struct nvme_fw_download_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .offset = offset,
+ .data_len = xfer,
+ .data = fw_buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ err = nvme_fw_download(&args);
+ if (err < 0) {
+ perror("fw-download");
+ goto out_free;
+ } else if (err) {
+ nvme_show_status(err);
+ goto out_free;
+ }
+ fw_buf += xfer;
+ fw_size -= xfer;
+ offset += xfer;
+ }
+
+ err = micron_fw_commit(dev_fd(dev), selectNo);
+
+ if (err == 0x10B || err == 0x20B) {
+ err = 0;
+ fprintf(stderr,
+ "Update successful! Power cycle for changes to take effect\n");
+ }
+
+out_free:
+ free(fw_buf);
+out:
+ close(fw_fd);
+ dev_close(dev);
+ return err;
+}
+
+static int micron_smbus_option(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ __u32 result = 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 fid = MICRON_FEATURE_SMBUS_OPTION;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_dev *dev;
+ int err = 0;
+
+ 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()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+
+ if (model != M5407 && model != M5411) {
+ printf("This option is not supported for specified drive\n");
+ dev_close(dev);
+ return err;
+ }
+
+ if (!strcmp(opt.option, "enable")) {
+ cdw11 = opt.value << 1 | 1;
+ err = nvme_set_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save,
+ &result);
+ if (!err)
+ printf("successfully enabled SMBus on drive\n");
+ else
+ printf("Failed to enabled SMBus on drive\n");
+ } else if (!strcmp(opt.option, "status")) {
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = 1,
+ .sel = opt.value,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err)
+ 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_features_simple(dev_fd(dev), fid, 1, cdw11, opt.save,
+ &result);
+ if (!err)
+ 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);
+ dev_close(dev);
+ return -1;
+ }
+
+ close(dev_fd(dev));
+ return err;
+}
+
+static int micron_temp_stats(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ 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;
+ struct nvme_dev *dev;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (!strcmp(cfg.fmt, "json"))
+ is_json = true;
+
+ err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
+ if (!err) {
+ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
+ temperature = temperature ? temperature - 273 : 0;
+ for (i = 0; i < SensorCount && tempSensors[i]; 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 && tempSensors[i]; 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 && tempSensors[i]; i++)
+ printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
+ }
+ }
+ dev_close(dev);
+ return err;
+}
+
+static int micron_pcie_stats(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ int i, err = 0, bus, domain, device, function, ctrlIdx;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ struct nvme_dev *dev;
+ 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 };
+ struct nvme_passthru_cmd admin_cmd = { 0 };
+ enum eDriveModel eModel = UNKNOWN_MODEL;
+ char *res;
+ bool is_json = true;
+ bool counters = false;
+ struct format {
+ char *fmt;
+ };
+ const char *desc = "Retrieve PCIe event counters";
+ const char *fmt = "output format json|normal";
+ struct format cfg = {
+ .fmt = "json",
+ };
+ struct pcie_error_counters {
+ __u16 receiver_error;
+ __u16 bad_tlp;
+ __u16 bad_dllp;
+ __u16 replay_num_rollover;
+ __u16 replay_timer_timeout;
+ __u16 advisory_non_fatal_error;
+ __u16 DLPES;
+ __u16 poisoned_tlp;
+ __u16 FCPC;
+ __u16 completion_timeout;
+ __u16 completion_abort;
+ __u16 unexpected_completion;
+ __u16 receiver_overflow;
+ __u16 malformed_tlp;
+ __u16 ecrc_error;
+ __u16 unsupported_request_error;
+ } pcie_error_counters = { 0 };
+
+ struct {
+ char *err;
+ int bit;
+ int val;
+ } pcie_correctable_errors[] = {
+ { "Unsupported Request Error Status (URES)", 20,
+ offsetof(struct pcie_error_counters, unsupported_request_error)},
+ { "ECRC Error Status (ECRCES)", 19,
+ offsetof(struct pcie_error_counters, ecrc_error)},
+ { "Malformed TLP Status (MTS)", 18,
+ offsetof(struct pcie_error_counters, malformed_tlp)},
+ { "Receiver Overflow Status (ROS)", 17,
+ offsetof(struct pcie_error_counters, receiver_overflow)},
+ { "Unexpected Completion Status (UCS)", 16,
+ offsetof(struct pcie_error_counters, unexpected_completion)},
+ { "Completer Abort Status (CAS)", 15,
+ offsetof(struct pcie_error_counters, completion_abort)},
+ { "Completion Timeout Status (CTS)", 14,
+ offsetof(struct pcie_error_counters, completion_timeout)},
+ { "Flow Control Protocol Error Status (FCPES)", 13,
+ offsetof(struct pcie_error_counters, FCPC)},
+ { "Poisoned TLP Status (PTS)", 12,
+ offsetof(struct pcie_error_counters, poisoned_tlp)},
+ { "Data Link Protocol Error Status (DLPES)", 4,
+ offsetof(struct pcie_error_counters, DLPES)},
+ },
+ pcie_uncorrectable_errors[] = {
+ { "Advisory Non-Fatal Error Status (ANFES)", 13,
+ offsetof(struct pcie_error_counters, advisory_non_fatal_error)},
+ { "Replay Timer Timeout Status (RTS)", 12,
+ offsetof(struct pcie_error_counters, replay_timer_timeout)},
+ { "REPLAY_NUM Rollover Status (RRS)", 8,
+ offsetof(struct pcie_error_counters, replay_num_rollover)},
+ { "Bad DLLP Status (BDS)", 7,
+ offsetof(struct pcie_error_counters, bad_dllp)},
+ { "Bad TLP Status (BTS)", 6,
+ offsetof(struct pcie_error_counters, bad_tlp)},
+ { "Receiver Error Status (RES)", 0,
+ offsetof(struct pcie_error_counters, receiver_error)},
+ };
+
+ __u32 correctable_errors;
+ __u32 uncorrectable_errors;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ /* pull log details based on the model name */
+ if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1)
+ ctrlIdx = 0;
+ eModel = GetDriveModel(ctrlIdx);
+ if (eModel == UNKNOWN_MODEL) {
+ printf("Unsupported drive model for vs-pcie-stats command\n");
+ goto out;
+ }
+
+ if (!strcmp(cfg.fmt, "normal"))
+ is_json = false;
+
+ if (eModel == M5407) {
+ admin_cmd.opcode = 0xD6;
+ admin_cmd.addr = (__u64)(uintptr_t)&pcie_error_counters;
+ admin_cmd.data_len = sizeof(pcie_error_counters);
+ admin_cmd.cdw10 = 1;
+ err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ if (!err) {
+ counters = true;
+ correctable_errors = 10;
+ uncorrectable_errors = 6;
+ goto print_stats;
+ }
+ }
+
+ 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);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
+ 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);
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ if (sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function) != 4)
+ domain = bus = device = function = 0;
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (!fp) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (!res) {
+ printf("Failed to retrieve error count\n");
+ pclose(fp);
+ goto out;
+ }
+ pclose(fp);
+
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (!fp) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(uncorrectable, sizeof(uncorrectable), fp);
+ if (!res) {
+ printf("Failed to retrieve error count\n");
+ pclose(fp);
+ goto out;
+ }
+ pclose(fp);
+
+ correctable_errors = (__u32)strtol(correctable, NULL, 16);
+ uncorrectable_errors = (__u32)strtol(uncorrectable, NULL, 16);
+
+print_stats:
+ if (is_json) {
+ struct json_object *root = json_create_object();
+ struct json_object *pcieErrors = json_create_array();
+ struct json_object *stats = json_create_object();
+ __u8 *pcounter = (__u8 *)&pcie_error_counters;
+
+ json_object_add_value_array(root, "PCIE Stats", pcieErrors);
+ for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++) {
+ __u16 val = counters ? *(__u16 *)(pcounter + pcie_correctable_errors[i].val) :
+ (correctable_errors >> pcie_correctable_errors[i].bit) & 1;
+ json_object_add_value_int(stats, pcie_correctable_errors[i].err, val);
+ }
+ for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++) {
+ __u16 val = counters ? *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val) :
+ (uncorrectable_errors >> pcie_uncorrectable_errors[i].bit) & 1;
+ json_object_add_value_int(stats, pcie_uncorrectable_errors[i].err, val);
+ }
+ json_array_add_value_object(pcieErrors, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else if (counters == true) {
+ __u8 *pcounter = (__u8 *)&pcie_error_counters;
+
+ for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++)
+ printf("%-42s : %-1hu\n", pcie_correctable_errors[i].err,
+ *(__u16 *)(pcounter + pcie_correctable_errors[i].val));
+ for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++)
+ printf("%-42s : %-1hu\n", pcie_uncorrectable_errors[i].err,
+ *(__u16 *)(pcounter + pcie_uncorrectable_errors[i].val));
+ } else if (eModel == M5407 || eModel == M5410) {
+ for (i = 0; i < ARRAY_SIZE(pcie_correctable_errors); i++)
+ printf("%-42s : %-1d\n", pcie_correctable_errors[i].err,
+ ((correctable_errors >> pcie_correctable_errors[i].bit) & 1));
+ for (i = 0; i < ARRAY_SIZE(pcie_uncorrectable_errors); i++)
+ printf("%-42s : %-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:
+ dev_close(dev);
+ return err;
+}
+
+static int micron_clear_pcie_correctable_errors(int argc, char **argv,
+ struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = -EINVAL, bus, domain, device, function;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ struct nvme_dev *dev;
+ char *businfo = NULL;
+ char *devicename = NULL;
+ char tdevice[PATH_MAX] = { 0 };
+ ssize_t sLinkSize = 0;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_passthru_cmd admin_cmd = { 0 };
+ char correctable[8] = { 0 };
+ 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()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+
+ /* For M51CX models, PCIe errors are cleared using 0xC3 feature */
+ if (model == M51CX) {
+ err = nvme_set_features_simple(dev_fd(dev), fid, 0, (1 << 31), false,
+ &result);
+ if (!err)
+ err = (int)result;
+ if (!err) {
+ printf("Device correctable errors are cleared!\n");
+ goto out;
+ }
+ } else if (model == M5407) {
+ admin_cmd.opcode = 0xD6;
+ admin_cmd.addr = 0;
+ admin_cmd.cdw10 = 0;
+ err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ if (!err) {
+ printf("Device correctable error counters are cleared!\n");
+ goto out;
+ } else {
+ /* proceed to clear status bits using sysfs interface */
+ }
+ }
+
+ 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;
+
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
+ 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;
+ memset(strTempFile2, 0x0, 1024);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1023);
+ if (sLinkSize < 0) {
+ err = -errno;
+ printf("Failed to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ if (sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function) != 4)
+ domain = bus = device = function = 0;
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus,
+ device, function);
+ err = -1;
+ fp = popen(command, "r");
+ if (!fp) {
+ 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) {
+ printf("Failed to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (!res) {
+ printf("Failed to retrieve error count\n");
+ pclose(fp);
+ goto out;
+ }
+ pclose(fp);
+ printf("Device correctable errors cleared!\n");
+ printf("Device correctable errors detected: %s\n", correctable);
+ err = 0;
+out:
+ dev_close(dev);
+ return err;
+}
+
+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;
+
+ memcpy(logD0, buf, sizeof(logD0));
+
+
+ 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)
+ 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; /* FB client spec version 1.0 sizes - M5410 models */
+ int size2; /* FB client spec version 0.7 sizes - M5407 models */
+}
+/* Smart Health Log information as per OCP spec M51CX models */
+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},
+},
+/* Extended SMART log information */
+e1_log_page[] = {
+ { "Reserved", 12},
+ { "Grown Bad Block Count", 4},
+ { "Per Block Max Erase Count", 4},
+ { "Power On Minutes", 4},
+ { "Reserved", 24},
+ { "Write Protect Reason", 4},
+ { "Reserved", 12},
+ { "Drive Capacity", 8},
+ { "Reserved", 8},
+ { "Total Erase Count", 8},
+ { "Lifetime Use Rate", 8},
+ { "Erase Fail Count", 8},
+ { "Reserved", 8},
+ { "Reported UC Errors", 8},
+ { "Reserved", 24},
+ { "Program Fail Count", 16},
+ { "Total Bytes Read", 16},
+ { "Total Bytes Written", 16},
+ { "Reserved", 16},
+ { "TU Size", 4},
+ { "Total Block Stripe Count", 4},
+ { "Free Block Stripe Count", 4},
+ { "Block Stripe Size", 8},
+ { "Reserved", 16},
+ { "User Block Min Erase Count", 4},
+ { "User Block Avg Erase Count", 4},
+ { "User Block Max Erase Count", 4},
+},
+/* Vendor Specific Health Log information */
+fb_log_page[] = {
+ { "Physical Media Units Written - TLC", 16, 16 },
+ { "Physical Media Units Written - SLC", 16, 16 },
+ { "Normalized Bad User NAND Block Count", 2, 2},
+ { "Raw Bad User NAND Block Count", 6, 6},
+ { "XOR Recovery Count", 8, 8},
+ { "Uncorrectable Read Error Count", 8, 8},
+ { "SSD End to End Corrected Errors", 8, 8},
+ { "SSD End to End Detected Counts", 4, 8},
+ { "SSD End to End Uncorrected Counts", 4, 8},
+ { "System data % life-used", 1, 1},
+ { "Reserved", 0, 3},
+ { "Minimum User Data Erase Count - TLC", 8, 8},
+ { "Maximum User Data Erase Count - TLC", 8, 8},
+ { "Average User Data Erase Count - TLC", 0, 8},
+ { "Minimum User Data Erase Count - SLC", 8, 8},
+ { "Maximum User Data Erase Count - SLC", 8, 8},
+ { "Average User Data Erase Count - SLC", 0, 8},
+ { "Normalized Program Fail Count", 2, 2},
+ { "Raw Program Fail Count", 6, 6},
+ { "Normalized Erase Fail Count", 2, 2},
+ { "Raw Erase Fail Count", 6, 6},
+ { "Pcie Correctable Error Count", 8, 8},
+ { "% Free Blocks (User)", 1, 1},
+ { "Reserved", 0, 3},
+ { "Security Version Number", 8, 8},
+ { "% Free Blocks (System)", 1, 1},
+ { "Reserved", 0, 3},
+ { "Dataset Management (Deallocate) Commands", 16, 16},
+ { "Incomplete TRIM Data", 8, 8},
+ { "% Age of Completed TRIM", 1, 2},
+ { "Background Back-Pressure Gauge", 1, 1},
+ { "Reserved", 0, 3},
+ { "Soft ECC Error Count", 8, 8},
+ { "Refresh Count", 8, 8},
+ { "Normalized Bad System NAND Block Count", 2, 2},
+ { "Raw Bad System NAND Block Count", 6, 6},
+ { "Endurance Estimate", 16, 16},
+ { "Thermal Throttling Status", 1, 1},
+ { "Thermal Throttling Count", 1, 1},
+ { "Unaligned I/O", 8, 8},
+ { "Physical Media Units Read", 16, 16},
+ { "Reserved", 279, 0},
+ { "Log Page Version", 2, 0},
+ { "READ CMDs exceeding threshold", 0, 4},
+ { "WRITE CMDs exceeding threshold", 0, 4},
+ { "TRIMs CMDs exceeding threshold", 0, 4},
+ { "Reserved", 0, 4},
+ { "Reserved", 0, 210},
+ { "Log Page Version", 0, 2},
+ { "Log Page GUID", 0, 16},
+};
+
+/*
+ * Common function to print Micron VS log pages
+ * - buf: raw log data
+ * - log_page: format of the data
+ * - field_count: log field count
+ * - stats: json object to add fields
+ * - spec: ocp spec index
+ */
+static void print_micron_vs_logs(__u8 *buf, struct micron_vs_logpage *log_page, int field_count,
+ struct json_object *stats, __u8 spec)
+{
+ __u64 lval_lo, lval_hi;
+ __u32 ival;
+ __u16 sval;
+ __u8 cval, lval[8] = { 0 };
+ int field;
+ int offset = 0;
+
+ for (field = 0; field < field_count; field++) {
+ char datastr[1024] = { 0 };
+ char *sfield = NULL;
+ int size = !spec ? log_page[field].size : log_page[field].size2;
+
+ if (!size)
+ continue;
+ sfield = log_page[field].field;
+ if (size == 16) {
+ if (strstr(sfield, "GUID")) {
+ sprintf(datastr, "0x%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset + 8])),
+ (uint64_t)le64_to_cpu(*(uint64_t *)(&buf[offset])));
+ } else {
+ lval_lo = *((__u64 *)(&buf[offset]));
+ lval_hi = *((__u64 *)(&buf[offset + 8]));
+ if (lval_hi)
+ sprintf(datastr, "0x%"PRIx64"%016"PRIx64"",
+ le64_to_cpu(lval_hi), le64_to_cpu(lval_lo));
+ else
+ sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
+ }
+ } else if (size == 8) {
+ lval_lo = *((__u64 *)(&buf[offset]));
+ sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
+ } else if (size == 7) {
+ /* 7 bytes will be in little-endian format, with last byte as MSB */
+ memcpy(&lval[0], &buf[offset], 7);
+ memcpy((void *)&lval_lo, lval, 8);
+ sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo));
+ } else if (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 (size == 4) {
+ ival = *((__u32 *)(&buf[offset]));
+ sprintf(datastr, "0x%x", le32_to_cpu(ival));
+ } else if (size == 2) {
+ sval = *((__u16 *)(&buf[offset]));
+ sprintf(datastr, "0x%04x", le16_to_cpu(sval));
+ } else if (size == 1) {
+ cval = buf[offset];
+ sprintf(datastr, "0x%02x", cval);
+ } else {
+ sprintf(datastr, "0");
+ }
+ offset += size;
+ /* do not print reserved values */
+ if (strstr(sfield, "Reserved"))
+ continue;
+ if (stats)
+ json_object_add_value_string(stats, sfield, datastr);
+ else
+ printf("%-40s : %-4s\n", sfield, datastr);
+ }
+}
+
+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 = ARRAY_SIZE(ocp_c0_log_page);
+
+ 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, 0);
+
+ if (is_json) {
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
+
+static void print_nand_stats_fb(__u8 *buf, __u8 *buf2, __u8 nsze, bool is_json, __u8 spec)
+{
+ struct json_object *root;
+ struct json_object *logPages;
+ struct json_object *stats = NULL;
+ int field_count = ARRAY_SIZE(fb_log_page);
+
+ 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, spec);
+
+ /* print last three entries from D0 log page */
+ if (buf2) {
+ init_d0_log_page(buf2, nsze);
+
+ if (is_json) {
+ for (int i = 0; i < 7; i++)
+ json_object_add_value_string(stats,
+ d0_log_page[i].field,
+ d0_log_page[i].datastr);
+ } else {
+ for (int i = 0; i < 7; i++)
+ printf("%-40s : %s\n", d0_log_page[i].field, d0_log_page[i].datastr);
+ }
+ }
+
+ if (is_json) {
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
+
+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 bool nsze_from_oacs; /* read nsze for now from idd[4059] */
+
+static int micron_nand_stats(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ 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 };
+ enum eDriveModel eModel = UNKNOWN_MODEL;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_dev *dev;
+ int 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (!strcmp(cfg.fmt, "normal"))
+ is_json = false;
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ printf("Error %d retrieving controller identification data\n", err);
+ goto out;
+ }
+
+ /* pull log details based on the model name */
+ if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1)
+ ctrlIdx = 0;
+ eModel = GetDriveModel(ctrlIdx);
+ if ((eModel == UNKNOWN_MODEL) || (eModel == M51CX)) {
+ printf("Unsupported drive model for vs-nand-stats command\n");
+ err = -1;
+ goto out;
+ }
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xD0, D0_log_size, extSmartLog);
+ has_d0_log = !err;
+
+ /* should check for firmware version if this log is supported or not */
+ if (eModel == M5407 || eModel == M5410) {
+ err = nvme_get_log_simple(dev_fd(dev), 0xFB, FB_log_size, logFB);
+ has_fb_log = !err;
+ }
+
+ nsze = (ctrl.vs[987] == 0x12);
+ if (!nsze && nsze_from_oacs)
+ nsze = ((ctrl.oacs >> 3) & 0x1);
+ err = 0;
+ if (has_fb_log) {
+ __u8 spec = (eModel == M5410) ? 0 : 1; /* FB spec version */
+
+ print_nand_stats_fb((__u8 *)logFB, (__u8 *)extSmartLog, nsze, is_json, spec);
+ } else if (has_d0_log) {
+ print_nand_stats_d0((__u8 *)extSmartLog, nsze, is_json);
+ } else {
+ printf("Unable to retrieve extended smart log for the drive\n");
+ err = -ENOTTY;
+ }
+out:
+ dev_close(dev);
+ if (err > 0)
+ nvme_show_status(err);
+
+ return err;
+}
+
+static void print_ext_smart_logs_e1(__u8 *buf, bool is_json)
+{
+ struct json_object *root;
+ struct json_object *logPages;
+ struct json_object *stats = NULL;
+ int field_count = ARRAY_SIZE(e1_log_page);
+
+ if (is_json) {
+ root = json_create_object();
+ stats = json_create_object();
+ logPages = json_create_array();
+ json_object_add_value_array(root, "SMART Extended Log:0xE1", logPages);
+ } else {
+ printf("SMART Extended Log:0xE1\n");
+ }
+
+ print_micron_vs_logs(buf, e1_log_page, field_count, stats, 0);
+
+ if (is_json) {
+ json_array_add_value_object(logPages, stats);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
+
+static int micron_smart_ext_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve extended SMART logs for the given device ";
+ unsigned int extSmartLog[E1_log_size/sizeof(int)] = { 0 };
+ enum eDriveModel eModel = UNKNOWN_MODEL;
+ int err = 0, ctrlIdx;
+ struct nvme_dev *dev;
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+ if (!strcmp(cfg.fmt, "normal"))
+ is_json = false;
+
+ if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1)
+ ctrlIdx = 0;
+ eModel = GetDriveModel(ctrlIdx);
+ if (eModel != M51CX) {
+ printf("Unsupported drive model for vs-smart-ext-log command\n");
+ err = -1;
+ goto out;
+ }
+ err = nvme_get_log_simple(dev_fd(dev), 0xE1, E1_log_size, extSmartLog);
+ if (!err)
+ print_ext_smart_logs_e1((__u8 *)extSmartLog, is_json);
+
+out:
+ dev_close(dev);
+ if (err > 0)
+ nvme_show_status(err);
+ return err;
+}
+
+static void GetDriveInfo(const char *strOSDirName, int nFD,
+ 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("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)
+{
+ __u8 outstr[1024];
+ time_t t;
+ struct tm *tmp;
+ size_t num;
+ char *strPDir;
+ char *strDest;
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (!tmp)
+ 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 *dir, struct nvme_id_ctrl *ctrlp)
+{
+ WriteData((__u8 *)ctrlp, sizeof(*ctrlp), dir,
+ "nvme_controller_identify_data.bin", "id-ctrl");
+}
+
+static void GetSmartlogData(int fd, const char *dir)
+{
+ struct nvme_smart_log smart_log;
+
+ if (!nvme_get_log_smart(fd, -1, false, &smart_log))
+ WriteData((__u8 *)&smart_log, sizeof(smart_log), dir,
+ "smart_data.bin", "smart log");
+}
+
+static void GetErrorlogData(int fd, int entries, const char *dir)
+{
+ 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)
+ return;
+
+ if (!nvme_get_log_error(fd, entries, false, error_log))
+ WriteData((__u8 *)error_log, logSize, dir,
+ "error_information_log.bin", "error log");
+
+ free(error_log);
+}
+
+static void GetGenericLogs(int fd, const char *dir)
+{
+ struct nvme_self_test_log self_test_log;
+ struct nvme_firmware_slot fw_log;
+ struct nvme_cmd_effects_log effects;
+ struct nvme_persistent_event_log pevent_log;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ void *pevent_log_info = NULL;
+ __u32 log_len = 0;
+ int err = 0;
+
+ /* get self test log */
+ if (!nvme_get_log_device_self_test(fd, &self_test_log))
+ WriteData((__u8 *)&self_test_log, sizeof(self_test_log), dir,
+ "drive_self_test.bin", "self test log");
+
+ /* get fw slot info log */
+ if (!nvme_get_log_fw_slot(fd, false, &fw_log))
+ WriteData((__u8 *)&fw_log, sizeof(fw_log), dir,
+ "firmware_slot_info_log.bin", "firmware log");
+
+ /* get effects log */
+ if (!nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects))
+ WriteData((__u8 *)&effects, sizeof(effects), dir,
+ "command_effects_log.bin", "effects log");
+
+ /* get persistent event log */
+ (void)nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_RELEASE_CTX,
+ sizeof(pevent_log), &pevent_log);
+ memset(&pevent_log, 0, sizeof(pevent_log));
+ err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_EST_CTX_AND_READ,
+ sizeof(pevent_log), &pevent_log);
+ if (err) {
+ fprintf(stderr, "Setting persistent event log read ctx failed (ignored)!\n");
+ return;
+ }
+
+ log_len = le64_to_cpu(pevent_log.tll);
+ pevent_log_info = nvme_alloc_huge(log_len, &mh);
+ if (!pevent_log_info) {
+ perror("could not alloc buffer for persistent event log page (ignored)!\n");
+ return;
+ }
+
+ err = nvme_get_log_persistent_event(fd, NVME_PEVENT_LOG_READ,
+ log_len, pevent_log_info);
+ if (!err)
+ WriteData((__u8 *)pevent_log_info, log_len, dir,
+ "persistent_event_log.bin", "persistent event log");
+}
+
+static void GetNSIDDInfo(int fd, const char *dir, int nsid)
+{
+ char file[PATH_MAX] = { 0 };
+ struct nvme_id_ns ns;
+
+ if (!nvme_identify_ns(fd, nsid, &ns)) {
+ 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];
+ 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+");
+ if (fpOSConfig) {
+ fprintf(fpOSConfig,
+ "\n\n\n\n%s\n-----------------------------------------------\n",
+ cmdArray[i].strcmdHeader);
+ fclose(fpOSConfig);
+ fpOSConfig = NULL;
+ }
+ snprintf(strBuffer, sizeof(strBuffer) - 1,
+ cmdArray[i].strCommand, strFileName);
+ if (system(strBuffer))
+ fprintf(stderr, "Failed to send \"%s\"\n", strBuffer);
+ }
+}
+
+static int micron_telemetry_log(int fd, __u8 type, __u8 **data,
+ int *logSize, int da)
+{
+ int err, bs = 512, offset = bs;
+ unsigned short data_area[4];
+ unsigned char ctrl_init = (type == 0x8);
+
+ __u8 *buffer = (unsigned char *)calloc(bs, 1);
+
+ if (!buffer)
+ return -1;
+ if (ctrl_init)
+ err = nvme_get_log_telemetry_ctrl(fd, true, 0, bs, buffer);
+ else
+ err = nvme_get_log_telemetry_host(fd, 0, bs, buffer);
+ if (err) {
+ fprintf(stderr, "Failed to get telemetry log header for 0x%X\n", type);
+ if (buffer)
+ free(buffer);
+ return err;
+ }
+
+ /* compute size of the log */
+ data_area[1] = buffer[9] << 8 | buffer[8];
+ data_area[2] = buffer[11] << 8 | buffer[10];
+ data_area[3] = buffer[13] << 8 | buffer[12];
+ data_area[0] = data_area[1] > data_area[2] ? data_area[1] : data_area[2];
+ data_area[0] = data_area[3] > data_area[0] ? data_area[3] : data_area[0];
+
+ if (!data_area[da]) {
+ fprintf(stderr, "Requested telemetry data for 0x%X is empty\n", type);
+ if (buffer) {
+ free(buffer);
+ buffer = NULL;
+ }
+ return -1;
+ }
+
+ *logSize = data_area[da] * bs;
+ offset = bs;
+ err = 0;
+ buffer = (unsigned char *)realloc(buffer, (size_t)(*logSize));
+ if (buffer) {
+ while (!err && offset != *logSize) {
+ if (ctrl_init)
+ err = nvme_get_log_telemetry_ctrl(fd, true, 0, *logSize, buffer + offset);
+ else
+ err = nvme_get_log_telemetry_host(fd, 0, *logSize, buffer + offset);
+ offset += bs;
+ }
+ }
+
+ if (!err && buffer) {
+ *data = buffer;
+ } else {
+ fprintf(stderr, "Failed to get telemetry data for 0x%x\n", type);
+ if (buffer)
+ 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, "nvmetelemetrylog.bin"},
+ {0x08, "nvmetelemetrylog.bin"},
+ };
+
+ for (i = 0; i < (int)(ARRAY_SIZE(tmap)); i++) {
+ err = micron_telemetry_log(fd, tmap[i].log, &buffer, &logSize, 0);
+ if (!err && logSize > 0 && buffer) {
+ sprintf(msg, "telemetry log: 0x%X", tmap[i].log);
+ WriteData(buffer, logSize, dir, tmap[i].file, msg);
+ }
+ if (buffer) {
+ 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)(ARRAY_SIZE(fmap)); i++) {
+ if (fmap[i].id == 0x03) {
+ len = 4096;
+ bufp = (unsigned char *)(&buf[0]);
+ } else {
+ len = 0;
+ bufp = NULL;
+ }
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .fid = fmap[i].id,
+ .nsid = 1,
+ .sel = 0,
+ .cdw11 = 0x0,
+ .uuidx = 0,
+ .data_len = len,
+ .data = bufp,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &attrVal,
+ };
+ err = nvme_get_features(&args);
+ if (!err) {
+ sprintf(msg, "feature: 0x%X", fmap[i].id);
+ WriteData((__u8 *)&attrVal, sizeof(attrVal), dir, fmap[i].file, msg);
+ if (bufp)
+ WriteData(bufp, len, dir, fmap[i].file, msg);
+ } else {
+ fprintf(stderr, "Feature 0x%x data not retrieved, error %d (ignored)!\n",
+ fmap[i].id, err);
+ errcnt++;
+ }
+ }
+ return (int)(errcnt == ARRAY_SIZE(fmap));
+}
+
+static int micron_drive_info(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Get drive HW information";
+ struct nvme_id_ctrl ctrl = { 0 };
+ struct nvme_passthru_cmd admin_cmd = { 0 };
+ struct fb_drive_info {
+ unsigned char hw_ver_major;
+ unsigned char hw_ver_minor;
+ unsigned char ftl_unit_size;
+ unsigned char bs_ver_major;
+ unsigned char bs_ver_minor;
+ } dinfo = { 0 };
+ enum eDriveModel model = UNKNOWN_MODEL;
+ bool is_json = false;
+ struct json_object *root, *driveInfo;
+ struct nvme_dev *dev;
+ struct format {
+ char *fmt;
+ };
+ int err = 0;
+
+ const char *fmt = "output format normal";
+ struct format cfg = {
+ .fmt = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+
+ if (model == UNKNOWN_MODEL) {
+ fprintf(stderr, "ERROR : Unsupported drive for vs-drive-info cmd");
+ dev_close(dev);
+ return -1;
+ }
+
+ if (!strcmp(cfg.fmt, "json"))
+ is_json = true;
+
+ if (model == M5407) {
+ admin_cmd.opcode = 0xD4,
+ admin_cmd.addr = (__u64) (uintptr_t) &dinfo;
+ admin_cmd.data_len = (__u32)sizeof(dinfo);
+ admin_cmd.cdw12 = 3;
+ err = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ if (err) {
+ fprintf(stderr, "ERROR : drive-info opcode failed with 0x%x\n", err);
+ dev_close(dev);
+ return -1;
+ }
+ } else {
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR : identify_ctrl() failed with 0x%x\n", err);
+ dev_close(dev);
+ return -1;
+ }
+ dinfo.hw_ver_major = ctrl.vs[820];
+ dinfo.hw_ver_minor = ctrl.vs[821];
+ dinfo.ftl_unit_size = ctrl.vs[822];
+ }
+
+ if (is_json) {
+ struct json_object *pinfo = json_create_object();
+ char tempstr[64] = { 0 };
+
+ root = json_create_object();
+ driveInfo = json_create_array();
+ json_object_add_value_array(root, "Micron Drive HW Information", driveInfo);
+ sprintf(tempstr, "%u.%u", dinfo.hw_ver_major, dinfo.hw_ver_minor);
+ json_object_add_value_string(pinfo, "Drive Hardware Version", tempstr);
+
+ if (dinfo.ftl_unit_size) {
+ sprintf(tempstr, "%u KB", dinfo.ftl_unit_size);
+ json_object_add_value_string(pinfo, "FTL_unit_size", tempstr);
+ }
+
+ if (dinfo.bs_ver_major || dinfo.bs_ver_minor) {
+ sprintf(tempstr, "%u.%u", dinfo.bs_ver_major, dinfo.bs_ver_minor);
+ json_object_add_value_string(pinfo, "Boot Spec.Version", tempstr);
+ }
+
+ json_array_add_value_object(driveInfo, pinfo);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ printf("Drive Hardware Version: %u.%u\n",
+ dinfo.hw_ver_major, dinfo.hw_ver_minor);
+
+ if (dinfo.ftl_unit_size)
+ printf("FTL_unit_size: %u KB\n", dinfo.ftl_unit_size);
+
+ if (dinfo.bs_ver_major || dinfo.bs_ver_minor)
+ printf("Boot Spec.Version: %u.%u\n",
+ dinfo.bs_ver_major, dinfo.bs_ver_minor);
+ }
+
+ dev_close(dev);
+ 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;
+}
+
+/* Binary format of firmware activation history entry */
+struct __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 __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];
+};
+
+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;
+ static const char * const ca[] = {"000b", "001b", "010b", "011b"};
+ char *ptr = formatted_entry;
+ int index = 0, entry_size = 82;
+
+ if ((entry->version != 1 && entry->version != 2) || entry->length != 64)
+ 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":%u:%u", (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 characters with spaces */
+ ptr = formatted_entry;
+ while (index < entry_size) {
+ if (ptr[index] == '\0')
+ ptr[index] = ' ';
+ index++;
+ }
+ return 0;
+}
+
+static void micron_fw_activation_history_header_print(void)
+{
+ /* header to be printed field widths = 10 | 12 | 10 | 11 | 12 | 9 | 9 | 9 */
+ printf("__________________________________________________________________________________\n");
+ printf(" | | | | | | |\n");
+ printf("Firmware | Power On | Power | Previous | New FW | Slot | Commit | Result\n");
+ printf("Activation| Hour | cycle | firmware | activated | number | Action |\n");
+ printf("Counter | | count | | | | Type |\n");
+ printf("__________|___________|_________|__________|___________|________|________|________\n");
+}
+
+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 };
+ enum eDriveModel eModel = UNKNOWN_MODEL;
+ struct nvme_dev *dev;
+ struct format {
+ char *fmt;
+ };
+ int err;
+
+ const char *fmt = "output format normal";
+ struct format cfg = {
+ .fmt = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel);
+ if (err < 0)
+ return -1;
+
+ if (strcmp(cfg.fmt, "normal")) {
+ fprintf(stderr, "only normal format is supported currently\n");
+ dev_close(dev);
+ return -1;
+ }
+
+ /* check if product supports fw_history log */
+ err = -EINVAL;
+ if (eModel != M51CX) {
+ fprintf(stderr, "Unsupported drive model for vs-fw-activate-history command\n");
+ goto out;
+ }
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xC2, 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 at least 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->log_page != 0xC2 || (table->version != 2 && table->version != 1)) {
+ fprintf(stderr, "Unsupported fw activation history page: %x, version: %x\n",
+ table->log_page, table->version);
+ goto out;
+ }
+
+ if (!table->num_entries) {
+ fprintf(stderr, "No entries were found in fw activation history log\n");
+ goto out;
+ }
+
+ micron_fw_activation_history_header_print();
+ 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))
+ printf("%s\n", formatted_output);
+ }
+out:
+ dev_close(dev);
+ return err;
+}
+
+#define MICRON_FID_LATENCY_MONITOR 0xD0
+#define MICRON_LOG_LATENCY_MONITOR 0xD1
+
+static int micron_latency_stats_track(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+ __u32 result = 0;
+ const char *desc = "Enable, Disable or Get cmd latency monitoring stats";
+ const char *option = "enable or disable or status, default is status";
+ const char *command =
+ "commands to monitor for - all|read|write|trim, default is all i.e, enabled for all commands";
+ const char *thrtime =
+ "The threshold value to use for latency monitoring in milliseconds, default is 800ms";
+
+ int fid = MICRON_FID_LATENCY_MONITOR;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ uint32_t command_mask = 0x7; /* 1:read 2:write 4:trim 7:all */
+ uint32_t timing_mask = 0x08080800; /* R[31-24]:W[23:16]:T[15:8]:0 */
+ uint32_t enable = 2;
+ struct nvme_dev *dev;
+ struct {
+ char *option;
+ char *command;
+ uint32_t threshold;
+ } opt = {
+ .option = "status",
+ .command = "all",
+ .threshold = 0
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("option", 'o', "option", &opt.option, option),
+ OPT_STRING("command", 'c', "command", &opt.command, command),
+ OPT_UINT("threshold", 't', &opt.threshold, thrtime),
+ OPT_END()
+ };
+
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return -1;
+
+ if (!strcmp(opt.option, "enable")) {
+ enable = 1;
+ } else if (!strcmp(opt.option, "disable")) {
+ enable = 0;
+ } else if (strcmp(opt.option, "status")) {
+ printf("Invalid control option %s specified\n", opt.option);
+ dev_close(dev);
+ return -1;
+ }
+
+ struct nvme_get_features_args g_args = {
+ .args_size = sizeof(g_args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = 0,
+ .sel = 0,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&g_args);
+ if (err) {
+ printf("Failed to retrieve latency monitoring feature status\n");
+ dev_close(dev);
+ return err;
+ }
+
+ /* If it is to retrieve the status only */
+ if (enable == 2) {
+ printf("Latency Tracking Statistics is currently %s",
+ (result & 0xFFFF0000) ? "enabled" : "disabled");
+ if ((result & 7) == 7) {
+ printf(" for All commands\n");
+ } else if ((result & 7) > 0) {
+ printf(" for");
+ if (result & 1)
+ printf(" Read");
+ if (result & 2)
+ printf(" Write");
+ if (result & 4)
+ printf(" Trim");
+ printf(" commands\n");
+ } else if (!result) {
+ printf("\n");
+ }
+ dev_close(dev);
+ return err;
+ }
+
+ /* read and validate threshold values if enable option is specified */
+ if (enable == 1) {
+ if (opt.threshold > 2550) {
+ printf("The maximum threshold value cannot be more than 2550 ms\n");
+ dev_close(dev);
+ return -1;
+ } else if (opt.threshold % 10) {
+ /* timing mask is in terms of 10ms units, so min allowed is 10ms */
+ printf("The threshold value should be multiple of 10 ms\n");
+ dev_close(dev);
+ return -1;
+ }
+ opt.threshold /= 10;
+ }
+
+ /* read-in command(s) to be monitored */
+ if (!strcmp(opt.command, "read")) {
+ command_mask = 0x1;
+ timing_mask = (opt.threshold << 24);
+ } else if (!strcmp(opt.command, "write")) {
+ command_mask = 0x2;
+ timing_mask = (opt.threshold << 16);
+ } else if (!strcmp(opt.command, "trim")) {
+ command_mask = 0x4;
+ timing_mask = (opt.threshold << 8);
+ } else if (strcmp(opt.command, "all")) {
+ printf("Invalid command %s specified for option %s\n",
+ opt.command, opt.option);
+ dev_close(dev);
+ return -1;
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = MICRON_FID_LATENCY_MONITOR,
+ .nsid = 0,
+ .cdw11 = enable,
+ .cdw12 = command_mask,
+ .save = 1,
+ .uuidx = 0,
+ .cdw13 = timing_mask,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (!err) {
+ printf("Successfully %sd latency monitoring for %s commands with %dms threshold\n",
+ opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10);
+ } else {
+ printf("Failed to %s latency monitoring for %s commands with %dms threshold\n",
+ opt.option, opt.command, !opt.threshold ? 800 : opt.threshold * 10);
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+
+static int micron_latency_stats_logs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+#define LATENCY_LOG_ENTRIES 16
+ struct latency_log_entry {
+ uint64_t timestamp;
+ uint32_t latency;
+ uint32_t cmdtag;
+ union {
+ struct {
+ uint32_t opcode:8;
+ uint32_t fuse:2;
+ uint32_t rsvd1:4;
+ uint32_t psdt:2;
+ uint32_t cid:16;
+ };
+ uint32_t dw0;
+ };
+ uint32_t nsid;
+ uint32_t slba_low;
+ uint32_t slba_high;
+ union {
+ struct {
+ uint32_t nlb:16;
+ uint32_t rsvd2:9;
+ uint32_t deac:1;
+ uint32_t prinfo:4;
+ uint32_t fua:1;
+ uint32_t lr:1;
+ };
+ uint32_t dw12;
+ };
+ uint32_t dsm;
+ uint32_t rfu[6];
+ } log[LATENCY_LOG_ENTRIES];
+ enum eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_dev *dev;
+ int err = -1;
+ const char *desc = "Display Latency tracking log information";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err)
+ return err;
+ memset(&log, 0, sizeof(log));
+ err = nvme_get_log_simple(dev_fd(dev), 0xD1, sizeof(log), &log);
+ if (err) {
+ if (err < 0)
+ printf("Unable to retrieve latency stats log the drive\n");
+ dev_close(dev);
+ return err;
+ }
+ /* print header and each log entry */
+ printf("Timestamp, Latency, CmdTag, Opcode, Fuse, Psdt, Cid, Nsid, Slba_L, Slba_H, Nlb, ");
+ printf("DEAC, PRINFO, FUA, LR\n");
+ for (int i = 0; i < LATENCY_LOG_ENTRIES; i++)
+ printf("%"PRIu64",%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u\n",
+ log[i].timestamp, log[i].latency, log[i].cmdtag, log[i].opcode,
+ log[i].fuse, log[i].psdt, log[i].cid, log[i].nsid,
+ log[i].slba_low, log[i].slba_high, log[i].nlb,
+ log[i].deac, log[i].prinfo, log[i].fua, log[i].lr);
+ printf("\n");
+ dev_close(dev);
+ return err;
+}
+
+static int micron_latency_stats_info(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "display command latency statistics";
+ const char *command = "command to display stats - all|read|write|trimdefault is all";
+ int err = 0;
+ struct nvme_dev *dev;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ #define LATENCY_BUCKET_COUNT 32
+ #define LATENCY_BUCKET_RSVD 32
+ struct micron_latency_stats {
+ uint64_t version; /* major << 32 | minior */
+ uint64_t all_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t read_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t write_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint64_t trim_cmds[LATENCY_BUCKET_COUNT + LATENCY_BUCKET_RSVD];
+ uint32_t reserved[255]; /* round up to 4K */
+ } log;
+
+ struct latency_thresholds {
+ uint32_t start;
+ uint32_t end;
+ char *unit;
+ } thresholds[LATENCY_BUCKET_COUNT] = {
+ {0, 50, "us"}, {50, 100, "us"}, {100, 150, "us"}, {150, 200, "us"},
+ {200, 300, "us"}, {300, 400, "us"}, {400, 500, "us"}, {500, 600, "us"},
+ {600, 700, "us"}, {700, 800, "us"}, {800, 900, "us"}, {900, 1000, "us"},
+ {1, 5, "ms"}, {5, 10, "ms"}, {10, 20, "ms"}, {20, 50, "ms"}, {50, 100, "ms"},
+ {100, 200, "ms"}, {200, 300, "ms"}, {300, 400, "ms"}, {400, 500, "ms"},
+ {500, 600, "ms"}, {600, 700, "ms"}, {700, 800, "ms"}, {800, 900, "ms"},
+ {900, 1000, "ms"}, {1, 2, "s"}, {2, 3, "s"}, {3, 4, "s"}, {4, 5, "s"},
+ {5, 8, "s"},
+ {8, INT_MAX, "s"},
+ };
+
+ struct {
+ char *command;
+ } opt = {
+ .command = "all"
+ };
+
+ uint64_t *cmd_stats = &log.all_cmds[0];
+ char *cmd_str = "All";
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("command", 'c', "command", &opt.command, command),
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+ if (!strcmp(opt.command, "read")) {
+ cmd_stats = &log.read_cmds[0];
+ cmd_str = "Read";
+ } else if (!strcmp(opt.command, "write")) {
+ cmd_stats = &log.write_cmds[0];
+ cmd_str = "Write";
+ } else if (!strcmp(opt.command, "trim")) {
+ cmd_stats = &log.trim_cmds[0];
+ cmd_str = "Trim";
+ } else if (strcmp(opt.command, "all")) {
+ printf("Invalid command option %s to display latency stats\n", opt.command);
+ dev_close(dev);
+ return -1;
+ }
+
+ memset(&log, 0, sizeof(log));
+ err = nvme_get_log_simple(dev_fd(dev), 0xD0, sizeof(log), &log);
+ if (err) {
+ if (err < 0)
+ printf("Unable to retrieve latency stats log the drive\n");
+ dev_close(dev);
+ return err;
+ }
+ printf("Micron IO %s Command Latency Statistics\n"
+ "Major Revision : %d\nMinor Revision : %d\n",
+ cmd_str, (int)(log.version >> 32), (int)(log.version & 0xFFFFFFFF));
+ printf("=============================================\n");
+ printf("Bucket Start End Command Count\n");
+ printf("=============================================\n");
+
+ for (int b = 0; b < LATENCY_BUCKET_COUNT; b++) {
+ int bucket = b + 1;
+ char start[32] = { 0 };
+ char end[32] = { 0 };
+
+ sprintf(start, "%u%s", thresholds[b].start, thresholds[b].unit);
+ if (thresholds[b].end == INT_MAX)
+ sprintf(end, "INF");
+ else
+ sprintf(end, "%u%s", thresholds[b].end, thresholds[b].unit);
+ printf("%2d %8s %8s %8"PRIu64"\n", bucket, start, end, cmd_stats[b]);
+ }
+ dev_close(dev);
+ return err;
+}
+
+static int micron_ocp_smart_health_logs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Smart or Extended Smart Health log for the given device ";
+ unsigned int logC0[C0_log_size/sizeof(int)] = { 0 };
+ unsigned int logFB[FB_log_size/sizeof(int)] = { 0 };
+ struct nvme_id_ctrl ctrl;
+ enum eDriveModel eModel = UNKNOWN_MODEL;
+ struct nvme_dev *dev;
+ bool is_json = true;
+ struct format {
+ char *fmt;
+ };
+ const char *fmt = "output format normal|json";
+ struct format cfg = {
+ .fmt = "json",
+ };
+ int err = 0;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("format", 'f', &cfg.fmt, fmt),
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &eModel);
+ if (err < 0)
+ return -1;
+
+ if (!strcmp(cfg.fmt, "normal"))
+ is_json = false;
+
+ /* For M5410 and M5407, this option prints 0xFB log page */
+ if (eModel == M5410 || eModel == M5407) {
+ __u8 spec = (eModel == M5410) ? 0 : 1;
+ __u8 nsze;
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err)
+ err = nvme_get_log_simple(dev_fd(dev), 0xFB, FB_log_size, logFB);
+ if (err) {
+ if (err < 0)
+ printf("Unable to retrieve smart log 0xFB for the drive\n");
+ goto out;
+ }
+
+ nsze = (ctrl.vs[987] == 0x12);
+ if (!nsze && nsze_from_oacs)
+ nsze = ((ctrl.oacs >> 3) & 0x1);
+ print_nand_stats_fb((__u8 *)logFB, NULL, nsze, is_json, spec);
+ goto out;
+ }
+
+ /* check for models that support 0xC0 log */
+ if (eModel != M51CX) {
+ printf("Unsupported drive model for vs-smart-add-log command\n");
+ err = -1;
+ goto out;
+ }
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xC0, C0_log_size, logC0);
+ if (!err)
+ print_smart_cloud_health_log((__u8 *)logC0, is_json);
+ else if (err < 0)
+ printf("Unable to retrieve extended smart log 0xC0 for the drive\n");
+out:
+ dev_close(dev);
+ if (err > 0)
+ nvme_show_status(err);
+ 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";
+ __u32 result = 0;
+ __u8 fid = MICRON_FEATURE_CLEAR_FW_ACTIVATION_HISTORY;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_dev *dev;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+ int err = 0;
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+
+ if (model != M51CX) {
+ printf("This option is not supported for specified drive\n");
+ dev_close(dev);
+ return err;
+ }
+
+ err = nvme_set_features_simple(dev_fd(dev), fid, 1 << 31, 0, 0, &result);
+ if (!err)
+ err = (int)result;
+ else
+ printf("Failed to clear fw activation history, error = 0x%x\n", err);
+
+ dev_close(dev);
+ 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 options1 - save (persistent), 0 - non-persistent and for status options: 0 - current, 1 - default, 2-saved";
+ int fid = MICRON_FEATURE_TELEMETRY_CONTROL_OPTION;
+ enum eDriveModel model = UNKNOWN_MODEL;
+ struct nvme_id_ctrl ctrl = { 0 };
+ struct nvme_dev *dev;
+
+ 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()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return -1;
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if ((ctrl.lpa & 0x8) != 0x8) {
+ printf("drive doesn't support host/controller generated telemetry logs\n");
+ dev_close(dev);
+ return err;
+ }
+
+ if (!strcmp(opt.option, "enable")) {
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = 1,
+ .cdw11 = 1,
+ .cdw12 = 0,
+ .save = (opt.select & 0x1),
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (!err)
+ printf("successfully set controller telemetry option\n");
+ else
+ printf("Failed to set controller telemetry option\n");
+ } else if (!strcmp(opt.option, "disable")) {
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = 1,
+ .cdw11 = 0,
+ .cdw12 = 0,
+ .save = (opt.select & 0x1),
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (!err)
+ printf("successfully disabled controller telemetry option\n");
+ else
+ printf("Failed to disable controller telemetry option\n");
+ } else if (!strcmp(opt.option, "status")) {
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = 1,
+ .sel = opt.select & 0x3,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err)
+ 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);
+ dev_close(dev);
+ return -1;
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+/* M51XX models log page header */
+struct micron_common_log_header {
+ uint8_t id;
+ uint8_t version;
+ uint16_t pn;
+ uint32_t log_size;
+ uint32_t max_size;
+ uint32_t write_pointer;
+ uint32_t next_pointer;
+ uint32_t overwritten_bytes;
+ uint8_t flags;
+ uint8_t reserved[7];
+};
+
+/* helper function to retrieve logs with specific offset and max chunk size */
+int nvme_get_log_lpo(int fd, __u8 log_id, __u32 lpo, __u32 chunk,
+ __u32 data_len, void *data)
+{
+ __u32 offset = lpo, xfer_len = data_len;
+ void *ptr = data;
+ struct nvme_get_log_args args = {
+ .lpo = offset,
+ .result = NULL,
+ .log = ptr,
+ .args_size = sizeof(args),
+ .fd = fd,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = log_id,
+ .len = xfer_len,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .uuidx = NVME_UUID_NONE,
+ .rae = false,
+ .ot = false,
+ };
+ int ret = 0;
+
+ /* divide data into multiple chunks */
+ do {
+ xfer_len = data_len - offset;
+ if (xfer_len > chunk)
+ xfer_len = chunk;
+
+ args.lpo = offset;
+ args.log = ptr;
+ args.len = xfer_len;
+ ret = nvme_get_log(&args);
+ if (ret)
+ return ret;
+ offset += xfer_len;
+ ptr += xfer_len;
+ } while (offset < data_len);
+ return ret;
+}
+
+/* retrieves logs with common log format */
+static int get_common_log(int fd, uint8_t id, uint8_t **buf, int *size)
+{
+ struct micron_common_log_header hdr = { 0 };
+ int log_size = sizeof(hdr), first = 0, second = 0;
+ uint8_t *buffer = NULL;
+ int ret = -1;
+ int chunk = 0x4000; /* max chunk size to be used for these logs */
+
+ ret = nvme_get_log_simple(fd, id, sizeof(hdr), &hdr);
+ if (ret) {
+ fprintf(stderr, "pull hdr failed for %u with error: 0x%x\n", id, ret);
+ return ret;
+ }
+
+ if (hdr.id != id || !hdr.log_size || !hdr.max_size ||
+ hdr.write_pointer < sizeof(hdr)) {
+ fprintf(stderr,
+ "invalid log data for LOG: 0x%X, id: 0x%X, size: %u, max: %u, wp: %u, flags: %u, np: %u\n",
+ id, hdr.id, hdr.log_size, hdr.max_size, hdr.write_pointer, hdr.flags,
+ hdr.next_pointer);
+ return 1;
+ }
+
+ /*
+ * we may have just 32-bytes for some models; write to wfile if log hasn't
+ * yet reached its max size
+ */
+ if (hdr.log_size == sizeof(hdr)) {
+ buffer = (uint8_t *)malloc(sizeof(hdr));
+ if (!buffer) {
+ fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n",
+ sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer, (uint8_t *)&hdr, sizeof(hdr));
+ } else if (hdr.log_size < hdr.max_size) {
+ buffer = (uint8_t *)malloc(sizeof(hdr) + hdr.log_size);
+ if (!buffer) {
+ fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n",
+ hdr.log_size + sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer, &hdr, sizeof(hdr));
+ ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, hdr.log_size,
+ buffer + sizeof(hdr));
+ if (!ret)
+ log_size += hdr.log_size;
+ } else if (hdr.log_size >= hdr.max_size) {
+ /*
+ * reached maximum, to maintain, sequence we need to depend on write
+ * pointer to detect wrap-overs. FW doesn't yet implement the condition
+ * hdr.log_size > hdr.max_size; also ignore over-written log data; we
+ * also ignore collisions for now
+ */
+ buffer = (uint8_t *)malloc(hdr.max_size + sizeof(hdr));
+ if (!buffer) {
+ fprintf(stderr, "malloc of %zu bytes failed for log: 0x%X\n",
+ hdr.max_size + sizeof(hdr), id);
+ return -ENOMEM;
+ }
+ memcpy(buffer, &hdr, sizeof(hdr));
+
+ first = hdr.max_size - hdr.write_pointer;
+ second = hdr.write_pointer - sizeof(hdr);
+
+ if (first) {
+ ret = nvme_get_log_lpo(fd, id, hdr.write_pointer, chunk, first,
+ buffer + sizeof(hdr));
+ if (ret) {
+ free(buffer);
+ fprintf(stderr, "failed to get log: 0x%X\n", id);
+ return ret;
+ }
+ log_size += first;
+ }
+ if (second) {
+ ret = nvme_get_log_lpo(fd, id, sizeof(hdr), chunk, second,
+ buffer + sizeof(hdr) + first);
+ if (ret) {
+ fprintf(stderr, "failed to get log: 0x%X\n", id);
+ free(buffer);
+ return ret;
+ }
+ log_size += second;
+ }
+ }
+ *buf = buffer;
+ *size = log_size;
+ return ret;
+}
+
+static int micron_internal_logs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = -EINVAL;
+ 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 };
+ int c_logs_index = 8; /* should be current size of aVendorLogs */
+ struct nvme_dev *dev;
+ 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 }
+ },
+ aM51CXLogs[] = {
+ { 0xE1, "nvmelog_E1.bin", 0, 0 },
+ { 0xE2, "nvmelog_E2.bin", 0, 0 },
+ { 0xE3, "nvmelog_E3.bin", 0, 0 },
+ { 0xE4, "nvmelog_E4.bin", 0, 0 },
+ { 0xE5, "nvmelog_E5.bin", 0, 0 },
+ { 0xE8, "nvmelog_E8.bin", 0, 0 },
+ { 0xE9, "nvmelog_E9.bin", 0, 0 },
+ { 0xEA, "nvmelog_EA.bin", 0, 0 },
+ };
+
+ enum 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ /* if telemetry type is specified, check for data area */
+ if (strlen(cfg.type)) {
+ 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");
+ 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");
+ 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");
+ goto out;
+ }
+
+ if (!strlen(cfg.package)) {
+ 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 */
+ if (sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx) != 1)
+ ctrlIdx = 0;
+ eModel = GetDriveModel(ctrlIdx);
+ if (eModel == UNKNOWN_MODEL) {
+ printf("Unsupported drive model for vs-internal-log collection\n");
+ goto out;
+ }
+
+ err = nvme_identify_ctrl(dev_fd(dev), &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");
+ goto out;
+ }
+ int logSize = 0; __u8 *buffer = NULL; const char *dir = ".";
+
+ err = micron_telemetry_log(dev_fd(dev), cfg.log, &buffer, &logSize,
+ cfg.data_area);
+ if (!err && logSize > 0 && buffer) {
+ sprintf(msg, "telemetry log: 0x%X", cfg.log);
+ WriteData(buffer, logSize, dir, cfg.package, msg);
+ free(buffer);
+ }
+ 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((int)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(dev_fd(dev), strCtrlDirName, i);
+
+ GetSmartlogData(dev_fd(dev), strCtrlDirName);
+ GetErrorlogData(dev_fd(dev), ctrl.elpe, strCtrlDirName);
+ GetGenericLogs(dev_fd(dev), strCtrlDirName);
+ /* pull if telemetry log data is supported */
+ if ((ctrl.lpa & 0x8) == 0x8)
+ GetTelemetryData(dev_fd(dev), strCtrlDirName);
+
+ GetFeatureSettings(dev_fd(dev), strCtrlDirName);
+
+ if (eModel != M5410 && eModel != M5407) {
+ memcpy(&aVendorLogs[c_logs_index], aM51XXLogs, sizeof(aM51XXLogs));
+ c_logs_index += ARRAY_SIZE(aM51XXLogs);
+ if (eModel == M51AX)
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51AXLogs, sizeof(aM51AXLogs));
+ else if (eModel == M51BX)
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51BXLogs, sizeof(aM51BXLogs));
+ else if (eModel == M51CX)
+ memcpy((char *)&aVendorLogs[c_logs_index], aM51CXLogs, sizeof(aM51CXLogs));
+ }
+
+ for (int i = 0; i < (int)(ARRAY_SIZE(aVendorLogs)) && aVendorLogs[i].ucLogPage; i++) {
+ err = -1;
+ switch (aVendorLogs[i].ucLogPage) {
+ case 0xE1:
+ fallthrough;
+ case 0xE5:
+ fallthrough;
+ case 0xE9:
+ err = 1;
+ break;
+ case 0xE2:
+ fallthrough;
+ case 0xE3:
+ fallthrough;
+ case 0xE4:
+ fallthrough;
+ case 0xE8:
+ fallthrough;
+ case 0xEA:
+ err = get_common_log(dev_fd(dev), aVendorLogs[i].ucLogPage,
+ &dataBuffer, &bSize);
+ break;
+ case 0xC1:
+ fallthrough;
+ case 0xC2:
+ fallthrough;
+ case 0xC4:
+ err = GetLogPageSize(dev_fd(dev), aVendorLogs[i].ucLogPage,
+ &bSize);
+ if (!err && bSize > 0)
+ err = GetCommonLogPage(dev_fd(dev), aVendorLogs[i].ucLogPage,
+ &dataBuffer, bSize);
+ break;
+ case 0xE6:
+ fallthrough;
+ case 0xE7:
+ puiIDDBuf = (unsigned int *)&ctrl;
+ uiMask = puiIDDBuf[1015];
+ if (!uiMask || (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));
+ }
+ dataBuffer = (unsigned char *)malloc(bSize);
+ if (bSize && dataBuffer) {
+ memset(dataBuffer, 0, bSize);
+ if (eModel == M5410 || eModel == M5407)
+ err = NVMEGetLogPage(dev_fd(dev),
+ aVendorLogs[i].ucLogPage, dataBuffer,
+ bSize);
+ else
+ err = nvme_get_log_simple(dev_fd(dev),
+ aVendorLogs[i].ucLogPage,
+ bSize, dataBuffer);
+ }
+ break;
+ case 0xF7:
+ fallthrough;
+ case 0xF9:
+ fallthrough;
+ case 0xFC:
+ fallthrough;
+ case 0xFD:
+ if (eModel == M51BX)
+ (void)NVMEResetLog(dev_fd(dev), aVendorLogs[i].ucLogPage,
+ aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
+ fallthrough;
+ default:
+ bSize = aVendorLogs[i].nLogSize;
+ dataBuffer = (unsigned char *)malloc(bSize);
+ if (!dataBuffer)
+ break;
+ memset(dataBuffer, 0, bSize);
+ err = nvme_get_log_simple(dev_fd(dev), aVendorLogs[i].ucLogPage,
+ bSize, dataBuffer);
+ maxSize = aVendorLogs[i].nMaxSize - bSize;
+ while (!err && 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_simple(dev_fd(dev),
+ aVendorLogs[i].ucLogPage,
+ bSize, dataBuffer);
+ if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef))
+ break;
+ maxSize -= bSize;
+ }
+ break;
+ }
+
+ if (!err && dataBuffer && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
+ sprintf(msg, "log 0x%x", aVendorLogs[i].ucLogPage);
+ WriteData(dataBuffer, bSize, strCtrlDirName, aVendorLogs[i].strFileName, msg);
+ }
+
+ if (dataBuffer) {
+ free(dataBuffer);
+ dataBuffer = NULL;
+ }
+ }
+
+ err = ZipAndRemoveDir(strMainDirName, cfg.package);
+out:
+ dev_close(dev);
+ return err;
+}
+
+#define MIN_LOG_SIZE 512
+static int micron_logpage_dir(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = -1;
+ const char *desc = "List the supported log pages";
+ enum eDriveModel model = UNKNOWN_MODEL;
+ char logbuf[MIN_LOG_SIZE];
+ struct nvme_dev *dev;
+ int i;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = micron_parse_options(&dev, argc, argv, desc, opts, &model);
+ if (err < 0)
+ return err;
+
+ struct nvme_supported_logs {
+ uint8_t log_id;
+ uint8_t supported;
+ char *desc;
+ } log_list[] = {
+ {0x00, 0, "Support Log Pages"},
+ {0x01, 0, "Error Information"},
+ {0x02, 0, "SMART / Health Information"},
+ {0x03, 0, "Firmware Slot Information"},
+ {0x04, 0, "Changed Namespace List"},
+ {0x05, 0, "Commands Supported and Effects"},
+ {0x06, 0, "Device Self Test"},
+ {0x07, 0, "Telemetry Host-Initiated"},
+ {0x08, 0, "Telemetry Controller-Initiated"},
+ {0x09, 0, "Endurance Group Information"},
+ {0x0A, 0, "Predictable Latency Per NVM Set"},
+ {0x0B, 0, "Predictable Latency Event Aggregate"},
+ {0x0C, 0, "Asymmetric Namespace Access"},
+ {0x0D, 0, "Persistent Event Log"},
+ {0x0E, 0, "Predictable Latency Event Aggregate"},
+ {0x0F, 0, "Endurance Group Event Aggregate"},
+ {0x10, 0, "Media Unit Status"},
+ {0x11, 0, "Supported Capacity Configuration List"},
+ {0x12, 0, "Feature Identifiers Supported and Effects"},
+ {0x13, 0, "NVMe-MI Commands Supported and Effects"},
+ {0x14, 0, "Command and Feature lockdown"},
+ {0x15, 0, "Boot Partition"},
+ {0x16, 0, "Rotational Media Information"},
+ {0x70, 0, "Discovery"},
+ {0x80, 0, "Reservation Notification"},
+ {0x81, 0, "Sanitize Status"},
+ {0xC0, 0, "SMART Cloud Health Log"},
+ {0xC2, 0, "Firmware Activation History"},
+ {0xC3, 0, "Latency Monitor Log"},
+ };
+
+ printf("Supported log page list\nLog ID : Description\n");
+ for (i = 0; i < ARRAY_SIZE(log_list); i++) {
+ err = nvme_get_log_simple(dev_fd(dev), log_list[i].log_id,
+ MIN_LOG_SIZE, &logbuf[0]);
+ if (err)
+ continue;
+ printf("%02Xh : %s\n", log_list[i].log_id, log_list[i].desc);
+ }
+
+ return err;
+}
diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h
new file mode 100644
index 0000000..4f7b892
--- /dev/null
+++ b/plugins/micron/micron-nvme.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/micron/micron-nvme
+
+#if !defined(MICRON_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define MICRON_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("micron", "Micron vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("select-download", "Selective Firmware Download", micron_selective_download)
+ ENTRY("vs-temperature-stats", "Retrieve Micron temperature statistics ", micron_temp_stats)
+ ENTRY("vs-pcie-stats", "Retrieve Micron PCIe error stats", micron_pcie_stats)
+ ENTRY("clear-pcie-correctable-errors", "Clear correctable PCIe errors", micron_clear_pcie_correctable_errors)
+ 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-smart-ext-log", "Retrieve extended SMART logs", micron_smart_ext_log)
+ 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("latency-tracking", "Latency monitoring feature control", micron_latency_stats_track)
+ ENTRY("latency-stats", "Latency information for tracked commands", micron_latency_stats_info)
+ ENTRY("latency-logs", "Latency log details tracked by drive", micron_latency_stats_logs)
+ 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)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/nbft/nbft-plugin.c b/plugins/nbft/nbft-plugin.c
new file mode 100644
index 0000000..2193ffb
--- /dev/null
+++ b/plugins/nbft/nbft-plugin.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <errno.h>
+#include <stdio.h>
+#include <fnmatch.h>
+
+#include "nvme-print.h"
+#include "nvme.h"
+#include "nbft.h"
+#include "libnvme.h"
+#include "fabrics.h"
+
+#define CREATE_CMD
+#include "nbft-plugin.h"
+
+static const char dash[100] = {[0 ... 98] = '-', [99] = '\0'};
+
+#define PCI_SEGMENT(sbdf) ((sbdf & 0xffff0000) >> 16)
+#define PCI_BUS(sbdf) ((sbdf & 0x0000ff00) >> 8)
+#define PCI_DEV(sbdf) ((sbdf & 0x000000f8) >> 3)
+#define PCI_FUNC(sbdf) ((sbdf & 0x00000007) >> 0)
+
+static const char *pci_sbdf_to_string(__u16 pci_sbdf)
+{
+ static char pcidev[13];
+
+ snprintf(pcidev, sizeof(pcidev), "%x:%x:%x.%x",
+ PCI_SEGMENT(pci_sbdf),
+ PCI_BUS(pci_sbdf),
+ PCI_DEV(pci_sbdf),
+ PCI_FUNC(pci_sbdf));
+ return pcidev;
+}
+
+static char *mac_addr_to_string(unsigned char mac_addr[6])
+{
+ static char mac_string[18];
+
+ snprintf(mac_string, sizeof(mac_string), "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac_addr[0],
+ mac_addr[1],
+ mac_addr[2],
+ mac_addr[3],
+ mac_addr[4],
+ mac_addr[5]);
+ return mac_string;
+}
+
+static json_object *hfi_to_json(struct nbft_info_hfi *hfi)
+{
+ struct json_object *hfi_json;
+
+ hfi_json = json_create_object();
+ if (!hfi_json)
+ return NULL;
+
+ if (json_object_add_value_int(hfi_json, "index", hfi->index)
+ || json_object_add_value_string(hfi_json, "transport", hfi->transport))
+ goto fail;
+
+ if (strcmp(hfi->transport, "tcp") == 0) {
+ if (json_object_add_value_string(hfi_json, "pcidev",
+ pci_sbdf_to_string(hfi->tcp_info.pci_sbdf))
+ || json_object_add_value_string(hfi_json, "mac_addr",
+ mac_addr_to_string(hfi->tcp_info.mac_addr))
+ || json_object_add_value_int(hfi_json, "vlan",
+ hfi->tcp_info.vlan)
+ || json_object_add_value_int(hfi_json, "ip_origin",
+ hfi->tcp_info.ip_origin)
+ || json_object_add_value_string(hfi_json, "ipaddr",
+ hfi->tcp_info.ipaddr)
+ || json_object_add_value_int(hfi_json, "subnet_mask_prefix",
+ hfi->tcp_info.subnet_mask_prefix)
+ || json_object_add_value_string(hfi_json, "gateway_ipaddr",
+ hfi->tcp_info.gateway_ipaddr)
+ || json_object_add_value_int(hfi_json, "route_metric",
+ hfi->tcp_info.route_metric)
+ || json_object_add_value_string(hfi_json, "primary_dns_ipaddr",
+ hfi->tcp_info.primary_dns_ipaddr)
+ || json_object_add_value_string(hfi_json, "secondary_dns_ipaddr",
+ hfi->tcp_info.secondary_dns_ipaddr)
+ || json_object_add_value_string(hfi_json, "dhcp_server_ipaddr",
+ hfi->tcp_info.dhcp_server_ipaddr)
+ || (hfi->tcp_info.host_name
+ && json_object_add_value_string(hfi_json, "host_name",
+ hfi->tcp_info.host_name))
+ || json_object_add_value_int(hfi_json, "this_hfi_is_default_route",
+ hfi->tcp_info.this_hfi_is_default_route)
+ || json_object_add_value_int(hfi_json, "dhcp_override",
+ hfi->tcp_info.dhcp_override))
+ goto fail;
+ else
+ return hfi_json;
+ }
+fail:
+ json_free_object(hfi_json);
+ return NULL;
+}
+
+static json_object *ssns_to_json(struct nbft_info_subsystem_ns *ss)
+{
+ struct json_object *ss_json;
+ struct json_object *hfi_array_json;
+ char json_str[40];
+ char *json_str_p;
+ int i;
+
+ ss_json = json_create_object();
+ if (!ss_json)
+ return NULL;
+
+ hfi_array_json = json_create_array();
+ if (!hfi_array_json)
+ goto fail;
+
+ for (i = 0; i < ss->num_hfis; i++)
+ if (json_array_add_value_object(hfi_array_json,
+ json_object_new_int(ss->hfis[i]->index)))
+ goto fail;
+
+ if (json_object_add_value_int(ss_json, "index", ss->index)
+ || json_object_add_value_int(ss_json, "num_hfis", ss->num_hfis)
+ || json_object_object_add(ss_json, "hfis", hfi_array_json)
+ || json_object_add_value_string(ss_json, "transport", ss->transport)
+ || json_object_add_value_string(ss_json, "traddr", ss->traddr)
+ || json_object_add_value_string(ss_json, "trsvcid", ss->trsvcid)
+ || json_object_add_value_int(ss_json, "subsys_port_id", ss->subsys_port_id)
+ || json_object_add_value_int(ss_json, "nsid", ss->nsid))
+ goto fail;
+
+ memset(json_str, 0, sizeof(json_str));
+ json_str_p = json_str;
+
+ switch (ss->nid_type) {
+ case NBFT_INFO_NID_TYPE_EUI64:
+ if (json_object_add_value_string(ss_json, "nid_type", "eui64"))
+ goto fail;
+ for (i = 0; i < 8; i++)
+ json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]);
+ break;
+
+ case NBFT_INFO_NID_TYPE_NGUID:
+ if (json_object_add_value_string(ss_json, "nid_type", "nguid"))
+ goto fail;
+ for (i = 0; i < 16; i++)
+ json_str_p += sprintf(json_str_p, "%02x", ss->nid[i]);
+ break;
+
+ case NBFT_INFO_NID_TYPE_NS_UUID:
+ if (json_object_add_value_string(ss_json, "nid_type", "uuid"))
+ goto fail;
+ nvme_uuid_to_string(ss->nid, json_str);
+ break;
+
+ default:
+ break;
+ }
+ if (json_object_add_value_string(ss_json, "nid", json_str))
+ goto fail;
+
+ if ((ss->subsys_nqn
+ && json_object_add_value_string(ss_json, "subsys_nqn", ss->subsys_nqn))
+ || json_object_add_value_int(ss_json, "controller_id", ss->controller_id)
+ || json_object_add_value_int(ss_json, "asqsz", ss->asqsz)
+ || (ss->dhcp_root_path_string
+ && json_object_add_value_string(ss_json, "dhcp_root_path_string",
+ ss->dhcp_root_path_string))
+ || json_object_add_value_int(ss_json, "pdu_header_digest_required",
+ ss->pdu_header_digest_required)
+ || json_object_add_value_int(ss_json, "data_digest_required",
+ ss->data_digest_required))
+ goto fail;
+
+ return ss_json;
+fail:
+ json_free_object(ss_json);
+ return NULL;
+}
+
+static json_object *discovery_to_json(struct nbft_info_discovery *disc)
+{
+ struct json_object *disc_json;
+
+ disc_json = json_create_object();
+ if (!disc_json)
+ return NULL;
+
+ if (json_object_add_value_int(disc_json, "index", disc->index)
+ || (disc->security
+ && json_object_add_value_int(disc_json, "security", disc->security->index))
+ || (disc->hfi
+ && json_object_add_value_int(disc_json, "hfi", disc->hfi->index))
+ || (disc->uri
+ && json_object_add_value_string(disc_json, "uri", disc->uri))
+ || (disc->nqn
+ && json_object_add_value_string(disc_json, "nqn", disc->nqn))) {
+ json_free_object(disc_json);
+ return NULL;
+ } else
+ return disc_json;
+}
+
+static const char *primary_admin_host_flag_to_str(unsigned int primary)
+{
+ static const char * const str[] = {
+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_NOT_INDICATED] = "not indicated",
+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_UNSELECTED] = "unselected",
+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_SELECTED] = "selected",
+ [NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED] = "reserved",
+ };
+
+ if (primary > NBFT_INFO_PRIMARY_ADMIN_HOST_FLAG_RESERVED)
+ return "INVALID";
+ return str[primary];
+}
+
+static struct json_object *nbft_to_json(struct nbft_info *nbft, bool show_subsys,
+ bool show_hfi, bool show_discovery)
+{
+ struct json_object *nbft_json, *host_json;
+
+ nbft_json = json_create_object();
+ if (!nbft_json)
+ return NULL;
+
+ if (json_object_add_value_string(nbft_json, "filename", nbft->filename))
+ goto fail;
+
+ host_json = json_create_object();
+ if (!host_json)
+ goto fail;
+ if ((nbft->host.nqn
+ && json_object_add_value_string(host_json, "nqn", nbft->host.nqn))
+ || (nbft->host.id
+ && json_object_add_value_string(host_json, "id",
+ util_uuid_to_string(nbft->host.id))))
+ goto fail;
+ json_object_add_value_int(host_json, "host_id_configured",
+ nbft->host.host_id_configured);
+ json_object_add_value_int(host_json, "host_nqn_configured",
+ nbft->host.host_nqn_configured);
+ json_object_add_value_string(host_json, "primary_admin_host_flag",
+ primary_admin_host_flag_to_str(nbft->host.primary));
+ if (json_object_object_add(nbft_json, "host", host_json)) {
+ json_free_object(host_json);
+ goto fail;
+ }
+
+ if (show_subsys) {
+ struct json_object *subsys_array_json, *subsys_json;
+ struct nbft_info_subsystem_ns **ss;
+
+ subsys_array_json = json_create_array();
+ if (!subsys_array_json)
+ goto fail;
+ for (ss = nbft->subsystem_ns_list; ss && *ss; ss++) {
+ subsys_json = ssns_to_json(*ss);
+ if (!subsys_json)
+ goto fail;
+ if (json_object_array_add(subsys_array_json, subsys_json)) {
+ json_free_object(subsys_json);
+ goto fail;
+ }
+ }
+ if (json_object_object_add(nbft_json, "subsystem", subsys_array_json)) {
+ json_free_object(subsys_array_json);
+ goto fail;
+ }
+ }
+ if (show_hfi) {
+ struct json_object *hfi_array_json, *hfi_json;
+ struct nbft_info_hfi **hfi;
+
+ hfi_array_json = json_create_array();
+ if (!hfi_array_json)
+ goto fail;
+ for (hfi = nbft->hfi_list; hfi && *hfi; hfi++) {
+ hfi_json = hfi_to_json(*hfi);
+ if (!hfi_json)
+ goto fail;
+ if (json_object_array_add(hfi_array_json, hfi_json)) {
+ json_free_object(hfi_json);
+ goto fail;
+ }
+ }
+ if (json_object_object_add(nbft_json, "hfi", hfi_array_json)) {
+ json_free_object(hfi_array_json);
+ goto fail;
+ }
+ }
+ if (show_discovery) {
+ struct json_object *discovery_array_json, *discovery_json;
+ struct nbft_info_discovery **disc;
+
+ discovery_array_json = json_create_array();
+ if (!discovery_array_json)
+ goto fail;
+ for (disc = nbft->discovery_list; disc && *disc; disc++) {
+ discovery_json = discovery_to_json(*disc);
+ if (!discovery_json)
+ goto fail;
+ if (json_object_array_add(discovery_array_json, discovery_json)) {
+ json_free_object(discovery_json);
+ goto fail;
+ }
+ }
+ if (json_object_object_add(nbft_json, "discovery", discovery_array_json)) {
+ json_free_object(discovery_array_json);
+ goto fail;
+ }
+ }
+ return nbft_json;
+fail:
+ json_free_object(nbft_json);
+ return NULL;
+}
+
+static int json_show_nbfts(struct list_head *nbft_list, bool show_subsys,
+ bool show_hfi, bool show_discovery)
+{
+ struct json_object *nbft_json_array, *nbft_json;
+ struct nbft_file_entry *entry;
+
+ nbft_json_array = json_create_array();
+ if (!nbft_json_array)
+ return -ENOMEM;
+
+ list_for_each(nbft_list, entry, node) {
+ nbft_json = nbft_to_json(entry->nbft, show_subsys, show_hfi, show_discovery);
+ if (!nbft_json)
+ goto fail;
+ if (json_object_array_add(nbft_json_array, nbft_json)) {
+ json_free_object(nbft_json);
+ goto fail;
+ }
+ }
+
+ json_print_object(nbft_json_array, NULL);
+ printf("\n");
+ json_free_object(nbft_json_array);
+ return 0;
+fail:
+ json_free_object(nbft_json_array);
+ return -ENOMEM;
+}
+
+static void print_nbft_hfi_info(struct nbft_info *nbft)
+{
+ struct nbft_info_hfi **hfi;
+ unsigned int ip_width = 8, gw_width = 8, dns_width = 8;
+
+ hfi = nbft->hfi_list;
+ if (!hfi || !*hfi)
+ return;
+
+ for (; *hfi; hfi++) {
+ unsigned int len;
+
+ len = strlen((*hfi)->tcp_info.ipaddr);
+ if (len > ip_width)
+ ip_width = len;
+ len = strlen((*hfi)->tcp_info.gateway_ipaddr);
+ if (len > gw_width)
+ gw_width = len;
+ len = strlen((*hfi)->tcp_info.primary_dns_ipaddr);
+ if (len > dns_width)
+ dns_width = len;
+ }
+
+ printf("\nNBFT HFIs:\n\n");
+ printf("%-3.3s|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4.4s|%-*.*s|%-*.*s\n",
+ "Idx", "Trsp", "PCI Addr", "MAC Addr", "DHCP",
+ ip_width, ip_width, "IP Addr", "Mask",
+ gw_width, gw_width, "Gateway", dns_width, dns_width, "DNS");
+ printf("%-.3s+%-.4s+%-.10s+%-.17s+%-.4s+%-.*s+%-.4s+%-.*s+%-.*s\n",
+ dash, dash, dash, dash, dash, ip_width, dash, dash,
+ gw_width, dash, dns_width, dash);
+ for (hfi = nbft->hfi_list; *hfi; hfi++)
+ printf("%-3d|%-4.4s|%-10.10s|%-17.17s|%-4.4s|%-*.*s|%-4d|%-*.*s|%-*.*s\n",
+ (*hfi)->index,
+ (*hfi)->transport,
+ pci_sbdf_to_string((*hfi)->tcp_info.pci_sbdf),
+ mac_addr_to_string((*hfi)->tcp_info.mac_addr),
+ (*hfi)->tcp_info.dhcp_override ? "yes" : "no",
+ ip_width, ip_width, (*hfi)->tcp_info.ipaddr,
+ (*hfi)->tcp_info.subnet_mask_prefix,
+ gw_width, gw_width, (*hfi)->tcp_info.gateway_ipaddr,
+ dns_width, dns_width, (*hfi)->tcp_info.primary_dns_ipaddr);
+}
+
+static void print_nbft_discovery_info(struct nbft_info *nbft)
+{
+ struct nbft_info_discovery **disc;
+ unsigned int nqn_width = 20, uri_width = 12;
+
+ disc = nbft->discovery_list;
+ if (!disc || !*disc)
+ return;
+
+ for (; *disc; disc++) {
+ size_t len;
+
+ len = strlen((*disc)->uri);
+ if (len > uri_width)
+ uri_width = len;
+ len = strlen((*disc)->nqn);
+ if (len > nqn_width)
+ nqn_width = len;
+ }
+
+ printf("\nNBFT Discovery Controllers:\n\n");
+ printf("%-3.3s|%-*.*s|%-*.*s\n", "Idx", uri_width, uri_width, "URI",
+ nqn_width, nqn_width, "NQN");
+ printf("%-.3s+%-.*s+%-.*s\n", dash, uri_width, dash, nqn_width, dash);
+ for (disc = nbft->discovery_list; *disc; disc++)
+ printf("%-3d|%-*.*s|%-*.*s\n", (*disc)->index,
+ uri_width, uri_width, (*disc)->uri,
+ nqn_width, nqn_width, (*disc)->nqn);
+}
+
+#define HFIS_LEN 20
+static size_t print_hfis(const struct nbft_info_subsystem_ns *ss, char buf[HFIS_LEN])
+{
+ char hfi_buf[HFIS_LEN];
+ size_t len, ofs;
+ int i;
+
+ len = snprintf(hfi_buf, sizeof(hfi_buf), "%d", ss->hfis[0]->index);
+ for (i = 1; i < ss->num_hfis; i++) {
+ ofs = len;
+ len += snprintf(hfi_buf + ofs, sizeof(hfi_buf) - ofs, ",%d",
+ ss->hfis[i]->index);
+ /*
+ * If the list doesn't fit in HFIS_LEN characters,
+ * truncate and end with "..."
+ */
+ if (len >= sizeof(hfi_buf)) {
+ while (ofs < sizeof(hfi_buf) - 1)
+ hfi_buf[ofs++] = '.';
+ hfi_buf[ofs] = '\0';
+ len = sizeof(hfi_buf) - 1;
+ break;
+ }
+ }
+ if (buf)
+ memcpy(buf, hfi_buf, len + 1);
+ return len;
+}
+
+
+static void print_nbft_subsys_info(struct nbft_info *nbft)
+{
+ struct nbft_info_subsystem_ns **ss;
+ unsigned int nqn_width = 20, adr_width = 8, hfi_width = 4;
+
+ ss = nbft->subsystem_ns_list;
+ if (!ss || !*ss)
+ return;
+ for (; *ss; ss++) {
+ size_t len;
+
+ len = strlen((*ss)->subsys_nqn);
+ if (len > nqn_width)
+ nqn_width = len;
+ len = strlen((*ss)->traddr);
+ if (len > adr_width)
+ adr_width = len;
+ len = print_hfis(*ss, NULL);
+ if (len > hfi_width)
+ hfi_width = len;
+ }
+
+ printf("\nNBFT Subsystems:\n\n");
+ printf("%-3.3s|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n",
+ "Idx", nqn_width, nqn_width, "NQN",
+ "Trsp", adr_width, adr_width, "Address", "SvcId", hfi_width, hfi_width, "HFIs");
+ printf("%-.3s+%-.*s+%-.4s+%-.*s+%-.5s+%-.*s\n",
+ dash, nqn_width, dash, dash, adr_width, dash, dash, hfi_width, dash);
+ for (ss = nbft->subsystem_ns_list; *ss; ss++) {
+ char hfi_buf[HFIS_LEN];
+
+ print_hfis(*ss, hfi_buf);
+ printf("%-3d|%-*.*s|%-4.4s|%-*.*s|%-5.5s|%-*.*s\n",
+ (*ss)->index, nqn_width, nqn_width, (*ss)->subsys_nqn,
+ (*ss)->transport, adr_width, adr_width, (*ss)->traddr,
+ (*ss)->trsvcid, hfi_width, hfi_width, hfi_buf);
+ }
+}
+
+static void normal_show_nbft(struct nbft_info *nbft, bool show_subsys,
+ bool show_hfi, bool show_discovery)
+{
+ printf("%s:\n", nbft->filename);
+ if ((!nbft->hfi_list || !*nbft->hfi_list) &&
+ (!nbft->security_list || !*nbft->security_list) &&
+ (!nbft->discovery_list || !*nbft->discovery_list) &&
+ (!nbft->subsystem_ns_list || !*nbft->subsystem_ns_list))
+ printf("(empty)\n");
+ else {
+ if (show_subsys)
+ print_nbft_subsys_info(nbft);
+ if (show_hfi)
+ print_nbft_hfi_info(nbft);
+ if (show_discovery)
+ print_nbft_discovery_info(nbft);
+ }
+}
+
+static void normal_show_nbfts(struct list_head *nbft_list, bool show_subsys,
+ bool show_hfi, bool show_discovery)
+{
+ bool not_first = false;
+ struct nbft_file_entry *entry;
+
+ list_for_each(nbft_list, entry, node) {
+ if (not_first)
+ printf("\n");
+ normal_show_nbft(entry->nbft, show_subsys, show_hfi, show_discovery);
+ not_first = true;
+ }
+}
+
+int show_nbft(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Display contents of the ACPI NBFT files.";
+ struct list_head nbft_list;
+ char *format = "normal";
+ char *nbft_path = NBFT_SYSFS_PATH;
+ enum nvme_print_flags flags;
+ int ret;
+ bool show_subsys = false, show_hfi = false, show_discovery = false;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &format, "Output format: normal|json"),
+ OPT_FLAG("subsystem", 's', &show_subsys, "show NBFT subsystems"),
+ OPT_FLAG("hfi", 'H', &show_hfi, "show NBFT HFIs"),
+ OPT_FLAG("discovery", 'd', &show_discovery, "show NBFT discovery controllers"),
+ OPT_STRING("nbft-path", 0, "STR", &nbft_path, "user-defined path for NBFT tables"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(format, &flags);
+ if (ret < 0)
+ return ret;
+
+ if (!(show_subsys || show_hfi || show_discovery))
+ show_subsys = show_hfi = show_discovery = true;
+
+ list_head_init(&nbft_list);
+ ret = read_nbft_files(&nbft_list, nbft_path);
+ if (!ret) {
+ if (flags == NORMAL)
+ normal_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery);
+ else if (flags == JSON)
+ ret = json_show_nbfts(&nbft_list, show_subsys, show_hfi, show_discovery);
+ free_nbfts(&nbft_list);
+ }
+ return ret;
+}
diff --git a/plugins/nbft/nbft-plugin.h b/plugins/nbft/nbft-plugin.h
new file mode 100644
index 0000000..018349d
--- /dev/null
+++ b/plugins/nbft/nbft-plugin.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/nbft/nbft-plugin
+
+#if !defined(NBFT) || defined(CMD_HEADER_MULTI_READ)
+#define NBFT
+
+#include "cmd.h"
+
+PLUGIN(NAME("nbft", "ACPI NBFT table extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("show", "Show contents of ACPI NBFT tables", show_nbft)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/netapp/netapp-nvme.c b/plugins/netapp/netapp-nvme.c
new file mode 100644
index 0000000..2ecdcc5
--- /dev/null
+++ b/plugins/netapp/netapp-nvme.c
@@ -0,0 +1,654 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018 NetApp, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+
+#include "util/suffix.h"
+
+#define CREATE_CMD
+#include "netapp-nvme.h"
+
+#define ONTAP_C2_LOG_ID 0xC2
+#define ONTAP_C2_LOG_SIZE 4096
+#define ONTAP_LABEL_LEN 260
+#define ONTAP_NS_PATHLEN 525
+
+enum {
+ NNORMAL,
+ NJSON,
+ NCOLUMN,
+};
+
+enum {
+ ONTAP_C2_LOG_SUPPORTED_LSP = 0x0,
+ ONTAP_C2_LOG_NSINFO_LSP = 0x1,
+};
+
+enum {
+ ONTAP_VSERVER_TLV = 0x11,
+ ONTAP_VOLUME_TLV = 0x12,
+ ONTAP_NS_TLV = 0x13,
+};
+
+static const char *dev_path = "/dev/";
+
+struct smdevice_info {
+ unsigned int nsid;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_id_ns ns;
+ char dev[265];
+};
+
+struct ontapdevice_info {
+ unsigned int nsid;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_id_ns ns;
+ unsigned char uuid[NVME_UUID_LEN];
+ unsigned char log_data[ONTAP_C2_LOG_SIZE];
+ char dev[265];
+};
+
+#define ARRAY_LABEL_LEN 60
+#define VOLUME_LABEL_LEN 60
+
+/*
+ * Format of the string isn't tightly controlled yet. For now, squash UCS-2 into
+ * ASCII. dst buffer must be at least count + 1 bytes long
+ */
+static void netapp_convert_string(char *dst, char *src, unsigned int count)
+{
+ int i;
+
+ if (!dst || !src || !count)
+ return;
+
+ memset(dst, 0, count + 1);
+ for (i = 0; i < count; i++)
+ dst[i] = src[i * 2 + 1];
+ /* the json routines won't accept empty strings */
+ if (strlen(dst) == 0 && count)
+ dst[0] = ' ';
+}
+
+static void netapp_nguid_to_str(char *str, __u8 *nguid)
+{
+ int i;
+
+ memset(str, 0, 33);
+ for (i = 0; i < 16; i++)
+ str += sprintf(str, "%02x", nguid[i]);
+}
+
+static void netapp_get_ns_size(char *size, unsigned long long *lba,
+ struct nvme_id_ns *ns)
+{
+ __u8 lba_index;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns->flbas, &lba_index);
+ *lba = 1ULL << ns->lbaf[lba_index].ds;
+ double nsze = le64_to_cpu(ns->nsze) * (*lba);
+ const char *s_suffix = suffix_si_get(&nsze);
+
+ sprintf(size, "%.2f%sB", nsze, s_suffix);
+}
+
+static void ontap_labels_to_str(char *dst, char *src, int count)
+{
+ int i;
+
+ memset(dst, 0, ONTAP_LABEL_LEN);
+ for (i = 0; i < count; i++) {
+ if (src[i] >= '!' && src[i] <= '~')
+ dst[i] = src[i];
+ else
+ break;
+ }
+ dst[i] = '\0';
+}
+
+static void netapp_get_ontap_labels(char *vsname, char *nspath,
+ unsigned char *log_data)
+{
+ int lsp, tlv, label_len;
+ char *vserver_name, *volume_name, *namespace_name;
+ char vol_name[ONTAP_LABEL_LEN], ns_name[ONTAP_LABEL_LEN];
+ const char *ontap_vol = "/vol/";
+ int i, j;
+
+ /* get the lsp */
+ lsp = (*(__u8 *)&log_data[16]) & 0x0F;
+ if (lsp != ONTAP_C2_LOG_NSINFO_LSP)
+ /* lsp not related to nsinfo */
+ return;
+
+ /* get the vserver tlv and name */
+ tlv = *(__u8 *)&log_data[32];
+ if (tlv == ONTAP_VSERVER_TLV) {
+ label_len = (*(__u16 *)&log_data[34]) * 4;
+ vserver_name = (char *)&log_data[36];
+ ontap_labels_to_str(vsname, vserver_name, label_len);
+ } else {
+ /* not the expected vserver tlv */
+ fprintf(stderr, "Unable to fetch ONTAP vserver name\n");
+ return;
+ }
+
+ i = 36 + label_len;
+ j = i + 2;
+ /* get the volume tlv and name */
+ tlv = *(__u8 *)&log_data[i];
+ if (tlv == ONTAP_VOLUME_TLV) {
+ label_len = (*(__u16 *)&log_data[j]) * 4;
+ volume_name = (char *)&log_data[j + 2];
+ ontap_labels_to_str(vol_name, volume_name, label_len);
+ } else {
+ /* not the expected volume tlv */
+ fprintf(stderr, "Unable to fetch ONTAP volume name\n");
+ return;
+ }
+
+ i += 4 + label_len;
+ j += 4 + label_len;
+ /* get the namespace tlv and name */
+ tlv = *(__u8 *)&log_data[i];
+ if (tlv == ONTAP_NS_TLV) {
+ label_len = (*(__u16 *)&log_data[j]) * 4;
+ namespace_name = (char *)&log_data[j + 2];
+ ontap_labels_to_str(ns_name, namespace_name, label_len);
+ } else {
+ /* not the expected namespace tlv */
+ fprintf(stderr, "Unable to fetch ONTAP namespace name\n");
+ return;
+ }
+
+ snprintf(nspath, ONTAP_NS_PATHLEN, "%s%s%s%s", ontap_vol,
+ vol_name, "/", ns_name);
+}
+
+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)
+{
+ struct json_object *device_attrs;
+
+ device_attrs = json_create_object();
+ json_object_add_value_string(device_attrs, "Device", devname);
+ json_object_add_value_string(device_attrs, "Array_Name", arrayname);
+ json_object_add_value_string(device_attrs, "Volume_Name", volname);
+ json_object_add_value_int(device_attrs, "NSID", nsid);
+ json_object_add_value_string(device_attrs, "Volume_ID", nguid);
+ json_object_add_value_string(device_attrs, "Controller", ctrl);
+ json_object_add_value_string(device_attrs, "Access_State", astate);
+ json_object_add_value_string(device_attrs, "Size", size);
+ json_object_add_value_int(device_attrs, "LBA_Data_Size", lba);
+ json_object_add_value_int(device_attrs, "Namespace_Size", nsze);
+
+ json_array_add_value_object(devices, device_attrs);
+}
+
+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)
+{
+ struct json_object *device_attrs;
+
+ device_attrs = json_create_object();
+ json_object_add_value_string(device_attrs, "Device", devname);
+ json_object_add_value_string(device_attrs, "Vserver", vsname);
+ json_object_add_value_string(device_attrs, "Namespace_Path", nspath);
+ json_object_add_value_int(device_attrs, "NSID", nsid);
+ json_object_add_value_string(device_attrs, "UUID", uuid);
+ json_object_add_value_string(device_attrs, "Size", size);
+ json_object_add_value_int(device_attrs, "LBA_Data_Size", lba);
+ json_object_add_value_int(device_attrs, "Namespace_Size", nsze);
+
+ json_array_add_value_object(devices, device_attrs);
+}
+
+static void netapp_smdevices_print(struct smdevice_info *devices, int count, int format)
+{
+ struct json_object *root = 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];
+ char nguid_str[33];
+ char basestr[] =
+ "%s, Array Name %s, Volume Name %s, NSID %d, Volume ID %s, Controller %c, Access State %s, %s\n";
+ char columnstr[] = "%-16s %-30s %-30s %4d %32s %c %-12s %9s\n";
+ char *formatstr = basestr; /* default to "normal" output format */
+ __u8 lba_index;
+
+ if (format == NCOLUMN) {
+ /* for column output, change output string and print column headers */
+ formatstr = columnstr;
+ printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s\n",
+ "Device", "Array Name", "Volume Name", "NSID",
+ "Volume ID", "Ctrl", "Access State", " Size");
+ printf("%-16s %-30s %-30s %-4s %-32s %-4s %-12s %-9s\n",
+ "----------------", "------------------------------",
+ "------------------------------", "----",
+ "--------------------------------", "----",
+ "------------", "---------");
+ } else if (format == NJSON) {
+ /* prepare for json output */
+ root = json_create_object();
+ json_devices = json_create_array();
+ }
+
+ for (i = 0; i < count; i++) {
+ nvme_id_ns_flbas_to_lbaf_inuse(devices[i].ns.flbas, &lba_index);
+ unsigned long long lba = 1ULL << devices[i].ns.lbaf[lba_index].ds;
+ double nsze = le64_to_cpu(devices[i].ns.nsze) * lba;
+ const char *s_suffix = suffix_si_get(&nsze);
+ char size[128];
+
+ sprintf(size, "%.2f%sB", nsze, s_suffix);
+ netapp_convert_string(array_label, (char *)&devices[i].ctrl.vs[20],
+ ARRAY_LABEL_LEN / 2);
+ slta = devices[i].ctrl.vs[0] & 0x1;
+ netapp_convert_string(volume_label, (char *)devices[i].ns.vs,
+ VOLUME_LABEL_LEN / 2);
+ netapp_nguid_to_str(nguid_str, devices[i].ns.nguid);
+ if (format == NJSON)
+ netapp_smdevice_json(json_devices, devices[i].dev,
+ array_label, volume_label, devices[i].nsid,
+ nguid_str, slta ? "A" : "B", "unknown", size,
+ lba, le64_to_cpu(devices[i].ns.nsze));
+ else
+ printf(formatstr, devices[i].dev, array_label,
+ volume_label, devices[i].nsid, nguid_str,
+ slta ? 'A' : 'B', "unknown", size);
+ }
+
+ if (format == NJSON) {
+ /* complete the json output */
+ json_object_add_value_array(root, "SMdevices", json_devices);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
+
+static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
+ int count, int format)
+{
+ struct json_object *root = NULL;
+ struct json_object *json_devices = NULL;
+ char vsname[ONTAP_LABEL_LEN] = " ";
+ char nspath[ONTAP_NS_PATHLEN] = " ";
+ unsigned long long lba;
+ char size[128];
+ char uuid_str[37] = " ";
+ int i;
+
+ char basestr[] = "%s, Vserver %s, Namespace Path %s, NSID %d, UUID %s, %s\n";
+ char columnstr[] = "%-16s %-25s %-50s %-4d %-38s %-9s\n";
+
+ /* default to 'normal' output format */
+ char *formatstr = basestr;
+
+ if (format == NCOLUMN) {
+ /* change output string and print column headers */
+ formatstr = columnstr;
+ printf("%-16s %-25s %-50s %-4s %-38s %-9s\n",
+ "Device", "Vserver", "Namespace Path",
+ "NSID", "UUID", "Size");
+ printf("%-16s %-25s %-50s %-4s %-38s %-9s\n",
+ "----------------", "-------------------------",
+ "--------------------------------------------------",
+ "----", "--------------------------------------",
+ "---------");
+ } else if (format == NJSON) {
+ /* prepare for json output */
+ root = json_create_object();
+ json_devices = json_create_array();
+ }
+
+ for (i = 0; i < count; i++) {
+
+ netapp_get_ns_size(size, &lba, &devices[i].ns);
+ nvme_uuid_to_string(devices[i].uuid, uuid_str);
+ netapp_get_ontap_labels(vsname, nspath, devices[i].log_data);
+
+ if (format == NJSON) {
+ netapp_ontapdevice_json(json_devices, devices[i].dev,
+ vsname, nspath, devices[i].nsid,
+ uuid_str, size, lba,
+ le64_to_cpu(devices[i].ns.nsze));
+ } else
+ printf(formatstr, devices[i].dev, vsname, nspath,
+ devices[i].nsid, uuid_str, size);
+ }
+
+ if (format == NJSON) {
+ /* complete the json output */
+ json_object_add_value_array(root, "ONTAPdevices", json_devices);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+}
+
+static int nvme_get_ontap_c2_log(int fd, __u32 nsid, void *buf, __u32 buflen)
+{
+ struct nvme_passthru_cmd get_log;
+ int err;
+
+ memset(buf, 0, buflen);
+ memset(&get_log, 0, sizeof(struct nvme_passthru_cmd));
+
+ get_log.opcode = nvme_admin_get_log_page;
+ get_log.nsid = nsid;
+ get_log.addr = (__u64)(uintptr_t)buf;
+ get_log.data_len = buflen;
+
+ __u32 numd = (get_log.data_len >> 2) - 1;
+ __u32 numdu = numd >> 16;
+ __u32 numdl = numd & 0xFFFF;
+
+ get_log.cdw10 = ONTAP_C2_LOG_ID | (numdl << 16);
+ get_log.cdw10 |= ONTAP_C2_LOG_NSINFO_LSP << 8;
+ get_log.cdw11 = numdu;
+
+ err = nvme_submit_admin_passthru(fd, &get_log, NULL);
+ if (err) {
+ fprintf(stderr, "ioctl error %0x\n", err);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int netapp_smdevices_get_info(int fd, struct smdevice_info *item,
+ const char *dev)
+{
+ int err;
+
+ err = nvme_identify_ctrl(fd, &item->ctrl);
+ if (err) {
+ fprintf(stderr,
+ "Identify Controller failed to %s (%s)\n", dev,
+ err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ return 0;
+ }
+
+ if (strncmp("NetApp E-Series", item->ctrl.mn, 15) != 0)
+ return 0; /* not the right model of controller */
+
+ err = nvme_get_nsid(fd, &item->nsid);
+ err = nvme_identify_ns(fd, item->nsid, &item->ns);
+ if (err) {
+ fprintf(stderr,
+ "Unable to identify namespace for %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ return 0;
+ }
+ strncpy(item->dev, dev, sizeof(item->dev) - 1);
+
+ return 1;
+}
+
+static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_info *item,
+ const char *dev)
+{
+ int err;
+ void *nsdescs;
+
+ err = nvme_identify_ctrl(fd, &item->ctrl);
+ if (err) {
+ fprintf(stderr, "Identify Controller failed to %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ return 0;
+ }
+
+ if (strncmp("NetApp ONTAP Controller", item->ctrl.mn, 23) != 0)
+ /* not the right controller model */
+ return 0;
+
+ err = nvme_get_nsid(fd, &item->nsid);
+
+ err = nvme_identify_ns(fd, item->nsid, &item->ns);
+ if (err) {
+ fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ return 0;
+ }
+
+ if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) {
+ fprintf(stderr, "Cannot allocate controller list payload\n");
+ return 0;
+ }
+
+ err = nvme_identify_ns_descs(fd, item->nsid, nsdescs);
+ if (err) {
+ fprintf(stderr, "Unable to identify namespace descriptor for %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ free(nsdescs);
+ return 0;
+ }
+
+ memcpy(item->uuid, nsdescs + sizeof(struct nvme_ns_id_desc), sizeof(item->uuid));
+ free(nsdescs);
+
+ err = nvme_get_ontap_c2_log(fd, item->nsid, item->log_data, ONTAP_C2_LOG_SIZE);
+ if (err) {
+ fprintf(stderr, "Unable to get log page data for %s (%s)\n",
+ dev, err < 0 ? strerror(-err) :
+ nvme_status_to_string(err, false));
+ return 0;
+ }
+
+ strncpy(item->dev, dev, sizeof(item->dev) - 1);
+
+ return 1;
+}
+
+static int netapp_nvme_filter(const struct dirent *d)
+{
+ char path[264];
+ struct stat bd;
+ int ctrl, ns, partition;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme")) {
+ snprintf(path, sizeof(path), "%s%s", dev_path, d->d_name);
+ if (stat(path, &bd))
+ return 0;
+ if (sscanf(d->d_name, "nvme%dn%d", &ctrl, &ns) != 2)
+ return 0;
+ if (sscanf(d->d_name, "nvme%dn%dp%d", &ctrl, &ns, &partition) == 3)
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int netapp_output_format(char *format)
+{
+ if (!format)
+ return -EINVAL;
+ if (!strcmp(format, "normal"))
+ return NNORMAL;
+ if (!strcmp(format, "json"))
+ return NJSON;
+ if (!strcmp(format, "column"))
+ return NCOLUMN;
+ return -EINVAL;
+}
+
+/* handler for 'nvme netapp smdevices' */
+static int netapp_smdevices(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Display information about E-Series volumes.";
+
+ struct dirent **devices;
+ int num, i, fd, ret, fmt;
+ struct smdevice_info *smdevices;
+ char path[264];
+ int num_smdevices = 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|column"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ fmt = netapp_output_format(cfg.output_format);
+ if (fmt != NNORMAL && fmt != NCOLUMN && fmt != NJSON) {
+ fprintf(stderr, "Unrecognized output format: %s\n", cfg.output_format);
+ return -EINVAL;
+ }
+
+ num = scandir(dev_path, &devices, netapp_nvme_filter, alphasort);
+ if (num <= 0) {
+ fprintf(stderr, "No NVMe devices detected.\n");
+ return num;
+ }
+
+ smdevices = calloc(num, sizeof(*smdevices));
+ if (!smdevices) {
+ fprintf(stderr, "Unable to allocate memory for devices.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "%s%s", dev_path,
+ devices[i]->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ continue;
+ }
+
+ num_smdevices += netapp_smdevices_get_info(fd,
+ &smdevices[num_smdevices], path);
+ close(fd);
+ }
+
+ if (num_smdevices)
+ netapp_smdevices_print(smdevices, num_smdevices, fmt);
+
+ for (i = 0; i < num; i++)
+ free(devices[i]);
+ free(devices);
+ free(smdevices);
+ return 0;
+}
+
+/* handler for 'nvme netapp ontapdevices' */
+static int netapp_ontapdevices(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Display information about ONTAP devices.";
+ struct dirent **devices;
+ int num, i, fd, ret, fmt;
+ struct ontapdevice_info *ontapdevices;
+ char path[264];
+ int num_ontapdevices = 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|column"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ fmt = netapp_output_format(cfg.output_format);
+ if (fmt != NNORMAL && fmt != NCOLUMN && fmt != NJSON) {
+ fprintf(stderr, "Unrecognized output format: %s\n", cfg.output_format);
+ return -EINVAL;
+ }
+
+ num = scandir(dev_path, &devices, netapp_nvme_filter, alphasort);
+ if (num <= 0) {
+ fprintf(stderr, "No NVMe devices detected.\n");
+ return num;
+ }
+
+ ontapdevices = calloc(num, sizeof(*ontapdevices));
+ if (!ontapdevices) {
+ fprintf(stderr, "Unable to allocate memory for devices.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < num; i++) {
+ snprintf(path, sizeof(path), "%s%s", dev_path,
+ devices[i]->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: %s\n", path,
+ strerror(errno));
+ continue;
+ }
+
+ num_ontapdevices += netapp_ontapdevices_get_info(fd,
+ &ontapdevices[num_ontapdevices], path);
+
+ close(fd);
+ }
+
+ if (num_ontapdevices)
+ netapp_ontapdevices_print(ontapdevices, num_ontapdevices, fmt);
+
+ for (i = 0; i < num; i++)
+ free(devices[i]);
+ free(devices);
+ free(ontapdevices);
+ return 0;
+}
diff --git a/plugins/netapp/netapp-nvme.h b/plugins/netapp/netapp-nvme.h
new file mode 100644
index 0000000..73de4b4
--- /dev/null
+++ b/plugins/netapp/netapp-nvme.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/netapp/netapp-nvme
+
+#if !defined(NETAPP_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define NETAPP_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("netapp", "NetApp vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smdevices", "NetApp SMdevices", netapp_smdevices)
+ ENTRY("ontapdevices", "NetApp ONTAPdevices", netapp_ontapdevices)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/nvidia/nvidia-nvme.c b/plugins/nvidia/nvidia-nvme.c
new file mode 100644
index 0000000..71e0bc3
--- /dev/null
+++ b/plugins/nvidia/nvidia-nvme.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.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..3d870e1
--- /dev/null
+++ b/plugins/nvidia/nvidia-nvme.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/ocp/meson.build b/plugins/ocp/meson.build
new file mode 100644
index 0000000..64447ff
--- /dev/null
+++ b/plugins/ocp/meson.build
@@ -0,0 +1,8 @@
+sources += [
+ 'plugins/ocp/ocp-utils.c',
+ 'plugins/ocp/ocp-nvme.c',
+ 'plugins/ocp/ocp-clear-features.c',
+ 'plugins/ocp/ocp-smart-extended-log.c',
+ 'plugins/ocp/ocp-fw-activation-history.c',
+]
+
diff --git a/plugins/ocp/ocp-clear-features.c b/plugins/ocp/ocp-clear-features.c
new file mode 100644
index 0000000..0f49584
--- /dev/null
+++ b/plugins/ocp/ocp-clear-features.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Authors: haro.panosyan@solidigm.com
+ * leonardo.da.cunha@solidigm.com
+ */
+
+#include <unistd.h>
+#include "ocp-utils.h"
+#include "nvme-print.h"
+
+static const __u8 OCP_FID_CLEAR_FW_ACTIVATION_HISTORY = 0xC1;
+static const __u8 OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS = 0xC3;
+
+static int ocp_clear_feature(int argc, char **argv, const char *desc, const __u8 fid)
+{
+ __u32 result = 0;
+ __u32 clear = 1 << 31;
+ struct nvme_dev *dev;
+ int uuid_index = 0;
+ bool uuid = true;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (opts[0].seen)
+ uuid = false;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ fprintf(stderr, "ERROR: No OCP UUID index found\n");
+ goto close_dev;
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .result = &result,
+ .data = NULL,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .nsid = 0,
+ .cdw11 = clear,
+ .cdw12 = 0,
+ .cdw13 = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .save = 0,
+ .uuidx = uuid_index,
+ .fid = fid,
+ };
+
+ err = nvme_set_features(&args);
+
+ if (err == 0)
+ printf("Success : %s\n", desc);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ printf("Fail : %s\n", desc);
+close_dev:
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
+
+int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "OCP Clear Firmware Update History";
+
+ return ocp_clear_feature(argc, argv, desc, OCP_FID_CLEAR_FW_ACTIVATION_HISTORY);
+}
+
+int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "OCP Clear PCIe Correctable Error Counters";
+
+ return ocp_clear_feature(argc, argv, desc,
+ OCP_FID_CLEAR_PCIE_CORRECTABLE_ERROR_COUNTERS);
+}
diff --git a/plugins/ocp/ocp-clear-features.h b/plugins/ocp/ocp-clear-features.h
new file mode 100644
index 0000000..99766dd
--- /dev/null
+++ b/plugins/ocp/ocp-clear-features.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Authors: haro.panosyan@solidigm.com
+ * leonardo.da.cunha@solidigm.com
+ */
+
+int ocp_clear_fw_update_history(int argc, char **argv, struct command *cmd, struct plugin *plugin);
+
+int ocp_clear_pcie_correctable_errors(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
diff --git a/plugins/ocp/ocp-fw-activation-history.c b/plugins/ocp/ocp-fw-activation-history.c
new file mode 100644
index 0000000..ad96c6b
--- /dev/null
+++ b/plugins/ocp/ocp-fw-activation-history.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: karl.dedow@solidigm.com
+ */
+
+#include "ocp-fw-activation-history.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "nvme-print.h"
+
+#include "ocp-utils.h"
+
+static const unsigned char ocp_fw_activation_history_guid[16] = {
+ 0x6D, 0x79, 0x9a, 0x76,
+ 0xb4, 0xda, 0xf6, 0xa3,
+ 0xe2, 0x4d, 0xb2, 0x8a,
+ 0xac, 0xf3, 0x1c, 0xd1
+};
+
+struct __packed fw_activation_history_entry {
+ __u8 ver_num;
+ __u8 entry_length;
+ __u16 reserved1;
+ __u16 activation_count;
+ __u64 timestamp;
+ __u64 reserved2;
+ __u64 power_cycle_count;
+ char previous_fw[8];
+ char new_fw[8];
+ __u8 slot_number;
+ __u8 commit_action;
+ __u16 result;
+ __u8 reserved3[14];
+};
+
+struct __packed fw_activation_history {
+ __u8 log_id;
+ __u8 reserved1[3];
+ __u32 valid_entries;
+ struct fw_activation_history_entry entries[20];
+ __u8 reserved2[2790];
+ __u16 log_page_version;
+ __u64 log_page_guid[2];
+};
+
+static void ocp_fw_activation_history_normal(const struct fw_activation_history *fw_history)
+{
+ printf("Firmware History Log:\n");
+
+ printf(" %-26s%d\n", "log identifier:", fw_history->log_id);
+ printf(" %-26s%d\n", "valid entries:", le32_to_cpu(fw_history->valid_entries));
+
+ printf(" entries:\n");
+
+ for (int index = 0; index < fw_history->valid_entries; index++) {
+ const struct fw_activation_history_entry *entry = &fw_history->entries[index];
+
+ printf(" entry[%d]:\n", le32_to_cpu(index));
+ printf(" %-22s%d\n", "version number:", entry->ver_num);
+ printf(" %-22s%d\n", "entry length:", entry->entry_length);
+ printf(" %-22s%d\n", "activation count:",
+ le16_to_cpu(entry->activation_count));
+ printf(" %-22s%"PRIu64"\n", "timestamp:",
+ le64_to_cpu(entry->timestamp));
+ printf(" %-22s%"PRIu64"\n", "power cycle count:",
+ le64_to_cpu(entry->power_cycle_count));
+ printf(" %-22s%.*s\n", "previous firmware:", (int)sizeof(entry->previous_fw),
+ entry->previous_fw);
+ printf(" %-22s%.*s\n", "new firmware:", (int)sizeof(entry->new_fw),
+ entry->new_fw);
+ printf(" %-22s%d\n", "slot number:", entry->slot_number);
+ printf(" %-22s%d\n", "commit action type:", entry->commit_action);
+ printf(" %-22s%d\n", "result:", le16_to_cpu(entry->result));
+ }
+
+ printf(" %-26s%d\n", "log page version:",
+ le16_to_cpu(fw_history->log_page_version));
+
+ printf(" %-26s0x%"PRIx64"%"PRIx64"\n", "log page guid:",
+ le64_to_cpu(fw_history->log_page_guid[1]),
+ le64_to_cpu(fw_history->log_page_guid[0]));
+
+ printf("\n");
+}
+
+static void ocp_fw_activation_history_json(const struct fw_activation_history *fw_history)
+{
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_uint(root, "log identifier", fw_history->log_id);
+ json_object_add_value_uint(root, "valid entries", le32_to_cpu(fw_history->valid_entries));
+
+ struct json_object *entries = json_create_array();
+
+ for (int index = 0; index < fw_history->valid_entries; index++) {
+ const struct fw_activation_history_entry *entry = &fw_history->entries[index];
+ struct json_object *entry_obj = json_create_object();
+
+ json_object_add_value_uint(entry_obj, "version number", entry->ver_num);
+ json_object_add_value_uint(entry_obj, "entry length", entry->entry_length);
+ json_object_add_value_uint(entry_obj, "activation count",
+ le16_to_cpu(entry->activation_count));
+ json_object_add_value_uint64(entry_obj, "timestamp",
+ le64_to_cpu(entry->timestamp));
+ json_object_add_value_uint(entry_obj, "power cycle count",
+ le64_to_cpu(entry->power_cycle_count));
+
+ struct json_object *fw = json_object_new_string_len(entry->previous_fw,
+ sizeof(entry->previous_fw));
+
+ json_object_add_value_object(entry_obj, "previous firmware", fw);
+
+ fw = json_object_new_string_len(entry->new_fw, sizeof(entry->new_fw));
+
+ json_object_add_value_object(entry_obj, "new firmware", fw);
+ json_object_add_value_uint(entry_obj, "slot number", entry->slot_number);
+ json_object_add_value_uint(entry_obj, "commit action type", entry->commit_action);
+ json_object_add_value_uint(entry_obj, "result", le16_to_cpu(entry->result));
+
+ json_array_add_value_object(entries, entry_obj);
+ }
+
+ json_object_add_value_array(root, "entries", entries);
+
+ json_object_add_value_uint(root, "log page version",
+ le16_to_cpu(fw_history->log_page_version));
+
+ char guid[2 * sizeof(fw_history->log_page_guid) + 3] = { 0 };
+
+ sprintf(guid, "0x%"PRIx64"%"PRIx64"",
+ le64_to_cpu(fw_history->log_page_guid[1]),
+ le64_to_cpu(fw_history->log_page_guid[0]));
+ json_object_add_value_string(root, "log page guid", guid);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+
+ printf("\n");
+}
+
+int ocp_fw_activation_history_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const __u8 log_id = 0xC2;
+ const char *description = "Retrieves the OCP firmware activation history log.";
+
+ char *format = "normal";
+
+ OPT_ARGS(options) = {
+ OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
+ OPT_END()
+ };
+
+ struct nvme_dev *dev = NULL;
+ int err = parse_and_open(&dev, argc, argv, description, options);
+
+ if (err)
+ return err;
+
+ int uuid_index = 0;
+
+ /*
+ * Best effort attempt at uuid. Otherwise, assume no index (i.e. 0)
+ * Log GUID check will ensure correctness of returned data
+ */
+ ocp_get_uuid_index(dev, &uuid_index);
+
+ struct fw_activation_history fw_history = { 0 };
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &fw_history,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = log_id,
+ .len = sizeof(fw_history),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = 0,
+ .uuidx = uuid_index,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+
+ if (err)
+ nvme_show_status(err);
+
+ dev_close(dev);
+
+ int guid_cmp_res = memcmp(fw_history.log_page_guid, ocp_fw_activation_history_guid,
+ sizeof(ocp_fw_activation_history_guid));
+
+ if (!err && guid_cmp_res) {
+ fprintf(stderr,
+ "Error: Unexpected data. Log page guid does not match with expected.\n");
+ err = -EINVAL;
+ }
+
+ if (!err) {
+ enum nvme_print_flags print_flag;
+
+ err = validate_output_format(format, &print_flag);
+ if (err < 0) {
+ fprintf(stderr, "Error: Invalid output format.\n");
+ return err;
+ }
+
+ if (print_flag == JSON)
+ ocp_fw_activation_history_json(&fw_history);
+ else if (print_flag == NORMAL)
+ ocp_fw_activation_history_normal(&fw_history);
+ }
+
+ return err;
+}
diff --git a/plugins/ocp/ocp-fw-activation-history.h b/plugins/ocp/ocp-fw-activation-history.h
new file mode 100644
index 0000000..a7f9058
--- /dev/null
+++ b/plugins/ocp/ocp-fw-activation-history.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Authors: karl.dedow@solidigm.com
+ */
+
+#ifndef OCP_FIRMWARE_ACTIVATION_HISTORY_H
+#define OCP_FIRMWARE_ACTIVATION_HISTORY_H
+
+struct command;
+struct plugin;
+
+int ocp_fw_activation_history_log(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin);
+
+#endif
diff --git a/plugins/ocp/ocp-nvme.c b/plugins/ocp/ocp-nvme.c
new file mode 100644
index 0000000..53ae0f4
--- /dev/null
+++ b/plugins/ocp/ocp-nvme.c
@@ -0,0 +1,2971 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Meta Platforms, Inc.
+ *
+ * Authors: Arthur Shau <arthurshau@meta.com>,
+ * Wei Zhang <wzhang@meta.com>,
+ * Venkat Ramesh <venkatraghavan@meta.com>
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "util/types.h"
+#include "nvme-print.h"
+
+#include "ocp-smart-extended-log.h"
+#include "ocp-clear-features.h"
+#include "ocp-fw-activation-history.h"
+
+#define CREATE_CMD
+#include "ocp-nvme.h"
+#include "ocp-utils.h"
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Latency Monitor Log
+
+#define C3_LATENCY_MON_LOG_BUF_LEN 0x200
+#define C3_LATENCY_MON_OPCODE 0xC3
+#define C3_LATENCY_MON_VERSION 0x0001
+#define C3_GUID_LENGTH 16
+#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5
+
+#define C3_ACTIVE_BUCKET_TIMER_INCREMENT 5
+#define C3_ACTIVE_THRESHOLD_INCREMENT 5
+#define C3_MINIMUM_WINDOW_INCREMENT 100
+#define C3_BUCKET_NUM 4
+
+static __u8 lat_mon_guid[C3_GUID_LENGTH] = {
+ 0x92, 0x7a, 0xc0, 0x8c,
+ 0xd0, 0x84, 0x6c, 0x9c,
+ 0x70, 0x43, 0xe6, 0xd4,
+ 0x58, 0x5e, 0xd4, 0x85
+};
+
+#define READ 3
+#define WRITE 2
+#define TRIM 1
+#define RESERVED 0
+
+struct __packed ssd_latency_monitor_log {
+ __u8 feature_status; /* 0x00 */
+ __u8 rsvd1; /* 0x01 */
+ __le16 active_bucket_timer; /* 0x02 */
+ __le16 active_bucket_timer_threshold; /* 0x04 */
+ __u8 active_threshold_a; /* 0x06 */
+ __u8 active_threshold_b; /* 0x07 */
+ __u8 active_threshold_c; /* 0x08 */
+ __u8 active_threshold_d; /* 0x09 */
+ __le16 active_latency_config; /* 0x0A */
+ __u8 active_latency_min_window; /* 0x0C */
+ __u8 rsvd2[0x13]; /* 0x0D */
+
+ __le32 active_bucket_counter[4][4]; /* 0x20 - 0x5F */
+ __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */
+ __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */
+ __le16 active_latency_stamp_units; /* 0xD8 */
+ __u8 rsvd3[0x16]; /* 0xDA */
+
+ __le32 static_bucket_counter[4][4]; /* 0x0F0 - 0x12F */
+ __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */
+ __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */
+ __le16 static_latency_stamp_units; /* 0x1A8 */
+ __u8 rsvd4[0x16]; /* 0x1AA */
+
+ __le16 debug_log_trigger_enable; /* 0x1C0 */
+ __le16 debug_log_measured_latency; /* 0x1C2 */
+ __le64 debug_log_latency_stamp; /* 0x1C4 */
+ __le16 debug_log_ptr; /* 0x1CC */
+ __le16 debug_log_counter_trigger; /* 0x1CE */
+ __u8 debug_log_stamp_units; /* 0x1D0 */
+ __u8 rsvd5[0x1D]; /* 0x1D1 */
+
+ __le16 log_page_version; /* 0x1EE */
+ __u8 log_page_guid[0x10]; /* 0x1F0 */
+};
+
+struct __packed feature_latency_monitor {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ __u8 reserved[4083];
+};
+
+static int ocp_print_C3_log_normal(struct nvme_dev *dev,
+ struct ssd_latency_monitor_log *log_data)
+{
+ char ts_buf[128];
+ int i, j;
+
+ printf("-Latency Monitor/C3 Log Page Data-\n");
+ printf(" Controller : %s\n", dev->name);
+ printf(" Feature Status 0x%x\n",
+ log_data->feature_status);
+ printf(" Active Bucket Timer %d min\n",
+ C3_ACTIVE_BUCKET_TIMER_INCREMENT *
+ le16_to_cpu(log_data->active_bucket_timer));
+ printf(" Active Bucket Timer Threshold %d min\n",
+ C3_ACTIVE_BUCKET_TIMER_INCREMENT *
+ le16_to_cpu(log_data->active_bucket_timer_threshold));
+ printf(" Active Threshold A %d ms\n",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_a+1));
+ printf(" Active Threshold B %d ms\n",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_b+1));
+ printf(" Active Threshold C %d ms\n",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_c+1));
+ printf(" Active Threshold D %d ms\n",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_d+1));
+ printf(" Active Latency Configuration 0x%x \n",
+ le16_to_cpu(log_data->active_latency_config));
+ printf(" Active Latency Minimum Window %d ms\n",
+ C3_MINIMUM_WINDOW_INCREMENT *
+ le16_to_cpu(log_data->active_latency_min_window));
+ printf(" Active Latency Stamp Units %d\n",
+ le16_to_cpu(log_data->active_latency_stamp_units));
+ printf(" Static Latency Stamp Units %d\n",
+ le16_to_cpu(log_data->static_latency_stamp_units));
+ printf(" Debug Log Trigger Enable %d\n",
+ le16_to_cpu(log_data->debug_log_trigger_enable));
+ printf(" Debug Log Measured Latency %d\n",
+ le16_to_cpu(log_data->debug_log_measured_latency));
+ if (le64_to_cpu(log_data->debug_log_latency_stamp) == -1) {
+ printf(" Debug Log Latency Time Stamp N/A\n");
+ } else {
+ convert_ts(le64_to_cpu(log_data->debug_log_latency_stamp), ts_buf);
+ printf(" Debug Log Latency Time Stamp %s\n", ts_buf);
+ }
+ printf(" Debug Log Pointer %d\n",
+ le16_to_cpu(log_data->debug_log_ptr));
+ printf(" Debug Counter Trigger Source %d\n",
+ le16_to_cpu(log_data->debug_log_counter_trigger));
+ printf(" Debug Log Stamp Units %d\n",
+ le16_to_cpu(log_data->debug_log_stamp_units));
+ printf(" Log Page Version %d\n",
+ le16_to_cpu(log_data->log_page_version));
+
+ char guid[(C3_GUID_LENGTH * 2) + 1];
+ char *ptr = &guid[0];
+
+ for (i = C3_GUID_LENGTH - 1; i >= 0; i--)
+ ptr += sprintf(ptr, "%02X", log_data->log_page_guid[i]);
+
+ printf(" Log Page GUID %s\n", guid);
+ printf("\n");
+
+ printf(" Read Write Deallocate/Trim\n");
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n",
+ i,
+ le32_to_cpu(log_data->active_bucket_counter[i][READ]),
+ le32_to_cpu(log_data->active_bucket_counter[i][WRITE]),
+ le32_to_cpu(log_data->active_bucket_counter[i][TRIM]));
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Active Latency Time Stamp: Bucket %d ", i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) {
+ printf(" N/A ");
+ } else {
+ convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf);
+ printf("%s ", ts_buf);
+ }
+ }
+ printf("\n");
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
+ i,
+ le16_to_cpu(log_data->active_measured_latency[3-i][READ-1]),
+ le16_to_cpu(log_data->active_measured_latency[3-i][WRITE-1]),
+ le16_to_cpu(log_data->active_measured_latency[3-i][TRIM-1]));
+ }
+
+ printf("\n");
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Static Bucket Counter: Bucket %d %27d %27d %27d\n",
+ i,
+ le32_to_cpu(log_data->static_bucket_counter[i][READ]),
+ le32_to_cpu(log_data->static_bucket_counter[i][WRITE]),
+ le32_to_cpu(log_data->static_bucket_counter[i][TRIM]));
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Static Latency Time Stamp: Bucket %d ", i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) {
+ printf(" N/A ");
+ } else {
+ convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf);
+ printf("%s ", ts_buf);
+ }
+ }
+ printf("\n");
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
+ i,
+ le16_to_cpu(log_data->static_measured_latency[3-i][READ-1]),
+ le16_to_cpu(log_data->static_measured_latency[3-i][WRITE-1]),
+ le16_to_cpu(log_data->static_measured_latency[3-i][TRIM-1]));
+ }
+
+ return 0;
+}
+
+static void ocp_print_C3_log_json(struct ssd_latency_monitor_log *log_data)
+{
+ struct json_object *root;
+ char ts_buf[128];
+ char buf[128];
+ int i, j;
+ char *operation[3] = {"Trim", "Write", "Read"};
+
+ root = json_create_object();
+
+ json_object_add_value_uint(root, "Feature Status",
+ log_data->feature_status);
+ json_object_add_value_uint(root, "Active Bucket Timer",
+ C3_ACTIVE_BUCKET_TIMER_INCREMENT *
+ le16_to_cpu(log_data->active_bucket_timer));
+ json_object_add_value_uint(root, "Active Bucket Timer Threshold",
+ C3_ACTIVE_BUCKET_TIMER_INCREMENT *
+ le16_to_cpu(log_data->active_bucket_timer_threshold));
+ json_object_add_value_uint(root, "Active Threshold A",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_a + 1));
+ json_object_add_value_uint(root, "Active Threshold B",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_b + 1));
+ json_object_add_value_uint(root, "Active Threshold C",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_c + 1));
+ json_object_add_value_uint(root, "Active Threshold D",
+ C3_ACTIVE_THRESHOLD_INCREMENT *
+ le16_to_cpu(log_data->active_threshold_d + 1));
+ json_object_add_value_uint(root, "Active Latency Configuration",
+ le16_to_cpu(log_data->active_latency_config));
+ json_object_add_value_uint(root, "Active Latency Minimum Window",
+ C3_MINIMUM_WINDOW_INCREMENT *
+ le16_to_cpu(log_data->active_latency_min_window));
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Active Bucket Counter: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ json_object_add_value_uint(bucket, operation[j],
+ le32_to_cpu(log_data->active_bucket_counter[i][j+1]));
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Active Latency Time Stamp: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->active_latency_timestamp[3-i][j]) == -1) {
+ json_object_add_value_string(bucket, operation[j], "NA");
+ } else {
+ convert_ts(le64_to_cpu(log_data->active_latency_timestamp[3-i][j]), ts_buf);
+ json_object_add_value_string(bucket, operation[j], ts_buf);
+ }
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Active Measured Latency: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ json_object_add_value_uint(bucket, operation[j],
+ le16_to_cpu(log_data->active_measured_latency[3-i][j]));
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ json_object_add_value_uint(root, "Active Latency Stamp Units",
+ le16_to_cpu(log_data->active_latency_stamp_units));
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Static Bucket Counter: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ json_object_add_value_uint(bucket, operation[j],
+ le32_to_cpu(log_data->static_bucket_counter[i][j+1]));
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Static Latency Time Stamp: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->static_latency_timestamp[3-i][j]) == -1) {
+ json_object_add_value_string(bucket, operation[j], "NA");
+ } else {
+ convert_ts(le64_to_cpu(log_data->static_latency_timestamp[3-i][j]), ts_buf);
+ json_object_add_value_string(bucket, operation[j], ts_buf);
+ }
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ for (i = 0; i < C3_BUCKET_NUM; i++) {
+ struct json_object *bucket;
+
+ bucket = json_create_object();
+ sprintf(buf, "Static Measured Latency: Bucket %d", i);
+ for (j = 2; j >= 0; j--) {
+ json_object_add_value_uint(bucket, operation[j],
+ le16_to_cpu(log_data->static_measured_latency[3-i][j]));
+ }
+ json_object_add_value_object(root, buf, bucket);
+ }
+
+ json_object_add_value_uint(root, "Static Latency Stamp Units",
+ le16_to_cpu(log_data->static_latency_stamp_units));
+ json_object_add_value_uint(root, "Debug Log Trigger Enable",
+ le16_to_cpu(log_data->debug_log_trigger_enable));
+ json_object_add_value_uint(root, "Debug Log Measured Latency",
+ le16_to_cpu(log_data->debug_log_measured_latency));
+ if (le64_to_cpu(log_data->debug_log_latency_stamp) == -1) {
+ json_object_add_value_string(root, "Debug Log Latency Time Stamp", "NA");
+ } else {
+ convert_ts(le64_to_cpu(log_data->debug_log_latency_stamp), ts_buf);
+ json_object_add_value_string(root, "Debug Log Latency Time Stamp", ts_buf);
+ }
+ json_object_add_value_uint(root, "Debug Log Pointer",
+ le16_to_cpu(log_data->debug_log_ptr));
+ json_object_add_value_uint(root, "Debug Counter Trigger Source",
+ le16_to_cpu(log_data->debug_log_counter_trigger));
+ json_object_add_value_uint(root, "Debug Log Stamp Units",
+ le16_to_cpu(log_data->debug_log_stamp_units));
+ json_object_add_value_uint(root, "Log Page Version",
+ le16_to_cpu(log_data->log_page_version));
+
+ char guid[(C3_GUID_LENGTH * 2) + 1];
+ char *ptr = &guid[0];
+
+ for (i = C3_GUID_LENGTH - 1; i >= 0; i--)
+ ptr += sprintf(ptr, "%02X", log_data->log_page_guid[i]);
+
+ json_object_add_value_string(root, "Log Page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static int get_c3_log_page(struct nvme_dev *dev, char *format)
+{
+ struct ssd_latency_monitor_log *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ int i;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ data = malloc(sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C3_LATENCY_MON_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C3_LATENCY_MON_OPCODE,
+ C3_LATENCY_MON_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+ if (!ret) {
+ log_data = (struct ssd_latency_monitor_log *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != C3_LATENCY_MON_VERSION) {
+ fprintf(stderr,
+ "ERROR : OCP : invalid latency monitor version\n");
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * check log page guid
+ * Verify GUID matches
+ */
+ for (i = 0; i < 16; i++) {
+ if (lat_mon_guid[i] != log_data->log_page_guid[i]) {
+ int j;
+
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C3 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", lat_mon_guid[j]);
+
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C3_log_normal(dev, log_data);
+ break;
+ case JSON:
+ ocp_print_C3_log_json(log_data);
+ break;
+ default:
+ fprintf(stderr, "unhandled output format\n");
+
+ }
+ } else {
+ fprintf(stderr,
+ "ERROR : OCP : Unable to read C3 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int ocp_latency_monitor_log(int argc, char **argv,
+ struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve latency monitor log data.";
+ struct nvme_dev *dev;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c3_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr,
+ "ERROR : OCP : Failure reading the C3 Log Page, ret = %d\n",
+ ret);
+
+ dev_close(dev);
+ return ret;
+}
+
+int ocp_set_latency_monitor_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = -1;
+ struct nvme_dev *dev;
+ __u32 result;
+ struct feature_latency_monitor buf = {0,};
+ __u32 nsid = NVME_NSID_ALL;
+ struct stat nvme_stat;
+ struct nvme_id_ctrl ctrl;
+
+ const char *desc = "Set Latency Monitor feature.";
+ const char *active_bucket_timer_threshold = "This is the value that loads the Active Bucket Timer Threshold.";
+ const char *active_threshold_a = "This is the value that loads into the Active Threshold A.";
+ const char *active_threshold_b = "This is the value that loads into the Active Threshold B.";
+ const char *active_threshold_c = "This is the value that loads into the Active Threshold C.";
+ const char *active_threshold_d = "This is the value that loads into the Active Threshold D.";
+ const char *active_latency_config = "This is the value that loads into the Active Latency Configuration.";
+ const char *active_latency_minimum_window = "This is the value that loads into the Active Latency Minimum Window.";
+ const char *debug_log_trigger_enable = "This is the value that loads into the Debug Log Trigger Enable.";
+ const char *discard_debug_log = "Discard Debug Log.";
+ const char *latency_monitor_feature_enable = "Latency Monitor Feature Enable.";
+
+ struct config {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ };
+
+ struct config cfg = {
+ .active_bucket_timer_threshold = 0x7E0,
+ .active_threshold_a = 0x5,
+ .active_threshold_b = 0x13,
+ .active_threshold_c = 0x1E,
+ .active_threshold_d = 0x2E,
+ .active_latency_config = 0xFFF,
+ .active_latency_minimum_window = 0xA,
+ .debug_log_trigger_enable = 0,
+ .discard_debug_log = 0,
+ .latency_monitor_feature_enable = 0x7,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("active_bucket_timer_threshold", 't', &cfg.active_bucket_timer_threshold, active_bucket_timer_threshold),
+ OPT_UINT("active_threshold_a", 'a', &cfg.active_threshold_a, active_threshold_a),
+ OPT_UINT("active_threshold_b", 'b', &cfg.active_threshold_b, active_threshold_b),
+ OPT_UINT("active_threshold_c", 'c', &cfg.active_threshold_c, active_threshold_c),
+ OPT_UINT("active_threshold_d", 'd', &cfg.active_threshold_d, active_threshold_d),
+ OPT_UINT("active_latency_config", 'f', &cfg.active_latency_config, active_latency_config),
+ OPT_UINT("active_latency_minimum_window", 'w', &cfg.active_latency_minimum_window, active_latency_minimum_window),
+ OPT_UINT("debug_log_trigger_enable", 'r', &cfg.debug_log_trigger_enable, debug_log_trigger_enable),
+ OPT_UINT("discard_debug_log", 'l', &cfg.discard_debug_log, discard_debug_log),
+ OPT_UINT("latency_monitor_feature_enable", 'e', &cfg.latency_monitor_feature_enable, latency_monitor_feature_enable),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = fstat(dev_fd(dev), &nvme_stat);
+ if (err < 0)
+ return err;
+
+ if (S_ISBLK(nvme_stat.st_mode)) {
+ err = nvme_get_nsid(dev_fd(dev), &nsid);
+ if (err < 0) {
+ perror("invalid-namespace-id");
+ return err;
+ }
+ }
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err)
+ return err;
+
+ memset(&buf, 0, sizeof(struct feature_latency_monitor));
+
+ buf.active_bucket_timer_threshold = cfg.active_bucket_timer_threshold;
+ buf.active_threshold_a = cfg.active_threshold_a;
+ buf.active_threshold_b = cfg.active_threshold_b;
+ buf.active_threshold_c = cfg.active_threshold_c;
+ buf.active_threshold_d = cfg.active_threshold_d;
+ buf.active_latency_config = cfg.active_latency_config;
+ buf.active_latency_minimum_window = cfg.active_latency_minimum_window;
+ buf.debug_log_trigger_enable = cfg.debug_log_trigger_enable;
+ buf.discard_debug_log = cfg.discard_debug_log;
+ buf.latency_monitor_feature_enable = cfg.latency_monitor_feature_enable;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = NVME_FEAT_OCP_LATENCY_MONITOR,
+ .nsid = 0,
+ .cdw12 = 0,
+ .save = 1,
+ .data_len = sizeof(struct feature_latency_monitor),
+ .data = (void *)&buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err < 0) {
+ perror("set-feature");
+ } else if (!err) {
+ printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n", NVME_FEAT_OCP_LATENCY_MONITOR);
+ printf("active bucket timer threshold: 0x%x\n", buf.active_bucket_timer_threshold);
+ printf("active threshold a: 0x%x\n", buf.active_threshold_a);
+ printf("active threshold b: 0x%x\n", buf.active_threshold_b);
+ printf("active threshold c: 0x%x\n", buf.active_threshold_c);
+ printf("active threshold d: 0x%x\n", buf.active_threshold_d);
+ printf("active latency config: 0x%x\n", buf.active_latency_config);
+ printf("active latency minimum window: 0x%x\n", buf.active_latency_minimum_window);
+ printf("debug log trigger enable: 0x%x\n", buf.debug_log_trigger_enable);
+ printf("discard debug log: 0x%x\n", buf.discard_debug_log);
+ printf("latency monitor feature enable: 0x%x\n", buf.latency_monitor_feature_enable);
+ } else if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err, false), err);
+ }
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// EOL/PLP Failure Mode
+
+static const char *eol_plp_failure_mode_to_string(__u8 mode)
+{
+ switch (mode) {
+ case 1:
+ return "Read only mode (ROM)";
+ case 2:
+ return "Write through mode (WTM)";
+ case 3:
+ return "Normal mode";
+ default:
+ break;
+ }
+
+ return "Reserved";
+}
+
+static int eol_plp_failure_mode_get(struct nvme_dev *dev, const __u32 nsid,
+ const __u8 fid, __u8 sel)
+{
+ __u32 result;
+ int err;
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = sel,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ nvme_show_result("End of Life Behavior (feature: %#0*x): %#0*x (%s: %s)",
+ fid ? 4 : 2, fid, result ? 10 : 8, result,
+ nvme_select_to_string(sel),
+ eol_plp_failure_mode_to_string(result));
+ if (sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: %#0*x.", fid ? 4 : 2, fid);
+ }
+
+ return err;
+}
+
+static int eol_plp_failure_mode_set(struct nvme_dev *dev, const __u32 nsid,
+ const __u8 fid, __u8 mode, bool save,
+ bool uuid)
+{
+ __u32 result;
+ int err;
+ int uuid_index = 0;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = mode << 30,
+ .cdw12 = 0,
+ .save = save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define EOL/PLP failure mode");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ nvme_show_result("Successfully set mode (feature: %#0*x): %#0*x (%s: %s).",
+ fid ? 4 : 2, fid, mode ? 10 : 8, mode,
+ save ? "Save" : "Not save",
+ eol_plp_failure_mode_to_string(mode));
+ }
+
+ return err;
+}
+
+static int eol_plp_failure_mode(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Define EOL or PLP circuitry failure mode.\n"
+ "No argument prints current mode.";
+ const char *mode = "[0-3]: default/rom/wtm/normal";
+ const char *save = "Specifies that the controller shall save the attribute";
+ const char *sel = "[0-3,8]: current/default/saved/supported/changed";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc2;
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u8 mode;
+ bool save;
+ __u8 sel;
+ };
+
+ struct config cfg = {
+ .mode = 0,
+ .save = false,
+ .sel = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("mode", 'm', &cfg.mode, mode),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (argconfig_parse_seen(opts, "mode"))
+ err = eol_plp_failure_mode_set(dev, nsid, fid, cfg.mode,
+ cfg.save,
+ !argconfig_parse_seen(opts, "no-uuid"));
+ else
+ err = eol_plp_failure_mode_get(dev, nsid, fid, cfg.sel);
+
+ dev_close(dev);
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Telemetry Log
+
+#define TELEMETRY_HEADER_SIZE 512
+#define TELEMETRY_BYTE_PER_BLOCK 512
+#define TELEMETRY_TRANSFER_SIZE 1024
+#define FILE_NAME_SIZE 2048
+
+enum TELEMETRY_TYPE {
+ TELEMETRY_TYPE_NONE = 0,
+ TELEMETRY_TYPE_HOST = 7,
+ TELEMETRY_TYPE_CONTROLLER = 8,
+ TELEMETRY_TYPE_HOST_0 = 9,
+ TELEMETRY_TYPE_HOST_1 = 10,
+};
+
+struct telemetry_initiated_log {
+ __u8 LogIdentifier;
+ __u8 Reserved1[4];
+ __u8 IEEE[3];
+ __le16 DataArea1LastBlock;
+ __le16 DataArea2LastBlock;
+ __le16 DataArea3LastBlock;
+ __u8 Reserved2[368];
+ __u8 DataAvailable;
+ __u8 DataGenerationNumber;
+ __u8 ReasonIdentifier[128];
+};
+
+struct telemetry_data_area_1 {
+ __le16 major_version;
+ __le16 minor_version;
+ __u8 reserved1[4];
+ __le64 timestamp;
+ __u8 log_page_guid[16];
+ __u8 no_of_tps_supp;
+ __u8 tps;
+ __u8 reserved2[6];
+ __le16 sls;
+ __u8 reserved3[8];
+ __le16 fw_revision;
+ __u8 reserved4[32];
+ __le16 da1_stat_start;
+ __le16 da1_stat_size;
+ __le16 da2_stat_start;
+ __le16 da2_stat_size;
+ __u8 reserved5[32];
+ __u8 event_fifo_da[16];
+ __le64 event_fifo_start[16];
+ __le64 event_fifo_size[16];
+ __u8 reserved6[80];
+ __u8 smart_health_info[512];
+ __u8 smart_health_info_extended[512];
+};
+static void get_serial_number(struct nvme_id_ctrl *ctrl, char *sn)
+{
+ int i;
+ /* Remove trailing spaces from the name */
+ for (i = 0; i < sizeof(ctrl->sn); i++) {
+ if (ctrl->sn[i] == ' ')
+ break;
+ sn[i] = ctrl->sn[i];
+ }
+}
+
+static int get_telemetry_header(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
+ __u32 data_len, void *data, __u8 nLSP, __u8 nRAE)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = ns,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+
+ __u32 numd = (data_len >> 2) - 1;
+ __u16 numdu = numd >> 16;
+ __u16 numdl = numd & 0xffff;
+
+ cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16;
+ cmd.cdw11 = numdu;
+ cmd.cdw12 = 0;
+ cmd.cdw13 = 0;
+ cmd.cdw14 = 0;
+
+ return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+}
+
+static void print_telemetry_header(struct telemetry_initiated_log *logheader,
+ int tele_type)
+{
+ if (logheader) {
+ unsigned int i = 0, j = 0;
+
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Header ============\n");
+ else
+ printf("========= Telemetry Controller Header =========\n");
+
+ printf("Log Identifier : 0x%02X\n", logheader->LogIdentifier);
+ printf("IEEE : 0x%02X%02X%02X\n",
+ logheader->IEEE[0], logheader->IEEE[1], logheader->IEEE[2]);
+ printf("Data Area 1 Last Block : 0x%04X\n",
+ le16_to_cpu(logheader->DataArea1LastBlock));
+ printf("Data Area 2 Last Block : 0x%04X\n",
+ le16_to_cpu(logheader->DataArea2LastBlock));
+ printf("Data Area 3 Last Block : 0x%04X\n",
+ le16_to_cpu(logheader->DataArea3LastBlock));
+ printf("Data Available : 0x%02X\n", logheader->DataAvailable);
+ printf("Data Generation Number : 0x%02X\n", logheader->DataGenerationNumber);
+ printf("Reason Identifier :\n");
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 16; j++)
+ printf("%02X ", logheader->ReasonIdentifier[127 - ((i * 16) + j)]);
+ printf("\n");
+ }
+ printf("===============================================\n\n");
+ }
+}
+static int get_telemetry_data(struct nvme_dev *dev, __u32 ns, __u8 tele_type,
+ __u32 data_len, void *data, __u8 nLSP, __u8 nRAE,
+ __u64 offset)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = ns,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+ __u32 numd = (data_len >> 2) - 1;
+ __u16 numdu = numd >> 16;
+ __u16 numdl = numd & 0xffff;
+ cmd.cdw10 = tele_type | (nLSP & 0x0F) << 8 | (nRAE & 0x01) << 15 | (numdl & 0xFFFF) << 16;
+ cmd.cdw11 = numdu;
+ cmd.cdw12 = offset;
+ cmd.cdw13 = 0;
+ cmd.cdw14 = 0;
+ return nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+}
+static void print_telemetry_data_area_1(struct telemetry_data_area_1 *da1,
+ int tele_type)
+{
+ if (da1) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 =========\n");
+ printf("Major Version : 0x%x\n", le16_to_cpu(da1->major_version));
+ printf("Minor Version : 0x%x\n", le16_to_cpu(da1->minor_version));
+ for (i = 0; i < 4; i++)
+ printf("reserved1 : 0x%x\n", da1->reserved1[i]);
+ printf("Timestamp : %"PRIu64"\n", le64_to_cpu(da1->timestamp));
+ for (i = 15; i >= 0; i--)
+ printf("%x", da1->log_page_guid[i]);
+ printf("Number Telemetry Profiles Supported : 0x%x\n", da1->no_of_tps_supp);
+ printf("Telemetry Profile Selected (TPS) : 0x%x\n", da1->tps);
+ for (i = 0; i < 6; i++)
+ printf("reserved2 : 0x%x\n", da1->reserved2[i]);
+ printf("Telemetry String Log Size (SLS) : 0x%x\n", le16_to_cpu(da1->sls));
+ for (i = 0; i < 8; i++)
+ printf("reserved3 : 0x%x\n", da1->reserved3[i]);
+ printf("Firmware Revision : 0x%x\n", le16_to_cpu(da1->fw_revision));
+ for (i = 0; i < 32; i++)
+ printf("reserved4 : 0x%x\n", da1->reserved4[i]);
+ printf("Data Area 1 Statistic Start : 0x%x\n", le16_to_cpu(da1->da1_stat_start));
+ printf("Data Area 1 Statistic Size : 0x%x\n", le16_to_cpu(da1->da1_stat_size));
+ printf("Data Area 2 Statistic Start : 0x%x\n", le16_to_cpu(da1->da2_stat_start));
+ printf("Data Area 2 Statistic Size : 0x%x\n", le16_to_cpu(da1->da2_stat_size));
+ for (i = 0; i < 32; i++)
+ printf("reserved5 : 0x%x\n", da1->reserved5[i]);
+ for (i = 0; i < 17; i++){
+ printf("Event FIFO %d Data Area : 0x%x\n", i, da1->event_fifo_da[i]);
+ printf("Event FIFO %d Start : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_start[i]));
+ printf("Event FIFO %d Size : %"PRIu64"\n", i, le64_to_cpu(da1->event_fifo_size[i]));
+ }
+ for (i = 0; i < 80; i++)
+ printf("reserved6 : 0x%x\n", da1->reserved6[i]);
+ for (i = 0; i < 512; i++){
+ printf("SMART / Health Information : 0x%x\n", da1->smart_health_info[i]);
+ printf("SMART / Health Information Extended : 0x%x\n", da1->smart_health_info_extended[i]);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da1_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
+{
+ if (da1_stat) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 8) < buf_size) {
+ printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
+ printf("Statistics info : 0x%x\n", da1_stat[i+2]);
+ printf("NS info : 0x%x\n", da1_stat[i+3]);
+ printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
+ printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
+ i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da1_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
+{
+ if (da1_fifo) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 FIFO ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 FIFO =========\n");
+ while((i + 4) < buf_size) {
+ printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
+ printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
+ printf("Event Data Size : 0x%x\n", da1_fifo[3]);
+ i = 4 + ((da1_fifo[3]) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da2_stat(__u8 *da1_stat, int tele_type, __u16 buf_size)
+{
+ if (da1_stat) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 8) < buf_size) {
+ printf("Statistics Identifier : 0x%x\n", (da1_stat[i] | da1_stat[i+1] << 8));
+ printf("Statistics info : 0x%x\n", da1_stat[i+2]);
+ printf("NS info : 0x%x\n", da1_stat[i+3]);
+ printf("Statistic Data Size : 0x%x\n", (da1_stat[i+4] | da1_stat[i+5] << 8));
+ printf("Reserved : 0x%x\n", (da1_stat[i+6] | da1_stat[i+7] << 8));
+ i = 8 + ((da1_stat[i+4] | da1_stat[i+5] << 8) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+static void print_telemetry_da2_fifo(__u8 *da1_fifo, int tele_type, __u16 buf_size)
+{
+ if (da1_fifo) {
+ unsigned int i = 0;
+ if (tele_type == TELEMETRY_TYPE_HOST)
+ printf("============ Telemetry Host Data area 1 Statistics ============\n");
+ else
+ printf("========= Telemetry Controller Data area 1 Statistics =========\n");
+ while((i + 4) < buf_size) {
+ printf("Debug Event Class Type : 0x%x\n", da1_fifo[i]);
+ printf("Event ID : 0x%x\n", (da1_fifo[i+1] | da1_fifo[i+2] << 8));
+ printf("Event Data Size : 0x%x\n", da1_fifo[3]);
+ i = 4 + ((da1_fifo[3]) * 4);
+ }
+ printf("===============================================\n\n");
+ }
+}
+
+static int extract_dump_get_log(struct nvme_dev *dev, char *featurename, char *filename, char *sn,
+ int dumpsize, int transfersize, __u32 nsid, __u8 log_id,
+ __u8 lsp, __u64 offset, bool rae)
+{
+ int i = 0, err = 0;
+
+ char *data = calloc(transfersize, sizeof(char));
+ char filepath[FILE_NAME_SIZE] = {0,};
+ int output = 0;
+ int total_loop_cnt = dumpsize / transfersize;
+ int last_xfer_size = dumpsize % transfersize;
+
+ if (last_xfer_size)
+ total_loop_cnt++;
+ else
+ last_xfer_size = transfersize;
+
+ if (filename == 0)
+ snprintf(filepath, FILE_NAME_SIZE, "%s_%s.bin", featurename, sn);
+ else
+ snprintf(filepath, FILE_NAME_SIZE, "%s%s_%s.bin", filename, featurename, sn);
+
+ for (i = 0; i < total_loop_cnt; i++) {
+ memset(data, 0, transfersize);
+
+ struct nvme_get_log_args args = {
+ .lpo = offset,
+ .result = NULL,
+ .log = (void *)data,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = log_id,
+ .len = transfersize,
+ .nsid = nsid,
+ .lsp = lsp,
+ .uuidx = 0,
+ .rae = rae,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err) {
+ if (i > 0)
+ goto close_output;
+ else
+ goto end;
+ }
+
+ if (i != total_loop_cnt - 1) {
+ if (!i) {
+ output = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ err = -13;
+ goto end;
+ }
+ }
+ if (write(output, data, transfersize) < 0) {
+ err = -10;
+ goto close_output;
+ }
+ } else {
+ if (write(output, data, last_xfer_size) < 0) {
+ err = -10;
+ goto close_output;
+ }
+ }
+ offset += transfersize;
+ printf("%d%%\r", (i + 1) * 100 / total_loop_cnt);
+ }
+ printf("100%%\nThe log file was saved at \"%s\"\n", filepath);
+
+close_output:
+ close(output);
+
+end:
+ free(data);
+ return err;
+}
+
+static int get_telemetry_dump(struct nvme_dev *dev, char *filename, char *sn,
+ enum TELEMETRY_TYPE tele_type, int data_area, bool header_print)
+{
+ __u32 err = 0, nsid = 0;
+ __u8 lsp = 0, rae = 0;
+ unsigned int i = 0;
+ char data[TELEMETRY_TRANSFER_SIZE] = { 0 };
+ char data1[1536] = { 0 };
+ char *featurename = 0;
+ struct telemetry_initiated_log *logheader = (struct telemetry_initiated_log *)data;
+ struct telemetry_data_area_1 *da1 = (struct telemetry_data_area_1 *)data1;
+ __u64 offset = 0, size = 0;
+ char dumpname[FILE_NAME_SIZE] = { 0 };
+
+ if (tele_type == TELEMETRY_TYPE_HOST_0) {
+ featurename = "Host(0)";
+ lsp = 0;
+ rae = 0;
+ tele_type = TELEMETRY_TYPE_HOST;
+ } else if (tele_type == TELEMETRY_TYPE_HOST_1) {
+ featurename = "Host(1)";
+ lsp = 1;
+ rae = 0;
+ tele_type = TELEMETRY_TYPE_HOST;
+ } else {
+ featurename = "Controller";
+ lsp = 0;
+ rae = 1;
+ }
+
+ err = get_telemetry_header(dev, nsid, tele_type, TELEMETRY_HEADER_SIZE,
+ (void *)data, lsp, rae);
+ if (err)
+ return err;
+
+ if (header_print)
+ print_telemetry_header(logheader, tele_type);
+ err = get_telemetry_data(dev, nsid, tele_type, 1536,
+ (void *)data1, lsp, rae, 512);
+ if (err)
+ return err;
+ print_telemetry_data_area_1(da1, tele_type);
+ char *da1_stat = calloc((da1->da1_stat_size * 4), sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->da1_stat_size) * 4,
+ (void *)da1_stat, lsp, rae, (da1->da1_stat_start) * 4);
+ if (err)
+ return err;
+ print_telemetry_da1_stat((void *)da1_stat, tele_type, (da1->da1_stat_size) * 4);
+ for (i = 0; i < 17 ; i++){
+ if (da1->event_fifo_da[i] == 1){
+ char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
+ (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
+ if (err)
+ return err;
+ print_telemetry_da1_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ }
+ char *da2_stat = calloc((da1->da2_stat_size * 4), sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->da2_stat_size) * 4,
+ (void *)da2_stat, lsp, rae, (da1->da2_stat_start) * 4);
+ if (err)
+ return err;
+ print_telemetry_da2_stat((void *)da2_stat, tele_type, (da1->da2_stat_size) * 4);
+ for (i = 0; i < 17 ; i++){
+ if (da1->event_fifo_da[i] == 2){
+ char *da1_fifo = calloc((da1->event_fifo_size[i]) * 4, sizeof(char));
+ err = get_telemetry_data(dev, nsid, tele_type, (da1->event_fifo_size[i]) * 4,
+ (void *)da1_stat, lsp, rae, (da1->event_fifo_start[i]) * 4);
+ if (err)
+ return err;
+ print_telemetry_da2_fifo((void *)da1_fifo, tele_type, (da1->event_fifo_size[i]) * 4);
+ }
+ }
+
+ switch (data_area) {
+ case 1:
+ offset = TELEMETRY_HEADER_SIZE;
+ size = le16_to_cpu(logheader->DataArea1LastBlock);
+ break;
+ case 2:
+ offset = TELEMETRY_HEADER_SIZE
+ + (le16_to_cpu(logheader->DataArea1LastBlock) * TELEMETRY_BYTE_PER_BLOCK);
+ size = le16_to_cpu(logheader->DataArea2LastBlock)
+ - le16_to_cpu(logheader->DataArea1LastBlock);
+ break;
+ case 3:
+ offset = TELEMETRY_HEADER_SIZE
+ + (le16_to_cpu(logheader->DataArea2LastBlock) * TELEMETRY_BYTE_PER_BLOCK);
+ size = le16_to_cpu(logheader->DataArea3LastBlock)
+ - le16_to_cpu(logheader->DataArea2LastBlock);
+ break;
+ default:
+ break;
+ }
+
+ if (!size) {
+ printf("Telemetry %s Area %d is empty.\n", featurename, data_area);
+ return err;
+ }
+
+ snprintf(dumpname, FILE_NAME_SIZE,
+ "Telemetry_%s_Area_%d", featurename, data_area);
+ err = extract_dump_get_log(dev, dumpname, filename, sn, size * TELEMETRY_BYTE_PER_BLOCK,
+ TELEMETRY_TRANSFER_SIZE, nsid, tele_type,
+ 0, offset, rae);
+
+ return err;
+}
+
+static int ocp_telemetry_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ struct nvme_dev *dev;
+ int err = 0;
+ const char *desc = "Retrieve and save telemetry log.";
+ const char *type = "Telemetry Type; 'host[Create bit]' or 'controller'";
+ const char *area = "Telemetry Data Area; 1 or 3";
+ const char *file = "Output file name with path;\n"
+ "e.g. '-o ./path/name'\n'-o ./path1/path2/';\n"
+ "If requested path does not exist, the directory will be newly created.";
+
+ __u32 nsid = NVME_NSID_ALL;
+ struct stat nvme_stat;
+ char sn[21] = {0,};
+ struct nvme_id_ctrl ctrl;
+ bool is_support_telemetry_controller;
+
+ int tele_type = 0;
+ int tele_area = 0;
+
+ struct config {
+ char *type;
+ int area;
+ char *file;
+ };
+
+ struct config cfg = {
+ .type = NULL,
+ .area = 0,
+ .file = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STR("telemetry_type", 't', &cfg.type, type),
+ OPT_INT("telemetry_data_area", 'a', &cfg.area, area),
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = fstat(dev_fd(dev), &nvme_stat);
+ if (err < 0)
+ return err;
+
+ if (S_ISBLK(nvme_stat.st_mode)) {
+ err = nvme_get_nsid(dev_fd(dev), &nsid);
+ if (err < 0)
+ return err;
+ }
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err)
+ return err;
+
+ get_serial_number(&ctrl, sn);
+
+ is_support_telemetry_controller = ((ctrl.lpa & 0x8) >> 3);
+
+ if (!cfg.type && !cfg.area) {
+ tele_type = TELEMETRY_TYPE_NONE;
+ tele_area = 0;
+ } else if (cfg.type && cfg.area) {
+ if (!strcmp(cfg.type, "host0"))
+ tele_type = TELEMETRY_TYPE_HOST_0;
+ else if (!strcmp(cfg.type, "host1"))
+ tele_type = TELEMETRY_TYPE_HOST_1;
+ else if (!strcmp(cfg.type, "controller"))
+ tele_type = TELEMETRY_TYPE_CONTROLLER;
+
+ tele_area = cfg.area;
+
+ if ((tele_area != 1 && tele_area != 3) ||
+ (tele_type == TELEMETRY_TYPE_CONTROLLER && tele_area != 3)) {
+ printf("\nUnsupported parameters entered.\n");
+ printf("Possible combinations; {'host0',1}, {'host0',3}, {'host1',1}, {'host1',3}, {'controller',3}\n");
+ return err;
+ }
+ } else {
+ printf("\nShould provide these all; 'telemetry_type' and 'telemetry_data_area'\n");
+ return err;
+ }
+
+ if (tele_type == TELEMETRY_TYPE_NONE) {
+ printf("\n-------------------------------------------------------------\n");
+ /* Host 0 (lsp == 0) must be executed before Host 1 (lsp == 1). */
+ printf("\nExtracting Telemetry Host 0 Dump (Data Area 1)...\n");
+
+ err = get_telemetry_dump(dev, cfg.file, sn,
+ TELEMETRY_TYPE_HOST_0, 1, true);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+
+ printf("\n-------------------------------------------------------------\n");
+
+ printf("\nExtracting Telemetry Host 0 Dump (Data Area 3)...\n");
+
+ err = get_telemetry_dump(dev, cfg.file, sn,
+ TELEMETRY_TYPE_HOST_0, 3, false);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+
+ printf("\n-------------------------------------------------------------\n");
+
+ printf("\nExtracting Telemetry Host 1 Dump (Data Area 1)...\n");
+
+ err = get_telemetry_dump(dev, cfg.file, sn,
+ TELEMETRY_TYPE_HOST_1, 1, true);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+
+ printf("\n-------------------------------------------------------------\n");
+
+ printf("\nExtracting Telemetry Host 1 Dump (Data Area 3)...\n");
+
+ err = get_telemetry_dump(dev, cfg.file, sn,
+ TELEMETRY_TYPE_HOST_1, 3, false);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+
+ printf("\n-------------------------------------------------------------\n");
+
+ printf("\nExtracting Telemetry Controller Dump (Data Area 3)...\n");
+
+ if (is_support_telemetry_controller == true) {
+ err = get_telemetry_dump(dev, cfg.file, sn,
+ TELEMETRY_TYPE_CONTROLLER, 3, true);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+ }
+
+ printf("\n-------------------------------------------------------------\n");
+ } else if (tele_type == TELEMETRY_TYPE_CONTROLLER) {
+ printf("Extracting Telemetry Controller Dump (Data Area %d)...\n", tele_area);
+
+ if (is_support_telemetry_controller == true) {
+ err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+ }
+ } else {
+ printf("Extracting Telemetry Host(%d) Dump (Data Area %d)...\n",
+ (tele_type == TELEMETRY_TYPE_HOST_0) ? 0 : 1, tele_area);
+
+ err = get_telemetry_dump(dev, cfg.file, sn, tele_type, tele_area, true);
+ if (err)
+ fprintf(stderr, "NVMe Status: %s(%x)\n", nvme_status_to_string(err, false), err);
+ }
+
+ printf("telemetry-log done.\n");
+
+return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Unsupported Requirement Log Page (LID : C5h)
+
+/* C5 Unsupported Requirement Log Page */
+#define C5_GUID_LENGTH 16
+#define C5_UNSUPPORTED_REQS_LEN 4096
+#define C5_UNSUPPORTED_REQS_OPCODE 0xC5
+#define C5_UNSUPPORTED_REQS_LOG_VERSION 0x1
+#define C5_NUM_UNSUPPORTED_REQ_ENTRIES 253
+
+static __u8 unsupported_req_guid[C5_GUID_LENGTH] = {
+ 0x2F, 0x72, 0x9C, 0x0E,
+ 0x99, 0x23, 0x2C, 0xBB,
+ 0x63, 0x48, 0x32, 0xD0,
+ 0xB7, 0x98, 0xBB, 0xC7
+};
+
+/*
+ * struct unsupported_requirement_log - unsupported requirement list
+ * @unsupported_count: Number of Unsupported Requirement IDs
+ * @rsvd1: Reserved
+ * @unsupported_req_list: Unsupported Requirements lists upto 253.
+ * @rsvd2: Reserved
+ * @log_page_version: indicates the version of the mapping this log page uses.
+ * Shall be set to 0001h
+ * @log_page_guid: Shall be set to C7BB98B7D0324863BB2C23990E9C722Fh.
+ */
+struct __packed unsupported_requirement_log {
+ __le16 unsupported_count;
+ __u8 rsvd1[14];
+ __u8 unsupported_req_list[C5_NUM_UNSUPPORTED_REQ_ENTRIES][16];
+ __u8 rsvd2[14];
+ __le16 log_page_version;
+ __u8 log_page_guid[C5_GUID_LENGTH];
+};
+
+/* Function declaration for unsupported requirement log page (LID:C5h) */
+static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
+
+static int ocp_print_C5_log_normal(struct nvme_dev *dev,
+ struct unsupported_requirement_log *log_data)
+{
+ int j;
+
+ printf("Unsupported Requirement-C5 Log Page Data-\n");
+
+ printf(" Number Unsupported Req IDs : 0x%x\n", le16_to_cpu(log_data->unsupported_count));
+
+ for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++)
+ printf(" Unsupported Requirement List %d : %s\n", j, log_data->unsupported_req_list[j]);
+
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (j = C5_GUID_LENGTH - 1; j >= 0; j--)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+
+ return 0;
+}
+
+static void ocp_print_C5_log_json(struct unsupported_requirement_log *log_data)
+{
+ int j;
+ struct json_object *root;
+ char unsup_req_list_str[40];
+ char guid_buf[C5_GUID_LENGTH];
+ char *guid = guid_buf;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "Number Unsupported Req IDs", le16_to_cpu(log_data->unsupported_count));
+
+ memset((void *)unsup_req_list_str, 0, 40);
+ for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) {
+ sprintf((char *)unsup_req_list_str, "Unsupported Requirement List %d", j);
+ json_object_add_value_string(root, unsup_req_list_str, (char *)log_data->unsupported_req_list[j]);
+ }
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((void *)guid, 0, C5_GUID_LENGTH);
+ for (j = C5_GUID_LENGTH - 1; j >= 0; j--)
+ guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
+ json_object_add_value_string(root, "Log page GUID", guid_buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void ocp_print_c5_log_binary(struct unsupported_requirement_log *log_data)
+{
+ return d_raw((unsigned char *)log_data, sizeof(*log_data));
+}
+
+static int get_c5_log_page(struct nvme_dev *dev, char *format)
+{
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ int i;
+ struct unsupported_requirement_log *log_data;
+ int j;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C5_UNSUPPORTED_REQS_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C5_UNSUPPORTED_REQS_OPCODE,
+ C5_UNSUPPORTED_REQS_LEN, data);
+ if (!ret) {
+ log_data = (struct unsupported_requirement_log *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != C5_UNSUPPORTED_REQS_LOG_VERSION) {
+ fprintf(stderr, "ERROR : OCP : invalid unsupported requirement version\n");
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * check log page guid
+ * Verify GUID matches
+ */
+ for (i = 0; i < 16; i++) {
+ if (unsupported_req_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C5 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", unsupported_req_guid[j]);
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C5_log_normal(dev, log_data);
+ break;
+ case JSON:
+ ocp_print_C5_log_json(log_data);
+ break;
+ case BINARY:
+ ocp_print_c5_log_binary(log_data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C3 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+
+static int ocp_unsupported_requirements_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve unsupported requirements log data.";
+ struct nvme_dev *dev;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c5_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C5 Log Page, ret = %d\n", ret);
+
+ dev_close(dev);
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Error Recovery Log Page(0xC1)
+
+#define C1_ERROR_RECOVERY_LOG_BUF_LEN 0x200
+#define C1_ERROR_RECOVERY_OPCODE 0xC1
+#define C1_ERROR_RECOVERY_VERSION 0x0002
+#define C1_GUID_LENGTH 16
+static __u8 error_recovery_guid[C1_GUID_LENGTH] = {
+ 0x44, 0xd9, 0x31, 0x21,
+ 0xfe, 0x30, 0x34, 0xae,
+ 0xab, 0x4d, 0xfd, 0x3d,
+ 0xba, 0x83, 0x19, 0x5a
+};
+
+/**
+ * struct ocp_error_recovery_log_page - Error Recovery Log Page
+ * @panic_reset_wait_time: Panic Reset Wait Time
+ * @panic_reset_action: Panic Reset Action
+ * @device_recover_action_1: Device Recovery Action 1
+ * @panic_id: Panic ID
+ * @device_capabilities: Device Capabilities
+ * @vendor_specific_recovery_opcode: Vendor Specific Recovery Opcode
+ * @reserved: Reserved
+ * @vendor_specific_command_cdw12: Vendor Specific Command CDW12
+ * @vendor_specific_command_cdw13: Vendor Specific Command CDW13
+ * @vendor_specific_command_timeout: Vendor Specific Command Timeout
+ * @device_recover_action_2: Device Recovery Action 2
+ * @device_recover_action_2_timeout: Device Recovery Action 2 Timeout
+ * @reserved2: Reserved
+ * @log_page_version: Log Page Version
+ * @log_page_guid: Log Page GUID
+ */
+struct __packed ocp_error_recovery_log_page {
+ __le16 panic_reset_wait_time; /* 2 bytes - 0x00 - 0x01 */
+ __u8 panic_reset_action; /* 1 byte - 0x02 */
+ __u8 device_recover_action_1; /* 1 byte - 0x03 */
+ __le64 panic_id; /* 8 bytes - 0x04 - 0x0B */
+ __le32 device_capabilities; /* 4 bytes - 0x0C - 0x0F */
+ __u8 vendor_specific_recovery_opcode; /* 1 byte - 0x10 */
+ __u8 reserved[0x3]; /* 3 bytes - 0x11 - 0x13 */
+ __le32 vendor_specific_command_cdw12; /* 4 bytes - 0x14 - 0x17 */
+ __le32 vendor_specific_command_cdw13; /* 4 bytes - 0x18 - 0x1B */
+ __u8 vendor_specific_command_timeout; /* 1 byte - 0x1C */
+ __u8 device_recover_action_2; /* 1 byte - 0x1D */
+ __u8 device_recover_action_2_timeout; /* 1 byte - 0x1E */
+ __u8 reserved2[0x1cf]; /* 463 bytes - 0x1F - 0x1ED */
+ __le16 log_page_version; /* 2 bytes - 0x1EE - 0x1EF */
+ __u8 log_page_guid[0x10]; /* 16 bytes - 0x1F0 - 0x1FF */
+};
+
+static void ocp_print_c1_log_normal(struct ocp_error_recovery_log_page *log_data);
+static void ocp_print_c1_log_json(struct ocp_error_recovery_log_page *log_data);
+static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data);
+static int get_c1_log_page(struct nvme_dev *dev, char *format);
+static int ocp_error_recovery_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
+
+static void ocp_print_c1_log_normal(struct ocp_error_recovery_log_page *log_data)
+{
+ int i;
+
+ printf(" Error Recovery/C1 Log Page Data\n");
+ printf(" Panic Reset Wait Time : 0x%x\n", le16_to_cpu(log_data->panic_reset_wait_time));
+ printf(" Panic Reset Action : 0x%x\n", log_data->panic_reset_action);
+ printf(" Device Recovery Action 1 : 0x%x\n", log_data->device_recover_action_1);
+ printf(" Panic ID : 0x%x\n", le32_to_cpu(log_data->panic_id));
+ printf(" Device Capabilities : 0x%x\n", le32_to_cpu(log_data->device_capabilities));
+ printf(" Vendor Specific Recovery Opcode : 0x%x\n", log_data->vendor_specific_recovery_opcode);
+ printf(" Vendor Specific Command CDW12 : 0x%x\n", le32_to_cpu(log_data->vendor_specific_command_cdw12));
+ printf(" Vendor Specific Command CDW13 : 0x%x\n", le32_to_cpu(log_data->vendor_specific_command_cdw13));
+ printf(" Vendor Specific Command Timeout : 0x%x\n", log_data->vendor_specific_command_timeout);
+ printf(" Device Recovery Action 2 : 0x%x\n", log_data->device_recover_action_2);
+ printf(" Device Recovery Action 2 Timeout : 0x%x\n", log_data->device_recover_action_2_timeout);
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (i = C1_GUID_LENGTH - 1; i >= 0; i--)
+ printf("%x", log_data->log_page_guid[i]);
+ printf("\n");
+}
+
+static void ocp_print_c1_log_json(struct ocp_error_recovery_log_page *log_data)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ char guid[64];
+
+ json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time));
+ json_object_add_value_int(root, "Panic Reset Action", log_data->panic_reset_action);
+ json_object_add_value_int(root, "Device Recovery Action 1", log_data->device_recover_action_1);
+ json_object_add_value_int(root, "Panic ID", le32_to_cpu(log_data->panic_id));
+ json_object_add_value_int(root, "Device Capabilities", le32_to_cpu(log_data->device_capabilities));
+ json_object_add_value_int(root, "Vendor Specific Recovery Opcode", log_data->vendor_specific_recovery_opcode);
+ json_object_add_value_int(root, "Vendor Specific Command CDW12", le32_to_cpu(log_data->vendor_specific_command_cdw12));
+ json_object_add_value_int(root, "Vendor Specific Command CDW13", le32_to_cpu(log_data->vendor_specific_command_cdw13));
+ json_object_add_value_int(root, "Vendor Specific Command Timeout", log_data->vendor_specific_command_timeout);
+ json_object_add_value_int(root, "Device Recovery Action 2", log_data->device_recover_action_2);
+ json_object_add_value_int(root, "Device Recovery Action 2 Timeout", log_data->device_recover_action_2_timeout);
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((void *)guid, 0, 64);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void ocp_print_c1_log_binary(struct ocp_error_recovery_log_page *log_data)
+{
+ return d_raw((unsigned char *)log_data, sizeof(*log_data));
+}
+
+static int get_c1_log_page(struct nvme_dev *dev, char *format)
+{
+ struct ocp_error_recovery_log_page *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ int i, j;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C1_ERROR_RECOVERY_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C1_ERROR_RECOVERY_OPCODE, C1_ERROR_RECOVERY_LOG_BUF_LEN, data);
+
+ if (!ret) {
+ log_data = (struct ocp_error_recovery_log_page *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != C1_ERROR_RECOVERY_VERSION) {
+ fprintf(stderr, "ERROR : OCP : invalid error recovery log page version\n");
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * check log page guid
+ * Verify GUID matches
+ */
+ for (i = 0; i < 16; i++) {
+ if (error_recovery_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C1 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", error_recovery_guid[j]);
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_c1_log_normal(log_data);
+ break;
+ case JSON:
+ ocp_print_c1_log_json(log_data);
+ break;
+ case BINARY:
+ ocp_print_c1_log_binary(log_data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C1 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int ocp_error_recovery_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve C1h Error Recovery Log data.";
+ struct nvme_dev *dev;
+ int ret = 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|binary"),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c1_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C1h Log Page, ret = %d\n", ret);
+ dev_close(dev);
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Device Capabilities (Log Identifier C4h) Requirements
+
+#define C4_DEV_CAP_REQ_LEN 0x1000
+#define C4_DEV_CAP_REQ_OPCODE 0xC4
+#define C4_DEV_CAP_REQ_VERSION 0x0001
+#define C4_GUID_LENGTH 16
+static __u8 dev_cap_req_guid[C4_GUID_LENGTH] = {
+ 0x97, 0x42, 0x05, 0x0d,
+ 0xd1, 0xe1, 0xc9, 0x98,
+ 0x5d, 0x49, 0x58, 0x4b,
+ 0x91, 0x3c, 0x05, 0xb7
+};
+
+/**
+ * struct ocp_device_capabilities_log_page - Device Capability Log page
+ * @pcie_exp_port: PCI Express Ports
+ * @oob_management_support: OOB Management Support
+ * @wz_cmd_support: Write Zeroes Command Support
+ * @sanitize_cmd_support: Sanitize Command Support
+ * @dsm_cmd_support: Dataset Management Command Support
+ * @wu_cmd_support: Write Uncorrectable Command Support
+ * @fused_operation_support: Fused Operation Support
+ * @min_valid_dssd_pwr_state: Minimum Valid DSSD Power State
+ * @dssd_pwr_state_desc: DSSD Power State Descriptors
+ * @vendor_specific_command_timeout: Vendor Specific Command Timeout
+ * @reserved: Reserved
+ * @log_page_version: Log Page Version
+ * @log_page_guid: Log Page GUID
+ */
+struct __packed ocp_device_capabilities_log_page {
+ __le16 pcie_exp_port;
+ __le16 oob_management_support;
+ __le16 wz_cmd_support;
+ __le16 sanitize_cmd_support;
+ __le16 dsm_cmd_support;
+ __le16 wu_cmd_support;
+ __le16 fused_operation_support;
+ __le16 min_valid_dssd_pwr_state;
+ __u8 dssd_pwr_state_desc[128];
+ __u8 reserved[3934];
+ __le16 log_page_version;
+ __u8 log_page_guid[16];
+};
+
+static void ocp_print_c4_log_normal(struct ocp_device_capabilities_log_page *log_data);
+static void ocp_print_c4_log_json(struct ocp_device_capabilities_log_page *log_data);
+static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log_data);
+static int get_c4_log_page(struct nvme_dev *dev, char *format);
+static int ocp_device_capabilities_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
+
+static void ocp_print_c4_log_normal(struct ocp_device_capabilities_log_page *log_data)
+{
+ int i;
+
+ printf(" Device Capability/C4 Log Page Data\n");
+ printf(" PCI Express Ports : 0x%x\n", le16_to_cpu(log_data->pcie_exp_port));
+ printf(" OOB Management Support : 0x%x\n", le16_to_cpu(log_data->oob_management_support));
+ printf(" Write Zeroes Command Support : 0x%x\n", le16_to_cpu(log_data->wz_cmd_support));
+ printf(" Sanitize Command Support : 0x%x\n", le16_to_cpu(log_data->sanitize_cmd_support));
+ printf(" Dataset Management Command Support : 0x%x\n", le16_to_cpu(log_data->dsm_cmd_support));
+ printf(" Write Uncorrectable Command Support : 0x%x\n", le16_to_cpu(log_data->wu_cmd_support));
+ printf(" Fused Operation Support : 0x%x\n", le16_to_cpu(log_data->fused_operation_support));
+ printf(" Minimum Valid DSSD Power State : 0x%x\n", le16_to_cpu(log_data->min_valid_dssd_pwr_state));
+ printf(" DSSD Power State Descriptors : 0x");
+ for (i = 0; i <= 127; i++)
+ printf("%x", log_data->dssd_pwr_state_desc[i]);
+ printf("\n");
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (i = C4_GUID_LENGTH - 1; i >= 0; i--)
+ printf("%x", log_data->log_page_guid[i]);
+ printf("\n");
+}
+
+static void ocp_print_c4_log_json(struct ocp_device_capabilities_log_page *log_data)
+{
+ struct json_object *root = json_create_object();
+ char guid[64];
+ int i;
+
+ json_object_add_value_int(root, "PCI Express Ports", le16_to_cpu(log_data->pcie_exp_port));
+ json_object_add_value_int(root, "OOB Management Support", le16_to_cpu(log_data->oob_management_support));
+ json_object_add_value_int(root, "Write Zeroes Command Support", le16_to_cpu(log_data->wz_cmd_support));
+ json_object_add_value_int(root, "Sanitize Command Support", le16_to_cpu(log_data->sanitize_cmd_support));
+ json_object_add_value_int(root, "Dataset Management Command Support", le16_to_cpu(log_data->dsm_cmd_support));
+ json_object_add_value_int(root, "Write Uncorrectable Command Support", le16_to_cpu(log_data->wu_cmd_support));
+ json_object_add_value_int(root, "Fused Operation Support", le16_to_cpu(log_data->fused_operation_support));
+ json_object_add_value_int(root, "Minimum Valid DSSD Power State", le16_to_cpu(log_data->min_valid_dssd_pwr_state));
+ for (i = 0; i <= 127; i++)
+ json_object_add_value_int(root, "DSSD Power State Descriptors", log_data->dssd_pwr_state_desc[i]);
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((void *)guid, 0, 64);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void ocp_print_c4_log_binary(struct ocp_device_capabilities_log_page *log_data)
+{
+ return d_raw((unsigned char *)log_data, sizeof(*log_data));
+}
+
+static int get_c4_log_page(struct nvme_dev *dev, char *format)
+{
+ struct ocp_device_capabilities_log_page *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ int i, j;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * C4_DEV_CAP_REQ_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C4_DEV_CAP_REQ_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C4_DEV_CAP_REQ_OPCODE, C4_DEV_CAP_REQ_LEN, data);
+
+ if (!ret) {
+ log_data = (struct ocp_device_capabilities_log_page *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != C4_DEV_CAP_REQ_VERSION) {
+ fprintf(stderr, "ERROR : OCP : invalid device capabilities log page version\n");
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * check log page guid
+ * Verify GUID matches
+ */
+ for (i = 0; i < 16; i++) {
+ if (dev_cap_req_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C4 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", dev_cap_req_guid[j]);
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_c4_log_normal(log_data);
+ break;
+ case JSON:
+ ocp_print_c4_log_json(log_data);
+ break;
+ case BINARY:
+ ocp_print_c4_log_binary(log_data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C4 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int ocp_device_capabilities_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve C4h Device Capabilities Log data.";
+ struct nvme_dev *dev;
+ int ret = 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|binary"),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c4_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C4h Log Page, ret = %d\n", ret);
+ dev_close(dev);
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// DSSD Power State (Feature Identifier C7h) Set Feature
+
+static int set_dssd_power_state(struct nvme_dev *dev, const __u32 nsid,
+ const __u8 fid, __u8 power_state, bool save,
+ bool uuid)
+{
+ __u32 result;
+ int err;
+ int uuid_index = 0;
+
+ if (uuid) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ nvme_show_error("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = power_state,
+ .cdw12 = 0,
+ .save = save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define DSSD Power State");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set DSSD Power State (feature: 0xC7) to below values\n");
+ printf("DSSD Power State: 0x%x\n", power_state);
+ printf("Save bit Value: 0x%x\n", save);
+ }
+
+ return err;
+}
+
+static int set_dssd_power_state_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Define DSSD Power State (Feature Identifier C7h) Set Feature.";
+ const char *power_state = "DSSD Power State to set in watts";
+ const char *save = "Specifies that the controller shall save the attribute";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xC7;
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u8 power_state;
+ bool save;
+ };
+
+ struct config cfg = {
+ .power_state = 0,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("power-state", 'p', &cfg.power_state, power_state),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (argconfig_parse_seen(opts, "power state"))
+ err = set_dssd_power_state(dev, nsid, fid, cfg.power_state,
+ cfg.save,
+ !argconfig_parse_seen(opts, "no-uuid"));
+
+ dev_close(dev);
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// plp_health_check_interval
+
+static int set_plp_health_check_interval(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ const char *desc = "Define Issue Set Feature command (FID : 0xC6) PLP Health Check Interval";
+ const char *plp_health_interval = "[31:16]:PLP Health Check Interval";
+ const char *save = "Specifies that the controller shall save the attribute";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc6;
+ struct nvme_dev *dev;
+ int err;
+ __u32 result;
+ int uuid_index = 0;
+
+ struct config {
+ __le16 plp_health_interval;
+ bool save;
+ };
+
+ struct config cfg = {
+ .plp_health_interval = 0,
+ .save = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("plp_health_interval", 'p', &cfg.plp_health_interval, plp_health_interval),
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_FLAG("no-uuid", 'n', NULL,
+ "Skip UUID index search (UUID index not required for OCP 1.0)"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ if (!argconfig_parse_seen(opts, "no-uuid")) {
+ /* OCP 2.0 requires UUID index support */
+ err = ocp_get_uuid_index(dev, &uuid_index);
+ if (err || !uuid_index) {
+ printf("ERROR: No OCP UUID index found");
+ return err;
+ }
+ }
+
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .cdw11 = cfg.plp_health_interval << 16,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = uuid_index,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ nvme_show_perror("Define PLP Health Check Interval");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set the PLP Health Check Interval");
+ printf("PLP Health Check Interval: 0x%x\n", cfg.plp_health_interval);
+ printf("Save bit Value: 0x%x\n", cfg.save);
+ }
+ return err;
+}
+
+static int get_plp_health_check_interval(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ const char *desc = "Define Issue Get Feature command (FID : 0xC6) PLP Health Check Interval";
+ const char *sel = "[0-3,8]: current/default/saved/supported/changed";
+ const __u32 nsid = 0;
+ const __u8 fid = 0xc6;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u8 sel;
+ };
+
+ struct config cfg = {
+ .sel = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("sel", 'S', &cfg.sel, sel),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = fid,
+ .nsid = nsid,
+ .sel = cfg.sel,
+ .cdw11 = 0,
+ .uuidx = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_get_features(&args);
+ if (!err) {
+ printf("get-feature:0xC6 %s value: %#08x\n", nvme_select_to_string(cfg.sel), result);
+
+ if (cfg.sel == NVME_GET_FEATURES_SEL_SUPPORTED)
+ nvme_show_select_result(fid, result);
+ } else {
+ nvme_show_error("Could not get feature: 0xC6");
+ }
+
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Telemetry String Log Format Log Page (LID : C9h)
+
+/* C9 Telemetry String Log Format Log Page */
+#define C9_GUID_LENGTH 16
+#define C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE 0xC9
+#define C9_TELEMETRY_STR_LOG_LEN 432
+#define C9_TELEMETRY_STR_LOG_SIST_OFST 431
+
+/**
+ * struct telemetry_str_log_format - Telemetry String Log Format
+ * @log_page_version: indicates the version of the mapping this log page uses
+ * Shall be set to 01h.
+ * @reserved1: Reserved.
+ * @log_page_guid: Shall be set to B13A83691A8F408B9EA495940057AA44h.
+ * @sls: Shall be set to the number of DWORDS in the String Log.
+ * @reserved2: reserved.
+ * @sits: shall be set to the number of DWORDS in the Statistics
+ * Identifier String Table
+ * @ests: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the Event String Table
+ * @estsz: shall be set to the number of DWORDS in the Event String Table
+ * @vu_eve_sts: Shall be set to the number of DWORDS from byte 0 of this
+ * log page to the start of the VU Event String Table
+ * @vu_eve_st_sz: shall be set to the number of DWORDS in the VU Event String Table
+ * @ascts: the number of DWORDS from byte 0 of this log page until the ASCII Table Starts.
+ * @asctsz: the number of DWORDS in the ASCII Table
+ * @fifo1: FIFO 0 ASCII String
+ * @fifo2: FIFO 1 ASCII String
+ * @fifo3: FIFO 2 ASCII String
+ * @fifo4: FIFO 3 ASCII String
+ * @fif05: FIFO 4 ASCII String
+ * @fifo6: FIFO 5 ASCII String
+ * @fifo7: FIFO 6 ASCII String
+ * @fifo8: FIFO 7 ASCII String
+ * @fifo9: FIFO 8 ASCII String
+ * @fifo10: FIFO 9 ASCII String
+ * @fif011: FIFO 10 ASCII String
+ * @fif012: FIFO 11 ASCII String
+ * @fifo13: FIFO 12 ASCII String
+ * @fif014: FIFO 13 ASCII String
+ * @fif015: FIFO 14 ASCII String
+ * @fif016: FIFO 15 ASCII String
+ * @reserved3: reserved
+ */
+struct __attribute__((__packed__)) telemetry_str_log_format {
+ __u8 log_page_version;
+ __u8 reserved1[15];
+ __u8 log_page_guid[C9_GUID_LENGTH];
+ __le64 sls;
+ __u8 reserved2[24];
+ __le64 sits;
+ __le64 sitsz;
+ __le64 ests;
+ __le64 estsz;
+ __le64 vu_eve_sts;
+ __le64 vu_eve_st_sz;
+ __le64 ascts;
+ __le64 asctsz;
+ __u8 fifo1[16];
+ __u8 fifo2[16];
+ __u8 fifo3[16];
+ __u8 fifo4[16];
+ __u8 fifo5[16];
+ __u8 fifo6[16];
+ __u8 fifo7[16];
+ __u8 fifo8[16];
+ __u8 fifo9[16];
+ __u8 fifo10[16];
+ __u8 fifo11[16];
+ __u8 fifo12[16];
+ __u8 fifo13[16];
+ __u8 fifo14[16];
+ __u8 fifo15[16];
+ __u8 fifo16[16];
+ __u8 reserved3[48];
+};
+
+/*
+ * struct statistics_id_str_table_entry - Statistics Identifier String Table Entry
+ * @vs_si: Shall be set the Vendor Unique Statistic Identifier number.
+ * @reserved1: Reserved
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: Shall be set to the offset from DWORD 0/Byte 0 of the Start
+ * of the ASCII Table to the first character of the string for
+ * this Statistic Identifier string..
+ * @reserved2 reserved
+ */
+struct __attribute__((__packed__)) statistics_id_str_table_entry {
+ __le16 vs_si;
+ __u8 reserved1;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct event_id_str_table_entry - Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @ei: Shall be set to the Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved2 reserved
+ */
+struct __attribute__((__packed__)) event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved2;
+};
+
+/*
+ * struct vu_event_id_str_table_entry - VU Event Identifier String Table Entry
+ * @deb_eve_class: Shall be set the Debug Class.
+ * @vu_ei: Shall be set to the VU Event Identifier
+ * @ascii_id_len: Shall be set the number of ASCII Characters that are valid.
+ * @ascii_id_ofst: This is the offset from DWORD 0/ Byte 0 of the start of the
+ * ASCII table to the ASCII data for this identifier
+ * @reserved reserved
+ */
+struct __attribute__((__packed__)) vu_event_id_str_table_entry {
+ __u8 deb_eve_class;
+ __le16 vu_ei;
+ __u8 ascii_id_len;
+ __le64 ascii_id_ofst;
+ __le32 reserved;
+};
+
+/* Function declaration for Telemetry String Log Format (LID:C9h) */
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
+
+
+static int ocp_print_C9_log_normal(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
+{
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ __u8 ascii_table_info_arr[ascii_table_index];
+ int j;
+
+ printf(" Log Page Version : 0x%x\n", log_data->log_page_version);
+
+ printf(" Reserved : ");
+ for (j = 0; j < 15; j++)
+ printf("%d", log_data->reserved1[j]);
+ printf("\n");
+
+ printf(" Log page GUID : 0x");
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+
+ printf(" Telemetry String Log Size : 0x%lx\n", le64_to_cpu(log_data->sls));
+
+ printf(" Reserved : ");
+ for (j = 0; j < 24; j++)
+ printf("%d", log_data->reserved2[j]);
+ printf("\n");
+
+ printf(" Statistics Identifier String Table Start : 0x%lx\n", le64_to_cpu(log_data->sits));
+ printf(" Statistics Identifier String Table Size : 0x%lx\n", le64_to_cpu(log_data->sitsz));
+ printf(" Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->ests));
+ printf(" Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->estsz));
+ printf(" VU Event String Table Start : 0x%lx\n", le64_to_cpu(log_data->vu_eve_sts));
+ printf(" VU Event String Table Size : 0x%lx\n", le64_to_cpu(log_data->vu_eve_st_sz));
+ printf(" ASCII Table Start : 0x%lx\n", le64_to_cpu(log_data->ascts));
+ printf(" ASCII Table Size : 0x%lx\n", le64_to_cpu(log_data->asctsz));
+
+ printf(" FIFO 1 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo1[j], log_data->fifo1[j]);
+ }
+
+ printf(" FIFO 2 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo2[j], log_data->fifo2[j]);
+ }
+
+ printf(" FIFO 3 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo3[j], log_data->fifo3[j]);
+ }
+
+ printf(" FIFO 4 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+
+ printf(" %d %d %c \n", j, log_data->fifo4[j], log_data->fifo4[j]);
+ }
+
+ printf(" FIFO 5 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo5[j], log_data->fifo5[j]);
+ }
+
+ printf(" FIFO 6 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo6[j], log_data->fifo6[j]);
+ }
+
+ printf(" FIFO 7 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo7[j], log_data->fifo7[j]);
+ }
+
+ printf(" FIFO 8 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf("index value ascii_val");
+ printf(" %d %d %c \n", j, log_data->fifo8[j], log_data->fifo8[j]);
+ }
+
+ printf(" FIFO 9 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo9[j], log_data->fifo9[j]);
+ }
+
+ printf(" FIFO 10 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo10[j], log_data->fifo10[j]);
+ }
+
+ printf(" FIFO 11 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo11[j], log_data->fifo11[j]);
+ }
+
+ printf(" FIFO 12 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo12[j], log_data->fifo12[j]);
+ }
+
+ printf(" FIFO 13 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo13[j], log_data->fifo13[j]);
+ }
+
+ printf(" FIFO 14 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo14[j], log_data->fifo14[j]);
+ }
+
+ printf(" FIFO 15 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo15[j], log_data->fifo16[j]);
+ }
+
+ printf(" FIFO 16 ASCII String\n");
+ printf(" index value ascii_val\n");
+ for (j = 0; j < 16; j++){
+ printf(" %d %d %c \n", j, log_data->fifo16[j], log_data->fifo16[j]);
+ }
+
+ printf(" Reserved : ");
+ for (j = 0; j < 48; j++)
+ printf("%d", log_data->reserved3[j]);
+ printf("\n");
+
+ memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
+ memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
+ memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
+ memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
+
+ printf(" Statistics Identifier String Table\n");
+ for (j = 0; j < stat_id_index; j++){
+ printf(" Vendor Specific Statistic Identifier : 0x%x\n",le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ printf(" Reserved : 0x%d",stat_id_str_table_arr[j].reserved1);
+ printf(" ASCII ID Length : 0x%x\n",stat_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",stat_id_str_table_arr[j].reserved2);
+ }
+
+ printf(" Event Identifier String Table Entry\n");
+ for (j = 0; j < eve_id_index; j++){
+ printf(" Debug Event Class : 0x%x\n",event_id_str_table_arr[j].deb_eve_class);
+ printf(" Event Identifier : 0x%x\n",le16_to_cpu(event_id_str_table_arr[j].ei));
+ printf(" ASCII ID Length : 0x%x\n",event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",event_id_str_table_arr[j].reserved2);
+
+ }
+
+ printf(" VU Event Identifier String Table Entry\n");
+ for (j = 0; j < vu_eve_index; j++){
+ printf(" Debug Event Class : 0x%x\n",vu_event_id_str_table_arr[j].deb_eve_class);
+ printf(" VU Event Identifier : 0x%x\n",le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ printf(" ASCII ID Length : 0x%x\n",vu_event_id_str_table_arr[j].ascii_id_len);
+ printf(" ASCII ID offset : 0x%lx\n",le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ printf(" Reserved : 0x%d\n",vu_event_id_str_table_arr[j].reserved);
+
+ }
+
+ printf(" ASCII Table\n");
+ printf(" Byte Data_Byte ASCII_Character\n");
+ for (j = 0; j < ascii_table_index; j++){
+ printf(" %lld 0x%x %c \n",ascii_table_ofst+j,ascii_table_info_arr[j],ascii_table_info_arr[j]);
+ }
+ return 0;
+}
+
+static int ocp_print_C9_log_json(struct telemetry_str_log_format *log_data,__u8 *log_data_buf)
+{
+ struct json_object *root = json_create_object();
+ struct json_object *stat_table = json_create_object();
+ struct json_object *eve_table = json_create_object();
+ struct json_object *vu_eve_table = json_create_object();
+ struct json_object *entry = json_create_object();
+ char res_arr[48];
+ char *res = res_arr;
+ char guid_buf[C9_GUID_LENGTH];
+ char *guid = guid_buf;
+ char fifo_arr[16];
+ char *fifo = fifo_arr;
+ //calculating the index value for array
+ __le64 stat_id_index = (log_data->sitsz * 4) / 16;
+ __le64 eve_id_index = (log_data->estsz * 4) / 16;
+ __le64 vu_eve_index = (log_data->vu_eve_st_sz * 4) / 16;
+ __le64 ascii_table_index = (log_data->asctsz * 4);
+ //Calculating the offset for dynamic fields.
+ __le64 stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ __le64 event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ __le64 vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ __le64 ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ struct statistics_id_str_table_entry stat_id_str_table_arr[stat_id_index];
+ struct event_id_str_table_entry event_id_str_table_arr[eve_id_index];
+ struct vu_event_id_str_table_entry vu_event_id_str_table_arr[vu_eve_index];
+ __u8 ascii_table_info_arr[ascii_table_index];
+ char ascii_buf[ascii_table_index];
+ char *ascii = ascii_buf;
+ int j;
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ memset((__u8 *)res, 0, 15);
+ for (j = 0; j < 15; j++)
+ res += sprintf(res, "%d", log_data->reserved1[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ memset((void *)guid, 0, C9_GUID_LENGTH);
+ for (j = C9_GUID_LENGTH - 1; j >= 0; j--)
+ guid += sprintf(guid, "%02x", log_data->log_page_guid[j]);
+ json_object_add_value_string(root, "Log page GUID", guid_buf);
+
+ json_object_add_value_int(root, "Telemetry String Log Size", le64_to_cpu(log_data->sls));
+
+ memset((__u8 *)res, 0, 24);
+ for (j = 0; j < 24; j++)
+ res += sprintf(res, "%d", log_data->reserved2[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ json_object_add_value_int(root, "Statistics Identifier String Table Start", le64_to_cpu(log_data->sits));
+ json_object_add_value_int(root, "Event String Table Start", le64_to_cpu(log_data->ests));
+ json_object_add_value_int(root, "Event String Table Size", le64_to_cpu(log_data->estsz));
+ json_object_add_value_int(root, "VU Event String Table Start", le64_to_cpu(log_data->vu_eve_sts));
+ json_object_add_value_int(root, "VU Event String Table Size", le64_to_cpu(log_data->vu_eve_st_sz));
+ json_object_add_value_int(root, "ASCII Table Start", le64_to_cpu(log_data->ascts));
+ json_object_add_value_int(root, "ASCII Table Size", le64_to_cpu(log_data->asctsz));
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo1[j]);
+ json_object_add_value_string(root, "FIFO 1 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo2[j]);
+ json_object_add_value_string(root, "FIFO 2 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo3[j]);
+ json_object_add_value_string(root, "FIFO 3 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo4[j]);
+ json_object_add_value_string(root, "FIFO 4 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo5[j]);
+ json_object_add_value_string(root, "FIFO 5 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo6[j]);
+ json_object_add_value_string(root, "FIFO 6 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo7[j]);
+ json_object_add_value_string(root, "FIFO 7 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo8[j]);
+ json_object_add_value_string(root, "FIFO 8 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo9[j]);
+ json_object_add_value_string(root, "FIFO 9 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo10[j]);
+ json_object_add_value_string(root, "FIFO 10 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo11[j]);
+ json_object_add_value_string(root, "FIFO 11 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo12[j]);
+ json_object_add_value_string(root, "FIFO 12 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo13[j]);
+ json_object_add_value_string(root, "FIFO 13 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo14[j]);
+ json_object_add_value_string(root, "FIFO 14 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo15[j]);
+ json_object_add_value_string(root, "FIFO 15 ASCII String", fifo_arr);
+
+ memset((void *)fifo, 0, 16);
+ for (j = 0; j < 16; j++)
+ fifo += sprintf(fifo, "%c", log_data->fifo16[j]);
+ json_object_add_value_string(root, "FIFO 16 ASCII String", fifo_arr);
+
+ memset((__u8 *)res, 0, 48);
+ for (j = 0; j < 48; j++)
+ res += sprintf(res, "%d", log_data->reserved3[j]);
+ json_object_add_value_string(root, "Reserved", res_arr);
+
+ memcpy(stat_id_str_table_arr, (__u8*)log_data_buf + stat_id_str_table_ofst, (log_data->sitsz * 4));
+ memcpy(event_id_str_table_arr, (__u8*)log_data_buf + event_str_table_ofst, (log_data->estsz * 4));
+ memcpy(vu_event_id_str_table_arr, (__u8*)log_data_buf + vu_event_str_table_ofst, (log_data->vu_eve_st_sz * 4));
+ memcpy(ascii_table_info_arr, (__u8*)log_data_buf + ascii_table_ofst, (log_data->asctsz * 4));
+
+ for (j = 0; j < stat_id_index; j++){
+ json_object_add_value_int(entry, "Vendor Specific Statistic Identifier", le16_to_cpu(stat_id_str_table_arr[j].vs_si));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved1));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(stat_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(stat_id_str_table_arr[j].reserved2));
+ json_array_add_value_object(stat_table, entry);
+ }
+ json_object_add_value_array(root, "Statistics Identifier String Table", stat_table);
+
+ for (j = 0; j < eve_id_index; j++){
+ json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "Event Identifier", le16_to_cpu(event_id_str_table_arr[j].ei));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(event_id_str_table_arr[j].reserved2));
+ json_array_add_value_object(eve_table, entry);
+ }
+ json_object_add_value_array(root, "Event Identifier String Table Entry", eve_table);
+
+ for (j = 0; j < vu_eve_index; j++){
+ json_object_add_value_int(entry, "Debug Event Class", le16_to_cpu(vu_event_id_str_table_arr[j].deb_eve_class));
+ json_object_add_value_int(entry, "VU Event Identifier", le16_to_cpu(vu_event_id_str_table_arr[j].vu_ei));
+ json_object_add_value_int(entry, "ASCII ID Length", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_len));
+ json_object_add_value_int(entry, "ASCII ID offset", le64_to_cpu(vu_event_id_str_table_arr[j].ascii_id_ofst));
+ json_object_add_value_int(entry, "Reserved", le64_to_cpu(vu_event_id_str_table_arr[j].reserved));
+ json_array_add_value_object(vu_eve_table, entry);
+ }
+ json_object_add_value_array(root, "VU Event Identifier String Table Entry", vu_eve_table);
+
+ memset((void *)ascii, 0, ascii_table_index);
+ for (j = 0; j < ascii_table_index; j++)
+ ascii += sprintf(ascii, "%c", ascii_table_info_arr[j]);
+ json_object_add_value_string(root, "ASCII Table", ascii_buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ json_free_object(stat_table);
+ json_free_object(eve_table);
+ json_free_object(vu_eve_table);
+
+ return 0;
+}
+
+static void ocp_print_c9_log_binary(__u8 *log_data_buf,int total_log_page_size)
+{
+ return d_raw((unsigned char *)log_data_buf, total_log_page_size);
+}
+
+static int get_c9_log_page(struct nvme_dev *dev, char *format)
+{
+ int ret = 0;
+ __u8 *header_data;
+ struct telemetry_str_log_format *log_data;
+ enum nvme_print_flags fmt;
+ __u8 *full_log_buf_data = NULL;
+ __le64 stat_id_str_table_ofst = 0;
+ __le64 event_str_table_ofst = 0;
+ __le64 vu_event_str_table_ofst = 0;
+ __le64 ascii_table_ofst = 0;
+ __le64 total_log_page_sz = 0;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ header_data = (__u8 *)malloc(sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
+ if (!header_data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(header_data, 0, sizeof(__u8) * C9_TELEMETRY_STR_LOG_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
+ C9_TELEMETRY_STR_LOG_LEN, header_data);
+
+ if (!ret) {
+ log_data = (struct telemetry_str_log_format *)header_data;
+ printf("Statistics Identifier String Table Size = %lld\n",log_data->sitsz);
+ printf("Event String Table Size = %lld\n",log_data->estsz);
+ printf("VU Event String Table Size = %lld\n",log_data->vu_eve_st_sz);
+ printf("ASCII Table Size = %lld\n",log_data->asctsz);
+
+ //Calculating the offset for dynamic fields.
+ stat_id_str_table_ofst = C9_TELEMETRY_STR_LOG_SIST_OFST + (log_data->sitsz * 4);
+ event_str_table_ofst = stat_id_str_table_ofst + (log_data->estsz * 4);
+ vu_event_str_table_ofst = event_str_table_ofst + (log_data->vu_eve_st_sz * 4);
+ ascii_table_ofst = vu_event_str_table_ofst + (log_data->asctsz * 4);
+ total_log_page_sz = stat_id_str_table_ofst + event_str_table_ofst + vu_event_str_table_ofst + ascii_table_ofst;
+
+ printf("stat_id_str_table_ofst = %lld\n",stat_id_str_table_ofst);
+ printf("event_str_table_ofst = %lld\n",event_str_table_ofst);
+ printf("vu_event_str_table_ofst = %lld\n",vu_event_str_table_ofst);
+ printf("ascii_table_ofst = %lld\n",ascii_table_ofst);
+ printf("total_log_page_sz = %lld\n",total_log_page_sz);
+
+ full_log_buf_data = (__u8 *)malloc(sizeof(__u8) * total_log_page_sz);
+ if (!full_log_buf_data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(full_log_buf_data, 0, sizeof(__u8) * total_log_page_sz);
+
+ ret = nvme_get_log_simple(dev_fd(dev), C9_TELEMETRY_STRING_LOG_ENABLE_OPCODE,
+ total_log_page_sz, full_log_buf_data);
+
+ if (!ret) {
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C9_log_normal(log_data,full_log_buf_data);
+ break;
+ case JSON:
+ ocp_print_C9_log_json(log_data,full_log_buf_data);
+ break;
+ case BINARY:
+ ocp_print_c9_log_binary(full_log_buf_data,total_log_page_sz);
+ break;
+ default:
+ fprintf(stderr, "unhandled output format\n");
+ break;
+ }
+ } else{
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C9 data from buffer\n");
+ }
+
+ free(header_data);
+ free(full_log_buf_data);
+
+ return ret;
+}
+
+static int ocp_telemetry_str_log_format(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ struct nvme_dev *dev;
+ int ret = 0;
+ const char *desc = "Retrieve telemetry string log format";
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c9_log_page(dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C9 Log Page, ret = %d\n", ret);
+
+ dev_close(dev);
+
+ return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+/// Misc
+
+static int clear_fw_update_history(int argc, char **argv,
+ struct command *cmd, struct plugin *plugin)
+{
+ return ocp_clear_fw_update_history(argc, argv, cmd, plugin);
+}
+
+static int smart_add_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_smart_add_log(argc, argv, cmd, plugin);
+}
+
+static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_clear_pcie_correctable_errors(argc, argv, cmd, plugin);
+}
+
+static int fw_activation_history_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_fw_activation_history_log(argc, argv, cmd, plugin);
+}
diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h
new file mode 100644
index 0000000..95539b0
--- /dev/null
+++ b/plugins/ocp/ocp-nvme.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (c) 2022 Meta Platforms, Inc.
+ *
+ * Authors: Arthur Shau <arthurshau@fb.com>,
+ * Wei Zhang <wzhang@fb.com>,
+ * Venkat Ramesh <venkatraghavan@fb.com>
+ */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/ocp/ocp-nvme
+
+#if !defined(OCP_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define OCP_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("ocp", "OCP cloud SSD extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-add-log", "Retrieve extended SMART Information", smart_add_log)
+ ENTRY("latency-monitor-log", "Get Latency Monitor Log Page", ocp_latency_monitor_log)
+ ENTRY("set-latency-monitor-feature", "Set Latency Monitor feature", ocp_set_latency_monitor_feature)
+ ENTRY("internal-log", "Retrieve and save internal device telemetry log", ocp_telemetry_log)
+ ENTRY("clear-fw-activate-history", "Clear firmware update history log", clear_fw_update_history)
+ ENTRY("eol-plp-failure-mode", "Define EOL or PLP circuitry failure mode.", eol_plp_failure_mode)
+ ENTRY("clear-pcie-correctable-errors", "Clear PCIe correctable error counters", clear_pcie_correctable_error_counters)
+ ENTRY("fw-activate-history", "Get firmware activation history log", fw_activation_history_log)
+ ENTRY("unsupported-reqs-log", "Get Unsupported Requirements Log Page", ocp_unsupported_requirements_log)
+ ENTRY("error-recovery-log", "Retrieve Error Recovery Log Page", ocp_error_recovery_log)
+ ENTRY("device-capability-log", "Get Device capabilities Requirements Log Page", ocp_device_capabilities_log)
+ ENTRY("set-dssd-power-state-feature", "Get Device capabilities Requirements Log Page", set_dssd_power_state_feature)
+ ENTRY("set-plp-health-check-interval", "Set PLP Health Check Interval", set_plp_health_check_interval)
+ ENTRY("get-plp-health-check-interval", "Get PLP Health Check Interval", get_plp_health_check_interval)
+ ENTRY("telemetry-string-log", "Retrieve Telemetry string Log Page", ocp_telemetry_str_log_format)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/ocp/ocp-smart-extended-log.c b/plugins/ocp/ocp-smart-extended-log.c
new file mode 100644
index 0000000..0d8ba81
--- /dev/null
+++ b/plugins/ocp/ocp-smart-extended-log.c
@@ -0,0 +1,352 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Copyright (c) 2022 Meta Platforms, Inc.
+ *
+ * Authors: Arthur Shau <arthurshau@fb.com>,
+ * Wei Zhang <wzhang@fb.com>,
+ * Venkat Ramesh <venkatraghavan@fb.com>
+ */
+
+#include "ocp-smart-extended-log.h"
+
+#include <errno.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "nvme-print.h"
+
+/* C0 SCAO Log Page */
+#define C0_SMART_CLOUD_ATTR_LEN 0x200
+#define C0_SMART_CLOUD_ATTR_OPCODE 0xC0
+#define C0_GUID_LENGTH 16
+
+static __u8 scao_guid[C0_GUID_LENGTH] = {
+ 0xC5, 0xAF, 0x10, 0x28,
+ 0xEA, 0xBF, 0xF2, 0xA4,
+ 0x9C, 0x4F, 0x6F, 0x7C,
+ 0xC9, 0x14, 0xD5, 0xAF
+};
+
+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_EEDC = 72, /* End to end detected errors */
+ SCAO_EECE = 76, /* End to end corrected 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_PSCC = 200, /* Power State Change Count */
+ SCAO_LPV = 494, /* Log page version */
+ SCAO_LPG = 496, /* Log page GUID */
+};
+
+static void ocp_print_C0_log_normal(void *data)
+{
+ uint16_t smart_log_ver = 0;
+ __u8 *log_data = data;
+
+ printf("SMART Cloud Attributes :-\n");
+
+ printf(" Physical media units written - %"PRIu64" %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
+ printf(" Physical media units read - %"PRIu64" %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
+ 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 detected errors %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
+ printf(" End to end corrected errors %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EECE]));
+ 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 %s\n",
+ uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC])));
+ printf(" Endurance estimate %s\n",
+ uint128_t_to_string(le128_to_cpu(&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("%"PRIx64"%"PRIx64"\n", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
+ if (smart_log_ver > 2) {
+ printf(" Errata Version Field %d\n",
+ (__u8)log_data[SCAO_EVF]);
+ printf(" Point Version Field %"PRIu16"\n",
+ le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF]));
+ printf(" Minor Version Field %"PRIu16"\n",
+ le16_to_cpu(*(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(" Power State Change Count %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
+ printf("\n");
+}
+
+static void ocp_print_C0_log_json(void *data)
+{
+ struct json_object *root;
+ struct json_object *pmuw;
+ struct json_object *pmur;
+ uint16_t smart_log_ver = 0;
+ __u8 *log_data = data;
+ char guid[40];
+
+ root = json_create_object();
+ pmuw = json_create_object();
+ pmur = json_create_object();
+
+ json_object_add_value_uint64(pmuw, "hi",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW + 8] & 0xFFFFFFFFFFFFFFFF));
+ json_object_add_value_uint64(pmuw, "lo",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUW] & 0xFFFFFFFFFFFFFFFF));
+ json_object_add_value_object(root, "Physical media units written", pmuw);
+ json_object_add_value_uint64(pmur, "hi",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR + 8] & 0xFFFFFFFFFFFFFFFF));
+ json_object_add_value_uint64(pmur, "lo",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PMUR] & 0xFFFFFFFFFFFFFFFF));
+ json_object_add_value_object(root, "Physical media units read", pmur);
+ json_object_add_value_uint64(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_uint64(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_uint64(root, "XOR recovery count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
+ json_object_add_value_uint64(root, "Uncorrectable read error count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
+ json_object_add_value_uint64(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 detected errors",
+ (uint32_t)le32_to_cpu(*(uint32_t *)&log_data[SCAO_EEDC]));
+ 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, "System data percent used",
+ (__u8)log_data[SCAO_SDPU]);
+ json_object_add_value_uint64(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_uint64(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_uint64(root, "Unaligned I/O",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
+ json_object_add_value_uint64(root, "Security Version Number",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
+ json_object_add_value_uint64(root, "NUSE - Namespace utilization",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
+ json_object_add_value_uint128(root, "PLP start count",
+ le128_to_cpu(&log_data[SCAO_PSC]));
+ json_object_add_value_uint128(root, "Endurance estimate",
+ le128_to_cpu(&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);
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"", (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
+ 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",
+ le16_to_cpu(*(uint16_t *)&log_data[SCAO_PVF]));
+ json_object_add_value_uint(root, "Minor Version Field",
+ le16_to_cpu(*(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_object_add_value_uint(root, "Power State Change Count",
+ le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static int get_c0_log_page(int fd, char *format)
+{
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int i;
+ int ret;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR : OCP : invalid output format\n");
+ return ret;
+ }
+
+ data = malloc(sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR : OCP : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * C0_SMART_CLOUD_ATTR_LEN);
+
+ ret = nvme_get_log_simple(fd, C0_SMART_CLOUD_ATTR_OPCODE,
+ C0_SMART_CLOUD_ATTR_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(ret, false), ret);
+
+ if (ret == 0) {
+ /* check log page guid */
+ /* Verify GUID matches */
+ for (i = 0; i < 16; i++) {
+ if (scao_guid[i] != data[SCAO_LPG + i]) {
+ int j;
+
+ fprintf(stderr, "ERROR : OCP : Unknown GUID in C0 Log Page data\n");
+ fprintf(stderr, "ERROR : OCP : Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", scao_guid[j]);
+
+ fprintf(stderr, "\nERROR : OCP : Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", data[SCAO_LPG + j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* print the data */
+ switch (fmt) {
+ case NORMAL:
+ ocp_print_C0_log_normal(data);
+ break;
+ case JSON:
+ ocp_print_C0_log_json(data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR : OCP : Unable to read C0 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve the extended SMART health data.";
+ struct nvme_dev *dev;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_c0_log_page(dev_fd(dev), cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : OCP : Failure reading the C0 Log Page, ret = %d\n",
+ ret);
+ dev_close(dev);
+ return ret;
+}
diff --git a/plugins/ocp/ocp-smart-extended-log.h b/plugins/ocp/ocp-smart-extended-log.h
new file mode 100644
index 0000000..42c1f98
--- /dev/null
+++ b/plugins/ocp/ocp-smart-extended-log.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Copyright (c) 2022 Meta Platforms, Inc.
+ *
+ * Authors: Arthur Shau <arthurshau@fb.com>,
+ * Wei Zhang <wzhang@fb.com>,
+ * Venkat Ramesh <venkatraghavan@fb.com>
+ */
+
+#ifndef OCP_SMART_EXTENDED_LOG_H
+#define OCP_SMART_EXTENDED_LOG_H
+
+struct command;
+struct plugin;
+
+int ocp_smart_add_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
+
+#endif
diff --git a/plugins/ocp/ocp-utils.c b/plugins/ocp/ocp-utils.c
new file mode 100644
index 0000000..1257b30
--- /dev/null
+++ b/plugins/ocp/ocp-utils.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <unistd.h>
+#include "ocp-utils.h"
+#include "nvme-print.h"
+
+const unsigned char ocp_uuid[NVME_UUID_LEN] = {
+ 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94, 0xa2, 0x1d,
+ 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f };
+
+int ocp_get_uuid_index(struct nvme_dev *dev, int *index)
+{
+ struct nvme_id_uuid_list uuid_list;
+ int err = nvme_identify_uuid(dev_fd(dev), &uuid_list);
+
+ *index = 0;
+ if (err)
+ return err;
+
+ for (int i = 0; i < NVME_ID_UUID_LIST_MAX; i++) {
+ if (memcmp(ocp_uuid, &uuid_list.entry[i].uuid, NVME_UUID_LEN) == 0) {
+ *index = i + 1;
+ break;
+ }
+ }
+ return err;
+}
diff --git a/plugins/ocp/ocp-utils.h b/plugins/ocp/ocp-utils.h
new file mode 100644
index 0000000..d02bea9
--- /dev/null
+++ b/plugins/ocp/ocp-utils.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "nvme.h"
+
+/**
+ * ocp_get_uuid_index() - Get OCP UUID index
+ * @dev: nvme device
+ * @index: integer pointer to here to save the index
+ * @result: The command completion result from CQE dword0
+ *
+ * Return: Zero if nvme device has UUID list log page, or result of get uuid list otherwise.
+ */
+int ocp_get_uuid_index(struct nvme_dev *dev, int *index);
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c
new file mode 100644
index 0000000..f752d5d
--- /dev/null
+++ b/plugins/scaleflux/sfx-nvme.c
@@ -0,0 +1,1687 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <inttypes.h>
+#include <asm/byteorder.h>
+#include <sys/sysinfo.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <time.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-wrap.h"
+#include "nvme-print.h"
+#include "util/cleanup.h"
+
+#define CREATE_CMD
+#include "sfx-nvme.h"
+
+#define SFX_PAGE_SHIFT 12
+#define SECTOR_SHIFT 9
+
+#define SFX_GET_FREESPACE _IOWR('N', 0x240, struct sfx_freespace_ctx)
+#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)
+
+#define VANDA_MAJOR_IDX 0
+#define VANDA_MINOR_IDX 0
+
+#define MYRTLE_MAJOR_IDX 4
+#define MYRTLE_MINOR_IDX 1
+
+enum {
+ SFX_LOG_LATENCY_READ_STATS = 0xc1,
+ SFX_LOG_SMART = 0xc2,
+ 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,
+};
+
+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 out_of_space;
+ __u64 map_unit;
+ __u64 max_user_space;
+ __u64 extendible_user_cap_lba_count;
+ __u64 friendly_change_cap_support;
+};
+
+struct nvme_capacity_info {
+ __u64 lba_sec_sz;
+ __u64 phy_sec_sz;
+ __u64 used_space;
+ __u64 free_space;
+};
+
+struct __packed nvme_additional_smart_log_item {
+ __u8 key;
+ __u8 _kp[2];
+ __u8 norm;
+ __u8 _np;
+ union __packed {
+ __u8 raw[6];
+ struct __packed wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __packed thermal_throttle {
+ __u8 pct;
+ __u32 count;
+ } thermal_throttle;
+ };
+ __u8 _rp;
+};
+
+struct nvme_additional_smart_log {
+ struct nvme_additional_smart_log_item program_fail_cnt;
+ struct nvme_additional_smart_log_item erase_fail_cnt;
+ struct nvme_additional_smart_log_item wear_leveling_cnt;
+ struct nvme_additional_smart_log_item e2e_err_cnt;
+ struct nvme_additional_smart_log_item crc_err_cnt;
+ struct nvme_additional_smart_log_item timed_workload_media_wear;
+ struct nvme_additional_smart_log_item timed_workload_host_reads;
+ struct nvme_additional_smart_log_item timed_workload_timer;
+ struct nvme_additional_smart_log_item thermal_throttle_status;
+ struct nvme_additional_smart_log_item retry_buffer_overflow_cnt;
+ 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 raid_recover_cnt; /* errors which can be recovered by RAID */
+ struct nvme_additional_smart_log_item prog_timeout_cnt;
+ struct nvme_additional_smart_log_item erase_timeout_cnt;
+ struct nvme_additional_smart_log_item read_timeout_cnt;
+ struct nvme_additional_smart_log_item read_ecc_cnt; /* retry cnt */
+ struct nvme_additional_smart_log_item non_media_crc_err_cnt;
+ struct nvme_additional_smart_log_item compression_path_err_cnt;
+ struct nvme_additional_smart_log_item out_of_space_flag;
+ struct nvme_additional_smart_log_item physical_usage_ratio;
+ struct nvme_additional_smart_log_item grown_bb; /* grown bad block */
+};
+
+int nvme_query_cap(int fd, __u32 nsid, __u32 data_len, void *data)
+{
+ int rc = 0;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_query_cap_info,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+
+ rc = ioctl(fd, SFX_GET_FREESPACE, data);
+ return rc ? nvme_submit_admin_passthru(fd, &cmd, NULL) : 0;
+}
+
+int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_change_cap,
+ .nsid = nsid,
+ .cdw10 = (capacity & 0xffffffff),
+ .cdw11 = (capacity >> 32),
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_sfx_set_features,
+ .nsid = nsid,
+ .cdw10 = fid,
+ .cdw11 = value,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result)
+{
+ int err = 0;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_sfx_get_features,
+ .nsid = nsid,
+ .cdw10 = fid,
+ };
+
+ err = nvme_submit_admin_passthru(fd, &cmd, NULL);
+ if (!err && result)
+ *result = cmd.result;
+
+ return err;
+}
+
+static void show_sfx_smart_log_jsn(struct nvme_additional_smart_log *smart,
+ unsigned int nsid, const char *devname)
+{
+ struct json_object *root, *entry_stats, *dev_stats, *multi;
+
+ root = json_create_object();
+ json_object_add_value_string(root, "Intel Smart log", devname);
+
+ dev_stats = json_create_object();
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->program_fail_cnt.raw));
+ json_object_add_value_object(dev_stats, "program_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_fail_cnt.raw));
+ json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm);
+ multi = json_create_object();
+ json_object_add_value_int(multi, "min", le16_to_cpu(smart->wear_leveling_cnt.wear_level.min));
+ json_object_add_value_int(multi, "max", le16_to_cpu(smart->wear_leveling_cnt.wear_level.max));
+ json_object_add_value_int(multi, "avg", le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg));
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "wear_leveling", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->e2e_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "end_to_end_error_detection_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->crc_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "crc_error_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_media_wear.norm);
+ json_object_add_value_float(entry_stats, "raw", ((float)int48_to_long(smart->timed_workload_media_wear.raw)) / 1024);
+ json_object_add_value_object(dev_stats, "timed_workload_media_wear", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_host_reads.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_host_reads.raw));
+ json_object_add_value_object(dev_stats, "timed_workload_host_reads", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->timed_workload_timer.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->timed_workload_timer.raw));
+ json_object_add_value_object(dev_stats, "timed_workload_timer", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->thermal_throttle_status.norm);
+ multi = json_create_object();
+ json_object_add_value_int(multi, "pct", smart->thermal_throttle_status.thermal_throttle.pct);
+ json_object_add_value_int(multi, "cnt", smart->thermal_throttle_status.thermal_throttle.count);
+ json_object_add_value_object(entry_stats, "raw", multi);
+ json_object_add_value_object(dev_stats, "thermal_throttle_status", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->retry_buffer_overflow_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->retry_buffer_overflow_cnt.raw));
+ json_object_add_value_object(dev_stats, "retry_buffer_overflow_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->pll_lock_loss_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->pll_lock_loss_cnt.raw));
+ json_object_add_value_object(dev_stats, "pll_lock_loss_count", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->nand_bytes_written.raw));
+ json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm);
+ 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->raid_recover_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->raid_recover_cnt.raw));
+ json_object_add_value_object(dev_stats, "raid_recover_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->prog_timeout_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->prog_timeout_cnt.raw));
+ json_object_add_value_object(dev_stats, "prog_timeout_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->erase_timeout_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->erase_timeout_cnt.raw));
+ json_object_add_value_object(dev_stats, "erase_timeout_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->read_timeout_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->read_timeout_cnt.raw));
+ json_object_add_value_object(dev_stats, "read_timeout_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->read_ecc_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->read_ecc_cnt.raw));
+ json_object_add_value_object(dev_stats, "read_ecc_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->non_media_crc_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->non_media_crc_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "non_media_crc_err_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->compression_path_err_cnt.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->compression_path_err_cnt.raw));
+ json_object_add_value_object(dev_stats, "compression_path_err_cnt", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->out_of_space_flag.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->out_of_space_flag.raw));
+ json_object_add_value_object(dev_stats, "out_of_space_flag", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->physical_usage_ratio.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->physical_usage_ratio.raw));
+ json_object_add_value_object(dev_stats, "physical_usage_ratio", entry_stats);
+
+ entry_stats = json_create_object();
+ json_object_add_value_int(entry_stats, "normalized", smart->grown_bb.norm);
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(smart->grown_bb.raw));
+ json_object_add_value_object(dev_stats, "grown_bb", entry_stats);
+
+ json_object_add_value_object(root, "Device stats", dev_stats);
+
+ json_print_object(root, NULL);
+ printf("/n");
+ json_free_object(root);
+}
+
+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));
+ printf("non_media_crc_err_cnt : %3d%% %" PRIu64 "\n",
+ smart->non_media_crc_err_cnt.norm,
+ int48_to_long(smart->non_media_crc_err_cnt.raw));
+ printf("compression_path_err_cnt : %3d%% %" PRIu64 "\n",
+ smart->compression_path_err_cnt.norm,
+ int48_to_long(smart->compression_path_err_cnt.raw));
+ printf("out_of_space_flag : %3d%% %" PRIu64 "\n",
+ smart->out_of_space_flag.norm,
+ int48_to_long(smart->out_of_space_flag.raw));
+ printf("phy_capacity_used_ratio : %3d%% %" PRIu64 "\n",
+ smart->physical_usage_ratio.norm,
+ int48_to_long(smart->physical_usage_ratio.raw));
+ printf("grown_bb_count : %3d%% %" PRIu64 "\n",
+ smart->grown_bb.norm, int48_to_long(smart->grown_bb.raw));
+
+
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_additional_smart_log smart_log;
+ char *desc =
+ "Get ScaleFlux 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";
+ const char *json = "Dump output in json format";
+ struct nvme_dev *dev;
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ bool json;
+ };
+ int err;
+
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("json", 'j', &cfg.json, json),
+ OPT_END()
+ };
+
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
+ sizeof(smart_log), (void *)&smart_log);
+ if (!err) {
+ if (cfg.json)
+ show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id,
+ dev->name);
+ else if (!cfg.raw_binary)
+ show_sfx_smart_log(&smart_log, cfg.namespace_id,
+ dev->name);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ dev_close(dev);
+ return err;
+}
+
+struct __packed sfx_lat_stats_vanda {
+ __u16 maj;
+ __u16 min;
+ __u32 bucket_1[32]; /* 0~1ms, step 32us */
+ __u32 bucket_2[31]; /* 1~32ms, step 1ms */
+ __u32 bucket_3[31]; /* 32ms~1s, step 32ms */
+ __u32 bucket_4[1]; /* 1s~2s, specifically 1024ms~2047ms */
+ __u32 bucket_5[1]; /* 2s~4s, specifically 2048ms~4095ms */
+ __u32 bucket_6[1]; /* 4s+, specifically 4096ms+ */
+};
+
+struct __packed sfx_lat_stats_myrtle {
+ __u16 maj;
+ __u16 min;
+ __u32 bucket_1[64]; /* 0us~63us, step 1us */
+ __u32 bucket_2[64]; /* 63us~127us, step 1us */
+ __u32 bucket_3[64]; /* 127us~255us, step 2us */
+ __u32 bucket_4[64]; /* 255us~510us, step 4us */
+ __u32 bucket_5[64]; /* 510us~1.02ms step 8us */
+ __u32 bucket_6[64]; /* 1.02ms~2.04ms step 16us */
+ __u32 bucket_7[64]; /* 2.04ms~4.08ms step 32us */
+ __u32 bucket_8[64]; /* 4.08ms~8.16ms step 64us */
+ __u32 bucket_9[64]; /* 8.16ms~16.32ms step 128us */
+ __u32 bucket_10[64]; /* 16.32ms~32.64ms step 256us */
+ __u32 bucket_11[64]; /* 32.64ms~65.28ms step 512us */
+ __u32 bucket_12[64]; /* 65.28ms~130.56ms step 1.024ms */
+ __u32 bucket_13[64]; /* 130.56ms~261.12ms step 2.048ms */
+ __u32 bucket_14[64]; /* 261.12ms~522.24ms step 4.096ms */
+ __u32 bucket_15[64]; /* 522.24ms~1.04s step 8.192ms */
+ __u32 bucket_16[64]; /* 1.04s~2.09s step 16.384ms */
+ __u32 bucket_17[64]; /* 2.09s~4.18s step 32.768ms */
+ __u32 bucket_18[64]; /* 4.18s~8.36s step 65.536ms */
+ __u32 bucket_19[64]; /* 8.36s~ step 131.072ms */
+ __u64 average; /* average latency statistics */
+};
+
+
+struct __packed sfx_lat_status_ver {
+ __u16 maj;
+ __u16 min;
+};
+
+struct sfx_lat_stats {
+ union {
+ struct sfx_lat_status_ver ver;
+ struct sfx_lat_stats_vanda vanda;
+ struct sfx_lat_stats_myrtle myrtle;
+ };
+};
+
+static void show_lat_stats_vanda(struct sfx_lat_stats_vanda *stats, int write)
+{
+ int i;
+
+ printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read");
+ printf("-------------------------------------\n");
+ printf("Major Revision : %u\n", stats->maj);
+ printf("Minor Revision : %u\n", stats->min);
+
+ printf("\nGroup 1: Range is 0-1ms, step is 32us\n");
+ for (i = 0; i < 32; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_1[i]);
+
+ printf("\nGroup 2: Range is 1-32ms, step is 1ms\n");
+ for (i = 0; i < 31; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_2[i]);
+
+ printf("\nGroup 3: Range is 32ms-1s, step is 32ms:\n");
+ for (i = 0; i < 31; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_3[i]);
+
+ printf("\nGroup 4: Range is 1s-2s:\n");
+ printf("Bucket %2d: %u\n", 0, stats->bucket_4[0]);
+
+ printf("\nGroup 5: Range is 2s-4s:\n");
+ printf("Bucket %2d: %u\n", 0, stats->bucket_5[0]);
+
+ printf("\nGroup 6: Range is 4s+:\n");
+ printf("Bucket %2d: %u\n", 0, stats->bucket_6[0]);
+}
+
+static void show_lat_stats_myrtle(struct sfx_lat_stats_myrtle *stats, int write)
+{
+ int i;
+
+ printf("ScaleFlux IO %s Command Latency Statistics\n", write ? "Write" : "Read");
+ printf("-------------------------------------\n");
+ printf("Major Revision : %u\n", stats->maj);
+ printf("Minor Revision : %u\n", stats->min);
+
+ printf("\nGroup 1: Range is 0us~63us, step 1us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_1[i]);
+
+ printf("\nGroup 2: Range is 63us~127us, step 1us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_2[i]);
+
+ printf("\nGroup 3: Range is 127us~255us, step 2us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_3[i]);
+
+ printf("\nGroup 4: Range is 255us~510us, step 4us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_4[i]);
+
+ printf("\nGroup 5: Range is 510us~1.02ms step\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_5[i]);
+
+ printf("\nGroup 6: Range is 1.02ms~2.04ms step 16us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_6[i]);
+
+ printf("\nGroup 7: Range is 2.04ms~4.08ms step 32us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_7[i]);
+
+ printf("\nGroup 8: Range is 4.08ms~8.16ms step 64us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_8[i]);
+
+ printf("\nGroup 9: Range is 8.16ms~16.32ms step 128us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_9[i]);
+
+ printf("\nGroup 10: Range is 16.32ms~32.64ms step 256us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_10[i]);
+
+ printf("\nGroup 11: Range is 32.64ms~65.28ms step 512us\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_11[i]);
+
+ printf("\nGroup 12: Range is 65.28ms~130.56ms step 1.024ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_12[i]);
+
+ printf("\nGroup 13: Range is 130.56ms~261.12ms step 2.048ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_13[i]);
+
+ printf("\nGroup 14: Range is 261.12ms~522.24ms step 4.096ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_14[i]);
+
+ printf("\nGroup 15: Range is 522.24ms~1.04s step 8.192ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_15[i]);
+
+ printf("\nGroup 16: Range is 1.04s~2.09s step 16.384ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_16[i]);
+
+ printf("\nGroup 17: Range is 2.09s~4.18s step 32.768ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_17[i]);
+
+ printf("\nGroup 18: Range is 4.18s~8.36s step 65.536ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_18[i]);
+
+ printf("\nGroup 19: Range is 8.36s~ step 131.072ms\n");
+ for (i = 0; i < 64; i++)
+ printf("Bucket %2d: %u\n", i, stats->bucket_19[i]);
+
+ printf("\nAverage latency statistics %" PRIu64 "\n",
+ (uint64_t)stats->average);
+}
+
+
+static int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct sfx_lat_stats stats;
+ char *desc = "Get ScaleFlux Latency Statistics log and show it.";
+ const char *raw = "dump output in binary format";
+ const char *write = "Get write statistics (read default)";
+ struct nvme_dev *dev;
+ struct config {
+ bool raw_binary;
+ bool write;
+ };
+ int err;
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), cfg.write ? 0xc3 : 0xc1,
+ sizeof(stats), (void *)&stats);
+ if (!err) {
+ if ((stats.ver.maj == VANDA_MAJOR_IDX) && (stats.ver.min == VANDA_MINOR_IDX)) {
+ if (!cfg.raw_binary)
+ show_lat_stats_vanda(&stats.vanda, cfg.write);
+ else
+ d_raw((unsigned char *)&stats.vanda, sizeof(struct sfx_lat_stats_vanda));
+ } else if ((stats.ver.maj == MYRTLE_MAJOR_IDX) && (stats.ver.min == MYRTLE_MINOR_IDX)) {
+ if (!cfg.raw_binary)
+ show_lat_stats_myrtle(&stats.myrtle, cfg.write);
+ else
+ d_raw((unsigned char *)&stats.myrtle, sizeof(struct sfx_lat_stats_myrtle));
+ } else {
+ printf("ScaleFlux IO %s Command Latency Statistics Invalid Version Maj %d Min %d\n",
+ cfg.write ? "Write" : "Read", stats.ver.maj, stats.ver.min);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ dev_close(dev);
+ return err;
+}
+
+int sfx_nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+ __u32 numd = (data_len >> 2) - 1;
+ __u16 numdu = numd >> 16, numdl = numd & 0xffff;
+
+ cmd.cdw10 = log_id | (numdl << 16);
+ cmd.cdw11 = numdu;
+
+ return nvme_submit_admin_passthru(fd, &cmd, NULL);
+}
+
+/**
+ * @brief get bb table through admin_passthru
+ *
+ * @param fd
+ * @param buf
+ * @param size
+ *
+ * @return -1 fail ; 0 success
+ */
+static int get_bb_table(int fd, __u32 nsid, unsigned char *buf, __u64 size)
+{
+ if (fd < 0 || !buf || size != 256*4096*sizeof(unsigned char)) {
+ fprintf(stderr, "Invalid Param \r\n");
+ return -EINVAL;
+ }
+
+ return sfx_nvme_get_log(fd, nsid, SFX_LOG_BBT, size, (void *)buf);
+}
+
+/**
+ * @brief display bb table
+ *
+ * @param bd_table buffer that contain bb table dumped from drvier
+ * @param table_size buffer size (BYTES), should at least has 8 bytes for mf_bb_count and grown_bb_count
+ */
+static void bd_table_show(unsigned char *bd_table, __u64 table_size)
+{
+ __u32 mf_bb_count = 0;
+ __u32 grown_bb_count = 0;
+ __u32 total_bb_count = 0;
+ __u32 remap_mfbb_count = 0;
+ __u32 remap_gbb_count = 0;
+ __u64 *bb_elem;
+ __u64 *elem_end = (__u64 *)(bd_table + table_size);
+ __u64 i;
+
+ /*buf should at least have 8bytes for mf_bb_count & total_bb_count*/
+ if (!bd_table || table_size < sizeof(__u64))
+ return;
+
+ mf_bb_count = *((__u32 *)bd_table);
+ grown_bb_count = *((__u32 *)(bd_table + sizeof(__u32)));
+ total_bb_count = *((__u32 *)(bd_table + 2 * sizeof(__u32)));
+ remap_mfbb_count = *((__u32 *)(bd_table + 3 * sizeof(__u32)));
+ remap_gbb_count = *((__u32 *)(bd_table + 4 * sizeof(__u32)));
+ 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("REMAP_MFBB_TABLE [");
+ i = 0;
+ while (bb_elem < elem_end && i < remap_mfbb_count) {
+ printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
+ i++;
+ }
+ printf(" ]\n");
+
+ printf("REMAP_GBB_TABLE [");
+ i = 0;
+ while (bb_elem < elem_end && i < remap_gbb_count) {
+ printf(" 0x%"PRIx64"", (uint64_t)*(bb_elem++));
+ i++;
+ }
+ printf(" ]\n");
+}
+
+/**
+ * @brief "hooks of sfx get-bad-block"
+ *
+ * @param argc
+ * @param argv
+ * @param cmd
+ * @param plugin
+ *
+ * @return
+ */
+static int sfx_get_bad_block(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const __u64 buf_size = 256*4096*sizeof(unsigned char);
+ unsigned char *data_buf;
+ struct nvme_dev *dev;
+ int err = 0;
+
+ char *desc = "Get bad block table of sfx block device.";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ data_buf = malloc(buf_size);
+ if (!data_buf) {
+ fprintf(stderr, "malloc fail, errno %d\r\n", errno);
+ dev_close(dev);
+ return -1;
+ }
+
+ err = get_bb_table(dev_fd(dev), 0xffffffff, data_buf, buf_size);
+ if (err < 0) {
+ perror("get-bad-block");
+ } else if (err) {
+ nvme_show_status(err);
+ } else {
+ bd_table_show(data_buf, buf_size);
+ printf("ScaleFlux get bad block table: success\n");
+ }
+
+ free(data_buf);
+ dev_close(dev);
+ return 0;
+}
+
+static void show_cap_info(struct sfx_freespace_ctx *ctx)
+{
+
+ 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));
+ printf("map_unit :0x%"PRIx64"K\n", (uint64_t)(ctx->map_unit * 4));
+}
+
+static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct sfx_freespace_ctx ctx = { 0 };
+ char *desc = "query current capacity info";
+ const char *raw = "dump output in binary format";
+ struct nvme_dev *dev;
+ struct config {
+ bool raw_binary;
+ };
+ struct config cfg;
+ int err = 0;
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (nvme_query_cap(dev_fd(dev), 0xffffffff, sizeof(ctx), &ctx)) {
+ perror("sfx-query-cap");
+ err = -1;
+ }
+
+ if (!err) {
+ if (!cfg.raw_binary)
+ show_cap_info(&ctx);
+ else
+ d_raw((unsigned char *)&ctx, sizeof(ctx));
+ }
+ dev_close(dev);
+ return err;
+}
+
+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;
+ int extend = 0;
+
+ if (nvme_query_cap(fd, 0xffffffff, sizeof(freespace_ctx), &freespace_ctx))
+ return -1;
+
+ /*
+ * 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 provisioned 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 (trg_in_4k > ((__u64)provisoned_cap_4k*4)) {
+ fprintf(stderr, "WARNING: the target capacity is too large\n");
+ 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, canceled; 1 confirmed
+ */
+static int sfx_confirm_change(const char *str)
+{
+ unsigned 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 = (unsigned char)fgetc(stdin);
+ if (confirm != 'y' && confirm != 'Y') {
+ fprintf(stderr, "Canceled.\n");
+ return 0;
+ }
+ fprintf(stderr, "Sending operation ...\n");
+ return 1;
+}
+
+static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "dynamic change capacity";
+ const char *cap_gb = "cap size in GB";
+ const char *cap_byte = "cap size in byte";
+ const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
+ struct nvme_dev *dev;
+ __u64 cap_in_4k = 0;
+ __u64 cap_in_sec = 0;
+ int shrink = 0;
+ int err = -1;
+
+ struct config {
+ __u64 cap_in_byte;
+ __u32 capacity_in_gb;
+ bool force;
+ };
+
+ struct config cfg = {
+ .cap_in_byte = 0,
+ .capacity_in_gb = 0,
+ .force = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("cap", 'c', &cfg.capacity_in_gb, cap_gb),
+ OPT_SUFFIX("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
+ OPT_FLAG("force", 'f', &cfg.force, force),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ 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 %"PRIu64"B %"PRIu64" 4K\n",
+ cfg.capacity_in_gb, (uint64_t)cfg.cap_in_byte, (uint64_t)cap_in_4k);
+
+ if (change_sanity_check(dev_fd(dev), cap_in_4k, &shrink)) {
+ printf("ScaleFlux change-capacity: fail\n");
+ dev_close(dev);
+ return err;
+ }
+
+ if (!cfg.force && shrink && !sfx_confirm_change("Changing Cap may irrevocably delete this device's data")) {
+ dev_close(dev);
+ return 0;
+ }
+
+ err = nvme_change_cap(dev_fd(dev), 0xffffffff, cap_in_4k);
+ if (err < 0) {
+ perror("sfx-change-cap");
+ } else if (err) {
+ nvme_show_status(err);
+ } else {
+ printf("ScaleFlux change-capacity: success\n");
+ ioctl(dev_fd(dev), BLKRRPART);
+ }
+ dev_close(dev);
+ 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_UP_P_CAP:
+ return "UPDATE_PROVISION_CAPACITY";
+ default:
+ return "Unknown";
+ }
+}
+
+static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "ScaleFlux internal set features\n"
+ "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_dev *dev;
+ struct nvme_id_ns ns;
+ int err = 0;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ bool 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_FLAG("force", 's', &cfg.force, force),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ 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")) {
+ dev_close(dev);
+ return 0;
+ } else {
+ return sfx_clean_card(dev_fd(dev));
+ }
+
+ }
+
+ if (cfg.feature_id == SFX_FEAT_ATOMIC && cfg.value) {
+ if (cfg.namespace_id != 0xffffffff) {
+ err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id,
+ &ns);
+ if (err) {
+ if (err < 0)
+ perror("identify-namespace");
+ else
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+ }
+ /*
+ * atomic only support with sector-size = 4k now
+ */
+ if ((ns.flbas & 0xf) != 1) {
+ printf("Please change-sector size to 4K, then retry\n");
+ dev_close(dev);
+ return -EFAULT;
+ }
+ }
+ } else if (cfg.feature_id == SFX_FEAT_UP_P_CAP) {
+ if (cfg.value <= 0) {
+ fprintf(stderr, "Invalid Param\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ /*Warning for change pacp by GB*/
+ if (!cfg.force && !sfx_confirm_change("Changing physical capacity may irrevocably delete this device's data")) {
+ dev_close(dev);
+ return 0;
+ }
+ }
+
+ err = nvme_sfx_set_features(dev_fd(dev), cfg.namespace_id,
+ cfg.feature_id,
+ cfg.value);
+
+ if (err < 0) {
+ perror("ScaleFlux-set-feature");
+ dev_close(dev);
+ return errno;
+ } else if (!err) {
+ 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) {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "ScaleFlux internal set features\n"
+ "feature id 1: ATOMIC";
+ const char *feature_id = "hex feature name (required)";
+ const char *namespace_id = "desired namespace";
+ struct nvme_dev *dev;
+ __u32 result = 0;
+ int err = 0;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ };
+ struct config cfg = {
+ .namespace_id = 0,
+ .feature_id = 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_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ err = nvme_sfx_get_features(dev_fd(dev), cfg.namespace_id,
+ cfg.feature_id, &result);
+ if (err < 0) {
+ perror("ScaleFlux-get-feature");
+ dev_close(dev);
+ return errno;
+ } else if (!err) {
+ printf("ScaleFlux get-feature:%02x (%s), value:%d\n", cfg.feature_id,
+ sfx_feature_to_string(cfg.feature_id), result);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+ return err;
+
+}
+
+static int nvme_parse_evtlog(void *pevent_log_info, __u32 log_len, char *output)
+{
+ __u32 offset = 0;
+ __u32 length = log_len;
+ __u16 fw_core;
+ __u64 fw_time;
+ __u8 code_level;
+ __u8 code_type;
+ char str_buffer[512];
+ __u32 str_pos;
+ FILE *fd;
+ int err = 0;
+
+ enum sfx_evtlog_level {
+ sfx_evtlog_level_warning,
+ sfx_evtlog_level_error,
+ };
+
+ const char *sfx_evtlog_warning[4] = {
+ "RESERVED",
+ "TOO_MANY_BB",
+ "LOW_SPACE",
+ "HIGH_TEMPERATURE"
+ };
+
+ const char *sfx_evtlog_error[14] = {
+ "RESERVED",
+ "HAS_ASSERT",
+ "HAS_PANIC_DUMP",
+ "INVALID_FORMAT_CAPACITY",
+ "MAT_FAILED",
+ "FREEZE_DUE_TO_RECOVERY_FAILED",
+ "RFS_BROKEN",
+ "MEDIA_ERR_ON_PAGE_IN",
+ "MEDIA_ERR_ON_MPAGE_HEADER",
+ "CAPACITOR_BROKEN",
+ "READONLY_DUE_TO_RECOVERY_FAILED",
+ "RD_ERR_IN_GSD_RECOVERY",
+ "RD_ERR_ON_PF_RECOVERY",
+ "MEDIA_ERR_ON_FULL_RECOVERY"
+ };
+
+ struct sfx_nvme_evtlog_info {
+ __u16 time_stamp[4];
+ __u64 magic1;
+ __u8 reverse[10];
+ char evt_name[32];
+ __u64 magic2;
+ char fw_ver[24];
+ char bl2_ver[32];
+ __u16 code;
+ __u16 assert_id;
+ } __packed;
+
+ struct sfx_nvme_evtlog_info *info = NULL;
+
+ fd = fopen(output, "w+");
+ if (!fd) {
+ fprintf(stderr, "Failed to open %s file to write\n", output);
+ err = ENOENT;
+ goto ret;
+ }
+
+ while (length > 0) {
+ info = (struct sfx_nvme_evtlog_info *)(pevent_log_info + offset);
+
+ if ((info->magic1 == 0x474F4C545645) &&
+ (info->magic2 == 0x38B0B3ABA9BA)) {
+
+ memset(str_buffer, 0, 512);
+ str_pos = 0;
+
+ fw_core = info->time_stamp[3];
+ snprintf(str_buffer + str_pos, 16, "[%d-", fw_core);
+ str_pos = strlen(str_buffer);
+
+ fw_time = ((__u64)info->time_stamp[2] << 32) + ((__u64)info->time_stamp[1] << 16) + (__u64)info->time_stamp[0];
+ convert_ts(fw_time, str_buffer + str_pos);
+ str_pos = strlen(str_buffer);
+
+ strcpy(str_buffer + str_pos, "] event-log:\n");
+ str_pos = strlen(str_buffer);
+
+ snprintf(str_buffer + str_pos, 128,
+ " > fw_version: %s\n > bl2_version: %s\n",
+ info->fw_ver, info->bl2_ver);
+ str_pos = strlen(str_buffer);
+
+ code_level = (info->code & 0x100) >> 8;
+ code_type = (info->code % 0x100);
+ if (code_level == sfx_evtlog_level_warning) {
+ snprintf(str_buffer + str_pos, 128,
+ " > error_str: [WARNING][%s]\n\n",
+ sfx_evtlog_warning[code_type]);
+ } else {
+ if (info->assert_id)
+ snprintf(str_buffer + str_pos, 128,
+ " > error_str: [ERROR][%s]\n > assert_id: %d\n\n",
+ sfx_evtlog_error[code_type], info->assert_id);
+ else
+ snprintf(str_buffer + str_pos, 128,
+ " > error_str: [ERROR][%s]\n\n",
+ sfx_evtlog_error[code_type]);
+ }
+ str_pos = strlen(str_buffer);
+
+ if (fwrite(str_buffer, 1, str_pos, fd) != str_pos) {
+ fprintf(stderr, "Failed to write parse result to output file\n");
+ goto close_fd;
+ }
+ }
+
+ offset++;
+ length--;
+
+ if (!(offset % (log_len / 100)) || (offset == log_len))
+ util_spinner("Parse", (float) (offset) / (float) (log_len));
+ }
+
+ printf("\nParse-evtlog: Success\n");
+
+close_fd:
+ fclose(fd);
+ret:
+ return err;
+}
+
+static int nvme_dump_evtlog(struct nvme_dev *dev, __u32 namespace_id, __u32 storage_medium,
+ char *file, bool parse, char *output)
+{
+ struct nvme_persistent_event_log *pevent;
+ void *pevent_log_info;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ __u8 lsp_base;
+ __u32 offset = 0;
+ __u32 length = 0;
+ __u32 log_len;
+ __u32 single_len;
+ int err = 0;
+ FILE *fd = NULL;
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = NVME_LOG_LID_PERSISTENT_EVENT,
+ .nsid = namespace_id,
+ .lpo = NVME_LOG_LPO_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = NVME_LOG_LSI_NONE,
+ .rae = false,
+ .uuidx = NVME_UUID_NONE,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = 0,
+ .log = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+
+ if (!storage_medium) {
+ lsp_base = 0;
+ single_len = 64 * 1024 - 4;
+ } else {
+ lsp_base = 4;
+ single_len = 32 * 1024;
+ }
+
+ pevent = calloc(sizeof(*pevent), sizeof(__u8));
+ if (!pevent) {
+ err = -ENOMEM;
+ goto ret;
+ }
+
+ args.lsp = lsp_base + NVME_PEVENT_LOG_RELEASE_CTX;
+ args.log = pevent;
+ args.len = sizeof(*pevent);
+
+ err = nvme_get_log(&args);
+ if (err) {
+ fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err);
+ goto free_pevent;
+ }
+
+ args.lsp = lsp_base + NVME_PEVENT_LOG_EST_CTX_AND_READ;
+ err = nvme_get_log(&args);
+ if (err) {
+ fprintf(stderr, "Unable to get evtlog lsp=0x%x, ret = 0x%x\n", args.lsp, err);
+ goto free_pevent;
+ }
+
+ log_len = le64_to_cpu(pevent->tll);
+ if (log_len % 4)
+ log_len = (log_len / 4 + 1) * 4;
+
+ pevent_log_info = nvme_alloc_huge(single_len, &mh);
+ if (!pevent_log_info) {
+ err = -ENOMEM;
+ goto free_pevent;
+ }
+
+ fd = fopen(file, "wb+");
+ if (!fd) {
+ fprintf(stderr, "Failed to open %s file to write\n", file);
+ err = ENOENT;
+ goto free_pevent;
+ }
+
+ args.lsp = lsp_base + NVME_PEVENT_LOG_READ;
+ args.log = pevent_log_info;
+ length = log_len;
+ while (length > 0) {
+ args.lpo = offset;
+ if (length > single_len) {
+ args.len = single_len;
+ } else {
+ memset(args.log, 0, args.len);
+ args.len = length;
+ }
+ err = nvme_get_log(&args);
+ if (err) {
+ fprintf(stderr, "Unable to get evtlog offset=0x%x len 0x%x ret = 0x%x\n", offset, args.len, err);
+ goto close_fd;
+ }
+
+ if (fwrite(args.log, 1, args.len, fd) != args.len) {
+ fprintf(stderr, "Failed to write evtlog to file\n");
+ goto close_fd;
+ }
+
+ offset += args.len;
+ length -= args.len;
+ util_spinner("Parse", (float) (offset) / (float) (log_len));
+ }
+
+ printf("\nDump-evtlog: Success\n");
+
+ if (parse) {
+ nvme_free_huge(&mh);
+ pevent_log_info = nvme_alloc_huge(log_len, &mh);
+ if (!pevent_log_info) {
+ fprintf(stderr, "Failed to alloc enough memory 0x%x to parse evtlog\n", log_len);
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ fclose(fd);
+ fd = fopen(file, "rb");
+ if (!fd) {
+ fprintf(stderr, "Failed to open %s file to read\n", file);
+ err = ENOENT;
+ goto free_pevent;
+ }
+ if (fread(pevent_log_info, 1, log_len, fd) != log_len) {
+ fprintf(stderr, "Failed to read evtlog to buffer\n");
+ goto close_fd;
+ }
+
+ err = nvme_parse_evtlog(pevent_log_info, log_len, output);
+ }
+
+close_fd:
+ fclose(fd);
+free_pevent:
+ free(pevent);
+ret:
+ return err;
+}
+
+static int sfx_dump_evtlog(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "dump evtlog into file and parse";
+ const char *file = "evtlog file(required)";
+ const char *namespace_id = "desired namespace";
+ const char *storage_medium = "evtlog storage medium\n"
+ "0: nand(default) 1: nor";
+ const char *parse = "parse error & warning evtlog from evtlog file";
+ const char *output = "parse result output file";
+ struct nvme_dev *dev;
+ int err = 0;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 storage_medium;
+ bool parse;
+ char *output;
+ };
+ struct config cfg = {
+ .file = NULL,
+ .namespace_id = 0xffffffff,
+ .storage_medium = 0,
+ .parse = false,
+ .output = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("file", 'f', &cfg.file, file),
+ OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("storage_medium", 's', &cfg.storage_medium, storage_medium),
+ OPT_FLAG("parse", 'p', &cfg.parse, parse),
+ OPT_FILE("output", 'o', &cfg.output, output),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ goto ret;
+
+ if (!cfg.file) {
+ fprintf(stderr, "file required param\n");
+ err = EINVAL;
+ goto close_dev;
+ }
+
+ if (cfg.parse && !cfg.output) {
+ fprintf(stderr, "output file required if evtlog need be parsed\n");
+ err = EINVAL;
+ goto close_dev;
+ }
+
+ err = nvme_dump_evtlog(dev, cfg.namespace_id, cfg.storage_medium, cfg.file, cfg.parse, cfg.output);
+
+close_dev:
+ dev_close(dev);
+ret:
+ return err;
+}
+
+static int nvme_expand_cap(struct nvme_dev *dev, __u32 namespace_id, __u64 namespace_size,
+ __u64 namespace_cap, __u32 lbaf, __u32 units)
+{
+ struct dirent **devices;
+ char dev_name[32] = "";
+ int i = 0;
+ int num = 0;
+ int err = 0;
+
+ struct sfx_expand_cap_info {
+ __u64 namespace_size;
+ __u64 namespace_cap;
+ __u8 reserve[10];
+ __u8 lbaf;
+ __u8 reserve1[5];
+ } __packed;
+
+ if (S_ISCHR(dev->direct.stat.st_mode))
+ snprintf(dev_name, 32, "%sn%u", dev->name, namespace_id);
+ else
+ strcpy(dev_name, dev->name);
+
+ num = scandir("/dev", &devices, nvme_namespace_filter, alphasort);
+ if (num <= 0) {
+ err = num;
+ goto ret;
+ }
+
+ if (strcmp(dev_name, devices[num-1]->d_name)) {
+ fprintf(stderr, "Expand namespace not the last one\n");
+ err = EINVAL;
+ goto free_devices;
+ }
+
+ if (!units) {
+ namespace_size = IDEMA_CAP(namespace_size) / (1 << (lbaf * 3));
+ namespace_cap = IDEMA_CAP(namespace_cap) / (1 << (lbaf * 3));
+ }
+
+ struct sfx_expand_cap_info info = {
+ .namespace_size = namespace_size,
+ .namespace_cap = namespace_cap,
+ .lbaf = lbaf,
+ };
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_admin_ns_mgmt,
+ .nsid = namespace_id,
+ .addr = (__u64)(uintptr_t)&info,
+ .data_len = sizeof(info),
+ .cdw10 = 0x0e,
+ };
+
+ err = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+ if (err) {
+ fprintf(stderr, "Create ns failed\n");
+ nvme_show_status(err);
+ goto free_devices;
+ }
+
+free_devices:
+ for (i = 0; i < num; i++)
+ free(devices[i]);
+ free(devices);
+ret:
+ return err;
+}
+
+static int sfx_expand_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "expand capacity";
+ const char *namespace_id = "desired namespace";
+ const char *namespace_size = "namespace size(required)";
+ const char *namespace_cap = "namespace capacity(required)";
+ const char *lbaf = "LBA format to apply\n"
+ "0: 512(default) 1: 4096";
+ const char *units = "namespace size/capacity units\n"
+ "0: GB(default) 1: LBA";
+ struct nvme_dev *dev;
+ int err = 0;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 namespace_size;
+ __u64 namespace_cap;
+ __u32 lbaf;
+ __u32 units;
+ };
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ .lbaf = 0,
+ .units = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace_id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LONG("namespace_size", 's', &cfg.namespace_size, namespace_size),
+ OPT_LONG("namespace_cap", 'c', &cfg.namespace_cap, namespace_cap),
+ OPT_UINT("lbaf", 'l', &cfg.lbaf, lbaf),
+ OPT_UINT("units", 'u', &cfg.units, units),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ goto ret;
+
+ if (cfg.namespace_id == 0xffffffff) {
+ if (S_ISCHR(dev->direct.stat.st_mode)) {
+ fprintf(stderr, "namespace_id or blk device required\n");
+ err = EINVAL;
+ goto ret;
+ } else {
+ cfg.namespace_id = atoi(&dev->name[strlen(dev->name) - 1]);
+ }
+ }
+
+ if (!cfg.namespace_size) {
+ fprintf(stderr, "namespace_size required param\n");
+ err = EINVAL;
+ goto close_dev;
+ }
+
+ if (!cfg.namespace_cap) {
+ fprintf(stderr, "namespace_cap required param\n");
+ err = EINVAL;
+ goto close_dev;
+ }
+
+ err = nvme_expand_cap(dev, cfg.namespace_id, cfg.namespace_size, cfg.namespace_cap, cfg.lbaf, cfg.units);
+ if (err)
+ goto close_dev;
+
+ printf("%s: Success, create nsid:%d\n", cmd->name, cfg.namespace_id);
+
+close_dev:
+ dev_close(dev);
+ret:
+ return err;
+}
diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h
new file mode 100644
index 0000000..53e2217
--- /dev/null
+++ b/plugins/scaleflux/sfx-nvme.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/scaleflux/sfx-nvme
+
+#if !defined(SFX_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SFX_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("sfx", "ScaleFlux vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve ScaleFlux SMART Log, show it", get_additional_smart_log)
+ ENTRY("lat-stats", "Retrieve ScaleFlux IO Latency Statistics log, show it", get_lat_stats_log)
+ ENTRY("get-bad-block", "Retrieve bad block table of block device, show it", sfx_get_bad_block)
+ 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("dump-evtlog", "dump evtlog into file and parse warning & error log", sfx_dump_evtlog)
+ ENTRY("expand-cap", "expand the last namespace capacity lossless", sfx_expand_cap)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/seagate/seagate-diag.h b/plugins/seagate/seagate-diag.h
new file mode 100644
index 0000000..39f0d39
--- /dev/null
+++ b/plugins/seagate/seagate-diag.h
@@ -0,0 +1,388 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Do NOT modify or remove this copyright and license
+ *
+ * Copyright (c) 2017-2018 Seagate Technology LLC and/or its Affiliates, 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * \file seagate-diag.h
+ * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in.
+ *
+ * Author: Debabrata Bardhan <debabrata.bardhan@seagate.com>
+ */
+
+
+#ifndef SEAGATE_NVME_H
+#define SEAGATE_NVME_H
+
+#define SEAGATE_PLUGIN_VERSION_MAJOR 1
+#define SEAGATE_PLUGIN_VERSION_MINOR 2
+
+#define SEAGATE_OCP_PLUGIN_VERSION_MAJOR 1
+#define SEAGATE_OCP_PLUGIN_VERSION_MINOR 0
+
+#define PERSIST_FILE_SIZE (2764800)
+#define ONE_MB (1048576) /* (1024 * 1024) */
+#define PERSIST_CHUNK (65536) /* (1024 * 64) */
+#define FOUR_KB (4096)
+#define STX_NUM_LEGACY_DRV (123)
+
+
+const char* stx_jag_pan_mn[STX_NUM_LEGACY_DRV] = {"ST1000KN0002", "ST1000KN0012", "ST2000KN0002",
+ "ST2000KN0012", "ST4000KN0002", "XP1600HE10002",
+ "XP1600HE10012", "XP1600HE30002", "XP1600HE30012",
+ "XP1920LE10002", "XP1920LE10012", "XP1920LE30002",
+ "XP1920LE30012", "XP3200HE10002", "XP3200HE10012",
+ "XP3840LE10002", "XP3840LE10012", "XP400HE30002",
+ "XP400HE30012", "XP400HE30022", "XP400HE30032",
+ "XP480LE30002", "XP480LE30012", "XP480LE30022",
+ "XP480LE30032", "XP800HE10002", "XP800HE10012",
+ "XP800HE30002", "XP800HE30012", "XP800HE30022",
+ "XP800HE30032", "XP960LE10002", "XP960LE10012",
+ "XP960LE30002", "XP960LE30012", "XP960LE30022",
+ "XP960LE30032", "XP256LE30011", "XP256LE30021",
+ "XP7680LE80002", "XP7680LE80003", "XP15360LE80003",
+ "XP30720LE80003", "XP7200-1A2048", "XP7200-1A4096",
+ "XP7201-2A2048", "XP7201-2A4096", "XP7200-1A8192",
+ "ST1000HM0021", "ST1000HM0031", "ST1000HM0061",
+ "ST1000HM0071", "ST1000HM0081", "ST1200HM0001",
+ "ST1600HM0031", "ST1800HM0001", "ST1800HM0011",
+ "ST2000HM0011", "ST2000HM0031", "ST400HM0061",
+ "ST400HM0071", "ST500HM0021", "ST500HM0031",
+ "ST500HM0061", "ST500HM0071", "ST500HM0081",
+ "ST800HM0061", "ST800HM0071", "ST1600HM0011",
+ "ST1600KN0001", "ST1600KN0011", "ST1920HM0001",
+ "ST1920KN0001", "ST1920KN0011", "ST400HM0021",
+ "ST400KN0001", "ST400KN0011", "ST480HM0001",
+ "ST480KN0001", "ST480KN0011", "ST800HM0021",
+ "ST800KN0001", "ST800KN0011", "ST960HM0001",
+ "ST960KN0001", "ST960KN0011", "XF1441-1AA251024",
+ "XF1441-1AA252048", "XF1441-1AA25512", "XF1441-1AB251024",
+ "XF1441-1AB252048", "XF1441-1AB25512", "XF1441-1BA251024",
+ "XF1441-1BA252048", "XF1441-1BA25512", "XF1441-1BB251024",
+ "XF1441-1BB252048", "XF1441-1BB25512", "ST400HM0031",
+ "ST400KN0021", "ST400KN0031", "ST480HM0011",
+ "ST480KN0021", "ST480KN0031", "ST800HM0031",
+ "ST800KN0021", "ST800KN0031", "ST960HM0011",
+ "ST960KN0021", "ST960KN0031", "XM1441-1AA111024",
+ "XM1441-1AA112048", "XM1441-1AA11512", "XM1441-1AA801024",
+ "XM1441-1AA80512", "XM1441-1AB111024", "XM1441-1AB112048",
+ "XM1441-1BA111024", "XM1441-1BA112048", "XM1441-1BA11512",
+ "XM1441-1BA801024", "XM1441-1BA80512", "XM1441-1BB112048"};
+
+
+/***************************
+*Supported Log-Pages from FW
+***************************/
+
+typedef struct __attribute__((__packed__)) log_page_map_entry {
+ __u32 LogPageID;
+ __u32 LogPageSignature;
+ __u32 LogPageVersion;
+} log_page_map_entry;
+
+#define MAX_SUPPORTED_LOG_PAGE_ENTRIES ((4096 - sizeof(__u32)) / sizeof(log_page_map_entry))
+
+typedef struct __attribute__((__packed__)) log_page_map {
+ __u32 NumLogPages;
+ log_page_map_entry LogPageEntry[ MAX_SUPPORTED_LOG_PAGE_ENTRIES ];
+} log_page_map;
+/* EOF Supported Log-Pages from FW */
+
+
+/***************************
+* Extended-SMART Information
+***************************/
+#define NUMBER_EXTENDED_SMART_ATTRIBUTES 42
+
+typedef enum _EXTENDED_SMART_VERSION_
+{
+ EXTENDED_SMART_VERSION_NONE,
+ EXTENDED_SMART_VERSION_GEN,
+ EXTENDED_SMART_VERSION_VENDOR1,
+} EXTENDED_SMART_VERSION;
+
+typedef struct __attribute__((__packed__)) _SmartVendorSpecific
+{
+ __u8 AttributeNumber;
+ __u16 SmartStatus;
+ __u8 NominalValue;
+ __u8 LifetimeWorstValue;
+ __u32 Raw0_3;
+ __u8 RawHigh[3];
+} SmartVendorSpecific;
+
+typedef struct __attribute__((__packed__)) _EXTENDED_SMART_INFO_T
+{
+ __u16 Version;
+ SmartVendorSpecific vendorData[NUMBER_EXTENDED_SMART_ATTRIBUTES];
+ __u8 vendor_specific_reserved[6];
+} EXTENDED_SMART_INFO_T;
+
+typedef struct __attribute__((__packed__)) vendor_smart_attribute_data
+{
+ __u8 AttributeNumber;
+ __u8 Rsvd[3];
+ __u32 LSDword;
+ __u32 MSDword;
+} vendor_smart_attribute_data;
+
+struct __attribute__((__packed__)) nvme_temetry_log_hdr
+{
+ __u8 log_id;
+ __u8 rsvd1[4];
+ __u8 ieee_id[3];
+ __le16 tele_data_area1;
+ __le16 tele_data_area2;
+ __le16 tele_data_area3;
+ __u8 rsvd14[368];
+ __u8 tele_data_aval;
+ __u8 tele_data_gen_num;
+ __u8 reason_identifier[128];
+};
+
+typedef struct __attribute__((__packed__)) _U128
+{
+ __u64 LS__u64;
+ __u64 MS__u64;
+} U128;
+
+typedef struct __attribute__((__packed__)) _vendor_log_page_CF_Attr
+{
+ __u16 SuperCapCurrentTemperature;
+ __u16 SuperCapMaximumTemperature;
+ __u8 SuperCapStatus;
+ __u8 Reserved5to7[3];
+ U128 DataUnitsReadToDramNamespace;
+ U128 DataUnitsWrittenToDramNamespace;
+ __u64 DramCorrectableErrorCount;
+ __u64 DramUncorrectableErrorCount;
+} vendor_log_page_CF_Attr;
+
+typedef struct __attribute__((__packed__)) _vendor_log_page_CF
+{
+ vendor_log_page_CF_Attr AttrCF;
+ __u8 Vendor_Specific_Reserved[ 456 ]; /* 56-511 */
+} vendor_log_page_CF;
+
+typedef struct __attribute__((__packed__)) _STX_EXT_SMART_LOG_PAGE_C0
+{
+ U128 phyMediaUnitsWrt;
+ U128 phyMediaUnitsRd;
+ __u64 badUsrNandBlocks;
+ __u64 badSysNandBlocks;
+ __u64 xorRecoveryCnt;
+ __u64 ucRdEc;
+ __u64 softEccEc;
+ __u64 etoeCrrCnt;
+ __u64 sysDataUsed : 8;
+ __u64 refreshCount : 56;
+ __u64 usrDataEraseCnt;
+ __u16 thermalThrottling;
+ __u8 dssdSpecVerErrata;
+ __u16 dssdSpecVerPoint;
+ __u16 dssdSpecVerMinor;
+ __u8 dssdSpecVerMajor;
+ __u64 pcieCorrEc;
+ __u32 incompleteShutdowns;
+ __u32 rsvd_116_119;
+ __u8 freeBlocks;
+ __u8 rsvd_121_127[7];
+ __u16 capHealth;
+ __u8 nvmeErrataVer;
+ __u8 rsvd_131_135[5];
+ __u64 unalignedIO;
+ __u64 secVerNum;
+ __u64 totalNUSE;
+ U128 plpStartCnt;
+ U128 enduranceEstimate;
+ __u64 pcieLinkRetCnt;
+ __u64 powStateChangeCnt;
+ __u8 rsvd_208_493[286];
+ __u16 logPageVer;
+ U128 logPageGUID;
+} STX_EXT_SMART_LOG_PAGE_C0;
+
+/* EOF Extended-SMART Information*/
+
+
+/**************************
+* PCIE ERROR INFORMATION
+**************************/
+typedef struct __attribute__((__packed__)) pcie_error_log_page
+{
+ __u32 Version;
+ __u32 BadDllpErrCnt;
+ __u32 BadTlpErrCnt;
+ __u32 RcvrErrCnt;
+ __u32 ReplayTOErrCnt;
+ __u32 ReplayNumRolloverErrCnt;
+ __u32 FCProtocolErrCnt;
+ __u32 DllpProtocolErrCnt;
+ __u32 CmpltnTOErrCnt;
+ __u32 RcvrQOverflowErrCnt;
+ __u32 UnexpectedCplTlpErrCnt;
+ __u32 CplTlpURErrCnt;
+ __u32 CplTlpCAErrCnt;
+ __u32 ReqCAErrCnt;
+ __u32 ReqURErrCnt;
+ __u32 EcrcErrCnt;
+ __u32 MalformedTlpErrCnt;
+ __u32 CplTlpPoisonedErrCnt;
+ __u32 MemRdTlpPoisonedErrCnt;
+} pcie_error_log_page;
+/*EOF PCIE ERROR INFORMATION */
+
+/**************************************
+* FW Activation History Log INFORMATION
+***************************************/
+
+typedef struct __attribute__((__packed__)) _stx_fw_activ_his_ele
+{
+ __u8 entryVerNum;
+ __u8 entryLen;
+ __u16 rev02_03;
+ __u16 fwActivCnt;
+ __u64 timeStamp;
+ __u64 rev14_21;
+ __u64 powCycleCnt;
+ __u8 previousFW[8];
+ __u8 newFW[8];
+ __u8 slotNum;
+ __u8 commitActionType;
+ __u16 result;
+ __u8 rev50_63[14];
+} stx_fw_activ_his_ele;
+
+typedef struct __attribute__((__packed__)) _stx_fw_activ_history_log_page
+{
+ __u8 logID;
+ __u8 rev01_03[3];
+ __u32 numValidFwActHisEnt;
+ stx_fw_activ_his_ele fwActHisEnt[20];
+ __u8 rev1288_4077[2790];
+ __u16 logPageVer;
+ __u8 logPageGUID[16];
+} stx_fw_activ_history_log_page;
+
+/* FW Activation History Log INFORMATION */
+
+
+typedef enum
+{
+ VS_ATTR_SOFT_READ_ERROR_RATE, /* 0 OFFSET : 02 -13 bytes */
+ VS_ATTR_REALLOCATED_SECTOR_COUNT, /* 1 OFFSET : 14 -25 bytes */
+ VS_ATTR_POWER_ON_HOURS, /* 2 OFFSET : 26 -37 bytes */
+ VS_ATTR_POWER_FAIL_EVENT_COUNT, /* 3 OFFSET : 38 -49 bytes */
+ VS_ATTR_DEVICE_POWER_CYCLE_COUNT, /* 4 OFFSET : 50 -61 bytes */
+ VS_ATTR_GB_ERASED, /* 5 OFFSET : 62 -73 bytes */
+ VS_ATTR_LIFETIME_DEVSLEEP_EXIT_COUNT, /* 6 OFFSET : 74 -85 bytes */
+ VS_ATTR_LIFETIME_ENTERING_PS4_COUNT, /* 7 OFFSET : 86 -97 bytes */
+ VS_ATTR_LIFETIME_ENTERING_PS3_COUNT, /* 8 OFFSET : 98 -109 bytes */
+ VS_ATTR_RETIRED_BLOCK_COUNT, /* 9 OFFSET : 110 -121 bytes */
+ VS_ATTR_PROGRAM_FAILURE_COUNT, /* 10 OFFSET : 122 -133 bytes */
+ VS_ATTR_ERASE_FAIL_COUNT, /* 11 OFFSET : 134 -145 bytes */
+ VS_ATTR_AVG_ERASE_COUNT, /* 12 OFFSET : 146 -157 bytes */
+ VS_ATTR_UNEXPECTED_POWER_LOSS_COUNT, /* 13 OFFSET : 158 -169 bytes */
+ VS_ATTR_WEAR_RANGE_DELTA, /* 14 OFFSET : 170 -181 bytes */
+ VS_ATTR_SATA_INTERFACE_DOWNSHIFT_COUNT, /* 15 OFFSET : 182 -193 bytes */
+ VS_ATTR_END_TO_END_CRC_ERROR_COUNT, /* 16 OFFSET : 194 -205 bytes */
+ VS_ATTR_MAX_LIFE_TEMPERATURE, /* 17 OFFSET : 206 -217 bytes */
+ VS_ATTR_UNCORRECTABLE_RAISE_ERRORS, /* 18 OFFSET : 218 -229 bytes */
+ VS_ATTR_DRIVE_LIFE_PROTECTION_STATUS, /* 19 OFFSET : 230 -241 bytes */
+ VS_ATTR_REMAINING_SSD_LIFE, /* 20 OFFSET : 242 -253 bytes */
+ VS_ATTR_LIFETIME_WRITES_TO_FLASH, /* 21 OFFSET : 254 -265 bytes */
+ VS_ATTR_LIFETIME_WRITES_FROM_HOST, /* 22 OFFSET : 266 -277 bytes */
+ VS_ATTR_LIFETIME_READS_TO_HOST, /* 23 OFFSET : 278 -289 bytes */
+ VS_ATTR_FREE_SPACE, /* 24 OFFSET : 290 -301 bytes */
+ VS_ATTR_TRIM_COUNT_LSB, /* 25 OFFSET : 302 -313 bytes */
+ VS_ATTR_TRIM_COUNT_MSB, /* 26 OFFSET : 314 -325 bytes */
+ VS_ATTR_OP_PERCENTAGE, /* 27 OFFSET : 326 -337 bytes */
+ VS_ATTR_RAISE_ECC_CORRECTABLE_ERROR_COUNT, /* 28 OFFSET : 338 -349 bytes */
+ VS_ATTR_UNCORRECTABLE_ECC_ERRORS , /* 29 OFFSET : 350 -361 bytes */
+ VS_ATTR_LIFETIME_WRITES0_TO_FLASH, /* 30 OFFSET : 362-372 bytes */
+ VS_ATTR_LIFETIME_WRITES1_TO_FLASH, /* 31 OFFSET : 374-385 bytes */
+ VS_ATTR_LIFETIME_WRITES0_FROM_HOST, /* 32 OFFSET : 386-397 bytes */
+ VS_ATTR_LIFETIME_WRITES1_FROM_HOST, /* 33 OFFSET : 398-409 bytes */
+ VS_ATTR_LIFETIME_READ0_FROM_HOST, /* 34 OFFSET : 410-421 bytes */
+ VS_ATTR_LIFETIME_READ1_FROM_HOST, /* 35 OFFSET : 422-433 bytes */
+ VS_ATTR_PCIE_PHY_CRC_ERROR, /* 36 OFFSET : 434-445 bytes */
+ VS_ATTR_BAD_BLOCK_COUNT_SYSTEM, /* 37 OFFSET : 446-457 bytes */
+ VS_ATTR_BAD_BLOCK_COUNT_USER, /* 38 OFFSET : 458-469 bytes */
+ VS_ATTR_THERMAL_THROTTLING_STATUS, /* 39 OFFSET : 470-481 bytes */
+ VS_ATTR_POWER_CONSUMPTION, /* 40 OFFSET : 482-493 bytes */
+ VS_ATTR_MAX_SOC_LIFE_TEMPERATURE, /* 41 OFFSET : 494-505 bytes */
+ VS_MAX_ATTR_NUMBER
+} extended_smart_attributes;
+
+/*Smart attribute IDs */
+
+typedef enum
+{
+ VS_ATTR_ID_SOFT_READ_ERROR_RATE = 1,
+ VS_ATTR_ID_REALLOCATED_SECTOR_COUNT = 5,
+ VS_ATTR_ID_POWER_ON_HOURS = 9,
+ VS_ATTR_ID_POWER_FAIL_EVENT_COUNT = 11,
+ VS_ATTR_ID_DEVICE_POWER_CYCLE_COUNT = 12,
+ VS_ATTR_ID_RAW_READ_ERROR_RATE = 13,
+ VS_ATTR_ID_GROWN_BAD_BLOCK_COUNT = 40,
+ VS_ATTR_ID_END_2_END_CORRECTION_COUNT = 41,
+ VS_ATTR_ID_MIN_MAX_WEAR_RANGE_COUNT = 42,
+ VS_ATTR_ID_REFRESH_COUNT = 43,
+ VS_ATTR_ID_BAD_BLOCK_COUNT_USER = 44,
+ VS_ATTR_ID_BAD_BLOCK_COUNT_SYSTEM = 45,
+ VS_ATTR_ID_THERMAL_THROTTLING_STATUS = 46,
+ VS_ATTR_ID_ALL_PCIE_CORRECTABLE_ERROR_COUNT = 47,
+ VS_ATTR_ID_ALL_PCIE_UNCORRECTABLE_ERROR_COUNT = 48,
+ VS_ATTR_ID_INCOMPLETE_SHUTDOWN_COUNT = 49,
+ VS_ATTR_ID_GB_ERASED_LSB = 100,
+ VS_ATTR_ID_GB_ERASED_MSB = 101,
+ VS_ATTR_ID_LIFETIME_ENTERING_PS4_COUNT = 102,
+ VS_ATTR_ID_LIFETIME_ENTERING_PS3_COUNT = 103,
+ VS_ATTR_ID_LIFETIME_DEVSLEEP_EXIT_COUNT = 104,
+ VS_ATTR_ID_RETIRED_BLOCK_COUNT = 170,
+ VS_ATTR_ID_PROGRAM_FAILURE_COUNT = 171,
+ VS_ATTR_ID_ERASE_FAIL_COUNT = 172,
+ VS_ATTR_ID_AVG_ERASE_COUNT = 173,
+ VS_ATTR_ID_UNEXPECTED_POWER_LOSS_COUNT = 174,
+ VS_ATTR_ID_WEAR_RANGE_DELTA = 177,
+ VS_ATTR_ID_SATA_INTERFACE_DOWNSHIFT_COUNT = 183,
+ VS_ATTR_ID_END_TO_END_CRC_ERROR_COUNT = 184,
+ VS_ATTR_ID_UNCORRECTABLE_READ_ERRORS = 188,
+ VS_ATTR_ID_MAX_LIFE_TEMPERATURE = 194,
+ VS_ATTR_ID_RAISE_ECC_CORRECTABLE_ERROR_COUNT = 195,
+ VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS = 198,
+ VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS = 230,
+ VS_ATTR_ID_REMAINING_SSD_LIFE = 231,
+ VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB = 233,
+ VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB = 234,
+ VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB = 241,
+ VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB = 242,
+ VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB = 243,
+ VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB = 244,
+ VS_ATTR_ID_FREE_SPACE = 245,
+ VS_ATTR_ID_TRIM_COUNT_LSB = 250,
+ VS_ATTR_ID_TRIM_COUNT_MSB = 251,
+ VS_ATTR_ID_OP_PERCENTAGE = 252,
+ VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE = 253,
+} smart_attributes_ids;
+
+#define TELEMETRY_BLOCKS_TO_READ 8
+
+void seaget_d_raw(unsigned char *buf, int len, int fd);
+
+
+#define DP_CLASS_ID_FULL 0
+
+#endif
diff --git a/plugins/seagate/seagate-nvme.c b/plugins/seagate/seagate-nvme.c
new file mode 100644
index 0000000..887e5bc
--- /dev/null
+++ b/plugins/seagate/seagate-nvme.c
@@ -0,0 +1,1968 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Do NOT modify or remove this copyright and license
+ *
+ * Copyright (c) 2017-2018 Seagate Technology LLC and/or its Affiliates, 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * \file seagate-nvme.c
+ * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in.
+ *
+ * Author: Debabrata Bardhan <debabrata.bardhan@seagate.com>
+ */
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+#include <time.h>
+
+#define CREATE_CMD
+
+#include "seagate-nvme.h"
+#include "seagate-diag.h"
+
+
+/***************************************
+ * Command for "log-pages-supp"
+ ***************************************/
+static char *log_pages_supp_print(__u32 pageID)
+{
+ switch (pageID) {
+ case 0x01:
+ return "ERROR_INFORMATION";
+ case 0x02:
+ return "SMART_INFORMATION";
+ case 0x03:
+ return "FW_SLOT_INFORMATION";
+ case 0x04:
+ return "CHANGED_NAMESPACE_LIST";
+ case 0x05:
+ return "COMMANDS_SUPPORTED_AND_EFFECTS";
+ case 0x06:
+ return "DEVICE_SELF_TEST";
+ case 0x07:
+ return "TELEMETRY_HOST_INITIATED";
+ case 0x08:
+ return "TELEMETRY_CONTROLLER_INITIATED";
+ case 0xC0:
+ return "VS_MEDIA_SMART_LOG";
+ case 0xC1:
+ return "VS_DEBUG_LOG1";
+ case 0xC2:
+ return "VS_SEC_ERROR_LOG_PAGE";
+ case 0xC3:
+ return "VS_LIFE_TIME_DRIVE_HISTORY";
+ case 0xC4:
+ return "VS_EXTENDED_SMART_INFO";
+ case 0xC5:
+ return "VS_LIST_SUPPORTED_LOG_PAGE";
+ case 0xC6:
+ return "VS_POWER_MONITOR_LOG_PAGE";
+ case 0xC7:
+ return "VS_CRITICAL_EVENT_LOG_PAGE";
+ case 0xC8:
+ return "VS_RECENT_DRIVE_HISTORY";
+ case 0xC9:
+ return "VS_SEC_ERROR_LOG_PAGE";
+ case 0xCA:
+ return "VS_LIFE_TIME_DRIVE_HISTORY";
+ case 0xCB:
+ return "VS_PCIE_ERROR_LOG_PAGE";
+ case 0xCF:
+ return "DRAM Supercap SMART Attributes";
+ case 0xD6:
+ return "VS_OEM2_WORK_LOAD";
+ case 0xD7:
+ return "VS_OEM2_FW_SECURITY";
+ case 0xD8:
+ return "VS_OEM2_REVISION";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int stx_is_jag_pan(char *devMN)
+{
+ int match_found = 1; /* found = 0, not_found = 1 */
+
+ for (int i = 0; i < STX_NUM_LEGACY_DRV; i++) {
+ match_found = strncmp(devMN, stx_jag_pan_mn[i], strlen(stx_jag_pan_mn[i]));
+ if (!match_found)
+ break;
+ }
+
+ return match_found;
+}
+
+
+static void json_log_pages_supp(log_page_map *logPageMap)
+{
+ struct json_object *root;
+ struct json_object *logPages;
+ __u32 i = 0;
+
+ root = json_create_object();
+ logPages = json_create_array();
+ json_object_add_value_array(root, "supported_log_pages", logPages);
+
+ for (i = 0; i < le32_to_cpu(logPageMap->NumLogPages); i++) {
+ struct json_object *lbaf = json_create_object();
+
+ json_object_add_value_int(lbaf, "logpage_id",
+ le32_to_cpu(logPageMap->LogPageEntry[i].LogPageID));
+ json_object_add_value_string(lbaf, "logpage_name",
+ log_pages_supp_print(le32_to_cpu(logPageMap->LogPageEntry[i].LogPageID)));
+
+ json_array_add_value_object(logPages, lbaf);
+ }
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static int log_pages_supp(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+ __u32 i = 0;
+ log_page_map logPageMap;
+ const char *desc = "Retrieve Seagate Supported Log-Page information for the given device ";
+ const char *output_format = "output in binary format";
+ struct nvme_dev *dev;
+ int fmt;
+
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+ err = nvme_get_log_simple(dev_fd(dev), 0xc5,
+ sizeof(logPageMap), &logPageMap);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ printf("Seagate Supported Log-pages count :%d\n",
+ le32_to_cpu(logPageMap.NumLogPages));
+ printf("%-15s %-30s\n", "LogPage-Id", "LogPage-Name");
+
+ for (fmt = 0; fmt < 45; fmt++)
+ printf("-");
+ printf("\n");
+ } else
+ json_log_pages_supp(&logPageMap);
+
+ for (i = 0; i < le32_to_cpu(logPageMap.NumLogPages); i++) {
+ if (strcmp(cfg.output_format, "json")) {
+ printf("0x%-15X",
+ le32_to_cpu(logPageMap.LogPageEntry[i].LogPageID));
+ printf("%-30s\n",
+ log_pages_supp_print(le32_to_cpu(logPageMap.LogPageEntry[i].LogPageID)));
+ }
+ }
+ }
+
+ if (err > 0)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
+
+/* EOF Command for "log-pages-supp" */
+
+/***************************************
+ * Extended-SMART Information
+ ***************************************/
+static char *print_ext_smart_id(__u8 attrId)
+{
+ switch (attrId) {
+ case VS_ATTR_ID_SOFT_READ_ERROR_RATE:
+ return "Soft ECC error count";
+ case VS_ATTR_ID_REALLOCATED_SECTOR_COUNT:
+ return "Bad NAND block count";
+ case VS_ATTR_ID_POWER_ON_HOURS:
+ return "Power On Hours";
+ case VS_ATTR_ID_POWER_FAIL_EVENT_COUNT:
+ return "Power Fail Event Count";
+ case VS_ATTR_ID_DEVICE_POWER_CYCLE_COUNT:
+ return "Device Power Cycle Count";
+ case VS_ATTR_ID_RAW_READ_ERROR_RATE:
+ return "Raw Read Error Count";
+ case VS_ATTR_ID_GROWN_BAD_BLOCK_COUNT:
+ return "Bad NAND block count";
+ case VS_ATTR_ID_END_2_END_CORRECTION_COUNT:
+ return "SSD End to end correction counts";
+ case VS_ATTR_ID_MIN_MAX_WEAR_RANGE_COUNT:
+ return "User data erase counts";
+ case VS_ATTR_ID_REFRESH_COUNT:
+ return "Refresh count";
+ case VS_ATTR_ID_BAD_BLOCK_COUNT_USER:
+ return "User data erase fail count";
+ case VS_ATTR_ID_BAD_BLOCK_COUNT_SYSTEM:
+ return "System area erase fail count";
+ case VS_ATTR_ID_THERMAL_THROTTLING_STATUS:
+ return "Thermal throttling status and count";
+ case VS_ATTR_ID_ALL_PCIE_CORRECTABLE_ERROR_COUNT:
+ return "PCIe Correctable Error count";
+ case VS_ATTR_ID_ALL_PCIE_UNCORRECTABLE_ERROR_COUNT:
+ return "PCIe Uncorrectable Error count";
+ case VS_ATTR_ID_INCOMPLETE_SHUTDOWN_COUNT:
+ return "Incomplete shutdowns";
+ case VS_ATTR_ID_GB_ERASED_LSB:
+ return "LSB of Flash GB erased";
+ case VS_ATTR_ID_GB_ERASED_MSB:
+ return "MSB of Flash GB erased";
+ case VS_ATTR_ID_LIFETIME_DEVSLEEP_EXIT_COUNT:
+ return "LIFETIME_DEV_SLEEP_EXIT_COUNT";
+ case VS_ATTR_ID_LIFETIME_ENTERING_PS4_COUNT:
+ return "LIFETIME_ENTERING_PS4_COUNT";
+ case VS_ATTR_ID_LIFETIME_ENTERING_PS3_COUNT:
+ return "LIFETIME_ENTERING_PS3_COUNT";
+ case VS_ATTR_ID_RETIRED_BLOCK_COUNT:
+ return "Retired block count";
+ case VS_ATTR_ID_PROGRAM_FAILURE_COUNT:
+ return "Program fail count";
+ case VS_ATTR_ID_ERASE_FAIL_COUNT:
+ return "Erase Fail Count";
+ case VS_ATTR_ID_AVG_ERASE_COUNT:
+ return "System data % used";
+ case VS_ATTR_ID_UNEXPECTED_POWER_LOSS_COUNT:
+ return "Unexpected power loss count";
+ case VS_ATTR_ID_WEAR_RANGE_DELTA:
+ return "Wear range delta";
+ case VS_ATTR_ID_SATA_INTERFACE_DOWNSHIFT_COUNT:
+ return "PCIE_INTF_DOWNSHIFT_COUNT";
+ case VS_ATTR_ID_END_TO_END_CRC_ERROR_COUNT:
+ return "E2E_CRC_ERROR_COUNT";
+ case VS_ATTR_ID_UNCORRECTABLE_READ_ERRORS:
+ return "Uncorrectable Read Error Count";
+ case VS_ATTR_ID_MAX_LIFE_TEMPERATURE:
+ return "Max lifetime temperature";
+ case VS_ATTR_ID_RAISE_ECC_CORRECTABLE_ERROR_COUNT:
+ return "RAIS_ECC_CORRECT_ERR_COUNT";
+ case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
+ return "Uncorrectable RAISE error count";
+ case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
+ return "DRIVE_LIFE_PROTECTION_STATUS";
+ case VS_ATTR_ID_REMAINING_SSD_LIFE:
+ return "Remaining SSD life";
+ case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB:
+ return "LSB of Physical (NAND) bytes written";
+ case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB:
+ return "MSB of Physical (NAND) bytes written";
+ case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB:
+ return "LSB of Physical (HOST) bytes written";
+ case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB:
+ return "MSB of Physical (HOST) bytes written";
+ case VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB:
+ return "LSB of Physical (NAND) bytes read";
+ case VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB:
+ return "MSB of Physical (NAND) bytes read";
+ case VS_ATTR_ID_FREE_SPACE:
+ return "Free Space";
+ case VS_ATTR_ID_TRIM_COUNT_LSB:
+ return "LSB of Trim count";
+ case VS_ATTR_ID_TRIM_COUNT_MSB:
+ return "MSB of Trim count";
+ case VS_ATTR_ID_OP_PERCENTAGE:
+ return "OP percentage";
+ case VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE:
+ return "Max lifetime SOC temperature";
+ default:
+ return "Un-Known";
+ }
+}
+
+static __u64 smart_attribute_vs(__u16 verNo, SmartVendorSpecific attr)
+{
+ __u64 val = 0;
+ vendor_smart_attribute_data *attrVendor;
+
+ /**
+ * These are all Vendor A specific attributes.
+ */
+ if (verNo >= EXTENDED_SMART_VERSION_VENDOR1) {
+ attrVendor = (vendor_smart_attribute_data *)&attr;
+ memcpy(&val, &(attrVendor->LSDword), sizeof(val));
+ return val;
+ } else
+ return le32_to_cpu(attr.Raw0_3);
+}
+
+static void print_smart_log(__u16 verNo, SmartVendorSpecific attr, int lastAttr)
+{
+ static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
+ lsbLifWrtFrmHost = 0, msbLifWrtFrmHost = 0, lsbLifRdToHost = 0, msbLifRdToHost = 0, lsbTrimCnt = 0, msbTrimCnt = 0;
+ char buf[40] = {0};
+ char strBuf[35] = {0};
+ int hideAttr = 0;
+
+ if (attr.AttributeNumber == VS_ATTR_ID_GB_ERASED_LSB) {
+ lsbGbErased = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_GB_ERASED_MSB) {
+ msbGbErased = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) {
+ lsbLifWrtToFlash = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB) {
+ msbLifWrtToFlash = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) {
+ lsbLifWrtFrmHost = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB) {
+ msbLifWrtFrmHost = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) {
+ lsbLifRdToHost = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB) {
+ msbLifRdToHost = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_TRIM_COUNT_LSB) {
+ lsbTrimCnt = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if (attr.AttributeNumber == VS_ATTR_ID_TRIM_COUNT_MSB) {
+ msbTrimCnt = smart_attribute_vs(verNo, attr);
+ hideAttr = 1;
+ }
+
+ if ((attr.AttributeNumber) && (hideAttr != 1)) {
+ printf("%-40s", print_ext_smart_id(attr.AttributeNumber));
+ printf("%-15d", attr.AttributeNumber);
+ printf(" 0x%016"PRIx64"\n", (uint64_t)smart_attribute_vs(verNo, attr));
+ }
+
+ if (lastAttr == 1) {
+ sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_GB_ERASED_LSB) + 7));
+ printf("%-40s", strBuf);
+
+ printf("%-15d", VS_ATTR_ID_GB_ERASED_MSB << 8 | VS_ATTR_ID_GB_ERASED_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbGbErased, (uint64_t)lsbGbErased);
+ printf(" %s\n", buf);
+
+ sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) + 7));
+ printf("%-40s", strBuf);
+
+ printf("%-15d", VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtToFlash, (uint64_t)lsbLifWrtToFlash);
+ printf(" %s\n", buf);
+
+ sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) + 7));
+ printf("%-40s", strBuf);
+
+ printf("%-15d", VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtFrmHost, (uint64_t)lsbLifWrtFrmHost);
+ printf(" %s\n", buf);
+
+ sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) + 7));
+ printf("%-40s", strBuf);
+
+ printf("%-15d", VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifRdToHost, (uint64_t)lsbLifRdToHost);
+ printf(" %s\n", buf);
+
+ sprintf(strBuf, "%s", (print_ext_smart_id(VS_ATTR_ID_TRIM_COUNT_LSB) + 7));
+ printf("%-40s", strBuf);
+
+ printf("%-15d", VS_ATTR_ID_TRIM_COUNT_MSB << 8 | VS_ATTR_ID_TRIM_COUNT_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbTrimCnt, (uint64_t)lsbTrimCnt);
+ printf(" %s\n", buf);
+
+ }
+}
+
+static void json_print_smart_log(struct json_object *root, EXTENDED_SMART_INFO_T *ExtdSMARTInfo)
+{
+ struct json_object *lbafs;
+ int index = 0;
+
+ static __u64 lsbGbErased = 0, msbGbErased = 0, lsbLifWrtToFlash = 0, msbLifWrtToFlash = 0,
+ lsbLifWrtFrmHost = 0, msbLifWrtFrmHost = 0, lsbLifRdToHost = 0, msbLifRdToHost = 0, lsbTrimCnt = 0, msbTrimCnt = 0;
+ char buf[40] = {0};
+
+ lbafs = json_create_array();
+ json_object_add_value_array(root, "Extended-SMART-Attributes", lbafs);
+
+ for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++) {
+ struct json_object *lbaf = json_create_object();
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber) {
+ json_object_add_value_string(lbaf, "attribute_name", print_ext_smart_id(ExtdSMARTInfo->vendorData[index].AttributeNumber));
+ json_object_add_value_int(lbaf, "attribute_id", ExtdSMARTInfo->vendorData[index].AttributeNumber);
+ json_object_add_value_int(lbaf, "attribute_value", smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]));
+ json_array_add_value_object(lbafs, lbaf);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_GB_ERASED_LSB)
+ lsbGbErased = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_GB_ERASED_MSB)
+ msbGbErased = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB)
+ lsbLifWrtToFlash = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB)
+ msbLifWrtToFlash = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB)
+ lsbLifWrtFrmHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB)
+ msbLifWrtFrmHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB)
+ lsbLifRdToHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB)
+ msbLifRdToHost = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_TRIM_COUNT_LSB)
+ lsbTrimCnt = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+
+ if (ExtdSMARTInfo->vendorData[index].AttributeNumber == VS_ATTR_ID_TRIM_COUNT_MSB)
+ msbTrimCnt = smart_attribute_vs(ExtdSMARTInfo->Version, ExtdSMARTInfo->vendorData[index]);
+ }
+ }
+
+ struct json_object *lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_GB_ERASED_LSB) + 7));
+
+ json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_GB_ERASED_MSB << 8 | VS_ATTR_ID_GB_ERASED_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbGbErased, (uint64_t)lsbGbErased);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(lbafs, lbaf);
+
+
+ lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB) + 7));
+
+ json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtToFlash, (uint64_t)lsbLifWrtToFlash);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(lbafs, lbaf);
+
+
+ lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB) + 7));
+
+ json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifWrtFrmHost, (uint64_t)lsbLifWrtFrmHost);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(lbafs, lbaf);
+
+
+ lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB) + 7));
+
+ json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB << 8 | VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbLifRdToHost, (uint64_t)lsbLifRdToHost);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(lbafs, lbaf);
+
+
+ lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", (print_ext_smart_id(VS_ATTR_ID_TRIM_COUNT_LSB) + 7));
+
+ json_object_add_value_int(lbaf, "attribute_id", VS_ATTR_ID_TRIM_COUNT_MSB << 8 | VS_ATTR_ID_TRIM_COUNT_LSB);
+
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", (uint64_t)msbTrimCnt, (uint64_t)lsbTrimCnt);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(lbafs, lbaf);
+}
+
+static void print_smart_log_CF(vendor_log_page_CF *pLogPageCF)
+{
+ __u64 currentTemp, maxTemp;
+
+ printf("\n\nSeagate DRAM Supercap SMART Attributes :\n");
+ printf("%-39s %-19s\n", "Description", "Supercap Attributes");
+
+ printf("%-40s", "Super-cap current temperature");
+ currentTemp = pLogPageCF->AttrCF.SuperCapCurrentTemperature;
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(currentTemp));
+
+ maxTemp = pLogPageCF->AttrCF.SuperCapMaximumTemperature;
+ printf("%-40s", "Super-cap maximum temperature");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(maxTemp));
+
+ printf("%-40s", "Super-cap status");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.SuperCapStatus));
+
+ printf("%-40s", "Data units read to DRAM namespace");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64));
+
+ printf("%-40s", "Data units written to DRAM namespace");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64));
+
+ printf("%-40s", "DRAM correctable error count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramCorrectableErrorCount));
+
+ printf("%-40s", "DRAM uncorrectable error count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageCF->AttrCF.DramUncorrectableErrorCount));
+}
+
+static void json_print_smart_log_CF(struct json_object *root, vendor_log_page_CF *pLogPageCF)
+{
+ struct json_object *logPages;
+ unsigned int currentTemp, maxTemp;
+ char buf[40];
+
+ logPages = json_create_array();
+ json_object_add_value_array(root, "DRAM Supercap SMART Attributes", logPages);
+ struct json_object *lbaf = json_create_object();
+
+ currentTemp = pLogPageCF->AttrCF.SuperCapCurrentTemperature;
+ json_object_add_value_string(lbaf, "attribute_name", "Super-cap current temperature");
+ json_object_add_value_int(lbaf, "attribute_value", currentTemp);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ maxTemp = pLogPageCF->AttrCF.SuperCapMaximumTemperature;
+ json_object_add_value_string(lbaf, "attribute_name", "Super-cap maximum temperature");
+ json_object_add_value_int(lbaf, "attribute_value", maxTemp);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Super-cap status");
+ json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.SuperCapStatus);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Data units read to DRAM namespace");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Data units written to DRAM namespace");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "DRAM correctable error count");
+ json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.DramCorrectableErrorCount);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "DRAM uncorrectable error count");
+ json_object_add_value_int(lbaf, "attribute_value", pLogPageCF->AttrCF.DramUncorrectableErrorCount);
+ json_array_add_value_object(logPages, lbaf);
+}
+
+
+static void print_stx_smart_log_C0(STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0)
+{
+ printf("\n\nSeagate SMART Health Attributes :\n");
+ printf("%-39s %-19s\n", "Description", "Health Attributes");
+
+ printf("%-40s", "Physical Media Units Written");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64),
+ le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64));
+
+ printf("%-40s", "Physical Media Units Read");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64),
+ le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64));
+
+ printf("%-40s", "Bad User NAND Blocks");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badUsrNandBlocks));
+
+ printf("%-40s", "Bad System NAND Blocks");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->badSysNandBlocks));
+
+ printf("%-40s", "XOR Recovery Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->xorRecoveryCnt));
+
+ printf("%-40s", "Uncorrectable Read Error Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->ucRdEc));
+
+ printf("%-40s", "Soft ECC Error Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->softEccEc));
+
+ printf("%-40s", "End to End Correction Counts");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->etoeCrrCnt));
+
+ printf("%-40s", "System Data Used in Parcent");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->sysDataUsed));
+
+ printf("%-40s", "Refresh Counts");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->refreshCount));
+
+ printf("%-40s", "User Data Erase Counts");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->usrDataEraseCnt));
+
+ printf("%-40s", "Thermal Throttling Status and Count");
+ printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->thermalThrottling));
+
+ printf("%-40s", "DSSD Specification Version");
+ printf(" %d.%d.%d.%d\n", pLogPageC0->dssdSpecVerMajor,
+ le16_to_cpu(pLogPageC0->dssdSpecVerMinor),
+ le16_to_cpu(pLogPageC0->dssdSpecVerPoint),
+ pLogPageC0->dssdSpecVerErrata);
+
+ printf("%-40s", "PCIe Correctable Error Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieCorrEc));
+
+ printf("%-40s", "Incomplete Shutdowns");
+ printf(" 0x%08x\n", le32_to_cpu(pLogPageC0->incompleteShutdowns));
+
+ printf("%-40s", "Free Blocks in Percent");
+ printf(" %d\n", pLogPageC0->freeBlocks);
+
+ printf("%-40s", "Capacitor Health");
+ printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->capHealth));
+
+ printf("%-40s", "NVMe Errata Version");
+ printf(" %c\n", pLogPageC0->nvmeErrataVer);
+
+ printf("%-40s", "Unaligned IO");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->unalignedIO));
+
+ printf("%-40s", "Security Version Number");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->secVerNum));
+
+ printf("%-40s", "Total Namespace Utilization");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->totalNUSE));
+
+ printf("%-40s", "PLP Start Count");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64),
+ le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64));
+
+ printf("%-40s", "Endurance Estimate");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64),
+ le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64));
+
+ printf("%-40s", "PCIe Link Retraining Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->pcieLinkRetCnt));
+
+ printf("%-40s", "Power State Change Count");
+ printf(" 0x%016"PRIx64"\n", le64_to_cpu(pLogPageC0->powStateChangeCnt));
+
+ printf("%-40s", "Log Page Version");
+ printf(" 0x%04x\n", le16_to_cpu(pLogPageC0->logPageVer));
+
+ printf("%-40s", "Log Page GUID");
+ printf(" 0x%016"PRIx64"%016"PRIx64"\n", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64),
+ le64_to_cpu(pLogPageC0->logPageGUID.LS__u64));
+}
+
+static void json_print_stx_smart_log_C0(struct json_object *root, STX_EXT_SMART_LOG_PAGE_C0 *pLogPageC0)
+{
+ struct json_object *logPages;
+ char buf[40];
+
+ logPages = json_create_array();
+ json_object_add_value_array(root, "Seagate SMART Health Attributes", logPages);
+
+ struct json_object *lbaf = json_create_object();
+
+ json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Written");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.MS__u64),
+ le64_to_cpu(pLogPageC0->phyMediaUnitsWrt.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Physical Media Units Read");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->phyMediaUnitsRd.MS__u64),
+ le64_to_cpu(pLogPageC0->phyMediaUnitsRd.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Bad User NAND Blocks");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badUsrNandBlocks));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Bad System NAND Blocks");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->badSysNandBlocks));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "XOR Recovery Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->xorRecoveryCnt));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Uncorrectable Read Error Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->ucRdEc));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Soft ECC Error Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->softEccEc));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "End to End Correction Counts");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->etoeCrrCnt));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "System Data Used in Parcent");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->sysDataUsed));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Refresh Counts");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->refreshCount));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "User Data Erase Counts");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->usrDataEraseCnt));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Thermal Throttling Status and Count");
+ json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->thermalThrottling));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "DSSD Specification Version");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "%d.%d.%d.%d", pLogPageC0->dssdSpecVerMajor,
+ le16_to_cpu(pLogPageC0->dssdSpecVerMinor),
+ le16_to_cpu(pLogPageC0->dssdSpecVerPoint),
+ pLogPageC0->dssdSpecVerErrata);
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "PCIe Correctable Error Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieCorrEc));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Incomplete Shutdowns");
+ json_object_add_value_int(lbaf, "attribute_value", le32_to_cpu(pLogPageC0->incompleteShutdowns));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Free Blocks in Percent");
+ json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->freeBlocks);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Capacitor Health");
+ json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->capHealth));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "NVMe Errata Version");
+ json_object_add_value_int(lbaf, "attribute_value", pLogPageC0->nvmeErrataVer);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Unaligned IO");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->unalignedIO));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Security Version Number");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->secVerNum));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Total Namespace Utilization");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->totalNUSE));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "PLP Start Count");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->plpStartCnt.MS__u64),
+ le64_to_cpu(pLogPageC0->plpStartCnt.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Endurance Estimate");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->enduranceEstimate.MS__u64),
+ le64_to_cpu(pLogPageC0->enduranceEstimate.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "PCIe Link Retraining Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->pcieLinkRetCnt));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Power State Change Count");
+ json_object_add_value_int(lbaf, "attribute_value", le64_to_cpu(pLogPageC0->powStateChangeCnt));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Log Page Version");
+ json_object_add_value_int(lbaf, "attribute_value", le16_to_cpu(pLogPageC0->logPageVer));
+ json_array_add_value_object(logPages, lbaf);
+
+ lbaf = json_create_object();
+ json_object_add_value_string(lbaf, "attribute_name", "Log Page GUID");
+ memset(buf, 0, sizeof(buf));
+ sprintf(buf, "0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageC0->logPageGUID.MS__u64),
+ le64_to_cpu(pLogPageC0->logPageGUID.LS__u64));
+ json_object_add_value_string(lbaf, "attribute_value", buf);
+ json_array_add_value_object(logPages, lbaf);
+}
+
+static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_id_ctrl ctrl;
+ char modelNo[40];
+ STX_EXT_SMART_LOG_PAGE_C0 ehExtSmart;
+ EXTENDED_SMART_INFO_T ExtdSMARTInfo;
+ vendor_log_page_CF logPageCF;
+ struct json_object *root = json_create_object();
+ struct json_object *lbafs = json_create_array();
+ struct json_object *lbafs_ExtSmart, *lbafs_DramSmart;
+
+ const char *desc = "Retrieve the Firmware Activation History for Seagate NVMe drives";
+ const char *output_format = "output in binary format";
+ struct nvme_dev *dev;
+ int err, index = 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),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ printf("Seagate Extended SMART Information :\n");
+
+
+ /**
+ * Here we should identify if the drive is a Panthor or Jaguar.
+ * Here we need to extract the model no from ctrl-id abd use it
+ * to determine drive family.
+ */
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err) {
+ memcpy(modelNo, ctrl.mn, sizeof(modelNo));
+ } else {
+ nvme_show_status(err);
+ return err;
+ }
+
+ if (!stx_is_jag_pan(modelNo)) {
+ err = nvme_get_log_simple(dev_fd(dev), 0xC4, sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ printf("%-39s %-15s %-19s\n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
+ for (index = 0; index < 80; index++)
+ printf("-");
+ printf("\n");
+ for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++)
+ print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1));
+
+ } else {
+ lbafs_ExtSmart = json_create_object();
+ json_print_smart_log(lbafs_ExtSmart, &ExtdSMARTInfo);
+
+ json_object_add_value_array(root, "SMART-Attributes", lbafs);
+ json_array_add_value_object(lbafs, lbafs_ExtSmart);
+ }
+
+ /**
+ * Next get Log Page 0xCF
+ */
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xCF, sizeof(logPageCF), &logPageCF);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ print_smart_log_CF(&logPageCF);
+ } else {
+ lbafs_DramSmart = json_create_object();
+ json_print_smart_log_CF(lbafs_DramSmart, &logPageCF);
+ json_array_add_value_object(lbafs, lbafs_DramSmart);
+ json_print_object(root, NULL);
+ }
+ } else if (!strcmp(cfg.output_format, "json")) {
+ json_print_object(root, NULL);
+ json_free_object(root);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ } else {
+ err = nvme_get_log_simple(dev_fd(dev), 0xC0, sizeof(ehExtSmart), &ehExtSmart);
+
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ print_stx_smart_log_C0(&ehExtSmart);
+ } else {
+ lbafs_ExtSmart = json_create_object();
+ json_print_stx_smart_log_C0(lbafs_ExtSmart, &ehExtSmart);
+
+ json_object_add_value_array(root, "SMART-Attributes", lbafs);
+ json_array_add_value_object(lbafs, lbafs_ExtSmart);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+ }
+ }
+
+ if (err > 0)
+ nvme_show_status(err);
+ }
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xC4,
+ sizeof(ExtdSMARTInfo), &ExtdSMARTInfo);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ printf("%-39s %-15s %-19s\n", "Description", "Ext-Smart-Id", "Ext-Smart-Value");
+ for (index = 0; index < 80; index++)
+ printf("-");
+ printf("\n");
+ for (index = 0; index < NUMBER_EXTENDED_SMART_ATTRIBUTES; index++)
+ print_smart_log(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index], index == (NUMBER_EXTENDED_SMART_ATTRIBUTES - 1));
+
+ } else {
+ lbafs_ExtSmart = json_create_object();
+ json_print_smart_log(lbafs_ExtSmart, &ExtdSMARTInfo);
+
+ json_object_add_value_array(root, "SMART-Attributes", lbafs);
+ json_array_add_value_object(lbafs, lbafs_ExtSmart);
+ }
+
+ /**
+ * Next get Log Page 0xCF
+ */
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xCF,
+ sizeof(logPageCF), &logPageCF);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json")) {
+ print_smart_log_CF(&logPageCF);
+ } else {
+ lbafs_DramSmart = json_create_object();
+ json_print_smart_log_CF(lbafs_DramSmart, &logPageCF);
+ json_array_add_value_object(lbafs, lbafs_DramSmart);
+ json_print_object(root, NULL);
+ }
+ } else if (!strcmp(cfg.output_format, "json")) {
+ json_print_object(root, NULL);
+ }
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+
+ return err;
+}
+
+/*EOF Extended-SMART Information */
+
+/***************************************
+ * Temperature-Stats information
+ ***************************************/
+static void json_temp_stats(__u32 temperature, __u32 PcbTemp, __u32 SocTemp, __u32 maxTemperature,
+ __u32 MaxSocTemp, __u32 cf_err, __u32 scCurrentTemp, __u32 scMaxTem)
+{
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Current temperature", temperature);
+ json_object_add_value_int(root, "Current PCB temperature", PcbTemp);
+ json_object_add_value_int(root, "Current SOC temperature", SocTemp);
+ json_object_add_value_int(root, "Highest temperature", maxTemperature);
+ json_object_add_value_int(root, "Max SOC temperature", MaxSocTemp);
+ if (!cf_err) {
+ json_object_add_value_int(root, "SuperCap Current temperature", scCurrentTemp);
+ json_object_add_value_int(root, "SuperCap Max temperature", scMaxTem);
+ }
+
+ json_print_object(root, NULL);
+}
+
+static int temp_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_smart_log smart_log;
+ EXTENDED_SMART_INFO_T ExtdSMARTInfo;
+ vendor_log_page_CF logPageCF;
+
+ int err, cf_err;
+ int index;
+ const char *desc = "Retrieve Seagate Temperature Stats information for the given device ";
+ const char *output_format = "output in binary format";
+ unsigned int temperature = 0, PcbTemp = 0, SocTemp = 0, scCurrentTemp = 0, scMaxTemp = 0;
+ unsigned long long maxTemperature = 0, MaxSocTemp = 0;
+ struct nvme_dev *dev;
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ printf("Seagate Temperature Stats Information :\n");
+ /*STEP-1 : Get Current Temperature from SMART */
+ err = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
+ if (!err) {
+ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
+ temperature = temperature ? temperature - 273 : 0;
+ PcbTemp = le16_to_cpu(smart_log.temp_sensor[0]);
+ PcbTemp = PcbTemp ? PcbTemp - 273 : 0;
+ SocTemp = le16_to_cpu(smart_log.temp_sensor[1]);
+ SocTemp = SocTemp ? SocTemp - 273 : 0;
+ if (strcmp(cfg.output_format, "json")) {
+ printf("%-20s : %u C\n", "Current Temperature", temperature);
+ printf("%-20s : %u C\n", "Current PCB Temperature", PcbTemp);
+ printf("%-20s : %u C\n", "Current SOC Temperature", SocTemp);
+ }
+ }
+
+ /* STEP-2 : Get Max temperature form Ext SMART-id 194 */
+ err = nvme_get_log_simple(dev_fd(dev), 0xC4,
+ 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) {
+ maxTemperature = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
+ maxTemperature = maxTemperature ? maxTemperature - 273 : 0;
+ if (strcmp(cfg.output_format, "json"))
+ printf("%-20s : %d C\n", "Highest Temperature", (unsigned int)maxTemperature);
+ }
+
+ if (ExtdSMARTInfo.vendorData[index].AttributeNumber == VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE) {
+ MaxSocTemp = smart_attribute_vs(ExtdSMARTInfo.Version, ExtdSMARTInfo.vendorData[index]);
+ MaxSocTemp = MaxSocTemp ? MaxSocTemp - 273 : 0;
+ if (strcmp(cfg.output_format, "json"))
+ printf("%-20s : %d C\n", "Max SOC Temperature", (unsigned int)MaxSocTemp);
+ }
+ }
+ } else {
+ if (err > 0)
+ nvme_show_status(err);
+ }
+
+ cf_err = nvme_get_log_simple(dev_fd(dev), 0xCF,
+ sizeof(ExtdSMARTInfo), &logPageCF);
+
+ if (!cf_err) {
+ scCurrentTemp = logPageCF.AttrCF.SuperCapCurrentTemperature;
+ scCurrentTemp = scCurrentTemp ? scCurrentTemp - 273 : 0;
+ printf("%-20s : %d C\n", "Super-cap Current Temperature", scCurrentTemp);
+
+ scMaxTemp = logPageCF.AttrCF.SuperCapMaximumTemperature;
+ scMaxTemp = scMaxTemp ? scMaxTemp - 273 : 0;
+ printf("%-20s : %d C\n", "Super-cap Max Temperature", scMaxTemp);
+ }
+
+ if (!strcmp(cfg.output_format, "json"))
+ json_temp_stats(temperature, PcbTemp, SocTemp, maxTemperature, MaxSocTemp, cf_err, scCurrentTemp, scMaxTemp);
+
+ dev_close(dev);
+ return err;
+}
+/* EOF Temperature Stats information */
+
+/***************************************
+ * PCIe error-log information
+ ***************************************/
+static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
+{
+ __u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt +
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt +
+ pcieErrorLog.ReplayNumRolloverErrCnt;
+ __u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt +
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt +
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt +
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt +
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt +
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt +
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
+
+ printf("%-45s : %u\n", "PCIe Correctable Error Count", correctPcieEc);
+ printf("%-45s : %u\n", "PCIe Un-Correctable Error Count", uncorrectPcieEc);
+ printf("%-45s : %u\n", "Unsupported Request Error Status (URES)", pcieErrorLog.ReqURErrCnt);
+ printf("%-45s : %u\n", "ECRC Error Status (ECRCES)", pcieErrorLog.EcrcErrCnt);
+ printf("%-45s : %u\n", "Malformed TLP Status (MTS)", pcieErrorLog.MalformedTlpErrCnt);
+ printf("%-45s : %u\n", "Receiver Overflow Status (ROS)", pcieErrorLog.RcvrQOverflowErrCnt);
+ printf("%-45s : %u\n", "Unexpected Completion Status(UCS)", pcieErrorLog.UnexpectedCplTlpErrCnt);
+ printf("%-45s : %u\n", "Completion Timeout Status (CTS)", pcieErrorLog.CmpltnTOErrCnt);
+ printf("%-45s : %u\n", "Flow Control Protocol Error Status (FCPES)", pcieErrorLog.FCProtocolErrCnt);
+ printf("%-45s : %u\n", "Poisoned TLP Status (PTS)", pcieErrorLog.MemRdTlpPoisonedErrCnt);
+ printf("%-45s : %u\n", "Data Link Protocol Error Status(DLPES)", pcieErrorLog.DllpProtocolErrCnt);
+ printf("%-45s : %u\n", "Replay Timer Timeout Status(RTS)", pcieErrorLog.ReplayTOErrCnt);
+ printf("%-45s : %u\n", "Replay_NUM Rollover Status(RRS)", pcieErrorLog.ReplayNumRolloverErrCnt);
+ printf("%-45s : %u\n", "Bad DLLP Status (BDS)", pcieErrorLog.BadDllpErrCnt);
+ printf("%-45s : %u\n", "Bad TLP Status (BTS)", pcieErrorLog.BadTlpErrCnt);
+ printf("%-45s : %u\n", "Receiver Error Status (RES)", pcieErrorLog.RcvrErrCnt);
+ printf("%-45s : %u\n", "Cpl TLP Unsupported Request Error Count", pcieErrorLog.CplTlpURErrCnt);
+ printf("%-45s : %u\n", "Cpl TLP Completion Abort Error Count", pcieErrorLog.CplTlpCAErrCnt);
+ printf("%-45s : %u\n", "Cpl TLP Poisoned Error Count", pcieErrorLog.CplTlpPoisonedErrCnt);
+ printf("%-45s : %u\n", "Request Completion Abort Error Count", pcieErrorLog.ReqCAErrCnt);
+ printf("%-45s : %s\n", "Advisory Non-Fatal Error Status(ANFES)", "Not Supported");
+ printf("%-45s : %s\n", "Completer Abort Status (CAS)", "Not Supported");
+}
+
+static void json_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
+{
+ struct json_object *root = json_create_object();
+ __u32 correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt +
+ pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt +
+ pcieErrorLog.ReplayNumRolloverErrCnt;
+ __u32 uncorrectPcieEc = pcieErrorLog.FCProtocolErrCnt + pcieErrorLog.DllpProtocolErrCnt +
+ pcieErrorLog.CmpltnTOErrCnt + pcieErrorLog.RcvrQOverflowErrCnt +
+ pcieErrorLog.UnexpectedCplTlpErrCnt + pcieErrorLog.CplTlpURErrCnt +
+ pcieErrorLog.CplTlpCAErrCnt + pcieErrorLog.ReqCAErrCnt +
+ pcieErrorLog.ReqURErrCnt + pcieErrorLog.EcrcErrCnt +
+ pcieErrorLog.MalformedTlpErrCnt + pcieErrorLog.CplTlpPoisonedErrCnt +
+ pcieErrorLog.MemRdTlpPoisonedErrCnt;
+
+ json_object_add_value_int(root, "PCIe Correctable Error Count", correctPcieEc);
+ json_object_add_value_int(root, "PCIe Un-Correctable Error Count", uncorrectPcieEc);
+ json_object_add_value_int(root, "Unsupported Request Error Status (URES)", pcieErrorLog.ReqURErrCnt);
+ json_object_add_value_int(root, "ECRC Error Status (ECRCES)", pcieErrorLog.EcrcErrCnt);
+ json_object_add_value_int(root, "Malformed TLP Status (MTS)", pcieErrorLog.MalformedTlpErrCnt);
+ json_object_add_value_int(root, "Receiver Overflow Status (ROS)", pcieErrorLog.RcvrQOverflowErrCnt);
+ json_object_add_value_int(root, "Unexpected Completion Status(UCS)", pcieErrorLog.UnexpectedCplTlpErrCnt);
+ json_object_add_value_int(root, "Completion Timeout Status (CTS)", pcieErrorLog.CmpltnTOErrCnt);
+ json_object_add_value_int(root, "Flow Control Protocol Error Status (FCPES)", pcieErrorLog.FCProtocolErrCnt);
+ json_object_add_value_int(root, "Poisoned TLP Status (PTS)", pcieErrorLog.MemRdTlpPoisonedErrCnt);
+ json_object_add_value_int(root, "Data Link Protocol Error Status(DLPES)", pcieErrorLog.DllpProtocolErrCnt);
+ json_object_add_value_int(root, "Replay Timer Timeout Status(RTS)", pcieErrorLog.ReplayTOErrCnt);
+ json_object_add_value_int(root, "Replay_NUM Rollover Status(RRS)", pcieErrorLog.ReplayNumRolloverErrCnt);
+ json_object_add_value_int(root, "Bad DLLP Status (BDS)", pcieErrorLog.BadDllpErrCnt);
+ json_object_add_value_int(root, "Bad TLP Status (BTS)", pcieErrorLog.BadTlpErrCnt);
+ json_object_add_value_int(root, "Receiver Error Status (RES)", pcieErrorLog.RcvrErrCnt);
+ json_object_add_value_int(root, "Cpl TLP Unsupported Request Error Count", pcieErrorLog.CplTlpURErrCnt);
+ json_object_add_value_int(root, "Cpl TLP Completion Abort Error Count", pcieErrorLog.CplTlpCAErrCnt);
+ json_object_add_value_int(root, "Cpl TLP Poisoned Error Count", pcieErrorLog.CplTlpPoisonedErrCnt);
+ json_object_add_value_int(root, "Request Completion Abort Error Count", pcieErrorLog.ReqCAErrCnt);
+ json_print_object(root, NULL);
+}
+
+static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ pcie_error_log_page pcieErrorLog;
+ struct nvme_dev *dev;
+
+ const char *desc = "Retrieve Seagate PCIe error counters for the given device ";
+ const char *output_format = "output in binary format";
+ int err;
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ printf("Seagate PCIe error counters Information :\n");
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xCB,
+ sizeof(pcieErrorLog), &pcieErrorLog);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json"))
+ print_vs_pcie_error_log(pcieErrorLog);
+ else
+ json_vs_pcie_error_log(pcieErrorLog);
+
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+ return err;
+}
+/* EOF PCIE error-log information */
+
+
+/***************************************
+ * FW Activation History log
+ ***************************************/
+static void print_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis)
+{
+ __u32 i;
+ char prev_fw[9] = {0};
+ char new_fw[9] = {0};
+ char buf[80];
+
+ if (fwActivHis.numValidFwActHisEnt > 0) {
+ printf("\n\nSeagate FW Activation History :\n");
+ printf("%-9s %-21s %-7s %-13s %-9s %-5s %-15s %-9s\n", "Counter ", " Timestamp ", " PCC ", "Previous FW ", "New FW ", "Slot", "Commit Action", "Result");
+
+ for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) {
+
+ printf(" %-4d ", fwActivHis.fwActHisEnt[i].fwActivCnt);
+
+ time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
+ struct tm ts = *localtime(&t);
+
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
+ printf(" %-20s ", buf);
+ printf("%-5" PRId64 " ",
+ (uint64_t)fwActivHis.fwActHisEnt[i].powCycleCnt);
+
+ memset(prev_fw, 0, sizeof(prev_fw));
+ memcpy(prev_fw, fwActivHis.fwActHisEnt[i].previousFW, sizeof(fwActivHis.fwActHisEnt[i].previousFW));
+ printf("%-8s ", prev_fw);
+
+ memset(new_fw, 0, sizeof(new_fw));
+ memcpy(new_fw, fwActivHis.fwActHisEnt[i].newFW, sizeof(fwActivHis.fwActHisEnt[i].newFW));
+ printf("%-8s ", new_fw);
+
+ printf(" %-2d ", fwActivHis.fwActHisEnt[i].slotNum);
+ printf(" 0x%02x ", fwActivHis.fwActHisEnt[i].commitActionType);
+ printf(" 0x%02x\n", fwActivHis.fwActHisEnt[i].result);
+ }
+ } else {
+ printf("%s\n", "Do not have valid FW Activation History");
+ }
+}
+
+static void json_stx_vs_fw_activate_history(stx_fw_activ_history_log_page fwActivHis)
+{
+ struct json_object *root = json_create_object();
+ __u32 i;
+
+ char buf[80];
+
+ struct json_object *historyLogPage = json_create_array();
+
+ json_object_add_value_array(root, "Seagate FW Activation History", historyLogPage);
+
+ if (fwActivHis.numValidFwActHisEnt > 0) {
+ for (i = 0; i < fwActivHis.numValidFwActHisEnt; i++) {
+ struct json_object *lbaf = json_create_object();
+ char prev_fw[8] = { 0 };
+ char new_fw[8] = { 0 };
+
+ json_object_add_value_int(lbaf, "Counter", fwActivHis.fwActHisEnt[i].fwActivCnt);
+
+ time_t t = fwActivHis.fwActHisEnt[i].timeStamp / 1000;
+ struct tm ts = *localtime(&t);
+
+ strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &ts);
+ printf(" %-20s ", buf);
+ json_object_add_value_string(lbaf, "Timestamp", buf);
+
+ json_object_add_value_int(lbaf, "PCC", fwActivHis.fwActHisEnt[i].powCycleCnt);
+ sprintf(prev_fw, "%s", fwActivHis.fwActHisEnt[i].previousFW);
+ json_object_add_value_string(lbaf, "Previous_FW", prev_fw);
+
+ sprintf(new_fw, "%s", fwActivHis.fwActHisEnt[i].newFW);
+ json_object_add_value_string(lbaf, "New_FW", new_fw);
+
+ json_object_add_value_int(lbaf, "Slot", fwActivHis.fwActHisEnt[i].slotNum);
+ json_object_add_value_int(lbaf, "Commit_Action", fwActivHis.fwActHisEnt[i].commitActionType);
+ json_object_add_value_int(lbaf, "Result", fwActivHis.fwActHisEnt[i].result);
+
+ json_array_add_value_object(historyLogPage, lbaf);
+ }
+ } else {
+ printf("%s\n", "Do not have valid FW Activation History");
+ }
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static int stx_vs_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ stx_fw_activ_history_log_page fwActivHis;
+ struct nvme_dev *dev;
+
+ const char *desc = "Retrieve FW Activate History for Seagate device ";
+ const char *output_format = "output in binary format";
+ int err;
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err < 0) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ printf("Seagate FW Activation History Information :\n");
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xC2, sizeof(fwActivHis), &fwActivHis);
+ if (!err) {
+ if (strcmp(cfg.output_format, "json"))
+ print_stx_vs_fw_activate_history(fwActivHis);
+ else
+ json_stx_vs_fw_activate_history(fwActivHis);
+
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ dev_close(dev);
+ return err;
+}
+/* EOF FW Activation History log information */
+
+
+static int clear_fw_activate_history(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Clear FW Activation History for the given Seagate device ";
+ const char *save = "specifies that the controller shall save the attribute";
+ int err;
+ struct nvme_dev *dev;
+ struct nvme_id_ctrl ctrl;
+ char modelNo[40];
+ __u32 result;
+
+ struct config {
+ bool save;
+ };
+
+ struct config cfg = {
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err < 0) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err) {
+ memcpy(modelNo, ctrl.mn, sizeof(modelNo));
+ } else {
+ nvme_show_status(err);
+ return err;
+ }
+
+ if (!stx_is_jag_pan(modelNo)) {
+ printf("\nDevice does not support Clear FW Activation History\n");
+ } else {
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = 0xC1,
+ .nsid = 0,
+ .cdw11 = 0x80000000,
+ .cdw12 = 0,
+ .save = 0,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (err)
+ fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n",
+ __func__);
+ }
+
+ if (err < 0) {
+ perror("set-feature");
+ return errno;
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+
+static int vs_clr_pcie_correctable_errs(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Clear Seagate PCIe Correctable counters for the given device ";
+ const char *save = "specifies that the controller shall save the attribute";
+
+ struct nvme_id_ctrl ctrl;
+ char modelNo[40];
+
+ struct nvme_dev *dev;
+
+ __u32 result;
+ int err;
+
+ struct config {
+ bool save;
+ };
+
+ struct config cfg = {
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err) {
+ memcpy(modelNo, ctrl.mn, sizeof(modelNo));
+ } else {
+ nvme_show_status(err);
+ return err;
+ }
+
+ if (!stx_is_jag_pan(modelNo)) {
+ err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
+ } else {
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = 0xC3,
+ .nsid = 0,
+ .cdw11 = 0x80000000,
+ .cdw12 = 0,
+ .save = 0,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (err)
+ fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n", __func__);
+ }
+
+ err = nvme_set_features_simple(dev_fd(dev), 0xE1, 0, 0xCB, cfg.save, &result);
+
+ if (err < 0) {
+ perror("set-feature");
+ return errno;
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+static int get_host_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Capture the Telemetry Host-Initiated Data in either hex-dump (default) or binary format";
+ const char *namespace_id = "desired namespace";
+ const char *log_specific = "1 - controller shall capture Data representing the internal\n"
+ "state of the controller at the time the command is processed.\n"
+ "0 - controller shall not update the Telemetry Host Initiated Data.";
+ const char *raw = "output in raw format";
+ struct nvme_temetry_log_hdr tele_log;
+ int blkCnt, maxBlk = 0, blksToGet;
+ struct nvme_dev *dev;
+ unsigned char *log;
+ __le64 offset = 0;
+ int err, dump_fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 log_id;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ .log_id = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("log_specific", 'i', &cfg.log_id, log_specific),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ dump_fd = STDOUT_FILENO;
+ cfg.log_id = (cfg.log_id << 8) | 0x07;
+ err = nvme_get_nsid_log(dev_fd(dev), false, cfg.log_id,
+ cfg.namespace_id,
+ sizeof(tele_log), (void *)(&tele_log));
+ if (!err) {
+ maxBlk = tele_log.tele_data_area3;
+ offset += 512;
+
+ if (!cfg.raw_binary) {
+ printf("Device:%s log-id:%d namespace-id:%#x\n",
+ dev->name, cfg.log_id,
+ cfg.namespace_id);
+ printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n",
+ tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3);
+
+ d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt = 0;
+
+ while (blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if (!blksToGet) {
+ dev_close(dev);
+ return err;
+ }
+
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ memset(log, 0, bytesToGet);
+
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = cfg.log_id,
+ .nsid = cfg.namespace_id,
+ .lpo = offset,
+ .lsp = 0,
+ .lsi = 0,
+ .rae = true,
+ .uuidx = 0,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = bytesToGet,
+ .log = (void *)log,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_get_log(&args);
+ if (!err) {
+ offset += (__le64)bytesToGet;
+
+ if (!cfg.raw_binary) {
+ printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
+
+ d((unsigned char *)log, bytesToGet, 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+static int get_ctrl_tele(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Capture the Telemetry Controller-Initiated Data in either hex-dump (default) or binary format";
+ const char *namespace_id = "desired namespace";
+ const char *raw = "output in raw format";
+ struct nvme_dev *dev;
+ int err, dump_fd;
+ struct nvme_temetry_log_hdr tele_log;
+ __le64 offset = 0;
+ __u16 log_id;
+ int blkCnt, maxBlk = 0, blksToGet;
+ unsigned char *log;
+
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ dump_fd = STDOUT_FILENO;
+
+ log_id = 0x08;
+ err = nvme_get_nsid_log(dev_fd(dev), false, log_id, cfg.namespace_id,
+ sizeof(tele_log), (void *)(&tele_log));
+ if (!err) {
+ maxBlk = tele_log.tele_data_area3;
+ offset += 512;
+
+ if (!cfg.raw_binary) {
+ printf("Device:%s namespace-id:%#x\n",
+ dev->name, cfg.namespace_id);
+ printf("Data Block 1 Last Block:%d Data Block 2 Last Block:%d Data Block 3 Last Block:%d\n",
+ tele_log.tele_data_area1, tele_log.tele_data_area2, tele_log.tele_data_area3);
+
+ d((unsigned char *)(&tele_log), sizeof(tele_log), 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt = 0;
+
+ while (blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if (!blksToGet)
+ return err;
+
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ return -EINVAL;
+ }
+
+ memset(log, 0, bytesToGet);
+
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = log_id,
+ .nsid = cfg.namespace_id,
+ .lpo = offset,
+ .lsp = 0,
+ .lsi = 0,
+ .rae = true,
+ .uuidx = 0,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = bytesToGet,
+ .log = (void *)log,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_get_log(&args);
+ if (!err) {
+ offset += (__le64)bytesToGet;
+
+ if (!cfg.raw_binary) {
+ printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
+
+ d((unsigned char *)log, bytesToGet, 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+void seaget_d_raw(unsigned char *buf, int len, int fd)
+{
+ if (write(fd, (void *)buf, len) <= 0)
+ printf("%s: Write Failed\n", __func__);
+}
+
+
+static int vs_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Capture the Telemetry Controller-Initiated Data in binary format";
+ const char *namespace_id = "desired namespace";
+
+ const char *file = "dump file";
+ struct nvme_dev *dev;
+ int err, dump_fd;
+ int flags = O_WRONLY | O_CREAT;
+ int mode = 0664;
+ struct nvme_temetry_log_hdr tele_log;
+ __le64 offset = 0;
+ __u16 log_id;
+ int blkCnt, maxBlk = 0, blksToGet;
+ unsigned char *log;
+
+ struct config {
+ __u32 namespace_id;
+ char *file;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ .file = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FILE("dump-file", 'f', &cfg.file, file),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ dump_fd = STDOUT_FILENO;
+ if (strlen(cfg.file)) {
+ dump_fd = open(cfg.file, flags, mode);
+ if (dump_fd < 0) {
+ perror(cfg.file);
+ dev_close(dev);
+ return -EINVAL;
+ }
+ }
+
+ log_id = 0x08;
+ err = nvme_get_nsid_log(dev_fd(dev), false, log_id, cfg.namespace_id,
+ sizeof(tele_log), (void *)(&tele_log));
+ if (!err) {
+ maxBlk = tele_log.tele_data_area3;
+ offset += 512;
+
+ seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt = 0;
+
+ while (blkCnt < maxBlk) {
+ unsigned long long bytesToGet;
+
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if (!blksToGet)
+ goto out;
+
+ bytesToGet = (unsigned long long)blksToGet * 512;
+ log = malloc(bytesToGet);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ memset(log, 0, bytesToGet);
+
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = log_id,
+ .nsid = cfg.namespace_id,
+ .lpo = offset,
+ .lsp = 0,
+ .lsi = 0,
+ .rae = true,
+ .uuidx = 0,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = bytesToGet,
+ .log = (void *)log,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_get_log(&args);
+ if (!err) {
+ offset += (__le64)bytesToGet;
+
+ seaget_d_raw((unsigned char *)log, bytesToGet, dump_fd);
+
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror("log page");
+ }
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+out:
+ if (strlen(cfg.file))
+ close(dump_fd);
+
+ dev_close(dev);
+ return err;
+}
+
+/*SEAGATE-PLUGIN Version */
+static int seagate_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ printf("Seagate-Plugin version : %d.%d\n",
+ SEAGATE_PLUGIN_VERSION_MAJOR,
+ SEAGATE_PLUGIN_VERSION_MINOR);
+ return 0;
+}
+/*EOF SEAGATE-PLUGIN Version */
+
+/*OCP SEAGATE-PLUGIN Version */
+static int stx_ocp_plugin_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ printf("Seagate-OCP-Plugin version : %d.%d\n",
+ SEAGATE_OCP_PLUGIN_VERSION_MAJOR,
+ SEAGATE_OCP_PLUGIN_VERSION_MINOR);
+ return 0;
+}
+/*EOF OCP SEAGATE-PLUGIN Version */
diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h
new file mode 100644
index 0000000..99f6327
--- /dev/null
+++ b/plugins/seagate/seagate-nvme.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Do NOT modify or remove this copyright and license
+ *
+ * Copyright (c) 2017-2018 Seagate Technology LLC and/or its Affiliates, 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * \file seagate-nvme.h
+ * \brief This file defines the functions and macros to make building a nvme-cli seagate plug-in.
+ *
+ * Author: Debabrata Bardhan <debabrata.bardhan@seagate.com>
+ */
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/seagate/seagate-nvme
+
+#if !defined(SEAGATE_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SEAGATE_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("seagate", "Seagate vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("vs-temperature-stats", "Retrieve Seagate temperature statistics ", temp_stats)
+ ENTRY("vs-log-page-sup", "Retrieve Seagate Supported Log-pages Information ", log_pages_supp)
+ ENTRY("vs-smart-add-log", "Retrieve Seagate extended-SMART Information ", vs_smart_log)
+ ENTRY("vs-pcie-stats", "Retrieve Seagate PCIe error statistics ", vs_pcie_error_log)
+ ENTRY("clear-pcie-correctable-errors", "Clear Seagate PCIe error statistics ", vs_clr_pcie_correctable_errs)
+ ENTRY("get-host-tele", "Retrieve Seagate Host-Initiated Telemetry ", get_host_tele)
+ ENTRY("get-ctrl-tele", "Retrieve Seagate Controller-Initiated Telemetry ", get_ctrl_tele)
+ ENTRY("vs-internal-log", "Retrieve Seagate Controller-Initiated Telemetry in binary format", vs_internal_log)
+ ENTRY("vs-fw-activate-history", "Retrieve the Firmware Activation History", stx_vs_fw_activate_history)
+ ENTRY("clear-fw-activate-history", "Clear Firmware Activation History", clear_fw_activate_history)
+ ENTRY("plugin-version", "Shows Seagate plugin's version information ", seagate_plugin_version)
+ ENTRY("cloud-SSD-plugin-version", "Shows OCP Seagate plugin's version information ", stx_ocp_plugin_version)
+ )
+);
+
+#endif
+#include "define_cmd.h"
diff --git a/plugins/sed/meson.build b/plugins/sed/meson.build
new file mode 100644
index 0000000..4a2e544
--- /dev/null
+++ b/plugins/sed/meson.build
@@ -0,0 +1,4 @@
+sources += [
+ 'plugins/sed/sed.c',
+ 'plugins/sed/sedopal_cmd.c',
+]
diff --git a/plugins/sed/sed.c b/plugins/sed/sed.c
new file mode 100644
index 0000000..0471e54
--- /dev/null
+++ b/plugins/sed/sed.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <linux/fs.h>
+#include <sys/stat.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "sedopal_cmd.h"
+#include <linux/sed-opal.h>
+
+#define CREATE_CMD
+#include "sed.h"
+
+OPT_ARGS(no_opts) = {
+ OPT_END()
+};
+
+OPT_ARGS(key_opts) = {
+ OPT_FLAG("ask-key", 'k', &sedopal_ask_key,
+ "prompt for SED authentication key"),
+ OPT_END()
+};
+
+OPT_ARGS(revert_opts) = {
+ OPT_FLAG("destructive", 'e', &sedopal_destructive_revert,
+ "destructive revert"),
+ OPT_FLAG("psid", 'p', &sedopal_psid_revert, "PSID revert"),
+ OPT_END()
+};
+
+
+/*
+ * Open the NVMe device specified on the command line. It must be the
+ * NVMe block device (e.g. /dev/nvme0n1).
+ */
+static int sed_opal_open_device(struct nvme_dev **dev, int argc, char **argv,
+ const char *desc, struct argconfig_commandline_options *opts)
+{
+ int err;
+
+ err = parse_and_open(dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!S_ISBLK((*dev)->direct.stat.st_mode)) {
+ fprintf(stderr,
+ "ERROR : The NVMe block device must be specified\n");
+ err = -EINVAL;
+ dev_close(*dev);
+ }
+
+ return err;
+}
+
+static int sed_opal_discover(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Query SED device and display locking features";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, no_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_discover(dev->direct.fd);
+
+ dev_close(dev);
+ return err;
+}
+
+static int sed_opal_initialize(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Initialize a SED device for locking";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, no_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_initialize(dev->direct.fd);
+ if (err != 0)
+ fprintf(stderr, "initialize: SED error - %s\n",
+ sedopal_error_to_text(err));
+
+ dev_close(dev);
+ return err;
+}
+
+static int sed_opal_revert(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Revert a SED device from locking state";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, revert_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_revert(dev->direct.fd);
+ if (err != 0)
+ fprintf(stderr, "revert: SED error - %s\n",
+ sedopal_error_to_text(err));
+
+ dev_close(dev);
+ return err;
+}
+
+static int sed_opal_lock(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Lock a SED device";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, key_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_lock(dev->direct.fd);
+ if (err != 0)
+ fprintf(stderr, "lock: SED error - %s\n",
+ sedopal_error_to_text(err));
+
+ dev_close(dev);
+ return err;
+}
+
+static int sed_opal_unlock(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Unlock a SED device";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, key_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_unlock(dev->direct.fd);
+ if (err != 0)
+ fprintf(stderr, "unlock: SED error - %s\n",
+ sedopal_error_to_text(err));
+
+ dev_close(dev);
+ return err;
+}
+
+static int sed_opal_password(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err;
+ const char *desc = "Change the locking password of a SED device";
+ struct nvme_dev *dev;
+
+ err = sed_opal_open_device(&dev, argc, argv, desc, no_opts);
+ if (err)
+ return err;
+
+ err = sedopal_cmd_password(dev->direct.fd);
+ if (err != 0)
+ fprintf(stderr, "password: SED error - %s\n",
+ sedopal_error_to_text(err));
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/sed/sed.h b/plugins/sed/sed.h
new file mode 100644
index 0000000..1618272
--- /dev/null
+++ b/plugins/sed/sed.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/sed/sed
+
+#include "cmd.h"
+#include <linux/sed-opal.h>
+
+PLUGIN(NAME("sed", "SED Opal Command Set", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("discover", "Discover SED Opal Locking Features", sed_opal_discover, "1")
+ ENTRY("initialize", "Initialize a SED Opal Device for locking", sed_opal_initialize)
+ ENTRY("revert", "Revert a SED Opal Device from locking", sed_opal_revert)
+ ENTRY("lock", "Lock a SED Opal Device", sed_opal_lock)
+ ENTRY("unlock", "Unlock a SED Opal Device", sed_opal_unlock)
+ ENTRY("password", "Change the SED Opal Device password", sed_opal_password)
+ )
+);
+
+#include "define_cmd.h"
diff --git a/plugins/sed/sedopal_cmd.c b/plugins/sed/sedopal_cmd.c
new file mode 100644
index 0000000..649e0b2
--- /dev/null
+++ b/plugins/sed/sedopal_cmd.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <linux/sed-opal.h>
+#include "sedopal_spec.h"
+#include "sedopal_cmd.h"
+
+/*
+ * ask user for key rather than obtaining it from kernel keyring
+ */
+bool sedopal_ask_key;
+
+/*
+ * initiate dialog to ask for and confirm new password
+ */
+bool sedopal_ask_new_key;
+
+/*
+ * perform a destructive drive revert
+ */
+bool sedopal_destructive_revert;
+
+/*
+ * perform a PSID drive revert
+ */
+bool sedopal_psid_revert;
+
+/*
+ * Map method status codes to error text
+ */
+static const char * const sedopal_errors[] = {
+ [SED_STATUS_SUCCESS] = "Success",
+ [SED_STATUS_NOT_AUTHORIZED] = "Host Not Authorized",
+ [SED_STATUS_OBSOLETE_1] = "Obsolete",
+ [SED_STATUS_SP_BUSY] = "SP Session Busy",
+ [SED_STATUS_SP_FAILED] = "SP Failed",
+ [SED_STATUS_SP_DISABLED] = "SP Disabled",
+ [SED_STATUS_SP_FROZEN] = "SP Frozen",
+ [SED_STATUS_NO_SESSIONS_AVAILABLE] = "No Sessions Available",
+ [SED_STATUS_UNIQUENESS_CONFLICT] = "Uniqueness Conflict",
+ [SED_STATUS_INSUFFICIENT_SPACE] = "Insufficient Space",
+ [SED_STATUS_INSUFFICIENT_ROWS] = "Insufficient Rows",
+ [SED_STATUS_OBSOLETE_2] = "Obsolete",
+ [SED_STATUS_INVALID_PARAMETER] = "Invalid Parameter",
+ [SED_STATUS_OBSOLETE_3] = "Obsolete",
+ [SED_STATUS_OBSOLETE_4] = "Obsolete",
+ [SED_STATUS_TPER_MALFUNCTION] = "TPER Malfunction",
+ [SED_STATUS_TRANSACTION_FAILURE] = "Transaction Failure",
+ [SED_STATUS_RESPONSE_OVERFLOW] = "Response Overflow",
+ [SED_STATUS_AUTHORITY_LOCKED_OUT] = "Authority Locked Out",
+};
+
+const char *sedopal_error_to_text(int code)
+{
+ if (code == SED_STATUS_FAIL)
+ return "Failed";
+
+ if (code == SED_STATUS_NO_METHOD_STATUS)
+ return "Method returned no status";
+
+ if (code < SED_STATUS_SUCCESS ||
+ code > SED_STATUS_AUTHORITY_LOCKED_OUT)
+ return("Unknown Error");
+
+ return sedopal_errors[code];
+}
+
+/*
+ * Read a user entered password and do some basic validity checks.
+ */
+char *sedopal_get_password(char *prompt)
+{
+ char *pass;
+ int len;
+
+ pass = getpass(prompt);
+ if (pass == NULL)
+ return NULL;
+
+ len = strlen(pass);
+ if (len < SEDOPAL_MIN_PASSWORD_LEN)
+ return NULL;
+
+ if (len > SEDOPAL_MAX_PASSWORD_LEN)
+ return NULL;
+
+ return pass;
+}
+
+/*
+ * Initialize a SED Opal key. The key can either specify that the actual
+ * key should be looked up in the kernel keyring, or it should be
+ * populated in the key by prompting the user.
+ */
+int sedopal_set_key(struct opal_key *key)
+{
+#if !HAVE_KEY_TYPE
+ /*
+ * If key_type isn't avaialable, force key prompt
+ */
+ sedopal_ask_key = true;
+#endif
+
+ if (sedopal_ask_key) {
+ char *pass;
+ char *prompt;
+
+ /*
+ * set proper prompt
+ */
+ if (sedopal_ask_new_key)
+ prompt = SEDOPAL_NEW_PW_PROMPT;
+ else {
+ if (sedopal_psid_revert)
+ prompt = SEDOPAL_PSID_PROMPT;
+ else
+ prompt = SEDOPAL_CURRENT_PW_PROMPT;
+ }
+
+ pass = sedopal_get_password(prompt);
+ if (pass == NULL)
+ return -EINVAL;
+
+#if HAVE_KEY_TYPE
+ key->key_type = OPAL_INCLUDED;
+#endif
+ key->key_len = strlen(pass);
+ memcpy(key->key, pass, key->key_len);
+
+ /*
+ * If getting a new key, ask for it to be re-entered
+ * and verify the two entries are the same.
+ */
+ if (sedopal_ask_new_key) {
+ pass = sedopal_get_password(SEDOPAL_REENTER_PW_PROMPT);
+ if (strncmp((char *)key->key, pass, key->key_len)) {
+ fprintf(stderr,
+ "Error: passwords don't match\n");
+ return -EINVAL;
+ }
+ }
+ } else {
+#if HAVE_KEY_TYPE
+ key->key_type = OPAL_KEYRING;
+#endif
+ key->key_len = 0;
+ }
+
+ key->lr = 0;
+
+ return 0;
+}
+
+/*
+ * Prepare a drive for SED Opal locking.
+ */
+int sedopal_cmd_initialize(int fd)
+{
+ int rc;
+ struct opal_key key;
+ struct opal_lr_act lr_act = {};
+ struct opal_user_lr_setup lr_setup = {};
+
+ sedopal_ask_key = true;
+ rc = sedopal_set_key(&key);
+ if (rc != 0)
+ return rc;
+
+ /*
+ * take ownership of the device
+ */
+ rc = ioctl(fd, IOC_OPAL_TAKE_OWNERSHIP, &key);
+ if (rc != 0) {
+ fprintf(stderr,
+ "Error: failed to take device ownership - %d\n", rc);
+ return rc;
+ }
+
+ /*
+ * activate lsp
+ */
+ lr_act.num_lrs = 1;
+ lr_act.sum = false;
+ lr_act.key = key;
+
+ rc = ioctl(fd, IOC_OPAL_ACTIVATE_LSP, &lr_act);
+ if (rc != 0) {
+ fprintf(stderr, "Error: failed to activate LSP - %d\n", rc);
+ return rc;
+ }
+
+ /*
+ * setup global locking range
+ */
+ lr_setup.range_start = 0;
+ lr_setup.range_length = 0;
+ lr_setup.RLE = true;
+ lr_setup.WLE = true;
+
+ lr_setup.session.opal_key = key;
+ lr_setup.session.sum = 0;
+ lr_setup.session.who = OPAL_ADMIN1;
+
+ rc = ioctl(fd, IOC_OPAL_LR_SETUP, &lr_setup);
+ if (rc != 0) {
+ fprintf(stderr,
+ "Error: failed to setup locking range - %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/*
+ * Lock a SED Opal drive
+ */
+int sedopal_cmd_lock(int fd)
+{
+
+ return sedopal_lock_unlock(fd, OPAL_LK);
+}
+
+/*
+ * Unlock a SED Opal drive
+ */
+int sedopal_cmd_unlock(int fd)
+{
+
+ return sedopal_lock_unlock(fd, OPAL_RW);
+}
+
+/*
+ * Prepare and issue an ioctl to lock/unlock a drive
+ */
+int sedopal_lock_unlock(int fd, int lock_state)
+{
+ int rc;
+ struct opal_lock_unlock opal_lu = {};
+
+ rc = sedopal_set_key(&opal_lu.session.opal_key);
+ if (rc != 0)
+ return rc;
+
+ opal_lu.session.sum = 0;
+ opal_lu.session.who = OPAL_ADMIN1;
+ opal_lu.l_state = lock_state;
+
+ rc = ioctl(fd, IOC_OPAL_LOCK_UNLOCK, &opal_lu);
+ if (rc != 0)
+ fprintf(stderr,
+ "Error: failed locking or unlocking - %d\n", rc);
+
+ /*
+ * If the unlock was successful, force a re-read of the
+ * partition table.
+ */
+ if (rc == 0) {
+ rc = ioctl(fd, BLKRRPART, 0);
+ if (rc != 0)
+ fprintf(stderr,
+ "Error: failed re-reading partition\n");
+ }
+
+ return rc;
+}
+
+/*
+ * Confirm a destructive drive so that data is inadvertently erased
+ */
+static bool sedopal_confirm_revert(void)
+{
+ int rc;
+ char ans;
+ bool confirmed = false;
+
+ /*
+ * verify that destructive revert is really the intention
+ */
+ fprintf(stdout,
+ "Destructive revert erases drive data. Continue (y/n)? ");
+ rc = fscanf(stdin, " %c", &ans);
+ if ((rc == 1) && (ans == 'y' || ans == 'Y')) {
+ fprintf(stdout, "Are you sure (y/n)? ");
+ rc = fscanf(stdin, " %c", &ans);
+ if ((rc == 1) && (ans == 'y' || ans == 'Y'))
+ confirmed = true;
+ }
+
+ return confirmed;
+}
+
+/*
+ * perform a destructive drive revert
+ */
+static int sedopal_revert_destructive(int fd)
+{
+ struct opal_key key;
+ int rc;
+
+ if (!sedopal_confirm_revert()) {
+ fprintf(stderr, "Aborting destructive revert\n");
+ return -1;
+ }
+
+ /*
+ * for destructive revert, require that key is provided
+ */
+ sedopal_ask_key = true;
+
+ rc = sedopal_set_key(&key);
+ if (rc == 0)
+ rc = ioctl(fd, IOC_OPAL_REVERT_TPR, &key);
+
+ return rc;
+}
+
+/*
+ * perform a PSID drive revert
+ */
+static int sedopal_revert_psid(int fd)
+{
+#ifdef IOC_OPAL_PSID_REVERT_TPR
+ struct opal_key key;
+ int rc;
+
+ if (!sedopal_confirm_revert()) {
+ fprintf(stderr, "Aborting PSID revert\n");
+ return -1;
+ }
+
+ rc = sedopal_set_key(&key);
+ if (rc == 0) {
+ rc = ioctl(fd, IOC_OPAL_PSID_REVERT_TPR, &key);
+ if (rc != 0)
+ fprintf(stderr, "PSID_REVERT_TPR rc %d\n", rc);
+ }
+
+ return rc;
+#else
+ fprintf(stderr, "ERROR : PSID revert is not supported\n");
+ return -EOPNOTSUPP;
+#endif /* IOC_OPAL_PSID_REVERT_TPR */
+}
+
+/*
+ * revert a drive from the provisioned state to a state where locking
+ * is disabled.
+ */
+int sedopal_cmd_revert(int fd)
+{
+ int rc;
+
+ /*
+ * for revert, require that key/PSID is provided
+ */
+ sedopal_ask_key = true;
+
+ if (sedopal_psid_revert) {
+ rc = sedopal_revert_psid(fd);
+ } else if (sedopal_destructive_revert) {
+ rc = sedopal_revert_destructive(fd);
+ } else {
+#ifdef IOC_OPAL_REVERT_LSP
+ struct opal_revert_lsp revert_lsp;
+
+ rc = sedopal_set_key(&revert_lsp.key);
+ if (rc != 0)
+ return rc;
+
+ revert_lsp.options = OPAL_PRESERVE;
+ revert_lsp.__pad = 0;
+
+ rc = ioctl(fd, IOC_OPAL_REVERT_LSP, &revert_lsp);
+#else
+ rc = -EOPNOTSUPP;
+#endif
+ }
+
+ if (rc != 0)
+ fprintf(stderr, "Error: failed reverting drive - %d\n", rc);
+
+ return rc;
+}
+
+/*
+ * Change the password of a drive. The existing password must be
+ * provided and the new password is confirmed by re-entry.
+ */
+int sedopal_cmd_password(int fd)
+{
+ int rc;
+ struct opal_new_pw new_pw = {};
+
+ new_pw.new_user_pw.who = OPAL_ADMIN1;
+ new_pw.new_user_pw.opal_key.lr = 0;
+ new_pw.session.who = OPAL_ADMIN1;
+ new_pw.session.sum = 0;
+ new_pw.session.opal_key.lr = 0;
+
+ /*
+ * get current key
+ */
+ sedopal_ask_key = true;
+ if (sedopal_set_key(&new_pw.session.opal_key) != 0)
+ return -EINVAL;
+
+ /*
+ * get new key
+ */
+ sedopal_ask_new_key = true;
+ if (sedopal_set_key(&new_pw.new_user_pw.opal_key) != 0)
+ return -EINVAL;
+
+ rc = ioctl(fd, IOC_OPAL_SET_PW, &new_pw);
+ if (rc != 0)
+ fprintf(stderr, "Error: failed setting password - %d\n", rc);
+
+ return rc;
+}
+
+/*
+ * Print the state of locking features.
+ */
+void sedopal_print_locking_features(uint8_t features)
+{
+ printf("Locking Features:\n");
+ printf("\tLocking Supported: %s\n",
+ (features & OPAL_FEATURE_LOCKING_SUPPORTED) ? "Yes" : "No");
+ printf("\tLocking Feature Enabled: %s\n",
+ (features & OPAL_FEATURE_LOCKING_ENABLED) ? "Yes" : "No");
+ printf("\tLocked: %s\n",
+ (features & OPAL_FEATURE_LOCKED) ? "Yes" : "No");
+}
+
+/*
+ * Query a drive to determine if it's SED Opal capable and
+ * it's current locking status.
+ */
+int sedopal_cmd_discover(int fd)
+{
+#ifdef IOC_OPAL_DISCOVERY
+ int rc;
+ bool sedopal_locking_supported = false;
+ struct opal_discovery discover;
+ struct level_0_discovery_header *dh;
+ struct level_0_discovery_features *feat;
+ struct level_0_discovery_features *feat_end;
+ uint16_t code;
+ uint8_t locking_flags;
+ char buf[4096];
+
+ discover.data = (__u64)buf;
+ discover.size = sizeof(buf);
+
+ rc = ioctl(fd, IOC_OPAL_DISCOVERY, &discover);
+ if (rc < 0) {
+ fprintf(stderr, "Error: ioctl IOC_OPAL_DISCOVERY failed\n");
+ return rc;
+ }
+
+ /*
+ * The returned buffer contains a level 0 discovery header
+ * folowed by an array of level 0 feature records.
+ *
+ * TCG Opal Specification v2.0.2 section 3.1.1
+ */
+ dh = (struct level_0_discovery_header *)buf;
+ feat = (struct level_0_discovery_features *)(dh + 1);
+ feat_end = (struct level_0_discovery_features *)
+ (buf + be32toh(dh->parameter_length));
+
+ /*
+ * iterate through all the features that were returned
+ */
+ while (feat < feat_end) {
+ code = be16toh(feat->code);
+ switch (code) {
+ case OPAL_FEATURE_CODE_LOCKING:
+ locking_flags = feat->feature;
+ break;
+ case OPAL_FEATURE_CODE_OPALV2:
+ sedopal_locking_supported = true;
+ break;
+ default:
+ break;
+ }
+
+ feat++;
+ }
+
+ rc = 0;
+ if (!sedopal_locking_supported) {
+ fprintf(stderr, "Error: device does not support SED Opal\n");
+ rc = -1;
+ } else
+ sedopal_print_locking_features(locking_flags);
+
+ return rc;
+#else /* IOC_OPAL_DISCOVERY */
+ fprintf(stderr, "ERROR : NVMe device discovery is not supported\n");
+ return -EOPNOTSUPP;
+#endif
+}
diff --git a/plugins/sed/sedopal_cmd.h b/plugins/sed/sedopal_cmd.h
new file mode 100644
index 0000000..3b6eae2
--- /dev/null
+++ b/plugins/sed/sedopal_cmd.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _SED_OPAL_CMD_H
+#define _SED_OPAL_CMD_H
+
+#define SEDOPAL_CURRENT_PW_PROMPT "Password: "
+#define SEDOPAL_NEW_PW_PROMPT "New Password: "
+#define SEDOPAL_REENTER_PW_PROMPT "Re-enter New Password: "
+#define SEDOPAL_PSID_PROMPT "PSID: "
+
+#define SEDOPAL_MIN_PASSWORD_LEN 8
+#define SEDOPAL_MAX_PASSWORD_LEN 32
+
+#define NVME_DEV_PATH "/dev/nvme"
+
+extern bool sedopal_ask_key;
+extern bool sedopal_ask_new_key;
+extern bool sedopal_destructive_revert;
+extern bool sedopal_psid_revert;
+
+/*
+ * Sub-commands supported by the sedopal command
+ */
+enum sedopal_cmds {
+ SEDOPAL_CMD_NOT_SPECIFIED = -1,
+ SEDOPAL_CMD_INITIALIZE = 0,
+ SEDOPAL_CMD_LOCK = 1,
+ SEDOPAL_CMD_UNLOCK = 2,
+ SEDOPAL_CMD_REVERT = 3,
+ SEDOPAL_CMD_PASSWORD = 4,
+ SEDOPAL_CMD_DISCOVER = 5,
+};
+
+struct cmd_table {
+ int (*cmd_handler)(int fd);
+};
+
+/*
+ * command handlers
+ */
+int sedopal_cmd_initialize(int fd);
+int sedopal_cmd_lock(int fd);
+int sedopal_cmd_unlock(int fd);
+int sedopal_cmd_revert(int fd);
+int sedopal_cmd_password(int fd);
+int sedopal_cmd_discover(int fd);
+
+/*
+ * utility functions
+ */
+int sedopal_open_nvme_device(char *device);
+int sedopal_lock_unlock(int fd, int lock_state);
+const char *sedopal_error_to_text(int code);
+
+#endif /* _SED_OPAL_CMD_H */
diff --git a/plugins/sed/sedopal_spec.h b/plugins/sed/sedopal_spec.h
new file mode 100644
index 0000000..7523060
--- /dev/null
+++ b/plugins/sed/sedopal_spec.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef _SED_OPAL_SPEC_H
+#define _SED_OPAL_SPEC_H
+
+/*
+ * TCP Storage Architecture Core Specification Version 2.01
+ * section 5.1.5 Method Status Codes
+ */
+enum sed_status_codes {
+ SED_STATUS_SUCCESS = 0x00,
+ SED_STATUS_NOT_AUTHORIZED = 0x01,
+ SED_STATUS_OBSOLETE_1 = 0x02,
+ SED_STATUS_SP_BUSY = 0x03,
+ SED_STATUS_SP_FAILED = 0x04,
+ SED_STATUS_SP_DISABLED = 0x05,
+ SED_STATUS_SP_FROZEN = 0x06,
+ SED_STATUS_NO_SESSIONS_AVAILABLE = 0x07,
+ SED_STATUS_UNIQUENESS_CONFLICT = 0x08,
+ SED_STATUS_INSUFFICIENT_SPACE = 0x09,
+ SED_STATUS_INSUFFICIENT_ROWS = 0x0A,
+ SED_STATUS_OBSOLETE_2 = 0x0B,
+ SED_STATUS_INVALID_PARAMETER = 0x0C,
+ SED_STATUS_OBSOLETE_3 = 0x0D,
+ SED_STATUS_OBSOLETE_4 = 0x0E,
+ SED_STATUS_TPER_MALFUNCTION = 0x0F,
+ SED_STATUS_TRANSACTION_FAILURE = 0x10,
+ SED_STATUS_RESPONSE_OVERFLOW = 0x11,
+ SED_STATUS_AUTHORITY_LOCKED_OUT = 0x12,
+ SED_STATUS_FAIL = 0x3F,
+ SED_STATUS_NO_METHOD_STATUS = 0x89,
+};
+
+/*
+ * Definitions from TCG Opal Specification v2.0.2
+ */
+
+/*
+ * level 0 feature codes - section 3.1.1
+ */
+#define OPAL_FEATURE_CODE_LOCKING 0x0002
+#define OPAL_FEATURE_CODE_OPALV2 0x0203
+
+/* locking features */
+#define OPAL_FEATURE_LOCKING_SUPPORTED 0x01
+#define OPAL_FEATURE_LOCKING_ENABLED 0x02
+#define OPAL_FEATURE_LOCKED 0x04
+
+
+/*
+ * discovery header as specified in section 3.1.1.1
+ */
+struct level_0_discovery_header {
+ uint32_t parameter_length;
+ uint32_t revision;
+ uint64_t reserved;
+ uint8_t vendor_specific[32];
+};
+
+/*
+ * level 0 features as specified in section 3.1.1.3
+ */
+struct level_0_discovery_features {
+ uint16_t code;
+ uint8_t version;
+ uint8_t length;
+ uint8_t feature;
+ uint8_t reserved[11];
+};
+
+#endif /* _SED_OPAL_SPEC_H */
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
new file mode 100644
index 0000000..d4db8c7
--- /dev/null
+++ b/plugins/shannon/shannon-nvme.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "shannon-nvme.h"
+
+enum {
+ PROGRAM_FAIL_CNT,
+ ERASE_FAIL_CNT,
+ WEARLEVELING_COUNT,
+ E2E_ERR_CNT,
+ CRC_ERR_CNT,
+ TIME_WORKLOAD_MEDIA_WEAR,
+ TIME_WORKLOAD_HOST_READS,
+ TIME_WORKLOAD_TIMER,
+ THERMAL_THROTTLE,
+ RETRY_BUFFER_OVERFLOW,
+ PLL_LOCK_LOSS,
+ NAND_WRITE,
+ HOST_WRITE,
+ SRAM_ERROR_CNT,
+ ADD_SMART_ITEMS,
+};
+
+#pragma pack(push, 1)
+struct nvme_shannon_smart_log_item {
+ __u8 rsv1[3];
+ __u8 norm;
+ __u8 rsv2;
+ union {
+ __u8 item_val[6];
+ struct wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct thermal_throttle {
+ __u8 st;
+ __u32 count;
+ } thermal_throttle;
+ };
+ __u8 _resv;
+};
+#pragma pack(pop)
+
+struct nvme_shannon_smart_log {
+ struct nvme_shannon_smart_log_item items[ADD_SMART_ITEMS];
+ __u8 vend_spec_resv;
+};
+
+static void show_shannon_smart_log(struct nvme_shannon_smart_log *smart, unsigned int nsid,
+ const char *devname)
+{
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
+ devname, nsid);
+ printf("key normalized value\n");
+ printf("program_fail_count : %3d%% %"PRIu64"\n",
+ smart->items[PROGRAM_FAIL_CNT].norm,
+ int48_to_long(smart->items[PROGRAM_FAIL_CNT].item_val));
+ printf("erase_fail_count : %3d%% %"PRIu64"\n",
+ smart->items[ERASE_FAIL_CNT].norm,
+ int48_to_long(smart->items[ERASE_FAIL_CNT].item_val));
+ printf("wear_leveling : %3d%% min: %u, max: %u, avg: %u\n",
+ smart->items[WEARLEVELING_COUNT].norm,
+ le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.min),
+ le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.max),
+ le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.avg));
+ printf("end_to_end_error_detection_count: %3d%% %"PRIu64"\n",
+ smart->items[E2E_ERR_CNT].norm,
+ int48_to_long(smart->items[E2E_ERR_CNT].item_val));
+ printf("crc_error_count : %3d%% %"PRIu64"\n",
+ smart->items[CRC_ERR_CNT].norm,
+ int48_to_long(smart->items[CRC_ERR_CNT].item_val));
+ printf("timed_workload_media_wear : %3d%% %.3f%%\n",
+ smart->items[TIME_WORKLOAD_MEDIA_WEAR].norm,
+ ((float)int48_to_long(smart->items[TIME_WORKLOAD_MEDIA_WEAR].item_val)) / 1024);
+ printf("timed_workload_host_reads : %3d%% %"PRIu64"%%\n",
+ smart->items[TIME_WORKLOAD_HOST_READS].norm,
+ int48_to_long(smart->items[TIME_WORKLOAD_HOST_READS].item_val));
+ printf("timed_workload_timer : %3d%% %"PRIu64" min\n",
+ smart->items[TIME_WORKLOAD_TIMER].norm,
+ int48_to_long(smart->items[TIME_WORKLOAD_TIMER].item_val));
+ printf("thermal_throttle_status : %3d%% CurTTSta: %u%%, TTCnt: %u\n",
+ smart->items[THERMAL_THROTTLE].norm,
+ smart->items[THERMAL_THROTTLE].thermal_throttle.st,
+ smart->items[THERMAL_THROTTLE].thermal_throttle.count);
+ printf("retry_buffer_overflow_count : %3d%% %"PRIu64"\n",
+ smart->items[RETRY_BUFFER_OVERFLOW].norm,
+ int48_to_long(smart->items[RETRY_BUFFER_OVERFLOW].item_val));
+ printf("pll_lock_loss_count : %3d%% %"PRIu64"\n",
+ smart->items[PLL_LOCK_LOSS].norm,
+ int48_to_long(smart->items[PLL_LOCK_LOSS].item_val));
+ printf("nand_bytes_written : %3d%% sectors: %"PRIu64"\n",
+ smart->items[NAND_WRITE].norm,
+ int48_to_long(smart->items[NAND_WRITE].item_val));
+ printf("host_bytes_written : %3d%% sectors: %"PRIu64"\n",
+ smart->items[HOST_WRITE].norm,
+ int48_to_long(smart->items[HOST_WRITE].item_val));
+ printf("sram_error_count : %3d%% %"PRIu64"\n",
+ smart->items[RETRY_BUFFER_OVERFLOW].norm,
+ int48_to_long(smart->items[SRAM_ERROR_CNT].item_val));
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_shannon_smart_log smart_log;
+ char *desc =
+ "Get Shannon 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 nvme_dev *dev;
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ };
+ int err;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+ err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ show_shannon_smart_log(&smart_log, cfg.namespace_id, dev->name);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+ dev_close(dev);
+ return err;
+}
+
+static int get_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Read operating parameters of the\n"
+ "specified controller. Operating parameters are grouped\n"
+ "and identified by Feature Identifiers; each Feature\n"
+ "Identifier contains one or more attributes that may affect\n"
+ "behavior of the feature. Each Feature has three possible\n"
+ "settings: default, saveable, and current. If a Feature is\n"
+ "saveable, it may be modified by set-feature. Default values\n"
+ "are vendor-specific and not changeable. Use set-feature to\n"
+ "change saveable Features.\n\n"
+ "Available additional feature id:\n"
+ "0x02: Shannon power management\n";
+ const char *raw = "show infos 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";
+ struct nvme_dev *dev;
+ void *buf = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ enum nvme_features_id feature_id;
+ __u8 sel;
+ __u32 cdw11;
+ __u32 data_len;
+ bool raw_binary;
+ bool human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .feature_id = 0,
+ .sel = 0,
+ .cdw11 = 0,
+ .data_len = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_BYTE("sel", 's', &cfg.sel, sel),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (cfg.sel > 7) {
+ fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
+ dev_close(dev);
+ return -EINVAL;
+ }
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ dev_close(dev);
+ exit(ENOMEM);
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ struct nvme_get_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = cfg.namespace_id,
+ .sel = cfg.sel,
+ .cdw11 = cfg.cdw11,
+ .uuidx = 0,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_get_features(&args);
+ if (err > 0)
+ nvme_show_status(err);
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static int set_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Modify the saveable or changeable\n"
+ "current operating parameters of the controller. Operating\n"
+ "parameters are grouped and identified by Feature\n"
+ "Identifiers. Feature settings can be applied to the entire\n"
+ "controller and all associated namespaces, or to only a few\n"
+ "namespace(s) associated with the controller. Default values\n"
+ "for each Feature are vendor-specific and may not be modified.\n"
+ "Use get-feature to determine which Features are supported by\n"
+ "the controller and are saveable/changeable.\n\n"
+ "Available additional feature id:\n"
+ "0x02: Shannon power management\n";
+ 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 ffd = STDIN_FILENO;
+ struct nvme_dev *dev;
+ void *buf = NULL;
+ __u32 result;
+ int err;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ __u32 data_len;
+ bool save;
+ };
+
+ struct config cfg = {
+ .file = "",
+ .namespace_id = 0,
+ .feature_id = 0,
+ .value = 0,
+ .data_len = 0,
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("feature-id", 'f', &cfg.feature_id, feature_id),
+ OPT_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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ dev_close(dev);
+ return -ENOMEM;
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ 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;
+ }
+ }
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ fprintf(stderr, "failed to read data buffer from input file\n");
+ err = EINVAL;
+ goto free;
+ }
+ }
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = cfg.feature_id,
+ .nsid = cfg.namespace_id,
+ .cdw11 = cfg.value,
+ .cdw12 = 0,
+ .save = cfg.save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (err < 0) {
+ perror("set-feature");
+ goto free;
+ }
+ if (!err) {
+ if (buf)
+ d(buf, cfg.data_len, 16, 1);
+ } else if (err > 0)
+ nvme_show_status(err);
+
+free:
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static int shannon_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, NULL);
+}
+
+
+
diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h
new file mode 100644
index 0000000..255bb6b
--- /dev/null
+++ b/plugins/shannon/shannon-nvme.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/shannon/shannon-nvme
+
+#if !defined(SHANNON_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SHANNON_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("shannon", "Shannon vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Shannon SMART Log, show it", get_additional_smart_log)
+ ENTRY("set-additioal-feature", "Set additional Shannon feature", set_additional_feature)
+ ENTRY("get-additional-feature", "Get additional Shannon feature", get_additional_feature)
+ ENTRY("id-ctrl", "Retrieve Shannon ctrl id, show it", shannon_id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/solidigm/meson.build b/plugins/solidigm/meson.build
new file mode 100644
index 0000000..052afa1
--- /dev/null
+++ b/plugins/solidigm/meson.build
@@ -0,0 +1,16 @@
+sources += [
+ 'plugins/solidigm/solidigm-id-ctrl.c',
+ 'plugins/solidigm/solidigm-util.c',
+ 'plugins/solidigm/solidigm-smart.c',
+ 'plugins/solidigm/solidigm-garbage-collection.c',
+ 'plugins/solidigm/solidigm-latency-tracking.c',
+ 'plugins/solidigm/solidigm-log-page-dir.c',
+ 'plugins/solidigm/solidigm-telemetry.c',
+ 'plugins/solidigm/solidigm-internal-logs.c',
+ 'plugins/solidigm/solidigm-market-log.c',
+ 'plugins/solidigm/solidigm-temp-stats.c',
+ 'plugins/solidigm/solidigm-get-drive-info.c',
+ 'plugins/solidigm/solidigm-ocp-version.c',
+]
+subdir('solidigm-telemetry')
+
diff --git a/plugins/solidigm/solidigm-garbage-collection.c b/plugins/solidigm/solidigm-garbage-collection.c
new file mode 100644
index 0000000..a37e9c5
--- /dev/null
+++ b/plugins/solidigm/solidigm-garbage-collection.c
@@ -0,0 +1,138 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+#include "solidigm-garbage-collection.h"
+#include "solidigm-util.h"
+
+struct __packed gc_item {
+ __le32 timer_type;
+ __le64 timestamp;
+};
+
+#define VU_GC_MAX_ITEMS 100
+struct garbage_control_collection_log {
+ __le16 version_major;
+ __le16 version_minor;
+ struct __packed gc_item item[VU_GC_MAX_ITEMS];
+ __u8 reserved[2892];
+};
+
+static void vu_gc_log_show_json(struct garbage_control_collection_log *payload, const char *devname)
+{
+ struct json_object *gc_entries = json_create_array();
+
+ for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
+ struct __packed gc_item item = payload->item[i];
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "timestamp", le64_to_cpu(item.timestamp));
+ json_object_add_value_int(entry, "timer_type", le32_to_cpu(item.timer_type));
+ json_array_add_value_object(gc_entries, entry);
+ }
+
+ json_print_object(gc_entries, NULL);
+ json_free_object(gc_entries);
+}
+
+static void vu_gc_log_show(struct garbage_control_collection_log *payload, const char *devname,
+ __u8 uuid_index)
+{
+ printf("Solidigm Garbage Collection Log for NVME device:%s UUID-idx:%d\n", devname,
+ uuid_index);
+ printf("Timestamp Timer Type\n");
+
+ for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
+ struct __packed gc_item item = payload->item[i];
+
+ printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
+ }
+}
+
+int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ int err;
+ __u8 uuid_index;
+
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err) {
+ fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ uuid_index = solidigm_get_vu_uuid_index(dev);
+
+ struct garbage_control_collection_log gc_log;
+ const int solidigm_vu_gc_log_id = 0xfd;
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &gc_log,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = solidigm_vu_gc_log_id,
+ .len = sizeof(gc_log),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .uuidx = uuid_index,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (!err) {
+ if (flags & BINARY)
+ d_raw((unsigned char *)&gc_log, sizeof(gc_log));
+ else if (flags & JSON)
+ vu_gc_log_show_json(&gc_log, dev->name);
+ else
+ vu_gc_log_show(&gc_log, dev->name, uuid_index);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-garbage-collection.h b/plugins/solidigm/solidigm-garbage-collection.h
new file mode 100644
index 0000000..a3e34b2
--- /dev/null
+++ b/plugins/solidigm/solidigm-garbage-collection.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-get-drive-info.c b/plugins/solidigm/solidigm-get-drive-info.c
new file mode 100644
index 0000000..21f59bb
--- /dev/null
+++ b/plugins/solidigm/solidigm-get-drive-info.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Authors: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+#include "nvme-print.h"
+#include "nvme-wrap.h"
+#include "common.h"
+
+int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ const char *desc = "Get drive HW information";
+ const char *FTL_unit_size_str = "FTL_unit_size";
+ char *output_format = "normal";
+ enum nvme_print_flags flags;
+ nvme_root_t r;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+ struct nvme_id_ns ns = { 0 };
+ __u8 flbaf_inUse;
+ __u16 lba_size;
+ __u16 ftl_unit_size;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &output_format, "normal|json"),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(output_format, &flags);
+ if ((err < 0) || !(flags == NORMAL || flags == JSON)) {
+ nvme_show_error("Invalid output format");
+ return err;
+ }
+
+ r = nvme_scan(NULL);
+ c = nvme_scan_ctrl(r, dev->name);
+ n = c ? nvme_ctrl_first_ns(c) : nvme_scan_namespace(dev->name);
+ if (!n) {
+ nvme_show_error("solidigm-vs-drive-info: drive missing namespace");
+ return -EINVAL;
+ }
+
+ err = nvme_ns_identify(n, &ns);
+ if (err) {
+ nvme_show_error("identify namespace: %s", nvme_strerror(errno));
+ return err;
+ }
+
+ if (!(ns.nsfeat & 0x10)) {
+ nvme_show_error("solidigm-vs-drive-info: performance options not available");
+ return -EINVAL;
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &flbaf_inUse);
+ lba_size = 1 << ns.lbaf[flbaf_inUse].ds;
+ ftl_unit_size = (le16_to_cpu(ns.npwg) + 1) * lba_size / 1024;
+
+ if (flags == JSON) {
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, FTL_unit_size_str, ftl_unit_size);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ printf("%s: %d\n", FTL_unit_size_str, ftl_unit_size);
+ }
+
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-get-drive-info.h b/plugins/solidigm/solidigm-get-drive-info.h
new file mode 100644
index 0000000..ffc1bd2
--- /dev/null
+++ b/plugins/solidigm/solidigm-get-drive-info.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-id-ctrl.c b/plugins/solidigm/solidigm-id-ctrl.c
new file mode 100644
index 0000000..f45e758
--- /dev/null
+++ b/plugins/solidigm/solidigm-id-ctrl.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <inttypes.h>
+#include "common.h"
+#include "solidigm-id-ctrl.h"
+
+struct __packed nvme_vu_id_ctrl_field { /* CDR MR5 */
+ __u8 rsvd1[3];
+ __u8 ss;
+ char health[20];
+ __u8 cls;
+ __u8 nlw;
+ __u8 scap;
+ __u8 sstat;
+ char bl[8];
+ __u8 rsvd2[38];
+ __le64 ww;
+ char mic_bl[4];
+ char mic_fw[4];
+};
+
+void sldgm_id_ctrl(uint8_t *vs, struct json_object *root)
+{
+ // text output aligns nicely with property name up to 10 chars
+ const char *str_ss = "stripeSize";
+ const char *str_health = "health";
+ const char *str_cls = "linkSpeed";
+ const char *str_nlw = "negLnkWdth";
+ const char *str_scap = "secCapab";
+ const char *str_sstat = "secStatus";
+ const char *str_bl = "bootLoader";
+ const char *str_ww = "wwid";
+ const char *str_mic_bl = "bwLimGran";
+ const char *str_mic_fw = "ioLimGran";
+
+ struct nvme_vu_id_ctrl_field *id = (struct nvme_vu_id_ctrl_field *)vs;
+
+ const char str_heathy[sizeof(id->health)] = "healthy";
+ const char *health = id->health[0] ? id->health : str_heathy;
+
+ if (root == NULL) {
+ printf("%-10s: %u\n", str_ss, id->ss);
+ printf("%-10s: %.*s\n", str_health, (int)sizeof(id->health), health);
+ printf("%-10s: %u\n", str_cls, id->cls);
+ printf("%-10s: %u\n", str_nlw, id->nlw);
+ printf("%-10s: %u\n", str_scap, id->scap);
+ printf("%-10s: %u\n", str_sstat, id->sstat);
+ printf("%-10s: %.*s\n", str_bl, (int)sizeof(id->bl), id->bl);
+ printf("%-10s: 0x%016"PRIx64"\n", str_ww, le64_to_cpu(id->ww));
+ printf("%-10s: %.*s\n", str_mic_bl, (int)sizeof(id->mic_bl), id->mic_bl);
+ printf("%-10s: %.*s\n", str_mic_fw, (int)sizeof(id->mic_fw), id->mic_fw);
+ return;
+ }
+
+ json_object_add_value_uint(root, str_ss, id->ss);
+ json_object_object_add(root, str_health,
+ json_object_new_string_len(health, sizeof(id->health)));
+ json_object_add_value_uint(root, str_cls, id->cls);
+ json_object_add_value_uint(root, str_nlw, id->nlw);
+ json_object_add_value_uint(root, str_scap, id->scap);
+ json_object_add_value_uint(root, str_sstat, id->sstat);
+ json_object_object_add(root, str_bl, json_object_new_string_len(id->bl, sizeof(id->bl)));
+ json_object_add_value_uint64(root, str_ww, le64_to_cpu(id->ww));
+ json_object_object_add(root, str_mic_bl,
+ json_object_new_string_len(id->mic_bl, sizeof(id->mic_bl)));
+ json_object_object_add(root, str_mic_fw,
+ json_object_new_string_len(id->mic_fw, sizeof(id->mic_fw)));
+}
diff --git a/plugins/solidigm/solidigm-id-ctrl.h b/plugins/solidigm/solidigm-id-ctrl.h
new file mode 100644
index 0000000..ed6e438
--- /dev/null
+++ b/plugins/solidigm/solidigm-id-ctrl.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <inttypes.h>
+#include "util/json.h"
+void sldgm_id_ctrl(uint8_t *vs, struct json_object *root);
diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c
new file mode 100644
index 0000000..c604761
--- /dev/null
+++ b/plugins/solidigm/solidigm-internal-logs.c
@@ -0,0 +1,657 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Authors: leonardo.da.cunha@solidigm.com
+ * shankaralingegowda.singonahalli@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <linux/limits.h>
+#include <time.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "nvme-print.h"
+#include "solidigm-util.h"
+
+#define DWORD_SIZE 4
+
+enum log_type {
+ NLOG = 0,
+ EVENTLOG = 1,
+ ASSERTLOG = 2,
+};
+
+#pragma pack(push, internal_logs, 1)
+struct version {
+ __u16 major;
+ __u16 minor;
+};
+
+struct event_dump_instance {
+ __u32 numeventdumps;
+ __u32 coresize;
+ __u32 coreoffset;
+ __u32 eventidoffset[16];
+ __u8 eventIdValidity[16];
+};
+
+struct commom_header {
+ struct version ver;
+ __u32 header_size;
+ __u32 log_size;
+ __u32 numcores;
+};
+
+struct event_dump_header {
+ struct commom_header header;
+ __u32 eventidsize;
+ struct event_dump_instance edumps[0];
+};
+
+struct assert_dump_core {
+ __u32 coreoffset;
+ __u32 assertsize;
+ __u8 assertdumptype;
+ __u8 assertvalid;
+ __u8 reserved[2];
+};
+
+struct assert_dump_header {
+ struct commom_header header;
+ struct assert_dump_core core[];
+};
+
+struct nlog_dump_header_common {
+ struct version ver;
+ __u32 logselect;
+ __u32 totalnlogs;
+ __u32 nlognum;
+ char nlogname[4];
+ __u32 nlogbytesize;
+ __u32 nlogprimarybuffsize;
+ __u32 tickspersecond;
+ __u32 corecount;
+};
+
+struct nlog_dump_header3_0 {
+ struct nlog_dump_header_common common;
+ __u32 nlogpausestatus;
+ __u32 selectoffsetref;
+ __u32 selectnlogpause;
+ __u32 selectaddedoffset;
+ __u32 nlogbufnum;
+ __u32 nlogbufnummax;
+};
+
+struct nlog_dump_header4_0 {
+ struct nlog_dump_header_common common;
+ __u64 nlogpausestatus;
+ __u32 selectoffsetref;
+ __u32 selectnlogpause;
+ __u32 selectaddedoffset;
+ __u32 nlogbufnum;
+ __u32 nlogbufnummax;
+ __u32 coreselected;
+ __u32 reserved[2];
+};
+
+struct nlog_dump_header4_1 {
+ struct nlog_dump_header_common common;
+ __u64 nlogpausestatus;
+ __u32 selectoffsetref;
+ __u32 selectnlogpause;
+ __u32 selectaddedoffset;
+ __u32 nlogbufnum;
+ __u32 nlogbufnummax;
+ __u32 coreselected;
+ __u32 lpaPointer1High;
+ __u32 lpaPointer1Low;
+ __u32 lpaPointer2High;
+ __u32 lpaPointer2Low;
+};
+
+#pragma pack(pop, internal_logs)
+
+struct config {
+ __u32 namespace_id;
+ char *dir_prefix;
+ char *type;
+ bool verbose;
+};
+
+static void print_nlog_header(__u8 *buffer)
+{
+ struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *) buffer;
+
+ if (nlog_header->ver.major >= 3) {
+ printf("Version Major %u\n", nlog_header->ver.major);
+ printf("Version Minor %u\n", nlog_header->ver.minor);
+ printf("Log_select %u\n", nlog_header->logselect);
+ printf("totalnlogs %u\n", nlog_header->totalnlogs);
+ printf("nlognum %u\n", nlog_header->nlognum);
+ printf("nlogname %c%c%c%c\n", nlog_header->nlogname[3], nlog_header->nlogname[2],
+ nlog_header->nlogname[1], nlog_header->nlogname[0]);
+ printf("nlogbytesize %u\n", nlog_header->nlogbytesize);
+ printf("nlogprimarybuffsize %u\n", nlog_header->nlogprimarybuffsize);
+ printf("tickspersecond %u\n", nlog_header->tickspersecond);
+ printf("corecount %u\n", nlog_header->corecount);
+ }
+ if (nlog_header->ver.major >= 4) {
+ struct nlog_dump_header4_0 *nlog_header = (struct nlog_dump_header4_0 *) buffer;
+
+ printf("nlogpausestatus %"PRIu64"\n", (uint64_t)nlog_header->nlogpausestatus);
+ printf("selectoffsetref %u\n", nlog_header->selectoffsetref);
+ printf("selectnlogpause %u\n", nlog_header->selectnlogpause);
+ printf("selectaddedoffset %u\n", nlog_header->selectaddedoffset);
+ printf("nlogbufnum %u\n", nlog_header->nlogbufnum);
+ printf("nlogbufnummax %u\n", nlog_header->nlogbufnummax);
+ printf("coreselected %u\n\n", nlog_header->coreselected);
+ }
+}
+
+#define INTERNAL_LOG_MAX_BYTE_TRANSFER 4096
+#define INTERNAL_LOG_MAX_DWORD_TRANSFER (INTERNAL_LOG_MAX_BYTE_TRANSFER / 4)
+
+static int cmd_dump_repeat(struct nvme_passthru_cmd *cmd, __u32 total_dw_size,
+ int out_fd, int ioctl_fd, bool force_max_transfer)
+{
+ int err = 0;
+
+ while (total_dw_size > 0) {
+ size_t dword_tfer = min(INTERNAL_LOG_MAX_DWORD_TRANSFER, total_dw_size);
+
+ cmd->cdw10 = force_max_transfer ? INTERNAL_LOG_MAX_DWORD_TRANSFER : dword_tfer;
+ cmd->data_len = dword_tfer * 4;
+ err = nvme_submit_admin_passthru(ioctl_fd, cmd, NULL);
+ if (err)
+ return err;
+
+ if (out_fd > 0) {
+ err = write(out_fd, (const void *)(uintptr_t)cmd->addr, cmd->data_len);
+ if (err < 0) {
+ perror("write failure");
+ return err;
+ }
+ err = 0;
+ }
+ total_dw_size -= dword_tfer;
+ cmd->cdw13 += dword_tfer;
+ }
+ return err;
+}
+
+static int write_header(__u8 *buf, int fd, size_t amnt)
+{
+ if (write(fd, buf, amnt) < 0)
+ return 1;
+ return 0;
+}
+
+static int read_header(struct nvme_passthru_cmd *cmd, int ioctl_fd)
+{
+ memset((void *)(uintptr_t)cmd->addr, 0, INTERNAL_LOG_MAX_BYTE_TRANSFER);
+ return cmd_dump_repeat(cmd, INTERNAL_LOG_MAX_DWORD_TRANSFER, -1, ioctl_fd, false);
+}
+
+static int get_serial_number(char *str, int fd)
+{
+ struct nvme_id_ctrl ctrl = {0};
+ int err;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ return err;
+
+ /* Remove trailing spaces */
+ for (int i = sizeof(ctrl.sn) - 1; i && ctrl.sn[i] == ' '; i--)
+ ctrl.sn[i] = '\0';
+ sprintf(str, "%-.*s", (int)sizeof(ctrl.sn), ctrl.sn);
+ return err;
+}
+
+static int dump_assert_logs(struct nvme_dev *dev, struct config cfg)
+{
+ __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
+ __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
+ char file_path[PATH_MAX];
+ char file_name[] = "AssertLog.bin";
+ struct assert_dump_header *ad = (struct assert_dump_header *) head_buf;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = 0xd2,
+ .nsid = cfg.namespace_id,
+ .addr = (unsigned long)(void *)head_buf,
+ .cdw12 = ASSERTLOG,
+ .cdw13 = 0,
+ };
+ int output, err;
+
+ err = read_header(&cmd, dev_fd(dev));
+ if (err)
+ return err;
+
+ snprintf(file_path, sizeof(file_path), "%.*s/%s",
+ (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0)
+ return -errno;
+ err = write_header((__u8 *)ad, output, ad->header.header_size * DWORD_SIZE);
+ if (err) {
+ perror("write failure");
+ close(output);
+ return err;
+ }
+ cmd.addr = (unsigned long)(void *)buf;
+
+ if (cfg.verbose) {
+ printf("Assert Log, cores: %d log size: %d header size: %d\n", ad->header.numcores,
+ ad->header.log_size * DWORD_SIZE, ad->header.header_size * DWORD_SIZE);
+ for (__u32 i = 0; i < ad->header.numcores; i++)
+ printf("core %d assert size: %d\n", i, ad->core[i].assertsize * DWORD_SIZE);
+ }
+
+ for (__u32 i = 0; i < ad->header.numcores; i++) {
+ if (!ad->core[i].assertvalid)
+ continue;
+ cmd.cdw13 = ad->core[i].coreoffset;
+ err = cmd_dump_repeat(&cmd, ad->core[i].assertsize,
+ output,
+ dev_fd(dev), false);
+ if (err) {
+ close(output);
+ return err;
+ }
+ }
+ close(output);
+ printf("Successfully wrote log to %s\n", file_path);
+ return err;
+}
+
+static int dump_event_logs(struct nvme_dev *dev, struct config cfg)
+{
+ __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
+ __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
+ char file_path[PATH_MAX];
+ struct event_dump_header *ehdr = (struct event_dump_header *) head_buf;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = 0xd2,
+ .nsid = cfg.namespace_id,
+ .addr = (unsigned long)(void *)head_buf,
+ .cdw12 = EVENTLOG,
+ .cdw13 = 0,
+ };
+ int output;
+ int core_num, err;
+
+ err = read_header(&cmd, dev_fd(dev));
+ if (err)
+ return err;
+ snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0)
+ return -errno;
+ err = write_header(head_buf, output, INTERNAL_LOG_MAX_BYTE_TRANSFER);
+
+ core_num = ehdr->header.numcores;
+
+ if (err) {
+ close(output);
+ return err;
+ }
+ cmd.addr = (unsigned long)(void *)buf;
+
+ if (cfg.verbose)
+ printf("Event Log, cores: %d log size: %d\n", core_num, ehdr->header.log_size * 4);
+
+ for (__u32 j = 0; j < core_num; j++) {
+ if (cfg.verbose) {
+ for (int k = 0 ; k < 16; k++) {
+ printf("core: %d event: %d ", j, k);
+ printf("validity: %d ", ehdr->edumps[j].eventIdValidity[k]);
+ printf("offset: %d\n", ehdr->edumps[j].eventidoffset[k]);
+ }
+ }
+ cmd.cdw13 = ehdr->edumps[j].coreoffset;
+ err = cmd_dump_repeat(&cmd, ehdr->edumps[j].coresize,
+ output, dev_fd(dev), false);
+ if (err) {
+ close(output);
+ return err;
+ }
+ }
+ close(output);
+ printf("Successfully wrote log to %s\n", file_path);
+ return err;
+}
+
+static size_t get_nlog_header_size(struct nlog_dump_header_common *nlog_header)
+{
+ switch (nlog_header->ver.major) {
+ case 3:
+ return sizeof(struct nlog_dump_header3_0);
+ case 4:
+ if (nlog_header->ver.minor == 0)
+ return sizeof(struct nlog_dump_header4_0);
+ return sizeof(struct nlog_dump_header4_1);
+ default:
+ return INTERNAL_LOG_MAX_BYTE_TRANSFER;
+ }
+
+}
+
+/* dumps nlogs from specified core or all cores when core = -1 */
+static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core)
+{
+ int err = 0;
+ __u32 count, core_num;
+ __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER];
+ char file_path[PATH_MAX];
+ struct nlog_dump_header_common *nlog_header = (struct nlog_dump_header_common *)buf;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = 0xd2,
+ .nsid = cfg.namespace_id,
+ .addr = (unsigned long)(void *)buf
+ };
+
+ struct dump_select {
+ union {
+ struct {
+ __u32 selectLog : 3;
+ __u32 selectCore : 2;
+ __u32 selectNlog : 8;
+ };
+ __u32 raw;
+ };
+ } log_select;
+ int output;
+ bool is_open = false;
+ size_t header_size = 0;
+
+ log_select.selectCore = core < 0 ? 0 : core;
+ do {
+ log_select.selectNlog = 0;
+ do {
+ cmd.cdw13 = 0;
+ cmd.cdw12 = log_select.raw;
+ err = read_header(&cmd, dev_fd(dev));
+ if (err) {
+ if (is_open)
+ close(output);
+ return err;
+ }
+ count = nlog_header->totalnlogs;
+ core_num = core < 0 ? nlog_header->corecount : 0;
+ if (!header_size) {
+ snprintf(file_path, sizeof(file_path), "%s/NLog.bin",
+ cfg.dir_prefix);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0)
+ return -errno;
+ header_size = get_nlog_header_size(nlog_header);
+ is_open = true;
+ }
+ err = write_header(buf, output, header_size);
+ if (err)
+ break;
+ if (cfg.verbose)
+ print_nlog_header(buf);
+ cmd.cdw13 = 0x400;
+ err = cmd_dump_repeat(&cmd, nlog_header->nlogbytesize / 4,
+ output, dev_fd(dev), true);
+ if (err)
+ break;
+ } while (++log_select.selectNlog < count);
+ if (err)
+ break;
+ } while (++log_select.selectCore < core_num);
+ if (is_open) {
+ close(output);
+ printf("Successfully wrote log to %s\n", file_path);
+ }
+ return err;
+}
+
+enum telemetry_type {
+ HOSTGENOLD,
+ HOSTGENNEW,
+ CONTROLLER
+};
+
+static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype)
+{
+ _cleanup_free_ struct nvme_telemetry_log *log = NULL;
+ size_t log_size = 0;
+ int err = 0;
+ __u8 *buffer = NULL;
+ size_t bytes_remaining = 0;
+ enum nvme_telemetry_da da;
+ size_t max_data_tx;
+ char file_path[PATH_MAX];
+ char *file_name;
+ char *log_descr;
+ struct stat sb;
+
+ _cleanup_file_ int output = -1;
+
+ switch (ttype) {
+ case HOSTGENNEW:
+ file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin";
+ log_descr = "Generated Host Initiated";
+ break;
+ case HOSTGENOLD:
+ file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin";
+ log_descr = "Existing Host Initiated";
+ break;
+ case CONTROLLER:
+ file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin";
+ log_descr = "Controller Initiated";
+ break;
+ default:
+ return -EINVAL;
+ }
+ err = nvme_get_telemetry_max(dev_fd(dev), &da, &max_data_tx);
+ if (err)
+ return err;
+
+ if (max_data_tx > DRIVER_MAX_TX_256K)
+ max_data_tx = DRIVER_MAX_TX_256K;
+
+ switch (ttype) {
+ case HOSTGENNEW:
+ err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da,
+ &log, &log_size);
+ break;
+ case HOSTGENOLD:
+ err = nvme_get_telemetry_log(dev_fd(dev), false, false, false, max_data_tx, da,
+ &log, &log_size);
+ break;
+ case CONTROLLER:
+ err = nvme_get_telemetry_log(dev_fd(dev), false, true, true, max_data_tx, da, &log,
+ &log_size);
+ break;
+ }
+
+ if (err)
+ return err;
+
+ snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix);
+ if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ if (mkdir(file_path, 777) != 0) {
+ perror(file_path);
+ return -errno;
+ }
+ }
+
+ snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (output < 0)
+ return -errno;
+
+ bytes_remaining = log_size;
+ buffer = (__u8 *)log;
+
+ while (bytes_remaining) {
+ ssize_t bytes_written = write(output, buffer, bytes_remaining);
+
+ if (bytes_written < 0) {
+ err = -errno;
+ goto tele_close_output;
+ }
+
+ bytes_remaining -= bytes_written;
+ buffer += bytes_written;
+ }
+ printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path);
+
+tele_close_output:
+ close(output);
+ return err;
+}
+
+int solidigm_get_internal_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char folder[PATH_MAX];
+ char zip_name[PATH_MAX];
+ char *output_path;
+ char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1];
+ int log_count = 0;
+ int err;
+ _cleanup_nvme_dev_ struct nvme_dev *dev = NULL;
+ bool all = false;
+ time_t t;
+ struct tm tm;
+
+ const char *desc = "Get Debug Firmware Logs and save them.";
+ const char *type =
+ "Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL.";
+ const char *prefix = "Output dir prefix; defaults to device serial number.";
+ const char *verbose = "To print out verbose info.";
+ const char *namespace_id = "Namespace to get logs from.";
+
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .dir_prefix = NULL,
+ .type = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STR("type", 't', &cfg.type, type),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ if (!cfg.dir_prefix) {
+ err = get_serial_number(sn_prefix, dev_fd(dev));
+ if (err)
+ return err;
+ cfg.dir_prefix = sn_prefix;
+ }
+ t = time(NULL);
+ tm = *localtime(&t);
+ snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix,
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+ if (mkdir(folder, 0777) != 0) {
+ perror("mkdir");
+ return -errno;
+ }
+ cfg.dir_prefix = folder;
+ output_path = folder;
+
+ if (!cfg.type)
+ cfg.type = "ALL";
+ else {
+ for (char *p = cfg.type; *p; ++p)
+ *p = toupper(*p);
+ }
+
+ if (!strcmp(cfg.type, "ALL")) {
+ all = true;
+ }
+ if (all || !strcmp(cfg.type, "ASSERT")) {
+ err = dump_assert_logs(dev, cfg);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving Assert log");
+ }
+ if (all || !strcmp(cfg.type, "EVENT")) {
+ err = dump_event_logs(dev, cfg);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving Event log");
+ }
+ if (all || !strcmp(cfg.type, "NLOG")) {
+ err = dump_nlogs(dev, cfg, -1);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving Nlog");
+ }
+ if (all || !strcmp(cfg.type, "CONTROLLERINITTELEMETRY")) {
+ err = dump_telemetry(dev, cfg, CONTROLLER);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving Telemetry Controller Initiated");
+ }
+ if (all || !strcmp(cfg.type, "HOSTINITTELEMETRYNOGEN")) {
+ err = dump_telemetry(dev, cfg, HOSTGENOLD);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving previously existing Telemetry Host Initiated");
+ }
+ if (all || !strcmp(cfg.type, "HOSTINITTELEMETRY")) {
+ err = dump_telemetry(dev, cfg, HOSTGENNEW);
+ if (err == 0)
+ log_count++;
+ else if (err < 0)
+ perror("Error retrieving Telemetry Host Initiated");
+ }
+
+ if (log_count > 0) {
+ int ret_cmd;
+ char cmd[ARG_MAX];
+ char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1";
+
+ snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix);
+ snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix,
+ zip_name, where_err);
+ printf("Compressing logs to %s\n", zip_name);
+ ret_cmd = system(cmd);
+ if (ret_cmd == -1)
+ perror(cmd);
+ else {
+ output_path = zip_name;
+ snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix);
+ printf("Removing %s\n", cfg.dir_prefix);
+ if (system(cmd) != 0)
+ perror("Failed removing logs folder");
+ }
+ }
+
+ if (log_count == 0) {
+ if (err > 0)
+ nvme_show_status(err);
+ } else if ((log_count > 1) || cfg.verbose)
+ printf("Total: %d log files in %s\n", log_count, output_path);
+
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-internal-logs.h b/plugins/solidigm/solidigm-internal-logs.h
new file mode 100644
index 0000000..801af24
--- /dev/null
+++ b/plugins/solidigm/solidigm-internal-logs.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-latency-tracking.c b/plugins/solidigm/solidigm-latency-tracking.c
new file mode 100644
index 0000000..66f3c56
--- /dev/null
+++ b/plugins/solidigm/solidigm-latency-tracking.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+#include "solidigm-util.h"
+
+#define BUCKET_LIST_SIZE_4_0 152
+#define BUCKET_LIST_SIZE_4_1 1216
+
+#define BASE_RANGE_BITS_4_0 3
+#define BASE_RANGE_BITS_4_1 6
+
+struct latency_statistics {
+ __u16 version_major;
+ __u16 version_minor;
+ __u32 data[BUCKET_LIST_SIZE_4_1];
+ __u64 average_latency;
+};
+
+struct config {
+ bool enable;
+ bool disable;
+ bool read;
+ bool write;
+ unsigned char type;
+ char *output_format;
+};
+
+struct latency_tracker {
+ int fd;
+ __u8 uuid_index;
+ struct config cfg;
+ enum nvme_print_flags print_flags;
+ struct latency_statistics stats;
+ struct json_object *bucket_list;
+ __u32 bucket_list_size;
+ __u8 base_range_bits;
+ bool has_average_latency_field;
+};
+
+/* COL_WIDTH controls width of columns in NORMAL output. */
+#define COL_WIDTH 12
+#define BUCKET_LABEL_MAX_SIZE 10
+
+#define US_IN_S 1000000
+#define US_IN_MS 1000
+
+/*
+ * Edge buckets may have range [#s, inf) in some
+ * latency statistics formats.
+ */
+static void get_time_unit_label(char *label, __u32 microseconds,
+ bool bonded)
+{
+ char *string = "us";
+ int divisor = 1;
+
+ if (!bonded) {
+ snprintf(label, BUCKET_LABEL_MAX_SIZE, "%s", "+INF");
+ return;
+ }
+
+ if (microseconds > US_IN_S) {
+ string = "s";
+ divisor = US_IN_S;
+ } else if (microseconds > US_IN_MS) {
+ string = "ms";
+ divisor = US_IN_MS;
+ }
+
+ snprintf(label, BUCKET_LABEL_MAX_SIZE, "%4.2f%s", (float) microseconds / divisor,
+ string);
+}
+
+static void latency_tracker_bucket_parse(const struct latency_tracker *lt, int id,
+ __u32 lower_us, __u32 upper_us, bool upper_bounded)
+{
+ char buffer[BUCKET_LABEL_MAX_SIZE] = "";
+ __u32 bucket_data = le32_to_cpu(lt->stats.data[id]);
+
+ if (lt->print_flags == NORMAL) {
+ printf("%-*d", COL_WIDTH, id);
+
+ get_time_unit_label(buffer, lower_us, true);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ get_time_unit_label(buffer, upper_us, upper_bounded);
+ printf("%-*s", COL_WIDTH, buffer);
+
+ printf("%-*d\n", COL_WIDTH, bucket_data);
+ }
+
+ if (lt->print_flags == JSON) {
+ /*
+ * Creates a bucket under the "values" json_object. Format is:
+ * "values" : {
+ * "bucket" : {
+ * "id" : #,
+ * "start" : string,
+ * "end" : string,
+ * "value" : 0,
+ * },
+ */
+ struct json_object *bucket = json_create_object();
+
+ json_object_array_add(lt->bucket_list, bucket);
+ json_object_add_value_int(bucket, "id", id);
+
+ get_time_unit_label(buffer, lower_us, true);
+ json_object_add_value_string(bucket, "start", buffer);
+
+ get_time_unit_label(buffer, upper_us, upper_bounded);
+ json_object_add_value_string(bucket, "end", buffer);
+
+ json_object_add_value_int(bucket, "value", bucket_data);
+ }
+}
+
+static void latency_tracker_parse_linear(const struct latency_tracker *lt,
+ __u32 start_offset, __u32 end_offset,
+ __u32 bytes_per, __u32 us_step,
+ bool nonzero_print)
+{
+ for (int i = (start_offset / bytes_per) - 1; i < end_offset / bytes_per; i++) {
+ if (nonzero_print && !lt->stats.data[i])
+ continue;
+ latency_tracker_bucket_parse(lt, i, us_step * i, us_step * (i + 1), true);
+ }
+}
+
+/*
+ * Calculates bucket time slot. Valid starting on 4.0 revision.
+ */
+
+static int latency_tracker_bucket_pos2us(const struct latency_tracker *lt, int i)
+{
+ __u32 base_val = 1 << lt->base_range_bits;
+
+ if (i < (base_val << 1))
+ return i;
+
+ int error_bits = (i >> lt->base_range_bits) - 1;
+ int base = 1 << (error_bits + lt->base_range_bits);
+ int k = i % base_val;
+
+ return base + ((k + 0.5) * (1 << error_bits));
+}
+
+/*
+ * Creates a subroot in the following manner:
+ * {
+ * "latstats" : {
+ * "type" : "write" or "read",
+ * "values" : {
+ */
+static void latency_tracker_populate_json_root(const struct latency_tracker *lt,
+ struct json_object *root)
+{
+ struct json_object *subroot = json_create_object();
+
+ json_object_add_value_object(root, "latstats", subroot);
+ json_object_add_value_string(subroot, "type", lt->cfg.write ? "write" : "read");
+ if (lt->has_average_latency_field)
+ json_object_add_value_uint64(subroot, "average_latency",
+ le64_to_cpu(lt->stats.average_latency));
+ json_object_add_value_object(subroot, "values", lt->bucket_list);
+}
+
+static void latency_tracker_parse_3_0(const struct latency_tracker *lt)
+{
+ latency_tracker_parse_linear(lt, 4, 131, 4, 32, false);
+ latency_tracker_parse_linear(lt, 132, 255, 4, 1024, false);
+ latency_tracker_parse_linear(lt, 256, 379, 4, 32768, false);
+ latency_tracker_parse_linear(lt, 380, 383, 4, 32, true);
+ latency_tracker_parse_linear(lt, 384, 387, 4, 32, true);
+ latency_tracker_parse_linear(lt, 388, 391, 4, 32, true);
+}
+
+static void latency_tracker_parse_4_0(const struct latency_tracker *lt)
+{
+ for (unsigned int i = 0; i < lt->bucket_list_size; i++) {
+ int lower_us = latency_tracker_bucket_pos2us(lt, i);
+ int upper_us = latency_tracker_bucket_pos2us(lt, i + 1);
+
+ latency_tracker_bucket_parse(lt, i, lower_us, upper_us,
+ i < (lt->bucket_list_size - 1));
+ }
+}
+
+static void print_dash_separator(void)
+{
+ printf("--------------------------------------------------\n");
+}
+
+static void latency_tracker_pre_parse(struct latency_tracker *lt)
+{
+ if (lt->print_flags == NORMAL) {
+ printf("Solidigm IO %s Command Latency Tracking Statistics type %d\n",
+ lt->cfg.write ? "Write" : "Read", lt->cfg.type);
+ printf("UUID-idx: %d\n", lt->uuid_index);
+ printf("Major Revision: %u\nMinor Revision: %u\n",
+ le16_to_cpu(lt->stats.version_major), le16_to_cpu(lt->stats.version_minor));
+ if (lt->has_average_latency_field)
+ printf("Average Latency: %" PRIu64 "\n", le64_to_cpu(lt->stats.average_latency));
+ print_dash_separator();
+ printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
+ print_dash_separator();
+ }
+ if (lt->print_flags == JSON)
+ lt->bucket_list = json_object_new_array();
+}
+
+static void latency_tracker_post_parse(struct latency_tracker *lt)
+{
+ if (lt->print_flags == JSON) {
+ struct json_object *root = json_create_object();
+
+ latency_tracker_populate_json_root(lt, root);
+ json_print_object(root, NULL);
+ json_free_object(root);
+ printf("\n");
+ }
+}
+
+static void latency_tracker_parse(struct latency_tracker *lt)
+{
+ __u16 version_major = le16_to_cpu(lt->stats.version_major);
+ __u16 version_minor = le16_to_cpu(lt->stats.version_minor);
+
+ switch (version_major) {
+ case 3:
+ latency_tracker_pre_parse(lt);
+ latency_tracker_parse_3_0(lt);
+ break;
+ case 4:
+ if (version_minor >= 8)
+ lt->has_average_latency_field = true;
+ latency_tracker_pre_parse(lt);
+ if (!version_minor) {
+ lt->base_range_bits = BASE_RANGE_BITS_4_0;
+ lt->bucket_list_size = BUCKET_LIST_SIZE_4_0;
+ }
+ latency_tracker_parse_4_0(lt);
+ break;
+ default:
+ printf("Unsupported revision (%u.%u)\n",
+ version_major, version_minor);
+ break;
+ }
+
+ latency_tracker_post_parse(lt);
+}
+
+#define LATENCY_TRACKING_FID 0xe2
+#define LATENCY_TRACKING_FID_DATA_LEN 32
+
+static int latency_tracking_is_enable(struct latency_tracker *lt, __u32 *enabled)
+{
+ struct nvme_get_features_args args_get = {
+ .args_size = sizeof(args_get),
+ .fd = lt->fd,
+ .uuidx = lt->uuid_index,
+ .fid = LATENCY_TRACKING_FID,
+ .nsid = 0,
+ .sel = 0,
+ .cdw11 = 0,
+ .data_len = LATENCY_TRACKING_FID_DATA_LEN,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = enabled,
+ };
+ return nvme_get_features(&args_get);
+}
+
+static int latency_tracking_enable(struct latency_tracker *lt)
+{
+ __u32 result;
+ int err;
+
+ if (!(lt->cfg.enable || lt->cfg.disable))
+ return 0;
+
+ if (lt->cfg.enable && lt->cfg.disable) {
+ fprintf(stderr, "Cannot enable and disable simultaneously.\n");
+ return -EINVAL;
+ }
+
+ struct nvme_set_features_args args_set = {
+ .args_size = sizeof(args_set),
+ .fd = lt->fd,
+ .uuidx = lt->uuid_index,
+ .fid = LATENCY_TRACKING_FID,
+ .nsid = 0,
+ .cdw11 = lt->cfg.enable,
+ .cdw12 = 0,
+ .save = 0,
+ .cdw15 = 0,
+ .data_len = LATENCY_TRACKING_FID_DATA_LEN,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ err = nvme_set_features(&args_set);
+ if (err > 0) {
+ nvme_show_status(err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ if (lt->print_flags == NORMAL) {
+ printf("Successfully set enable bit for UUID-idx:%d FID:0x%X, to %i.\n",
+ lt->uuid_index, LATENCY_TRACKING_FID, lt->cfg.enable);
+ }
+ }
+ return err;
+}
+
+#define READ_LOG_ID 0xc1
+#define WRITE_LOG_ID 0xc2
+
+static int latency_tracker_get_log(struct latency_tracker *lt)
+{
+ int err;
+
+ if (lt->cfg.read && lt->cfg.write) {
+ fprintf(stderr, "Cannot capture read and write logs simultaneously.\n");
+ return -EINVAL;
+ }
+
+ if (!(lt->cfg.read || lt->cfg.write))
+ return 0;
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &lt->stats,
+ .args_size = sizeof(args),
+ .fd = lt->fd,
+ .uuidx = lt->uuid_index,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = lt->cfg.write ? WRITE_LOG_ID : READ_LOG_ID,
+ .len = sizeof(lt->stats),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = lt->cfg.type,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err)
+ return err;
+
+ if (lt->print_flags & BINARY)
+ d_raw((unsigned char *)&lt->stats,
+ sizeof(lt->stats));
+ else {
+ latency_tracker_parse(lt);
+ }
+ return err;
+}
+
+int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Get and Parse Solidigm Latency Tracking Statistics log.";
+ struct nvme_dev *dev;
+ __u32 enabled;
+ int err;
+
+ struct latency_tracker lt = {
+ .uuid_index = 0,
+ .cfg = {
+ .output_format = "normal",
+ },
+ .base_range_bits = BASE_RANGE_BITS_4_1,
+ .bucket_list_size = BUCKET_LIST_SIZE_4_1,
+ .has_average_latency_field = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("enable", 'e', &lt.cfg.enable, "Enable Latency Tracking"),
+ OPT_FLAG("disable", 'd', &lt.cfg.disable, "Disable Latency Tracking"),
+ OPT_FLAG("read", 'r', &lt.cfg.read, "Get read statistics"),
+ OPT_FLAG("write", 'w', &lt.cfg.write, "Get write statistics"),
+ OPT_BYTE("type", 't', &lt.cfg.type, "Log type to get"),
+ OPT_FMT("output-format", 'o', &lt.cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ lt.fd = dev_fd(dev);
+
+ err = validate_output_format(lt.cfg.output_format, &lt.print_flags);
+ if (err < 0) {
+ fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ if (lt.cfg.type > 0xf) {
+ fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type);
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) {
+ fprintf(stderr, "Log type option valid only when retrieving statistics\n");
+ dev_close(dev);
+ return -EINVAL;
+ }
+
+ lt.uuid_index = solidigm_get_vu_uuid_index(dev);
+
+ err = latency_tracking_enable(&lt);
+ if (err) {
+ dev_close(dev);
+ return err;
+ }
+
+ err = latency_tracker_get_log(&lt);
+ if (err) {
+ dev_close(dev);
+ return err;
+ }
+
+ if ((lt.cfg.read || lt.cfg.write || lt.cfg.enable || lt.cfg.disable)) {
+ dev_close(dev);
+ return 0;
+ }
+
+ err = latency_tracking_is_enable(&lt, &enabled);
+ if (!err) {
+ if (lt.print_flags == JSON) {
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "enabled", enabled);
+ json_print_object(root, NULL);
+ json_free_object(root);
+ printf("\n");
+ } else if (lt.print_flags == BINARY) {
+ putchar(enabled);
+ } else {
+ printf("Latency Statistics Tracking (UUID-idx:%d, FID:0x%X) is currently %i.\n",
+ lt.uuid_index, LATENCY_TRACKING_FID, enabled);
+ }
+ } else {
+ fprintf(stderr, "Could not read feature id 0xE2.\n");
+ }
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-latency-tracking.h b/plugins/solidigm/solidigm-latency-tracking.h
new file mode 100644
index 0000000..9a763a9
--- /dev/null
+++ b/plugins/solidigm/solidigm-latency-tracking.h
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-log-page-dir.c b/plugins/solidigm/solidigm-log-page-dir.c
new file mode 100644
index 0000000..bf272f8
--- /dev/null
+++ b/plugins/solidigm/solidigm-log-page-dir.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: karl.dedow@solidigm.com
+ */
+
+#include "solidigm-log-page-dir.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "nvme-print.h"
+
+#include "plugins/ocp/ocp-utils.h"
+
+#define MIN_VENDOR_LID 0xC0
+#define SOLIDIGM_MAX_UUID 2
+
+static const char dash[100] = {[0 ... 99] = '-'};
+
+struct lid_dir {
+ struct __packed {
+ bool supported;
+ const char *str;
+ } lid[NVME_LOG_SUPPORTED_LOG_PAGES_MAX];
+};
+
+static void init_lid_dir(struct lid_dir *lid_dir)
+{
+ static const char *unknown_str = "Unknown";
+
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ lid_dir->lid[lid].supported = false;
+ lid_dir->lid[lid].str = unknown_str;
+ }
+}
+
+static bool is_invalid_uuid(const struct nvme_id_uuid_list_entry entry)
+{
+ static const unsigned char ALL_ZERO_UUID[NVME_UUID_LEN] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ return memcmp(ALL_ZERO_UUID, entry.uuid, NVME_UUID_LEN) == 0;
+}
+
+static bool is_solidigm_uuid(const struct nvme_id_uuid_list_entry entry)
+{
+ static const unsigned char SOLIDIGM_UUID[NVME_UUID_LEN] = {
+ 0x96, 0x19, 0x58, 0x6e, 0xc1, 0x1b, 0x43, 0xad,
+ 0xaa, 0xaa, 0x65, 0x41, 0x87, 0xf6, 0xbb, 0xb2
+ };
+
+ return memcmp(SOLIDIGM_UUID, entry.uuid, NVME_UUID_LEN) == 0;
+}
+
+static bool is_ocp_uuid(const struct nvme_id_uuid_list_entry entry)
+{
+ static const unsigned char OCP_UUID[NVME_UUID_LEN] = {
+ 0xc1, 0x94, 0xd5, 0x5b, 0xe0, 0x94, 0x47, 0x94,
+ 0xa2, 0x1d, 0x29, 0x99, 0x8f, 0x56, 0xbe, 0x6f
+ };
+
+ return memcmp(OCP_UUID, entry.uuid, NVME_UUID_LEN) == 0;
+}
+
+static int get_supported_log_pages_log(struct nvme_dev *dev, int uuid_index,
+ struct nvme_supported_log_pages *supported)
+{
+ static const __u8 LID;
+
+ memset(supported, 0, sizeof(*supported));
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = supported,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = LID,
+ .len = sizeof(*supported),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = 0,
+ .uuidx = uuid_index,
+ .rae = false,
+ .ot = false,
+ };
+
+ return nvme_get_log(&args);
+}
+
+static struct lid_dir *get_standard_lids(struct nvme_supported_log_pages *supported)
+{
+ static struct lid_dir standard_dir = { 0 };
+
+ init_lid_dir(&standard_dir);
+
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ if (!supported->lid_support[lid] || lid >= MIN_VENDOR_LID)
+ continue;
+
+ standard_dir.lid[lid].supported = true;
+ standard_dir.lid[lid].str = nvme_log_to_string(lid);
+ }
+
+ return &standard_dir;
+}
+
+static void update_vendor_lid_supported(struct nvme_supported_log_pages *supported,
+ struct lid_dir *lid_dir)
+{
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ if (!supported->lid_support[lid] || lid < MIN_VENDOR_LID)
+ continue;
+
+ lid_dir->lid[lid].supported = true;
+ }
+}
+
+static struct lid_dir *get_solidigm_lids(struct nvme_supported_log_pages *supported)
+{
+ static struct lid_dir solidigm_dir = { 0 };
+
+ init_lid_dir(&solidigm_dir);
+ solidigm_dir.lid[0xC1].str = "Read Commands Latency Statistics";
+ solidigm_dir.lid[0xC2].str = "Write Commands Latency Statistics";
+ solidigm_dir.lid[0xC4].str = "Endurance Manager Statistics";
+ solidigm_dir.lid[0xC5].str = "Temperature Statistics";
+ solidigm_dir.lid[0xCA].str = "SMART Attributes";
+ solidigm_dir.lid[0xCB].str = "VU NVMe IO Queue Metrics Log Page";
+ solidigm_dir.lid[0xDD].str = "VU Marketing Description Log Page";
+ solidigm_dir.lid[0xEF].str = "Performance Rating and LBA Access Histogram";
+ solidigm_dir.lid[0xF2].str = "Get Power Usage Log Page";
+ solidigm_dir.lid[0xF6].str = "Vt Histo Get Log Page";
+ solidigm_dir.lid[0xF9].str = "Workload Tracker Get Log Page";
+ solidigm_dir.lid[0xFD].str = "Garbage Control Collection Log Page";
+ solidigm_dir.lid[0xFE].str = "Latency Outlier Log Page";
+
+ update_vendor_lid_supported(supported, &solidigm_dir);
+
+ return &solidigm_dir;
+}
+
+static struct lid_dir *get_ocp_lids(struct nvme_supported_log_pages *supported)
+{
+ static struct lid_dir ocp_dir = { 0 };
+
+ init_lid_dir(&ocp_dir);
+ ocp_dir.lid[0xC0].str = "OCP SMART / Health Information Extended";
+ ocp_dir.lid[0xC1].str = "OCP Error Recovery";
+ ocp_dir.lid[0xC2].str = "OCP Firmware Activation History";
+ ocp_dir.lid[0xC3].str = "OCP Latency Monitor";
+ ocp_dir.lid[0xC4].str = "OCP Device Capabilities";
+ ocp_dir.lid[0xC5].str = "OCP Unsupported Requirements";
+
+ update_vendor_lid_supported(supported, &ocp_dir);
+
+ return &ocp_dir;
+}
+
+static void supported_log_pages_normal(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
+{
+ printf("%-5s %-4s %-42s\n", "uuidx", "LID", "Description");
+ printf("%-.5s %-.4s %-.42s\n", dash, dash, dash);
+
+ for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
+ if (!lid_dir[uuid_index])
+ continue;
+
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ if (!lid_dir[uuid_index]->lid[lid].supported)
+ continue;
+
+ printf("%-5d 0x%02x %s\n", le32_to_cpu(uuid_index), le32_to_cpu(lid),
+ lid_dir[uuid_index]->lid[lid].str);
+ }
+ }
+}
+
+static void supported_log_pages_json(struct lid_dir *lid_dir[SOLIDIGM_MAX_UUID + 1])
+{
+ struct json_object *root = json_create_array();
+
+ for (int uuid_index = 0; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
+ if (!lid_dir[uuid_index])
+ continue;
+
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ if (!lid_dir[uuid_index]->lid[lid].supported)
+ continue;
+
+ struct json_object *lid_obj = json_create_object();
+
+ json_object_add_value_uint(lid_obj, "uuidx", le32_to_cpu(uuid_index));
+ json_object_add_value_uint(lid_obj, "lid", le32_to_cpu(lid));
+ json_object_add_value_string(lid_obj, "description",
+ lid_dir[uuid_index]->lid[lid].str);
+ json_array_add_value_object(root, lid_obj);
+ }
+ }
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+ printf("\n");
+}
+
+int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const int NO_UUID_INDEX = 0;
+ const char *description = "Retrieves list of supported log pages for each UUID index.";
+ char *format = "normal";
+
+ OPT_ARGS(options) = {
+ OPT_FMT("output-format", 'o', &format, "output format : normal | json"),
+ OPT_END()
+ };
+
+ struct nvme_dev *dev = NULL;
+ int err = parse_and_open(&dev, argc, argv, description, options);
+
+ if (err)
+ return err;
+
+ struct lid_dir *lid_dirs[SOLIDIGM_MAX_UUID + 1] = { 0 };
+ struct nvme_id_uuid_list uuid_list = { 0 };
+ struct nvme_supported_log_pages supported = { 0 };
+
+ err = get_supported_log_pages_log(dev, NO_UUID_INDEX, &supported);
+
+ if (!err) {
+ lid_dirs[NO_UUID_INDEX] = get_standard_lids(&supported);
+
+ // Assume VU logs are the Solidigm log pages if UUID not supported.
+ if (nvme_identify_uuid(dev_fd(dev), &uuid_list)) {
+ struct lid_dir *solidigm_lid_dir = get_solidigm_lids(&supported);
+
+ // Transfer supported Solidigm lids to lid directory at UUID index 0
+ for (int lid = 0; lid < NVME_LOG_SUPPORTED_LOG_PAGES_MAX; lid++) {
+ if (solidigm_lid_dir->lid[lid].supported)
+ lid_dirs[NO_UUID_INDEX]->lid[lid] = solidigm_lid_dir->lid[lid];
+ }
+ } else {
+ for (int uuid_index = 1; uuid_index <= SOLIDIGM_MAX_UUID; uuid_index++) {
+ if (is_invalid_uuid(uuid_list.entry[uuid_index - 1]))
+ break;
+ else if (get_supported_log_pages_log(dev, uuid_index, &supported))
+ continue;
+
+ if (is_solidigm_uuid(uuid_list.entry[uuid_index - 1]))
+ lid_dirs[uuid_index] = get_solidigm_lids(&supported);
+ else if (is_ocp_uuid(uuid_list.entry[uuid_index - 1]))
+ lid_dirs[uuid_index] = get_ocp_lids(&supported);
+ }
+ }
+ } else {
+ nvme_show_status(err);
+ }
+
+ if (!err) {
+ enum nvme_print_flags print_flag;
+
+ err = validate_output_format(format, &print_flag);
+ if (err < 0) {
+ fprintf(stderr, "Error: Invalid output format specified: %s.\n", format);
+ return err;
+ }
+
+ if (print_flag == NORMAL) {
+ supported_log_pages_normal(lid_dirs);
+ } else if (print_flag == JSON) {
+ supported_log_pages_json(lid_dirs);
+ }
+ }
+
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-log-page-dir.h b/plugins/solidigm/solidigm-log-page-dir.h
new file mode 100644
index 0000000..48777df
--- /dev/null
+++ b/plugins/solidigm/solidigm-log-page-dir.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Authors: karl.dedow@solidigm.com
+ */
+
+#ifndef SOLIDIGM_LOG_PAGE_DIRECTORY_H
+#define SOLIDIGM_LOG_PAGE_DIRECTORY_H
+
+struct command;
+struct plugin;
+
+int solidigm_get_log_page_directory_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin);
+
+#endif
diff --git a/plugins/solidigm/solidigm-market-log.c b/plugins/solidigm/solidigm-market-log.c
new file mode 100644
index 0000000..d7d38da
--- /dev/null
+++ b/plugins/solidigm/solidigm-market-log.c
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Authors: leonardo.da.cunha@solidigm.com
+ * Hardeep.Dhillon@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <linux/limits.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "nvme-print.h"
+
+#define MARKET_LOG_MAX_SIZE 512
+
+int sldgm_get_market_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Get Solidigm Marketing Name log and show it.";
+ const char *raw = "dump output in binary format";
+ struct nvme_dev *dev;
+ char log[MARKET_LOG_MAX_SIZE];
+ int err;
+
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_log_simple(dev_fd(dev), 0xdd, sizeof(log), log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ printf("Solidigm Marketing Name Log:\n%s\n", log);
+ else
+ d_raw((unsigned char *)&log, sizeof(log));
+ } else if (err > 0)
+
+ nvme_show_status(err);
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-market-log.h b/plugins/solidigm/solidigm-market-log.h
new file mode 100644
index 0000000..6f808c4
--- /dev/null
+++ b/plugins/solidigm/solidigm-market-log.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: hardeep.dhillon@solidigm.com
+ */
+
+int sldgm_get_market_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-nvme.c b/plugins/solidigm/solidigm-nvme.c
new file mode 100644
index 0000000..3fb86f5
--- /dev/null
+++ b/plugins/solidigm/solidigm-nvme.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022-2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "nvme.h"
+
+#define CREATE_CMD
+#include "solidigm-nvme.h"
+
+#include "solidigm-id-ctrl.h"
+#include "solidigm-smart.h"
+#include "solidigm-internal-logs.h"
+#include "solidigm-garbage-collection.h"
+#include "solidigm-latency-tracking.h"
+#include "solidigm-telemetry.h"
+#include "solidigm-log-page-dir.h"
+#include "solidigm-market-log.h"
+#include "solidigm-temp-stats.h"
+#include "solidigm-get-drive-info.h"
+#include "solidigm-ocp-version.h"
+
+#include "plugins/ocp/ocp-clear-features.h"
+#include "plugins/ocp/ocp-smart-extended-log.h"
+#include "plugins/ocp/ocp-fw-activation-history.h"
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, sldgm_id_ctrl);
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_additional_smart_log(argc, argv, cmd, plugin);
+}
+
+static int get_internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_internal_log(argc, argv, cmd, plugin);
+}
+
+static int get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_garbage_collection_log(argc, argv, cmd, plugin);
+}
+
+static int get_latency_tracking_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_latency_tracking_log(argc, argv, cmd, plugin);
+}
+
+static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return solidigm_get_telemetry_log(argc, argv, cmd, plugin);
+}
+
+static int clear_fw_update_history(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_clear_fw_update_history(argc, argv, cmd, plugin);
+}
+
+static int clear_pcie_correctable_error_counters(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_clear_pcie_correctable_errors(argc, argv, cmd, plugin);
+}
+
+static int smart_cloud(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_smart_add_log(argc, argv, cmd, plugin);
+}
+
+static int fw_activation_history(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return ocp_fw_activation_history_log(argc, argv, cmd, plugin);
+}
+
+static int get_log_page_directory_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return solidigm_get_log_page_directory_log(argc, argv, cmd, plugin);
+}
+
+static int get_market_log(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return sldgm_get_market_log(argc, argv, cmd, plugin);
+}
+
+static int get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return sldgm_get_temp_stats_log(argc, argv, cmd, plugin);
+}
+
+static int get_drive_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return sldgm_get_drive_info(argc, argv, cmd, plugin);
+}
+
+static int get_cloud_SSDplugin_version(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ return sldgm_ocp_version(argc, argv, cmd, plugin);
+}
diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h
new file mode 100644
index 0000000..bee8266
--- /dev/null
+++ b/plugins/solidigm/solidigm-nvme.h
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022-2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/solidigm/solidigm-nvme
+
+#if !defined(SOLIDIGM_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SOLIDIGM_NVME
+
+#include "cmd.h"
+
+#define SOLIDIGM_PLUGIN_VERSION "1.1"
+
+PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
+ COMMAND_LIST(
+ ENTRY("id-ctrl", "Send NVMe Identify Controller", id_ctrl)
+ ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
+ ENTRY("vs-smart-add-log", "Get SMART / health extended log (redirects to ocp plug-in)", smart_cloud)
+ ENTRY("vs-internal-log", "Retrieve Debug log binaries", get_internal_log)
+ ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log)
+ ENTRY("market-log", "Retrieve Market Log", get_market_log)
+ ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
+ ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log)
+ ENTRY("clear-pcie-correctable-errors ", "Clear PCIe Correctable Error Counters (redirects to ocp plug-in)", clear_pcie_correctable_error_counters)
+ ENTRY("clear-fw-activate-history", "Clear firmware update history log (redirects to ocp plug-in)", clear_fw_update_history)
+ ENTRY("vs-fw-activate-history", "Get firmware activation history log (redirects to ocp plug-in)", fw_activation_history)
+ ENTRY("log-page-directory", "Retrieve log page directory", get_log_page_directory_log)
+ ENTRY("temp-stats", "Retrieve Temperature Statistics log", get_temp_stats_log)
+ ENTRY("vs-drive-info", "Retrieve drive information", get_drive_info)
+ ENTRY("cloud-SSDplugin-version", "Prints plug-in OCP version", get_cloud_SSDplugin_version)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/solidigm/solidigm-ocp-version.c b/plugins/solidigm/solidigm-ocp-version.c
new file mode 100644
index 0000000..4048cc1
--- /dev/null
+++ b/plugins/solidigm/solidigm-ocp-version.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <stdio.h>
+#include "nvme.h"
+
+int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Prints OCP extensions version of Solidigm plugin";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ int err = argconfig_parse(argc, argv, desc, opts);
+
+ if (!err)
+ printf("1.0\n");
+
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-ocp-version.h b/plugins/solidigm/solidigm-ocp-version.h
new file mode 100644
index 0000000..d79452c
--- /dev/null
+++ b/plugins/solidigm/solidigm-ocp-version.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_ocp_version(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c
new file mode 100644
index 0000000..62245fa
--- /dev/null
+++ b/plugins/solidigm/solidigm-smart.c
@@ -0,0 +1,271 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#include "solidigm-smart.h"
+#include "solidigm-util.h"
+
+struct __packed nvme_additional_smart_log_item {
+ __u8 id;
+ __u8 _kp[2];
+ __u8 normalized;
+ __u8 _np;
+ union __packed {
+ __u8 raw[6];
+ struct __packed wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __packed thermal_throttle {
+ __u8 pct;
+ __u32 count;
+ } thermal_throttle;
+ };
+ __u8 _rp;
+};
+
+#define VU_SMART_PAGE_SIZE 512
+#define VU_SMART_MAX_ITEMS (VU_SMART_PAGE_SIZE / sizeof(struct nvme_additional_smart_log_item))
+struct vu_smart_log {
+ struct nvme_additional_smart_log_item item[VU_SMART_MAX_ITEMS];
+};
+
+static char *id_to_name(__u8 id)
+{
+ switch (id) {
+ case 0x0D:
+ return "soft_ecc_error_rate";
+ case 0x05:
+ return "relocatable_sector_count";
+ case 0xAB:
+ return "program_fail_count";
+ case 0xAC:
+ return "erase_fail_count";
+ case 0xAD:
+ return "wear_leveling_count";
+ case 0xAE:
+ return "unexpected_power_loss";
+ case 0xB8:
+ return "e2e_error_detect_count";
+ case 0xC7:
+ return "crc_error_count";
+ case 0xE2:
+ return "media_wear_percentage";
+ case 0xE3:
+ return "timed_work_load_host_reads";
+ case 0xE4:
+ return "timed_work_load_timer";
+ case 0xE5:
+ return "read_commands_in_flight_counter";
+ case 0xE6:
+ return "write_commands_in_flight_counter";
+ case 0xEA:
+ return "thermal_throttle_status";
+ case 0xEE:
+ return "re_sku_count";
+ case 0xF0:
+ return "retry_buffer_overflow_counter";
+ 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 0xFA:
+ return "host_read_collision_count";
+ case 0xFB:
+ return "host_write_collision_count";
+ case 0xFC:
+ return "xor_pass_count";
+ case 0xFD:
+ return "xor_fail_count";
+ case 0xFE:
+ return "xor_invoked_count";
+ default:
+ return "unknown";
+ }
+}
+
+static void smart_log_item_print(struct nvme_additional_smart_log_item *item)
+{
+ if (!item->id)
+ return;
+
+ printf("%#x %-45s %3d ",
+ item->id, id_to_name(item->id), item->normalized);
+
+ switch (item->id) {
+ case 0xAD:
+ printf("min: %u, max: %u, avg: %u\n",
+ le16_to_cpu(item->wear_level.min),
+ le16_to_cpu(item->wear_level.max),
+ le16_to_cpu(item->wear_level.avg));
+ return;
+ case 0xEA:
+ printf("%u%%, cnt: %u\n",
+ item->thermal_throttle.pct,
+ le32_to_cpu(item->thermal_throttle.count));
+ return;
+ default:
+ printf("%"PRIu64"\n", int48_to_long(item->raw));
+ }
+}
+
+static void smart_log_item_add_json(struct nvme_additional_smart_log_item *item, struct json_object *dev_stats)
+{
+ struct json_object *entry_stats = json_create_object();
+
+ if (!item->id)
+ return;
+
+ json_object_add_value_int(entry_stats, "normalized", item->normalized);
+
+ switch (item->id) {
+ case 0xAD:
+ json_object_add_value_int(entry_stats, "min", le16_to_cpu(item->wear_level.min));
+ json_object_add_value_int(entry_stats, "max", le16_to_cpu(item->wear_level.max));
+ json_object_add_value_int(entry_stats, "avg", le16_to_cpu(item->wear_level.avg));
+ break;
+ case 0xEA:
+ json_object_add_value_int(entry_stats, "percentage", item->thermal_throttle.pct);
+ json_object_add_value_int(entry_stats, "count", le32_to_cpu(item->thermal_throttle.count));
+ break;
+ default:
+ json_object_add_value_int(entry_stats, "raw", int48_to_long(item->raw));
+ }
+ json_object_add_value_object(dev_stats, id_to_name(item->id), entry_stats);
+}
+
+static void vu_smart_log_show_json(struct vu_smart_log *payload, unsigned int nsid, const char *devname)
+{
+ struct json_object *dev_stats = json_create_object();
+ struct nvme_additional_smart_log_item *item = payload->item;
+ struct json_object *root;
+
+ for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
+ smart_log_item_add_json(&item[i], dev_stats);
+
+ root = json_create_object();
+ json_object_add_value_string(root, "Solidigm SMART log", devname);
+ json_object_add_value_object(root, "Device stats", dev_stats);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static void vu_smart_log_show(struct vu_smart_log *payload, unsigned int nsid, const char *devname,
+ __u8 uuid_index)
+{
+ struct nvme_additional_smart_log_item *item = payload->item;
+
+ printf("Additional Smart Log for NVMe device:%s namespace-id:%x UUID-idx:%d\n",
+ devname, nsid, uuid_index);
+ printf("ID KEY Normalized Raw\n");
+
+ for (int i = 0; i < VU_SMART_MAX_ITEMS; i++)
+ smart_log_item_print(&item[i]);
+}
+
+int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "Get Solidigm vendor specific smart log (optionally, for the specified namespace), and show it.";
+ const int solidigm_vu_smart_log_id = 0xCA;
+ struct vu_smart_log smart_log_payload;
+ enum nvme_print_flags flags;
+ struct nvme_dev *dev;
+ int err;
+ __u8 uuid_index;
+
+ struct config {
+ __u32 namespace_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, "(optional) desired namespace"),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0) {
+ fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+ dev_close(dev);
+ return err;
+ }
+
+ uuid_index = solidigm_get_vu_uuid_index(dev);
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = &smart_log_payload,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = solidigm_vu_smart_log_id,
+ .len = sizeof(smart_log_payload),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .uuidx = uuid_index,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (!err) {
+ if (flags & JSON)
+ vu_smart_log_show_json(&smart_log_payload,
+ cfg.namespace_id, dev->name);
+ else if (flags & BINARY)
+ d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
+ else
+ vu_smart_log_show(&smart_log_payload, cfg.namespace_id,
+ dev->name, uuid_index);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
+
diff --git a/plugins/solidigm/solidigm-smart.h b/plugins/solidigm/solidigm-smart.h
new file mode 100644
index 0000000..e19ebe5
--- /dev/null
+++ b/plugins/solidigm/solidigm-smart.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-telemetry.c b/plugins/solidigm/solidigm-telemetry.c
new file mode 100644
index 0000000..2bebccc
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry.c
@@ -0,0 +1,189 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "nvme-print.h"
+#include "solidigm-telemetry.h"
+#include "solidigm-telemetry/telemetry-log.h"
+#include "solidigm-telemetry/cod.h"
+#include "solidigm-telemetry/header.h"
+#include "solidigm-telemetry/config.h"
+#include "solidigm-telemetry/data-area.h"
+#include "solidigm-util.h"
+
+static int read_file2buffer(char *file_name, char **buffer, size_t *length)
+{
+ FILE *fd = fopen(file_name, "rb");
+
+ if (!fd)
+ return errno;
+
+ fseek(fd, 0, SEEK_END);
+ size_t length_bytes = ftell(fd);
+
+ fseek(fd, 0, SEEK_SET);
+
+ *buffer = malloc(length_bytes);
+ if (!*buffer) {
+ fclose(fd);
+ return errno;
+ }
+ *length = fread(*buffer, 1, length_bytes, fd);
+ fclose(fd);
+ return 0;
+}
+
+struct config {
+ __u32 host_gen;
+ bool ctrl_init;
+ int data_area;
+ char *cfg_file;
+ bool is_input_file;
+};
+
+int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Parse Solidigm Telemetry log";
+ const char *hgen = "Controls when to generate new host initiated report. Default value '1' generates new host initiated report, value '0' causes retrieval of existing log.";
+ const char *cgen = "Gather report generated by the controller.";
+ const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
+ const char *cfile = "JSON configuration file";
+ const char *sfile = "data source <device> is binary file containing log dump instead of block or character device";
+ struct nvme_dev *dev;
+
+ struct telemetry_log tl = {
+ .root = json_create_object(),
+ .log = NULL,
+ };
+
+ struct config cfg = {
+ .host_gen = 1,
+ .ctrl_init = false,
+ .data_area = -1,
+ .cfg_file = NULL,
+ .is_input_file = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen),
+ OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen),
+ OPT_UINT("data-area", 'd', &cfg.data_area, dgen),
+ OPT_FILE("config-file", 'j', &cfg.cfg_file, cfile),
+ OPT_FLAG("source-file", 's', &cfg.is_input_file, sfile),
+ OPT_END()
+ };
+
+ int err = argconfig_parse(argc, argv, desc, opts);
+
+ if (err)
+ goto ret;
+
+ /* When not selected on the command line, get minimum data area required */
+ if (cfg.data_area == -1)
+ cfg.data_area = cfg.cfg_file ? 3 : 1;
+
+ if (cfg.is_input_file) {
+ if (optind >= argc) {
+ err = errno = EINVAL;
+ perror(argv[0]);
+ goto ret;
+ }
+ char *binary_file_name = argv[optind];
+
+ err = read_file2buffer(binary_file_name, (char **)&tl.log, &tl.log_size);
+ } else {
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ }
+ if (err)
+ goto ret;
+
+ if (cfg.host_gen > 1) {
+ SOLIDIGM_LOG_WARNING("Invalid host-generate value '%d'", cfg.host_gen);
+ err = EINVAL;
+ goto close_fd;
+ }
+
+ if (cfg.cfg_file) {
+ char *conf_str = NULL;
+ size_t length = 0;
+
+ err = read_file2buffer(cfg.cfg_file, &conf_str, &length);
+ if (err) {
+ SOLIDIGM_LOG_WARNING("Failed to open JSON configuration file %s: %s!",
+ cfg.cfg_file, strerror(err));
+ goto close_fd;
+ }
+ struct json_tokener *jstok = json_tokener_new();
+
+ tl.configuration = json_tokener_parse_ex(jstok, conf_str, length);
+ free(conf_str);
+ if (jstok->err != json_tokener_success) {
+ SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)",
+ cfg.cfg_file,
+ json_tokener_error_desc(jstok->err),
+ jstok->char_offset);
+ json_tokener_free(jstok);
+ err = EINVAL;
+ goto close_fd;
+ }
+ json_tokener_free(jstok);
+ }
+
+ if (!cfg.is_input_file) {
+ size_t max_data_tx;
+
+ err = nvme_get_telemetry_max(dev_fd(dev), NULL, &max_data_tx);
+ if (err < 0) {
+ SOLIDIGM_LOG_WARNING("identify_ctrl: %s",
+ nvme_strerror(errno));
+ goto close_fd;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ SOLIDIGM_LOG_WARNING("Failed to acquire identify ctrl %d!", err);
+ goto close_fd;
+ }
+ if (max_data_tx > DRIVER_MAX_TX_256K)
+ max_data_tx = DRIVER_MAX_TX_256K;
+
+ err = nvme_get_telemetry_log(dev_fd(dev), cfg.host_gen, cfg.ctrl_init, true,
+ max_data_tx, cfg.data_area, &tl.log, &tl.log_size);
+ if (err < 0) {
+ SOLIDIGM_LOG_WARNING("get-telemetry-log: %s",
+ nvme_strerror(errno));
+ goto close_fd;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ SOLIDIGM_LOG_WARNING("Failed to acquire telemetry log %d!", err);
+ goto close_fd;
+ }
+ }
+ solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
+
+ json_print_object(tl.root, NULL);
+ json_free_object(tl.root);
+ printf("\n");
+
+close_fd:
+ if (!cfg.is_input_file) {
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ }
+ret:
+ json_free_object(tl.configuration);
+ free(tl.log);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-telemetry.h b/plugins/solidigm/solidigm-telemetry.h
new file mode 100644
index 0000000..971ee2a
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-telemetry/cod.c b/plugins/solidigm/solidigm-telemetry/cod.c
new file mode 100644
index 0000000..363822a
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/cod.c
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+#include "common.h"
+#include "cod.h"
+
+const char *oemDataMapDesc[] = {
+ "Media Read Count", //Uid 0x00
+ "Host Read count", //Uid 0x01
+ "Media Write Count", //Uid 0x02
+ "Host Write Count", //Uid 0x03
+ "Device Model", // 0x04
+ "Serial Number", // 0x05
+ "Firmware Revision", // 0x06
+ "Drive Status", // 0x07
+ "Minimum Temperature", // 0x08
+ "Maximum Temperature", // 0x09
+ "Power Loss Protection Status", // 0x0a
+ "Lifetime Unsafe Shutdown Count", // 0x0b
+ "Lifetime Power Cycle Count", // 0x0c
+ "Minimum Read Latency", // 0x0d
+ "Maximum Read Latency", // 0x0e
+ "Average Read Latency", // 0x0f
+ "Minimum Write Latency", // 0x10
+ "Maximum Write Latency", // 0x11
+ "Average Write Latency", // 0x12
+ "Grown Defects Count", // 0x13
+ "DQS Recovery Count", // 0x14
+ "Program Fail Count", // 0x15
+ "Erase Fail Count", // 0x16
+ "Defrag Writes in Progress Count", // 0x17
+ "Total Defrag Writes Count", // 0x18
+ "Max Die Offline Number", // 0x19
+ "Current Die Offline Number", // 0x1A
+ "XOR Enable Status", // 0x1B
+ "Media Life Used", // 0x1C
+ "Uncorrectable Error Count", // 0x1D
+ "Current Wear Range Delta", // 0x1E
+ "Read Errors Corrected by XOR", // 0x1F
+ "Background Data Refresh", // 0x20
+ "Pmic Vin History Data 1 Min", // 0x21
+ "Pmic Vin History Data 1 Max", // 0x22
+ "Pmic Vin History Data 1 Avg", // 0x23
+ "Pmic Vin History Data 2 Min", // 0x24
+ "Pmic Vin History Data 2 Max", // 0x25
+ "Pmic Vin History Data 2 Avg", // 0x26
+ "Pmic Vin History Data Total Readings", // 0x27
+ "All Time Current Max Wear Level", // 0x28
+ "Media Wear Remaining", // 0x29
+ "Total Non-Defrag Writes", // 0x2A
+ "Media Health Relocations" //Uid 0x2B = 43
+};
+
+static const char *getOemDataMapDescription(uint32_t id)
+{
+ if (id < ARRAY_SIZE(oemDataMapDesc))
+ return oemDataMapDesc[id];
+ return "unknown";
+}
+
+#define OEMSIGNATURE 0x504D4443
+
+#pragma pack(push, cod, 1)
+struct cod_header {
+ uint32_t versionMajor;
+ uint32_t versionMinor;
+ uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation
+ uint32_t MapSizeInBytes; //!Total size of the map data structure in bytes
+ uint32_t EntryCount; //!Total number of entries in the entry list
+ uint8_t Reserved[12];
+};
+
+struct cod_item {
+ uint32_t DataFieldMapUid; //!The data field unique identifier value
+ uint32_t reserved1 : 8;
+ uint32_t dataFieldType : 8;
+ uint32_t issigned : 1;
+ uint32_t bigEndian : 1;
+ uint32_t dataInvalid : 1;
+ uint32_t reserved2 : 13;
+ uint32_t DataFieldSizeInBytes;
+ uint8_t Reserved1[4];
+ uint64_t DataFieldOffset;
+ uint8_t Reserved2[8];
+};
+
+struct cod_map {
+ struct cod_header header;
+ struct cod_item items[];
+};
+
+#pragma pack(pop, cod)
+
+void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
+{
+ enum cod_field_type {
+ INTEGER,
+ FLOAT,
+ STRING,
+ TWO_BYTE_ASCII,
+ FOUR_BYTE_ASCII,
+
+ UNKNOWN = 0xFF,
+ };
+ struct json_object *telemetry_header = NULL;
+ struct json_object *COD_offset = NULL;
+ struct json_object *reason_id = NULL;
+
+ if (!json_object_object_get_ex(tl->root, "telemetryHeader", &telemetry_header))
+ return;
+ if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id))
+ return;
+ if (!json_object_object_get_ex(reason_id, "oemDataMapOffset", &COD_offset))
+ return;
+
+ uint64_t offset = json_object_get_int(COD_offset);
+
+ if (!offset)
+ return;
+
+ if ((offset + sizeof(struct cod_header)) > tl->log_size) {
+ SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds.");
+ return;
+ }
+
+ const struct cod_map *data = (struct cod_map *) (((uint8_t *)tl->log) + offset);
+
+ uint32_t signature = be32_to_cpu(data->header.Signature);
+
+ if (signature != OEMSIGNATURE) {
+ SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature);
+ return;
+ }
+ if ((offset + data->header.MapSizeInBytes) > tl->log_size) {
+ SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds.");
+ return;
+ }
+
+ struct json_object *cod = json_create_object();
+
+ json_object_object_add(tl->root, "cod", cod);
+
+ for (uint64_t i = 0; i < data->header.EntryCount; i++) {
+ if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) >
+ tl->log_size) {
+ SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %"PRIu64"!",
+ i);
+ return;
+ }
+ struct cod_item item = data->items[i];
+
+ if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size)
+ continue;
+ if (item.dataInvalid)
+ continue;
+ uint8_t *val = ((uint8_t *)tl->log) + item.DataFieldOffset;
+ const char *key = getOemDataMapDescription(item.DataFieldMapUid);
+
+ switch (item.dataFieldType) {
+ case INTEGER:
+ if (item.issigned)
+ json_object_object_add(cod, key,
+ json_object_new_int64(le64_to_cpu(*(uint64_t *)val)));
+ else
+ json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val));
+ break;
+ case FLOAT:
+ json_object_add_value_float(cod, key, *(float *)val);
+ break;
+ case STRING:
+ json_object_object_add(cod, key,
+ json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes));
+ break;
+ case TWO_BYTE_ASCII:
+ json_object_object_add(cod, key,
+ json_object_new_string_len((const char *)val, 2));
+ break;
+ case FOUR_BYTE_ASCII:
+ json_object_object_add(cod, key,
+ json_object_new_string_len((const char *)val, 4));
+ break;
+ default:
+ SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid);
+ break;
+ }
+ }
+}
diff --git a/plugins/solidigm/solidigm-telemetry/cod.h b/plugins/solidigm/solidigm-telemetry/cod.h
new file mode 100644
index 0000000..032ccdc
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/cod.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "telemetry-log.h"
+void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl);
diff --git a/plugins/solidigm/solidigm-telemetry/config.c b/plugins/solidigm/solidigm-telemetry/config.c
new file mode 100644
index 0000000..eceeede
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/config.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+// max 16 bit unsigned integer number 65535
+#define MAX_16BIT_NUM_AS_STRING_SIZE 6
+
+#define OBJ_NAME_PREFIX "UID_"
+#define NLOG_OBJ_PREFIX OBJ_NAME_PREFIX "NLOG_"
+
+static bool config_get_by_version(const struct json_object *obj, int version_major,
+ int version_minor, struct json_object **value)
+{
+ char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
+ char str_subkey[MAX_16BIT_NUM_AS_STRING_SIZE];
+
+ snprintf(str_key, sizeof(str_key), "%d", version_major);
+ snprintf(str_subkey, sizeof(str_subkey), "%d", version_minor);
+ struct json_object *major_obj = NULL;
+
+ if (!json_object_object_get_ex(obj, str_key, &major_obj))
+ return false;
+ if (!json_object_object_get_ex(major_obj, str_subkey, value))
+ return false;
+ return value != NULL;
+}
+
+bool solidigm_config_get_struct_by_token_version(const struct json_object *config, int token_id,
+ int version_major, int version_minor,
+ struct json_object **value)
+{
+ struct json_object *token = NULL;
+ char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
+
+ snprintf(str_key, sizeof(str_key), "%d", token_id);
+ if (!json_object_object_get_ex(config, str_key, &token))
+ return false;
+ if (!config_get_by_version(token, version_major, version_minor, value))
+ return false;
+ return value != NULL;
+}
+
+const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token)
+{
+ struct json_object *nlog_names = NULL;
+ struct json_object *obj_name;
+ char hex_header[STR_HEX32_SIZE];
+ const char *name;
+
+ if (!json_object_object_get_ex(config, "TELEMETRY_OBJECT_UIDS", &nlog_names))
+ return NULL;
+ snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", token);
+
+ if (!json_object_object_get_ex(nlog_names, hex_header, &obj_name))
+ return NULL;
+ name = json_object_get_string(obj_name);
+ if (strncmp(NLOG_OBJ_PREFIX, name, strlen(NLOG_OBJ_PREFIX)))
+ return NULL;
+
+ return &name[strlen(OBJ_NAME_PREFIX)];
+}
+
+struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config)
+{
+ struct json_object *nlog_formats = NULL;
+
+ json_object_object_get_ex(config, "NLOG_FORMATS", &nlog_formats);
+ return nlog_formats;
+}
diff --git a/plugins/solidigm/solidigm-telemetry/config.h b/plugins/solidigm/solidigm-telemetry/config.h
new file mode 100644
index 0000000..4e56ba3
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/config.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+#include <stdbool.h>
+#include "util/json.h"
+
+#define STR_HEX32_SIZE sizeof("0x00000000")
+
+bool solidigm_config_get_struct_by_token_version(const struct json_object *obj,
+ int key, int subkey,
+ int subsubkey,
+ struct json_object **value);
+
+const char *solidigm_config_get_nlog_obj_name(const struct json_object *config, uint32_t token);
+struct json_object *solidigm_config_get_nlog_formats(const struct json_object *config);
+
diff --git a/plugins/solidigm/solidigm-telemetry/data-area.c b/plugins/solidigm/solidigm-telemetry/data-area.c
new file mode 100644
index 0000000..14d612b
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/data-area.c
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "common.h"
+#include "header.h"
+#include "cod.h"
+#include "data-area.h"
+#include "config.h"
+#include "nlog.h"
+#include <ctype.h>
+
+#define SIGNED_INT_PREFIX "int"
+#define BITS_IN_BYTE 8
+
+#define MAX_WARNING_SIZE 1024
+#define MAX_ARRAY_RANK 16
+
+static bool telemetry_log_get_value(const struct telemetry_log *tl,
+ uint64_t offset_bit, uint32_t size_bit,
+ bool is_signed, struct json_object **val_obj)
+{
+ uint32_t offset_bit_from_byte;
+ uint32_t additional_size_byte;
+ uint32_t offset_byte;
+ uint64_t val;
+
+ if (!size_bit) {
+ char err_msg[MAX_WARNING_SIZE];
+
+ snprintf(err_msg, MAX_WARNING_SIZE,
+ "Value with size_bit=0 not supported.");
+ *val_obj = json_object_new_string(err_msg);
+
+ return false;
+ }
+ additional_size_byte = (size_bit - 1) ? (size_bit - 1) / BITS_IN_BYTE : 0;
+ offset_byte = (uint32_t)offset_bit / BITS_IN_BYTE;
+
+ if (offset_byte > (tl->log_size - additional_size_byte)) {
+ char err_msg[MAX_WARNING_SIZE];
+
+ snprintf(err_msg, MAX_WARNING_SIZE,
+ "Value offset greater than binary size (%u > %zu).",
+ offset_byte, tl->log_size);
+ *val_obj = json_object_new_string(err_msg);
+
+ return false;
+ }
+
+ offset_bit_from_byte = (uint32_t) (offset_bit - ((uint64_t)offset_byte * BITS_IN_BYTE));
+
+ if ((size_bit + offset_bit_from_byte) > (sizeof(uint64_t) * BITS_IN_BYTE)) {
+ char err_msg[MAX_WARNING_SIZE];
+
+ snprintf(err_msg, MAX_WARNING_SIZE,
+ "Value crossing 64 bit, byte aligned boundary, not supported. size_bit=%u, offset_bit_from_byte=%u.",
+ size_bit, offset_bit_from_byte);
+ *val_obj = json_object_new_string(err_msg);
+
+ return false;
+ }
+
+ val = *(uint64_t *)(((char *)tl->log) + offset_byte);
+ val >>= offset_bit_from_byte;
+ if (size_bit < 64)
+ val &= (1ULL << size_bit) - 1;
+ if (is_signed) {
+ if (val >> (size_bit - 1))
+ val |= (0ULL - 1) << size_bit;
+ *val_obj = json_object_new_int64(val);
+ } else {
+ *val_obj = json_object_new_uint64(val);
+ }
+
+ return true;
+}
+
+static int telemetry_log_structure_parse(const struct telemetry_log *tl,
+ struct json_object *struct_def,
+ uint64_t parent_offset_bit,
+ struct json_object *output,
+ struct json_object *metadata)
+{
+ struct json_object *obj_arraySizeArray = NULL;
+ struct json_object *obj = NULL;
+ struct json_object *obj_memberList;
+ struct json_object *major_dimension = NULL;
+ struct json_object *sub_output;
+ bool is_enumeration = false;
+ bool has_member_list;
+ const char *type = "";
+ const char *name;
+ size_t array_rank;
+ uint64_t offset_bit;
+ uint32_t size_bit;
+ uint64_t linear_array_pos_bit;
+ uint32_t array_size_dimension[MAX_ARRAY_RANK];
+
+ if (!json_object_object_get_ex(struct_def, "name", &obj)) {
+ SOLIDIGM_LOG_WARNING("Warning: Structure definition missing property 'name': %s",
+ json_object_to_json_string(struct_def));
+ return -1;
+ }
+
+ name = json_object_get_string(obj);
+
+ if (metadata) {
+ json_object_get(obj);
+ json_object_object_add(metadata, "objName", obj);
+ }
+
+ if (json_object_object_get_ex(struct_def, "type", &obj))
+ type = json_object_get_string(obj);
+
+ if (!json_object_object_get_ex(struct_def, "offsetBit", &obj)) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Structure definition missing property 'offsetBit': %s",
+ json_object_to_json_string(struct_def));
+ return -1;
+ }
+
+ offset_bit = json_object_get_uint64(obj);
+
+ if (!json_object_object_get_ex(struct_def, "sizeBit", &obj)) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Structure definition missing property 'sizeBit': %s",
+ json_object_to_json_string(struct_def));
+ return -1;
+ }
+
+ size_bit = (uint32_t)json_object_get_uint64(obj);
+
+ if (json_object_object_get_ex(struct_def, "enum", &obj))
+ is_enumeration = json_object_get_boolean(obj);
+
+ has_member_list = json_object_object_get_ex(struct_def,
+ "memberList",
+ &obj_memberList);
+
+ if (!json_object_object_get_ex(struct_def, "arraySize",
+ &obj_arraySizeArray)) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Structure definition missing property 'arraySize': %s",
+ json_object_to_json_string(struct_def));
+ return -1;
+ }
+
+ array_rank = json_object_array_length(obj_arraySizeArray);
+ if (!array_rank) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Structure property 'arraySize' don't support flexible array: %s",
+ json_object_to_json_string(struct_def));
+ return -1;
+ }
+ if (array_rank > MAX_ARRAY_RANK) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Structure property 'arraySize' don't support more than %d dimensions: %s",
+ MAX_ARRAY_RANK, json_object_to_json_string(struct_def));
+ return -1;
+ }
+
+ for (size_t i = 0; i < array_rank; i++) {
+ struct json_object *dimension = json_object_array_get_idx(obj_arraySizeArray, i);
+
+ array_size_dimension[i] = json_object_get_int(dimension);
+ major_dimension = dimension;
+ }
+ if (array_rank > 1) {
+ uint32_t linear_pos_per_index = array_size_dimension[0];
+ uint32_t prev_index_offset_bit = 0;
+ struct json_object *dimension_output;
+
+ for (unsigned int i = 1; i < (array_rank - 1); i++)
+ linear_pos_per_index *= array_size_dimension[i];
+
+ dimension_output = json_create_array();
+ if (json_object_get_type(output) == json_type_array)
+ json_object_array_add(output, dimension_output);
+ else
+ json_object_add_value_array(output, name, dimension_output);
+
+ /*
+ * Make sure major_dimension object will not be
+ * deleted from memory when deleted from array
+ */
+ json_object_get(major_dimension);
+ json_object_array_del_idx(obj_arraySizeArray, array_rank - 1, 1);
+
+ for (unsigned int i = 0 ; i < array_size_dimension[0]; i++) {
+ struct json_object *sub_array = json_create_array();
+ uint64_t offset;
+
+ offset = parent_offset_bit + prev_index_offset_bit;
+
+ json_object_array_add(dimension_output, sub_array);
+ telemetry_log_structure_parse(tl, struct_def,
+ offset, sub_array, NULL);
+ prev_index_offset_bit += linear_pos_per_index * size_bit;
+ }
+
+ json_object_array_put_idx(obj_arraySizeArray, array_rank - 1,
+ major_dimension);
+
+ return 0;
+ }
+
+ linear_array_pos_bit = 0;
+ sub_output = output;
+
+ if (array_size_dimension[0] > 1) {
+ sub_output = json_create_array();
+ if (json_object_get_type(output) == json_type_array)
+ json_object_array_add(output, sub_output);
+ else
+ json_object_add_value_array(output, name, sub_output);
+ }
+
+ for (uint32_t j = 0; j < array_size_dimension[0]; j++) {
+ if (is_enumeration || !has_member_list) {
+ bool is_signed = !strncmp(type, SIGNED_INT_PREFIX, sizeof(SIGNED_INT_PREFIX)-1);
+ struct json_object *val_obj;
+ uint64_t offset;
+
+ offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
+ if (telemetry_log_get_value(tl, offset, size_bit, is_signed, &val_obj)) {
+ if (array_size_dimension[0] > 1)
+ json_object_array_put_idx(sub_output, j, val_obj);
+ else
+ json_object_object_add(sub_output, name, val_obj);
+ } else {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: %s From property '%s', array index %u, structure definition: %s",
+ json_object_get_string(val_obj), name, j,
+ json_object_to_json_string(struct_def));
+ json_free_object(val_obj);
+ }
+ } else {
+ struct json_object *sub_sub_output = json_create_object();
+ int num_members;
+
+ if (array_size_dimension[0] > 1)
+ json_object_array_put_idx(sub_output, j, sub_sub_output);
+ else
+ json_object_add_value_object(sub_output, name, sub_sub_output);
+
+ num_members = json_object_array_length(obj_memberList);
+ for (int k = 0; k < num_members; k++) {
+ struct json_object *member = json_object_array_get_idx(obj_memberList, k);
+ uint64_t offset;
+
+ offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
+ telemetry_log_structure_parse(tl, member, offset,
+ sub_sub_output, NULL);
+ }
+ }
+ linear_array_pos_bit += size_bit;
+ }
+ return 0;
+}
+
+static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl,
+ enum nvme_telemetry_da da,
+ uint32_t *offset, uint32_t *size)
+{
+ uint32_t offset_blocks = 1;
+ uint32_t last_block = tl->log->dalb1;
+ uint32_t last;
+
+ switch (da) {
+ case NVME_TELEMETRY_DA_1:
+ offset_blocks = 1;
+ last_block = tl->log->dalb1;
+ break;
+ case NVME_TELEMETRY_DA_2:
+ offset_blocks = tl->log->dalb1 + 1;
+ last_block = tl->log->dalb2;
+ break;
+ case NVME_TELEMETRY_DA_3:
+ offset_blocks = tl->log->dalb2 + 1;
+ last_block = tl->log->dalb3;
+ break;
+ case NVME_TELEMETRY_DA_4:
+ offset_blocks = tl->log->dalb3 + 1;
+ last_block = tl->log->dalb4;
+ break;
+ default:
+ return -1;
+ }
+
+ *offset = offset_blocks * NVME_LOG_TELEM_BLOCK_SIZE;
+ last = (last_block + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
+ *size = last - *offset;
+ if ((*offset > tl->log_size) || (last > tl->log_size) || (last <= *offset)) {
+ SOLIDIGM_LOG_WARNING("Warning: Data Area %d don't fit this Telemetry log.", da);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int telemetry_log_nlog_parse(const struct telemetry_log *tl, struct json_object *formats,
+ uint64_t nlog_file_offset, uint64_t nlog_size,
+ struct json_object *output, struct json_object *metadata)
+{
+ /* boundary check */
+ if (tl->log_size < (nlog_file_offset + nlog_size)) {
+ const char *name = "";
+ int media_bank = -1;
+ struct json_object *jobj;
+
+ if (json_object_object_get_ex(metadata, "objName", &jobj))
+ name = json_object_get_string(jobj);
+ if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
+ media_bank = json_object_get_int(jobj);
+ SOLIDIGM_LOG_WARNING("%s:%d do not fit this log dump.", name, media_bank);
+ return -1;
+ }
+ return solidigm_nlog_parse(((char *) tl->log) + nlog_file_offset,
+ nlog_size, formats, metadata, output);
+}
+
+struct toc_item {
+ uint32_t OffsetBytes;
+ uint32_t ContentSizeBytes;
+};
+
+struct data_area_header {
+ uint8_t versionMajor;
+ uint8_t versionMinor;
+ uint16_t TableOfContentsCount;
+ uint32_t DataAreaSize;
+ uint8_t Reserved[8];
+};
+
+struct table_of_contents {
+ struct data_area_header header;
+ struct toc_item items[];
+};
+
+struct telemetry_object_header {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t Token;
+ uint8_t CoreId;
+ uint8_t Reserved[3];
+};
+
+static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
+ enum nvme_telemetry_da da,
+ struct json_object *toc_array,
+ struct json_object *tele_obj_array)
+{
+
+ const struct telemetry_object_header *header;
+ const struct table_of_contents *toc;
+ char *payload;
+ uint32_t da_offset;
+ uint32_t da_size;
+ struct json_object *nlog_formats;
+
+ if (telemetry_log_data_area_get_offset(tl, da, &da_offset, &da_size))
+ return;
+
+ toc = (struct table_of_contents *)(((char *)tl->log) + da_offset);
+ payload = (char *) tl->log;
+ nlog_formats = solidigm_config_get_nlog_formats(tl->configuration);
+
+ for (int i = 0; i < toc->header.TableOfContentsCount; i++) {
+ struct json_object *structure_definition = NULL;
+ struct json_object *toc_item;
+ uint32_t obj_offset;
+ bool has_struct;
+ const char *nlog_name = NULL;
+ uint32_t header_offset = sizeof(const struct telemetry_object_header);
+
+ if ((char *)&toc->items[i] >
+ (((char *)toc) + da_size - sizeof(const struct toc_item))) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Data Area %d, Table of Contents item %d crossed Data Area size.",
+ da, i);
+ return;
+ }
+
+ obj_offset = toc->items[i].OffsetBytes;
+ if ((obj_offset + sizeof(const struct telemetry_object_header)) > da_size) {
+ SOLIDIGM_LOG_WARNING(
+ "Warning: Data Area %d, item %d data, crossed Data Area size.", da, i);
+ continue;
+ }
+
+ toc_item = json_create_object();
+ json_object_array_add(toc_array, toc_item);
+ json_object_add_value_uint(toc_item, "dataArea", da);
+ json_object_add_value_uint(toc_item, "dataAreaIndex", i);
+ json_object_add_value_uint(toc_item, "dataAreaOffset", obj_offset);
+ json_object_add_value_uint(toc_item, "fileOffset", obj_offset + da_offset);
+ json_object_add_value_uint(toc_item, "size", toc->items[i].ContentSizeBytes);
+
+ header = (const struct telemetry_object_header *) (payload + da_offset + obj_offset);
+ json_object_add_value_uint(toc_item, "telemMajor", header->versionMajor);
+ json_object_add_value_uint(toc_item, "telemMinor", header->versionMinor);
+ json_object_add_value_uint(toc_item, "objectId", header->Token);
+ json_object_add_value_uint(toc_item, "mediaBankId", header->CoreId);
+
+ has_struct = solidigm_config_get_struct_by_token_version(tl->configuration,
+ header->Token,
+ header->versionMajor,
+ header->versionMinor,
+ &structure_definition);
+ if (!has_struct) {
+ if (!nlog_formats)
+ continue;
+ nlog_name = solidigm_config_get_nlog_obj_name(tl->configuration,
+ header->Token);
+ if (!nlog_name)
+ continue;
+ }
+ struct json_object *tele_obj_item = json_create_object();
+
+ json_object_array_add(tele_obj_array, tele_obj_item);
+ json_object_get(toc_item);
+ json_object_add_value_object(tele_obj_item, "metadata", toc_item);
+ struct json_object *parsed_struct = json_create_object();
+
+ json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
+ struct json_object *obj_hasTelemObjHdr = NULL;
+ uint64_t object_file_offset;
+
+ if (json_object_object_get_ex(structure_definition,
+ "hasTelemObjHdr",
+ &obj_hasTelemObjHdr)) {
+ bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
+
+ if (hasHeader)
+ header_offset = 0;
+ }
+ object_file_offset = ((uint64_t)da_offset) + obj_offset + header_offset;
+ if (has_struct) {
+ telemetry_log_structure_parse(tl, structure_definition,
+ BITS_IN_BYTE * object_file_offset,
+ parsed_struct, toc_item);
+ } else if (nlog_formats) {
+ json_object_object_add(toc_item, "objName",
+ json_object_new_string(nlog_name));
+ telemetry_log_nlog_parse(tl, nlog_formats, object_file_offset,
+ toc->items[i].ContentSizeBytes - header_offset,
+ parsed_struct, toc_item);
+ }
+ }
+}
+
+int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
+ enum nvme_telemetry_da last_da)
+{
+ struct json_object *tele_obj_array = json_create_array();
+ struct json_object *toc_array = json_create_array();
+
+ solidigm_telemetry_log_header_parse(tl);
+ solidigm_telemetry_log_cod_parse(tl);
+ if (tl->configuration) {
+ json_object_add_value_array(tl->root, "tableOfContents", toc_array);
+ json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
+
+ for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
+ telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
+ }
+ return 0;
+}
diff --git a/plugins/solidigm/solidigm-telemetry/data-area.h b/plugins/solidigm/solidigm-telemetry/data-area.h
new file mode 100644
index 0000000..6b690d8
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/data-area.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+#include "telemetry-log.h"
+
+int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl,
+ enum nvme_telemetry_da last_da);
diff --git a/plugins/solidigm/solidigm-telemetry/header.c b/plugins/solidigm/solidigm-telemetry/header.c
new file mode 100644
index 0000000..866ebff
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/header.c
@@ -0,0 +1,223 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "common.h"
+#include "header.h"
+
+#pragma pack(push, reason_indentifier, 1)
+struct reason_indentifier_1_0 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ char FirmwareVersion[12]; //! Similar to IdentifyController.FR
+ char BootloaderVersion[12]; //! Bootloader version string
+ char SerialNumber[20]; //! Device serial number
+ uint8_t Reserved[56]; //! Reserved for future usage
+};
+static_assert(sizeof(const struct reason_indentifier_1_0) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_0");
+
+struct reason_indentifier_1_1 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ char FirmwareVersion[12]; //! Similar to IdentifyController.FR
+ char BootloaderVersion[12]; //! Bootloader version string
+ char SerialNumber[20]; //! Device serial number
+ uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
+ uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
+ uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
+ uint8_t Reserved[46]; //! Reserved for future usage
+};
+static_assert(sizeof(const struct reason_indentifier_1_1) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_1");
+
+struct reason_indentifier_1_2 {
+ uint16_t versionMajor;
+ uint16_t versionMinor;
+ uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
+ char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
+ uint8_t Reserved1[24]; //! pad over Fields removed from version 1.1
+ char SerialNumber[20]; //! Device serial number
+ uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
+ uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
+ uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
+ uint8_t ProductFamilyId;
+ uint8_t Reserved2[5]; //! Reserved for future usage
+ uint8_t DualPortReserved[40]; //! Reserved for dual port
+};
+static_assert(sizeof(const struct reason_indentifier_1_2) ==
+ MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
+ "Size mismatch for reason_indentifier_1_2");
+#pragma pack(pop, reason_indentifier)
+
+static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_0 *ri;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_0 *) tl->log->rsnident;
+ json_object_object_add(reason_id, "firmwareVersion",
+ json_object_new_string_len(ri->FirmwareVersion,
+ sizeof(ri->FirmwareVersion)));
+ json_object_object_add(reason_id, "bootloaderVersion",
+ json_object_new_string_len(ri->BootloaderVersion,
+ sizeof(ri->BootloaderVersion)));
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved[i]);
+
+ json_object_array_add(reserved, val);
+ }
+}
+
+static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_1 *ri;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_1 *) tl->log->rsnident;
+ json_object_object_add(reason_id, "firmwareVersion",
+ json_object_new_string_len(ri->FirmwareVersion,
+ sizeof(ri->FirmwareVersion)));
+ json_object_object_add(reason_id, "bootloaderVersion",
+ json_object_new_string_len(ri->BootloaderVersion,
+ sizeof(ri->BootloaderVersion)));
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+ json_object_add_value_uint64(reason_id, "oemDataMapOffset",
+ le64_to_cpu(ri->OemDataMapOffset));
+ json_object_add_value_uint(reason_id, "telemetryMajorVersion",
+ le16_to_cpu(ri->TelemetryMajorVersion));
+ json_object_add_value_uint(reason_id, "telemetryMinorVersion",
+ le16_to_cpu(ri->TelemetryMinorVersion));
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved[i]);
+
+ json_object_array_add(reserved, val);
+ }
+}
+
+static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl,
+ struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_2 *ri;
+ struct json_object *dp_reserved;
+ struct json_object *reserved;
+
+ ri = (struct reason_indentifier_1_2 *) tl->log->rsnident;
+
+ json_object_object_add(reason_id, "serialNumber",
+ json_object_new_string_len(ri->SerialNumber,
+ sizeof(ri->SerialNumber)));
+ json_object_add_value_uint64(reason_id, "oemDataMapOffset",
+ le64_to_cpu(ri->OemDataMapOffset));
+ json_object_add_value_uint(reason_id, "telemetryMajorVersion",
+ le16_to_cpu(ri->TelemetryMajorVersion));
+ json_object_add_value_uint(reason_id, "telemetryMinorVersion",
+ le16_to_cpu(ri->TelemetryMinorVersion));
+ json_object_add_value_uint(reason_id, "productFamilyId", ri->ProductFamilyId);
+
+ reserved = json_create_array();
+ json_object_add_value_array(reason_id, "reserved2", reserved);
+ for (int i = 0; i < sizeof(ri->Reserved2); i++) {
+ struct json_object *val = json_object_new_int(ri->Reserved2[i]);
+
+ json_object_array_add(reserved, val);
+ }
+
+ dp_reserved = json_create_array();
+ json_object_add_value_array(reason_id, "dualPortReserved", dp_reserved);
+ for (int i = 0; i < sizeof(ri->DualPortReserved); i++) {
+ struct json_object *val = json_object_new_int(ri->DualPortReserved[i]);
+
+ json_object_array_add(dp_reserved, val);
+ }
+}
+
+static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *tl, struct json_object *reason_id)
+{
+ const struct reason_indentifier_1_0 *ri1_0 =
+ (struct reason_indentifier_1_0 *) tl->log->rsnident;
+ uint16_t version_major = le16_to_cpu(ri1_0->versionMajor);
+ uint16_t version_minor = le16_to_cpu(ri1_0->versionMinor);
+
+ json_object_add_value_uint(reason_id, "versionMajor", version_major);
+ json_object_add_value_uint(reason_id, "versionMinor", version_minor);
+ json_object_add_value_uint(reason_id, "reasonCode", le32_to_cpu(ri1_0->reasonCode));
+ json_object_add_value_object(reason_id, "driveStatus",
+ json_object_new_string_len(ri1_0->DriveStatus,
+ sizeof(ri1_0->DriveStatus)));
+ if (version_major == 1) {
+ switch (version_minor) {
+ case 0:
+ telemetry_log_reason_id_parse1_0_ext(tl, reason_id);
+ break;
+ case 1:
+ telemetry_log_reason_id_parse1_1_ext(tl, reason_id);
+ break;
+ default:
+ telemetry_log_reason_id_parse1_2_ext(tl, reason_id);
+ break;
+ }
+ }
+}
+
+bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl)
+{
+ const struct nvme_telemetry_log *log;
+ struct json_object *ieee_oui_id;
+ struct json_object *reason_id;
+ struct json_object *header;
+
+ if (tl->log_size < sizeof(const struct nvme_telemetry_log)) {
+ SOLIDIGM_LOG_WARNING("Telemetry log too short.");
+ return false;
+ }
+
+ header = json_create_object();
+
+ json_object_object_add(tl->root, "telemetryHeader", header);
+ log = tl->log;
+
+ json_object_add_value_uint(header, "logIdentifier", log->lpi);
+ ieee_oui_id = json_create_array();
+
+ json_object_object_add(header, "ieeeOuiIdentifier", ieee_oui_id);
+ for (int i = 0; i < sizeof(log->ieee); i++) {
+ struct json_object *val = json_object_new_int(log->ieee[i]);
+
+ json_object_array_add(ieee_oui_id, val);
+ }
+ json_object_add_value_uint(header, "dataArea1LastBlock", log->dalb1);
+ json_object_add_value_uint(header, "dataArea2LastBlock", log->dalb2);
+ json_object_add_value_uint(header, "dataArea3LastBlock", log->dalb3);
+ json_object_add_value_uint(header, "hostInitiatedDataGeneration", log->hostdgn);
+ json_object_add_value_uint(header, "controllerInitiatedDataAvailable", log->ctrlavail);
+ json_object_add_value_uint(header, "controllerInitiatedDataGeneration", log->ctrldgn);
+
+ reason_id = json_create_object();
+ json_object_add_value_object(header, "reasonIdentifier", reason_id);
+ solidigm_telemetry_log_reason_id_parse(tl, reason_id);
+
+ return true;
+}
diff --git a/plugins/solidigm/solidigm-telemetry/header.h b/plugins/solidigm/solidigm-telemetry/header.h
new file mode 100644
index 0000000..027af55
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/header.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "telemetry-log.h"
+bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl);
diff --git a/plugins/solidigm/solidigm-telemetry/meson.build b/plugins/solidigm/solidigm-telemetry/meson.build
new file mode 100644
index 0000000..96273b7
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/meson.build
@@ -0,0 +1,7 @@
+sources += [
+ 'plugins/solidigm/solidigm-telemetry/cod.c',
+ 'plugins/solidigm/solidigm-telemetry/header.c',
+ 'plugins/solidigm/solidigm-telemetry/config.c',
+ 'plugins/solidigm/solidigm-telemetry/data-area.c',
+ 'plugins/solidigm/solidigm-telemetry/nlog.c',
+]
diff --git a/plugins/solidigm/solidigm-telemetry/nlog.c b/plugins/solidigm/solidigm-telemetry/nlog.c
new file mode 100644
index 0000000..926772b
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/nlog.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "nlog.h"
+#include "config.h"
+#include <string.h>
+#include <stdio.h>
+
+#include "ccan/ilog/ilog.h"
+
+#define LOG_ENTRY_HEADER_SIZE 1
+#define LOG_ENTRY_TIMESTAMP_SIZE 2
+#define LOG_ENTRY_NUM_ARGS_MAX 8
+#define LOG_ENTRY_MAX_SIZE (LOG_ENTRY_HEADER_SIZE + LOG_ENTRY_TIMESTAMP_SIZE + \
+ LOG_ENTRY_NUM_ARGS_MAX)
+#define NUM_ARGS_MASK ((1 << ((int)STATIC_ILOG_32(LOG_ENTRY_NUM_ARGS_MAX))) - 1)
+#define MAX_HEADER_MISMATCH_TRACK 10
+
+static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format)
+{
+ char hex_header[STR_HEX32_SIZE];
+
+ snprintf(hex_header, STR_HEX32_SIZE, "0x%08X", val);
+ return json_object_object_get_ex(formats, hex_header, format);
+}
+
+static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int pos)
+{
+ return nlog[pos % nlog_size];
+}
+
+static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset,
+ struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches)
+{
+ uint32_t event_count = 0;
+ int last_bad_header_pos = nlog_size + 1; // invalid nlog offset
+ uint32_t tail_count = 0;
+
+ for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) {
+ struct json_object *format;
+ uint32_t header = nlog_get_pos(nlog, nlog_size, i);
+ uint32_t num_data;
+
+ if (header == 0 || !formats_find(formats, header, &format)) {
+ if (event_count > 0) {
+ //check if fould circular buffer tail
+ if (i != (last_bad_header_pos - 1)) {
+ if (tail_mismatches &&
+ (tail_count < MAX_HEADER_MISMATCH_TRACK))
+ tail_mismatches[tail_count] = header;
+ tail_count++;
+ }
+ last_bad_header_pos = i;
+ }
+ continue;
+ }
+ num_data = header & NUM_ARGS_MASK;
+ if (events) {
+ struct json_object *event = json_object_new_array();
+ struct json_object *param = json_object_new_array();
+ uint32_t val = nlog_get_pos(nlog, nlog_size, i - 1);
+
+ json_object_array_add(events, event);
+ json_object_array_add(event, json_object_new_int64(val));
+ val = nlog_get_pos(nlog, nlog_size, i - 2);
+ json_object_array_add(event, json_object_new_int64(val));
+ json_object_array_add(event, json_object_new_int64(header));
+ json_object_array_add(event, param);
+ for (uint32_t j = 0; j < num_data; j++) {
+ val = nlog_get_pos(nlog, nlog_size, i - 3 - j);
+ json_object_array_add(param, json_object_new_int64(val));
+ }
+ json_object_get(format);
+ json_object_array_add(event, format);
+ }
+ i -= 2 + num_data;
+ event_count++;
+ }
+ return tail_count;
+}
+
+int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_object *formats,
+ struct json_object *metadata, struct json_object *output)
+{
+ uint32_t smaller_tail_count = UINT32_MAX;
+ int best_offset = 0;
+ uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK];
+ struct json_object *events = json_object_new_array();
+ const uint32_t *nlog = (uint32_t *)buffer;
+ const uint32_t nlog_size = buff_size / sizeof(uint32_t);
+
+ for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) {
+ uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL,
+ offset_tail_mismatches[i]);
+ if (tail_count < smaller_tail_count) {
+ best_offset = i;
+ smaller_tail_count = tail_count;
+ }
+ if (tail_count == 0)
+ break;
+ }
+ if (smaller_tail_count > 1) {
+ const char *name = "";
+ int media_bank = -1;
+ char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK];
+ int pos = 0;
+ int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ?
+ smaller_tail_count : MAX_HEADER_MISMATCH_TRACK;
+ struct json_object *jobj;
+
+ if (json_object_object_get_ex(metadata, "objName", &jobj))
+ name = json_object_get_string(jobj);
+ if (json_object_object_get_ex(metadata, "mediaBankId", &jobj))
+ media_bank = json_object_get_int(jobj);
+
+ for (int i = 0; i < show_mismatch_num; i++)
+ pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ",
+ offset_tail_mismatches[best_offset][i]);
+
+ SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.",
+ name, media_bank, smaller_tail_count, str_mismatches);
+ }
+ nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL);
+
+ json_object_object_add(output, "events", events);
+ return 0;
+}
diff --git a/plugins/solidigm/solidigm-telemetry/nlog.h b/plugins/solidigm/solidigm-telemetry/nlog.h
new file mode 100644
index 0000000..f33aa45
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/nlog.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+#include "telemetry-log.h"
+
+int solidigm_nlog_parse(const char *buffer, uint64_t bufer_size,
+ struct json_object *formats, struct json_object *metadata,
+ struct json_object *output);
diff --git a/plugins/solidigm/solidigm-telemetry/telemetry-log.h b/plugins/solidigm/solidigm-telemetry/telemetry-log.h
new file mode 100644
index 0000000..e9eff73
--- /dev/null
+++ b/plugins/solidigm/solidigm-telemetry/telemetry-log.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#ifndef _SOLIDIGM_TELEMETRY_LOG_H
+#define _SOLIDIGM_TELEMETRY_LOG_H
+
+#include "libnvme.h"
+#include "util/json.h"
+#include <assert.h>
+
+#if !defined __cplusplus
+#define static_assert _Static_assert
+#endif
+
+#define VA_ARGS(...), ##__VA_ARGS__
+#define SOLIDIGM_LOG_WARNING(format, ...) fprintf(stderr, format"\n" VA_ARGS(__VA_ARGS__))
+
+#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
+
+struct telemetry_log {
+ struct nvme_telemetry_log *log;
+ size_t log_size;
+ struct json_object *root;
+ struct json_object *configuration;
+};
+
+#endif /* _SOLIDIGM_TELEMETRY_LOG_H */
diff --git a/plugins/solidigm/solidigm-temp-stats.c b/plugins/solidigm/solidigm-temp-stats.c
new file mode 100644
index 0000000..85a3c37
--- /dev/null
+++ b/plugins/solidigm/solidigm-temp-stats.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include <errno.h>
+
+#include "common.h"
+#include "nvme-print.h"
+#include "solidigm-util.h"
+
+#define SLDGM_TEMP_STATS_LID 0xC5
+
+struct temp_stats {
+ __le64 curr;
+ __le64 last_overtemp;
+ __le64 life_overtemp;
+ __le64 highest_temp;
+ __le64 lowest_temp;
+ __u8 rsvd[40];
+ __le64 max_operating_temp;
+ __le64 min_operating_temp;
+ __le64 est_offset;
+};
+
+static void show_temp_stats(struct temp_stats *stats)
+{
+ printf("Current temperature : %"PRIu64"\n", le64_to_cpu(stats->curr));
+ printf("Last critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->last_overtemp));
+ printf("Life critical overtemp flag : %"PRIu64"\n", le64_to_cpu(stats->life_overtemp));
+ printf("Highest temperature : %"PRIu64"\n", le64_to_cpu(stats->highest_temp));
+ printf("Lowest temperature : %"PRIu64"\n", le64_to_cpu(stats->lowest_temp));
+ printf("Max operating temperature : %"PRIu64"\n", le64_to_cpu(stats->max_operating_temp));
+ printf("Min operating temperature : %"PRIu64"\n", le64_to_cpu(stats->min_operating_temp));
+ printf("Estimated offset : %"PRIu64"\n", le64_to_cpu(stats->est_offset));
+}
+
+int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ unsigned char buffer[4096] = {0};
+ struct nvme_dev *dev;
+ __u8 uuid_idx;
+ int err;
+
+ const char *desc = "Get/show Temperature Statistics log.";
+ const char *raw = "dump output in binary format";
+ struct config {
+ bool raw_binary;
+ };
+
+ struct config cfg = {
+ .raw_binary = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ uuid_idx = solidigm_get_vu_uuid_index(dev);
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = buffer,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .uuidx = uuid_idx,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = SLDGM_TEMP_STATS_LID,
+ .len = sizeof(buffer),
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_LSP_NONE,
+ .rae = false,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (!err) {
+ uint64_t *guid = (uint64_t *)&buffer[4080];
+
+ if (guid[1] == 0xC7BB98B7D0324863 && guid[0] == 0xBB2C23990E9C722F) {
+ fprintf(stderr, "Error: Log page has 'OCP unsupported Requirements' GUID\n");
+ err = -EBADMSG;
+ goto closefd;
+ }
+ if (!cfg.raw_binary)
+ show_temp_stats((struct temp_stats *) buffer);
+ else
+ d_raw(buffer, sizeof(struct temp_stats));
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+closefd:
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/solidigm/solidigm-temp-stats.h b/plugins/solidigm/solidigm-temp-stats.h
new file mode 100644
index 0000000..58d5a86
--- /dev/null
+++ b/plugins/solidigm/solidigm-temp-stats.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+int sldgm_get_temp_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
diff --git a/plugins/solidigm/solidigm-util.c b/plugins/solidigm/solidigm-util.c
new file mode 100644
index 0000000..0171a49
--- /dev/null
+++ b/plugins/solidigm/solidigm-util.c
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "plugins/ocp/ocp-utils.h"
+#include "solidigm-util.h"
+
+__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev)
+{
+ int ocp_uuid_index = 0;
+
+ if (ocp_get_uuid_index(dev, &ocp_uuid_index) == 0)
+ if (ocp_uuid_index == 2)
+ return 1;
+
+ return 0;
+}
diff --git a/plugins/solidigm/solidigm-util.h b/plugins/solidigm/solidigm-util.h
new file mode 100644
index 0000000..fa5032f
--- /dev/null
+++ b/plugins/solidigm/solidigm-util.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2023 Solidigm.
+ *
+ * Author: leonardo.da.cunha@solidigm.com
+ */
+
+#include "nvme.h"
+
+#define DRIVER_MAX_TX_256K (256 * 1024)
+
+__u8 solidigm_get_vu_uuid_index(struct nvme_dev *dev);
diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c
new file mode 100644
index 0000000..4927012
--- /dev/null
+++ b/plugins/toshiba/toshiba-nvme.c
@@ -0,0 +1,573 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "toshiba-nvme.h"
+
+static const __u32 OP_SCT_STATUS = 0xE0;
+static const __u32 OP_SCT_COMMAND_TRANSFER = 0xE0;
+static const __u32 OP_SCT_DATA_TRANSFER = 0xE1;
+
+static const __u32 DW10_SCT_STATUS_COMMAND;
+static const __u32 DW10_SCT_COMMAND_TRANSFER = 0x1;
+
+static const __u32 DW11_SCT_STATUS_COMMAND;
+static const __u32 DW11_SCT_COMMAND_TRANSFER;
+
+static const __u16 INTERNAL_LOG_ACTION_CODE = 0xFFFB;
+static const __u16 CURRENT_LOG_FUNCTION_CODE = 0x0001;
+static const __u16 SAVED_LOG_FUNCTION_CODE = 0x0002;
+
+/* A bitmask field for supported devices */
+enum {
+ MASK_0 = 1 << 0,
+ MASK_1 = 1 << 1,
+ /*
+ * Future devices can use the remaining 31 bits from this field
+ * and should use 1 << 2, 1 << 3, etc.
+ */
+ MASK_IGNORE = 0
+};
+
+/* Internal device codes */
+enum {
+ CODE_0 = 0x0D,
+ CODE_1 = 0x10
+};
+
+
+static int nvme_sct_op(int fd, __u32 opcode, __u32 cdw10, __u32 cdw11, void *data, __u32 data_len)
+{
+ void *metadata = NULL;
+ const __u32 cdw2 = 0;
+ const __u32 cdw3 = 0;
+ const __u32 cdw12 = 0;
+ const __u32 cdw13 = 0;
+ const __u32 cdw14 = 0;
+ const __u32 cdw15 = 0;
+ const __u32 timeout = 0;
+ const __u32 metadata_len = 0;
+ const __u32 namespace_id = 0x0;
+ const __u32 flags = 0;
+ const __u32 rsvd = 0;
+ __u32 result;
+
+ return nvme_admin_passthru(fd, opcode, flags, rsvd, namespace_id, cdw2, cdw3, cdw10, cdw11,
+ cdw12, cdw13, cdw14, cdw15, data_len, data, metadata_len,
+ metadata, timeout, &result);
+}
+
+static int nvme_get_sct_status(int fd, __u32 device_mask)
+{
+ int err;
+ void *data = NULL;
+ size_t data_len = 512;
+ unsigned char *status;
+ __u32 supported = 0;
+
+ if (posix_memalign(&data, getpagesize(), data_len))
+ return -ENOMEM;
+
+ memset(data, 0, data_len);
+ err = nvme_sct_op(fd, OP_SCT_STATUS, DW10_SCT_STATUS_COMMAND, DW11_SCT_STATUS_COMMAND, data, data_len);
+ if (err) {
+ fprintf(stderr, "%s: SCT status failed :%d\n", __func__, err);
+ goto end;
+ }
+
+ status = data;
+ if (status[0] != 1U) {
+ /* Eek, wrong version in status header */
+ fprintf(stderr, "%s: unexpected value in SCT status[0]:(%x)\n", __func__, status[0]);
+ err = -1;
+ errno = EINVAL;
+ goto end;
+ }
+
+ /* Check if device is supported */
+ if (device_mask != MASK_IGNORE) {
+ switch (status[1]) {
+ case CODE_0:
+ supported = (device_mask & MASK_0);
+ break;
+ case CODE_1:
+ supported = (device_mask & MASK_1);
+ break;
+ default:
+ break;
+ };
+
+ if (!supported) {
+ fprintf(stderr, "%s: command unsupported on this device: (0x%x)\n", __func__, status[1]);
+ err = -1;
+ errno = EINVAL;
+ goto end;
+ }
+ }
+end:
+ if (data)
+ free(data);
+ return err;
+}
+
+static int nvme_sct_command_transfer_log(int fd, bool current)
+{
+ int err;
+ void *data = NULL;
+ size_t data_len = 512;
+ __u16 function_code, action_code = INTERNAL_LOG_ACTION_CODE;
+
+ if (current)
+ function_code = CURRENT_LOG_FUNCTION_CODE;
+ else
+ function_code = SAVED_LOG_FUNCTION_CODE;
+
+ if (posix_memalign(&data, getpagesize(), data_len))
+ return -ENOMEM;
+
+ memset(data, 0, data_len);
+ memcpy(data, &action_code, sizeof(action_code));
+ memcpy(data + 2, &function_code, sizeof(function_code));
+
+ err = nvme_sct_op(fd, OP_SCT_COMMAND_TRANSFER, DW10_SCT_COMMAND_TRANSFER, DW11_SCT_COMMAND_TRANSFER, data, data_len);
+ free(data);
+ return err;
+}
+
+static int nvme_sct_data_transfer(int fd, void *data, size_t data_len, size_t offset)
+{
+ __u32 dw10, dw11, lba_count = (data_len) / 512;
+
+ if (lba_count) {
+ /*
+ * the count is a 0-based value, which seems to mean
+ * that it's actually last lba
+ */
+ --lba_count;
+ }
+
+ dw10 = (offset << 16) | lba_count;
+ dw11 = (offset >> 16);
+ return nvme_sct_op(fd, OP_SCT_DATA_TRANSFER, dw10, dw11, data, data_len);
+}
+
+static int d_raw_to_fd(const unsigned char *buf, unsigned int len, int fd)
+{
+ int written = 0;
+ int remaining = len;
+
+ while (remaining) {
+ written = write(fd, buf, remaining);
+ if (written < 0) {
+ remaining = written;
+ break;
+ } else if (written <= remaining) {
+ remaining -= written;
+ } else {
+ /* Unexpected overwrite */
+ break;
+ }
+ }
+
+ /* return 0 on success or remaining/error */
+ return remaining;
+}
+
+/* Display progress (incoming 0->1.0) */
+static void progress_runner(float progress)
+{
+ const size_t barWidth = 70;
+ size_t i, pos;
+
+ fprintf(stdout, "[");
+ pos = barWidth * progress;
+ for (i = 0; i < barWidth; ++i) {
+ if (i <= pos)
+ fprintf(stdout, "=");
+ else
+ fprintf(stdout, " ");
+ }
+
+ fprintf(stdout, "] %d %%\r", (int)(progress * 100.0));
+ fflush(stdout);
+}
+
+static int nvme_get_internal_log(int fd, const char *const filename, bool current)
+{
+ int err;
+ int o_fd = -1;
+ void *page_data = NULL;
+ const size_t page_sector_len = 32;
+ const size_t page_data_len = page_sector_len * 512; /* 32 sectors per page */
+ uint32_t *area1_last_page;
+ uint32_t *area2_last_page;
+ uint32_t *area3_last_page;
+ uint32_t log_sectors = 0;
+ size_t pages;
+ __u32 pages_chunk;
+ /*
+ * By trial and error it seems that the largest transfer chunk size
+ * is 128 * 32 = 4k sectors = 2MB
+ */
+ const __u32 max_pages = 128;
+ size_t i;
+ unsigned int j;
+ float progress = 0.0;
+
+ err = nvme_sct_command_transfer_log(fd, current);
+ if (err) {
+ fprintf(stderr, "%s: SCT command transfer failed\n", __func__);
+ goto end;
+ }
+
+ if (posix_memalign(&page_data, getpagesize(), max_pages * page_data_len)) {
+ err = ENOMEM;
+ goto end;
+ }
+ memset(page_data, 0, max_pages * page_data_len);
+
+ /* Read the header to get the last log page - offsets 8->11, 12->15, 16->19 */
+ err = nvme_sct_data_transfer(fd, page_data, page_data_len, 0);
+ if (err) {
+ fprintf(stderr, "%s: SCT data transfer failed, page 0\n", __func__);
+ goto end;
+ }
+
+ area1_last_page = (uint32_t *) (page_data + 8);
+ area2_last_page = (uint32_t *) (page_data + 12);
+ area3_last_page = (uint32_t *) (page_data + 16);
+
+ /* The number of total log sectors is the maximum + 1; */
+ if (*area1_last_page > log_sectors)
+ log_sectors = *area1_last_page;
+ if (*area2_last_page > log_sectors)
+ log_sectors = *area2_last_page;
+ if (*area3_last_page > log_sectors)
+ log_sectors = *area3_last_page;
+
+ ++log_sectors;
+ pages = log_sectors / page_sector_len;
+ if (filename == NULL) {
+ fprintf(stdout, "Page: %u of %zu\n", 0u, pages);
+ d(page_data, page_data_len, 16, 1);
+ } else {
+ progress_runner(progress);
+ o_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (o_fd < 0) {
+ fprintf(stderr, "%s: couldn't output file %s\n", __func__, filename);
+ err = -EINVAL;
+ goto end;
+ }
+ err = d_raw_to_fd(page_data, page_data_len, o_fd);
+ if (err) {
+ fprintf(stderr, "%s: couldn't write all data to output file\n", __func__);
+ goto end;
+ }
+ }
+
+ /* Now read the rest */
+ for (i = 1; i < pages;) {
+ pages_chunk = max_pages;
+ if (pages_chunk + i >= pages)
+ pages_chunk = pages - i;
+
+ err = nvme_sct_data_transfer(fd, page_data,
+ pages_chunk * page_data_len,
+ i * page_sector_len);
+ if (err) {
+ fprintf(stderr, "%s: SCT data transfer command failed\n", __func__);
+ goto end;
+ }
+
+ progress = (float) (i) / (float) (pages);
+ progress_runner(progress);
+ if (filename == NULL) {
+ for (j = 0; j < pages_chunk; ++j) {
+ fprintf(stdout, "Page: %zu of %zu\n", i + j, pages);
+ d(page_data + (j * page_data_len), page_data_len, 16, 1);
+ }
+ } else {
+ progress_runner(progress);
+ err = d_raw_to_fd(page_data, pages_chunk * page_data_len, o_fd);
+ if (err) {
+ fprintf(stderr, "%s: couldn't write all data to output file\n",
+ __func__);
+ goto end;
+ }
+ }
+ i += pages_chunk;
+ }
+ progress = 1.0f;
+ progress_runner(progress);
+ fprintf(stdout, "\n");
+ err = nvme_get_sct_status(fd, MASK_IGNORE);
+ if (err) {
+ fprintf(stderr, "%s: bad SCT status\n", __func__);
+ goto end;
+ }
+end:
+ if (o_fd >= 0)
+ close(o_fd);
+ if (page_data)
+ free(page_data);
+ return err;
+}
+
+static int nvme_get_internal_log_file(int fd, const char *const filename, bool current)
+{
+ int err;
+
+ /* Check device supported */
+ err = nvme_get_sct_status(fd, MASK_0 | MASK_1);
+ if (!err)
+ err = nvme_get_internal_log(fd, filename, current);
+ return err;
+}
+
+enum LOG_PAGE_C0 {
+ ERROR_LOG_C0 = 0,
+ SMART_HEALTH_LOG_C0,
+ FIRMWARE_SLOT_INFO_C0,
+ COMMAND_EFFECTS_C0,
+ DEVICE_SELF_TEST_C0,
+ LOG_PAGE_DIRECTORY_C0,
+ SMART_ATTRIBUTES_C0,
+ NR_SMART_ITEMS_C0,
+};
+
+struct nvme_xdn_smart_log_c0 {
+ __u8 items[NR_SMART_ITEMS_C0];
+ __u8 resv[512 - NR_SMART_ITEMS_C0];
+};
+
+static void default_show_vendor_log_c0(struct nvme_dev *dev, __u32 nsid,
+ struct nvme_xdn_smart_log_c0 *smart)
+{
+ printf("Vendor Log Page Directory 0xC0 for NVME device:%s namespace-id:%x\n",
+ dev->name, nsid);
+ printf("Error Log : %u\n", smart->items[ERROR_LOG_C0]);
+ printf("SMART Health Log : %u\n", smart->items[SMART_HEALTH_LOG_C0]);
+ printf("Firmware Slot Info : %u\n", smart->items[FIRMWARE_SLOT_INFO_C0]);
+ printf("Command Effects : %u\n", smart->items[COMMAND_EFFECTS_C0]);
+ printf("Device Self Test : %u\n", smart->items[DEVICE_SELF_TEST_C0]);
+ printf("Log Page Directory : %u\n", smart->items[LOG_PAGE_DIRECTORY_C0]);
+ printf("SMART Attributes : %u\n", smart->items[SMART_ATTRIBUTES_C0]);
+}
+
+static int nvme_get_vendor_log(struct nvme_dev *dev, __u32 namespace_id,
+ int log_page, const char *const filename)
+{
+ int err;
+ void *log = NULL;
+ size_t log_len = 512;
+
+ if (posix_memalign(&log, getpagesize(), log_len)) {
+ err = ENOMEM;
+ goto end;
+ }
+
+ /* Check device supported */
+ err = nvme_get_sct_status(dev_fd(dev), MASK_0 | MASK_1);
+ if (err)
+ goto end;
+ err = nvme_get_nsid_log(dev_fd(dev), false, log_page, namespace_id,
+ log_len, log);
+ if (err) {
+ fprintf(stderr, "%s: couldn't get log 0x%x\n", __func__,
+ log_page);
+ goto end;
+ }
+ if (filename) {
+ int o_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+ if (o_fd < 0) {
+ fprintf(stderr, "%s: couldn't output file %s\n",
+ __func__, filename);
+ err = -EINVAL;
+ goto end;
+ }
+ err = d_raw_to_fd(log, log_len, o_fd);
+ if (err) {
+ fprintf(stderr, "%s: couldn't write all data to output file %s\n",
+ __func__, filename);
+ /* Attempt following close */
+ }
+ if (close(o_fd)) {
+ err = errno;
+ goto end;
+ }
+ } else {
+ if (log_page == 0xc0)
+ default_show_vendor_log_c0(dev, namespace_id, log);
+ else
+ d(log, log_len, 16, 1);
+ }
+end:
+ if (log)
+ free(log);
+ return err;
+}
+
+static int vendor_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "Get extended SMART information and show it.";
+ const char *namespace = "(optional) desired namespace";
+ const char *output_file = "(optional) binary output filename";
+ const char *log = "(optional) log ID (0xC0, or 0xCA), default 0xCA";
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u32 namespace_id;
+ const char *output_file;
+ int log;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0xffffffff,
+ .output_file = NULL,
+ .log = 0xca
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FILE("output-file", 'o', &cfg.output_file, output_file),
+ OPT_UINT("log", 'l', &cfg.log, log),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ fprintf(stderr, "%s: failed to parse arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((cfg.log != 0xC0) && (cfg.log != 0xCA)) {
+ fprintf(stderr, "%s: invalid log page 0x%x - should be 0xC0 or 0xCA\n", __func__, cfg.log);
+ err = -EINVAL;
+ goto end;
+ }
+
+ err = nvme_get_vendor_log(dev, cfg.namespace_id, cfg.log,
+ cfg.output_file);
+ if (err)
+ fprintf(stderr, "%s: couldn't get vendor log 0x%x\n", __func__, cfg.log);
+end:
+ if (err > 0)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
+
+static int internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ char *desc = "Get internal status log and show it.";
+ const char *output_file = "(optional) binary output filename";
+ const char *prev_log = "(optional) use previous log. Otherwise uses current log.";
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ const char *output_file;
+ bool prev_log;
+ };
+
+ struct config cfg = {
+ .output_file = NULL,
+ .prev_log = false
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.output_file, output_file),
+ OPT_FLAG("prev-log", 'p', &cfg.prev_log, prev_log),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ fprintf(stderr, "%s: failed to parse arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ if (cfg.prev_log)
+ printf("Getting previous log\n");
+ else
+ printf("Getting current log\n");
+
+ err = nvme_get_internal_log_file(dev_fd(dev), cfg.output_file,
+ !cfg.prev_log);
+ if (err < 0)
+ fprintf(stderr, "%s: couldn't get fw log\n", __func__);
+ if (err > 0)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
+
+static int clear_correctable_errors(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ char *desc = "Clear PCIe correctable error count.";
+ const __u32 namespace_id = 0xFFFFFFFF;
+ const __u32 feature_id = 0xCA;
+ const __u32 value = 1; /* Bit0 - reset clear PCIe correctable count */
+ const __u32 cdw12 = 0;
+ const bool save = false;
+ struct nvme_dev *dev;
+ __u32 result;
+ int err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ fprintf(stderr, "%s: failed to parse arguments\n", __func__);
+ return -EINVAL;
+ }
+
+ /* Check device supported */
+ err = nvme_get_sct_status(dev_fd(dev), MASK_0 | MASK_1);
+ if (err)
+ goto end;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = feature_id,
+ .nsid = namespace_id,
+ .cdw11 = value,
+ .cdw12 = cdw12,
+ .save = save,
+ .uuidx = 0,
+ .cdw15 = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+ err = nvme_set_features(&args);
+ if (err)
+ fprintf(stderr, "%s: couldn't clear PCIe correctable errors\n",
+ __func__);
+end:
+ if (err > 0)
+ nvme_show_status(err);
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/toshiba/toshiba-nvme.h b/plugins/toshiba/toshiba-nvme.h
new file mode 100644
index 0000000..6208f5d
--- /dev/null
+++ b/plugins/toshiba/toshiba-nvme.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/toshiba/toshiba-nvme
+
+#if !defined(TOSHIBA_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define TOSHIBA_NVME
+
+#include "cmd.h"
+#include "plugin.h"
+
+PLUGIN(NAME("toshiba", "Toshiba NVME plugin", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("vs-smart-add-log", "Extended SMART information", vendor_log)
+ ENTRY("vs-internal-log", "Get Internal Log", internal_log)
+ ENTRY("clear-pcie-correctable-errors", "Clear PCIe correctable error count", clear_correctable_errors)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/transcend/transcend-nvme.c b/plugins/transcend/transcend-nvme.c
new file mode 100644
index 0000000..547fbf4
--- /dev/null
+++ b/plugins/transcend/transcend-nvme.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+
+#define CREATE_CMD
+#include "transcend-nvme.h"
+
+static const __u32 OP_BAD_BLOCK = 0xc2;
+static const __u32 DW10_BAD_BLOCK = 0x400;
+static const __u32 DW12_BAD_BLOCK = 0x5a;
+
+static int getHealthValue(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_smart_log smart_log;
+ char *desc = "Get nvme health percentage.";
+ int percent_used = 0, healthvalue = 0;
+ struct nvme_dev *dev;
+ int result;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ result = parse_and_open(&dev, argc, argv, desc, opts);
+ if (result) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+ result = nvme_get_log_smart(dev_fd(dev), 0xffffffff, false, &smart_log);
+ if (!result) {
+ printf("Transcend NVME heath value: ");
+ percent_used = smart_log.percent_used;
+
+ if (percent_used > 100 || percent_used < 0) {
+ printf("0%%\n");
+ } else {
+ healthvalue = 100 - percent_used;
+ printf("%d%%\n", healthvalue);
+ }
+ }
+ dev_close(dev);
+ return result;
+}
+
+static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+
+ char *desc = "Get nvme bad block number.";
+ struct nvme_dev *dev;
+ int result;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ result = parse_and_open(&dev, argc, argv, desc, opts);
+ if (result) {
+ printf("\nDevice not found\n");
+ return -1;
+ }
+ unsigned char data[1] = {0};
+ struct nvme_passthru_cmd nvmecmd;
+
+ memset(&nvmecmd, 0, sizeof(nvmecmd));
+ nvmecmd.opcode = OP_BAD_BLOCK;
+ nvmecmd.cdw10 = DW10_BAD_BLOCK;
+ nvmecmd.cdw12 = DW12_BAD_BLOCK;
+ nvmecmd.addr = (__u64)(uintptr_t)data;
+ nvmecmd.data_len = 0x1;
+ result = nvme_submit_admin_passthru(dev_fd(dev), &nvmecmd, NULL);
+ if (!result) {
+ int badblock = data[0];
+
+ printf("Transcend NVME badblock count: %d\n", badblock);
+ }
+ dev_close(dev);
+ return result;
+}
diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h
new file mode 100644
index 0000000..9c89883
--- /dev/null
+++ b/plugins/transcend/transcend-nvme.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/transcend/transcend-nvme
+
+#if !defined(TRANSCEND_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define TRANSCEND_NVME
+
+#include "cmd.h"
+
+
+PLUGIN(NAME("transcend", "Transcend vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("healthvalue", "NVME health percentage", getHealthValue)
+ ENTRY("badblock", "Get NVME bad block number", getBadblock)
+
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/virtium/virtium-nvme.c b/plugins/virtium/virtium-nvme.c
new file mode 100644
index 0000000..0ba4b15
--- /dev/null
+++ b/plugins/virtium/virtium-nvme.c
@@ -0,0 +1,1051 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <time.h>
+#include <locale.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "util/types.h"
+
+#define CREATE_CMD
+#include "virtium-nvme.h"
+
+#define MIN2(a, b) (((a) < (b)) ? (a) : (b))
+
+#define HOUR_IN_SECONDS 3600
+
+#define MAX_HEADER_BUFF (20 * 1024)
+#define MAX_LOG_BUFF 4096
+#define DEFAULT_TEST_NAME "Put the name of your test here"
+
+static char vt_default_log_file_name[256];
+
+struct vtview_log_header {
+ char path[256];
+ char test_name[256];
+ long time_stamp;
+ struct nvme_id_ctrl raw_ctrl;
+ struct nvme_firmware_slot raw_fw;
+};
+
+struct vtview_smart_log_entry {
+ char path[256];
+ long time_stamp;
+ struct nvme_id_ns raw_ns;
+ struct nvme_id_ctrl raw_ctrl;
+ struct nvme_smart_log raw_smart;
+};
+
+struct vtview_save_log_settings {
+ double run_time_hrs;
+ double log_record_frequency_hrs;
+ const char *output_file;
+ const char *test_name;
+};
+
+static void vt_initialize_header_buffer(struct vtview_log_header *pbuff)
+{
+ memset(pbuff->path, 0, sizeof(pbuff->path));
+ memset(pbuff->test_name, 0, sizeof(pbuff->test_name));
+}
+
+static void vt_convert_data_buffer_to_hex_string(const unsigned char *bufPtr,
+ const unsigned int size, const bool isReverted, char *output)
+{
+ unsigned int i, pos;
+ const char hextable[16] = {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F',
+ };
+
+ memset(output, 0, (size * 2) + 1);
+
+ for (i = 0; i < size; i++) {
+ if (isReverted)
+ pos = size - 1 - i;
+ else
+ pos = i;
+ output[2 * i] = hextable[(bufPtr[pos] & 0xF0) >> 4];
+ output[2 * i + 1] = hextable[(bufPtr[pos] & 0x0F)];
+ }
+}
+
+/*
+ * Generate log file name.
+ * Log file name will be generated automatically if user leave log file option blank.
+ * Log file name will be generated as vtView-Smart-log-date-time.txt
+ */
+static void vt_generate_vtview_log_file_name(char *fname)
+{
+ time_t current;
+ struct tm tstamp;
+ char temp[256];
+
+ time(&current);
+
+ tstamp = *localtime(&current);
+ snprintf(temp, sizeof(temp), "./vtView-Smart-log-");
+ strcat(fname, temp);
+ strftime(temp, sizeof(temp), "%Y-%m-%d", &tstamp);
+ strcat(fname, temp);
+ snprintf(temp, sizeof(temp), ".txt");
+ strcat(fname, temp);
+}
+
+static void vt_convert_smart_data_to_human_readable_format(struct vtview_smart_log_entry *smart, char *text)
+{
+ char tempbuff[1024] = "";
+ int i;
+ int temperature = ((smart->raw_smart.temperature[1] << 8) | smart->raw_smart.temperature[0]) - 273;
+ double capacity;
+ char *curlocale;
+ char *templocale;
+ __u8 lba_index;
+
+ nvme_id_ns_flbas_to_lbaf_inuse(smart->raw_ns.flbas, &lba_index);
+
+ curlocale = setlocale(LC_ALL, NULL);
+ templocale = strdup(curlocale);
+
+ if (!templocale)
+ printf("Cannot malloc buffer\n");
+
+ setlocale(LC_ALL, "C");
+
+ unsigned long long lba = 1ULL << smart->raw_ns.lbaf[lba_index].ds;
+
+ capacity = le64_to_cpu(smart->raw_ns.nsze) * lba;
+
+ snprintf(tempbuff, sizeof(tempbuff), "log;%s;%lu;%s;%s;%-.*s;", smart->raw_ctrl.sn, smart->time_stamp, smart->path,
+ smart->raw_ctrl.mn, (int)sizeof(smart->raw_ctrl.fr), smart->raw_ctrl.fr);
+ strcpy(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Capacity;%lf;", capacity / 1000000000);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Critical_Warning;%u;", smart->raw_smart.critical_warning);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Temperature;%u;", temperature);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Available_Spare;%u;", smart->raw_smart.avail_spare);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Available_Spare_Threshold;%u;", smart->raw_smart.spare_thresh);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Percentage_Used;%u;", smart->raw_smart.percent_used);
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Read;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.data_units_read)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Written;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.data_units_written)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Host_Read_Commands;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.host_reads)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Host_Write_Commands;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.host_writes)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Controller_Busy_Time;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.ctrl_busy_time)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Power_Cycles;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.power_cycles)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Power_On_Hours;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.power_on_hours)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Unsafe_Shutdowns;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.unsafe_shutdowns)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Media_Errors;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.media_errors)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Num_Err_Log_Entries;%s;", uint128_t_to_string(le128_to_cpu(smart->raw_smart.num_err_log_entries)));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Warning_Temperature_Time;%u;", le32_to_cpu(smart->raw_smart.warning_temp_time));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Critical_Composite_Temperature_Time;%u;", le32_to_cpu(smart->raw_smart.critical_comp_time));
+ strcat(text, tempbuff);
+
+ for (i = 0; i < 8; i++) {
+ __s32 temp = le16_to_cpu(smart->raw_smart.temp_sensor[i]);
+
+ if (!temp) {
+ snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;NC;", i);
+ strcat(text, tempbuff);
+ continue;
+ }
+ snprintf(tempbuff, sizeof(tempbuff), "Temperature_Sensor_%d;%d;", i, temp - 273);
+ strcat(text, tempbuff);
+ }
+
+ snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T1_Trans_Count;%u;", le32_to_cpu(smart->raw_smart.thm_temp1_trans_count));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T2_Trans_Count;%u;", le32_to_cpu(smart->raw_smart.thm_temp2_trans_count));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T1_Total_Time;%u;", le32_to_cpu(smart->raw_smart.thm_temp1_total_time));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Thermal_Management_T2_Total_Time;%u;", le32_to_cpu(smart->raw_smart.thm_temp2_total_time));
+ strcat(text, tempbuff);
+
+ snprintf(tempbuff, sizeof(tempbuff), "NandWrites;%d;\n", 0);
+ strcat(text, tempbuff);
+
+ setlocale(LC_ALL, templocale);
+ free(templocale);
+}
+
+static void vt_header_to_string(const struct vtview_log_header *header, char *text)
+{
+ char timebuff[50] = "";
+ char tempbuff[MAX_HEADER_BUFF] = "";
+ char identext[16384] = "";
+ char fwtext[2048] = "";
+
+ strftime(timebuff, 50, "%Y-%m-%d %H:%M:%S", localtime(&(header->time_stamp)));
+ snprintf(tempbuff, MAX_HEADER_BUFF, "header;{\"session\":{\"testName\":\"%s\",\"dateTime\":\"%s\"},",
+ header->test_name, timebuff);
+ strcpy(text, tempbuff);
+
+ vt_convert_data_buffer_to_hex_string((unsigned char *)&(header->raw_ctrl), sizeof(header->raw_ctrl), false, identext);
+ vt_convert_data_buffer_to_hex_string((unsigned char *)&(header->raw_fw), sizeof(header->raw_fw), false, fwtext);
+ snprintf(tempbuff, MAX_HEADER_BUFF,
+ "\"devices\":[{\"model\":\"%s\",\"port\":\"%s\",\"SN\":\"%s\",\"type\":\"NVMe\",\"identify\":\"%s\",\"firmwareSlot\":\"%s\"}]}\n",
+ header->raw_ctrl.mn, header->path, header->raw_ctrl.sn, identext, fwtext);
+ strcat(text, tempbuff);
+}
+
+static int vt_append_text_file(const char *text, const char *filename)
+{
+ FILE *f;
+
+ f = fopen(filename, "a");
+ if (!f) {
+ printf("Cannot open %s\n", filename);
+ return -1;
+ }
+
+ fprintf(f, "%s", text);
+ fclose(f);
+ return 0;
+}
+
+static int vt_append_log(struct vtview_smart_log_entry *smart, const char *filename)
+{
+ char sm_log_text[MAX_LOG_BUFF] = "";
+
+ vt_convert_smart_data_to_human_readable_format(smart, sm_log_text);
+ return vt_append_text_file(sm_log_text, filename);
+}
+
+static int vt_append_header(const struct vtview_log_header *header, const char *filename)
+{
+ char header_text[MAX_HEADER_BUFF] = "";
+
+ vt_header_to_string(header, header_text);
+ return vt_append_text_file(header_text, filename);
+}
+
+static void vt_process_string(char *str, const size_t size)
+{
+ size_t i;
+
+ if (!size)
+ return;
+
+ i = size - 1;
+ while (i && (' ' == str[i])) {
+ str[i] = 0;
+ i--;
+ }
+}
+
+static int vt_add_entry_to_log(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
+{
+ struct vtview_smart_log_entry smart;
+ const char *filename;
+ int ret = 0;
+ unsigned int nsid = 0;
+
+ memset(smart.path, 0, sizeof(smart.path));
+ strncpy(smart.path, path, sizeof(smart.path) - 1);
+ if (!cfg->output_file)
+ filename = vt_default_log_file_name;
+ else
+ filename = cfg->output_file;
+
+ smart.time_stamp = time(NULL);
+ ret = nvme_get_nsid(fd, &nsid);
+
+ if (ret < 0) {
+ printf("Cannot read namespace-id\n");
+ return -1;
+ }
+
+ ret = nvme_identify_ns(fd, nsid, &smart.raw_ns);
+ if (ret) {
+ printf("Cannot read namespace identify\n");
+ return -1;
+ }
+
+ ret = nvme_identify_ctrl(fd, &smart.raw_ctrl);
+ if (ret) {
+ printf("Cannot read device identify controller\n");
+ return -1;
+ }
+
+ ret = nvme_get_log_smart(fd, NVME_NSID_ALL, false, &smart.raw_smart);
+ if (ret) {
+ printf("Cannot read device SMART log\n");
+ return -1;
+ }
+
+ vt_process_string(smart.raw_ctrl.sn, sizeof(smart.raw_ctrl.sn));
+ vt_process_string(smart.raw_ctrl.mn, sizeof(smart.raw_ctrl.mn));
+
+ ret = vt_append_log(&smart, filename);
+ return ret;
+}
+
+static int vt_update_vtview_log_header(const int fd, const char *path, const struct vtview_save_log_settings *cfg)
+{
+ struct vtview_log_header header;
+ const char *filename;
+ int ret = 0;
+
+ vt_initialize_header_buffer(&header);
+ if (strlen(path) > sizeof(header.path)) {
+ printf("filename too long\n");
+ errno = EINVAL;
+ return -1;
+ }
+ strcpy(header.path, path);
+
+ if (!cfg->test_name) {
+ strcpy(header.test_name, DEFAULT_TEST_NAME);
+ } else {
+ if (strlen(cfg->test_name) > sizeof(header.test_name)) {
+ printf("test name too long\n");
+ errno = EINVAL;
+ return -1;
+ }
+ strcpy(header.test_name, cfg->test_name);
+ }
+
+ if (!cfg->output_file)
+ filename = vt_default_log_file_name;
+ else
+ filename = cfg->output_file;
+
+ printf("Log file: %s\n", filename);
+ header.time_stamp = time(NULL);
+
+ ret = nvme_identify_ctrl(fd, &header.raw_ctrl);
+ if (ret) {
+ printf("Cannot read identify device\n");
+ return -1;
+ }
+
+ ret = nvme_get_log_fw_slot(fd, false, &header.raw_fw);
+ if (ret) {
+ printf("Cannot read device firmware log\n");
+ return -1;
+ }
+
+ vt_process_string(header.raw_ctrl.sn, sizeof(header.raw_ctrl.sn));
+ vt_process_string(header.raw_ctrl.mn, sizeof(header.raw_ctrl.mn));
+
+ ret = vt_append_header(&header, filename);
+ return ret;
+}
+
+static void vt_build_identify_lv2(unsigned int data, unsigned int start,
+ unsigned int count, const char **table,
+ bool isEnd)
+{
+ unsigned int i, end, pos, sh = 1;
+ unsigned int temp;
+
+ end = start + count;
+
+ for (i = start; i < end; i++) {
+ temp = ((data & (sh << i)) >> i);
+ pos = i * 2;
+ printf(" \"bit %u\":\"%ub %s\"\n", i, temp, table[pos]);
+ printf(" %s", table[pos + 1]);
+
+ if ((end - 1) != i || !isEnd)
+ printf(",\n");
+ else
+ printf("\n");
+ }
+
+ if (isEnd)
+ printf(" },\n");
+}
+
+static void vt_build_power_state_descriptor(const struct nvme_id_ctrl *ctrl)
+{
+ unsigned int i;
+ unsigned char *buf;
+
+ printf("{\n");
+ printf("\"Power State Descriptors\":{\n");
+ printf(" \"NOPS\":\"Non-Operational State,\"\n");
+ printf(" \"MPS\":\"Max Power Scale (0: in 0.01 Watts; 1: in 0.0001 Watts),\"\n");
+ printf(" \"ENLAT\":\"Entry Latency in microseconds,\"\n");
+ printf(" \"RWL\":\"Relative Write Latency,\"\n");
+ printf(" \"RRL\":\"Relative Read Latency,\"\n");
+ printf(" \"IPS\":\"Idle Power Scale (00b: Not reported; 01b: 0.0001 W; 10b: 0.01 W; 11b: Reserved),\"\n");
+ printf(" \"APS\":\"Active Power Scale (00b: Not reported; 01b: 0.0001 W; 10b: 0.01 W; 11b: Reserved),\"\n");
+ printf(" \"ACTP\":\"Active Power,\"\n");
+ printf(" \"MP\":\"Maximum Power,\"\n");
+ printf(" \"EXLAT\":\"Exit Latency in microsecond,\"\n");
+ printf(" \"RWT\":\"Relative Write Throughput,\"\n");
+ printf(" \"RRT\":\"Relative Read Throughput,\"\n");
+ printf(" \"IDLP\":\"Idle Power,\"\n");
+ printf(" \"APW\":\"Active Power Workload,\"\n");
+ printf(" \"Ofs\":\"BYTE Offset,\"\n");
+
+ printf(" \"Power State Descriptors\":\"\n");
+
+ printf("%6s%10s%5s%4s%6s%10s%10s%10s%4s%4s%4s%4s%10s%4s%6s%10s%4s%5s%6s\n", "Entry", "0fs 00-03", "NOPS", "MPS", "MP", "ENLAT", "EXLAT", "0fs 12-15",
+ "RWL", "RWT", "RRL", "RRT", "0fs 16-19", "IPS", "IDLP", "0fs 20-23", "APS", "APW", "ACTP");
+
+
+ printf("%6s%10s%5s%4s%6s%10s%10s%10s%4s%4s%4s%4s%10s%4s%6s%10s%4s%5s%6s\n", "=====", "=========", "====", "===", "=====", "=========", "=========",
+ "=========", "===", "===", "===", "===", "=========", "===", "=====", "=========", "===", "====", "=====");
+
+ for (i = 0; i < 32; i++) {
+ char s[100];
+ unsigned int temp;
+
+ printf("%6d", i);
+ buf = (unsigned char *) (&ctrl->psd[i]);
+ vt_convert_data_buffer_to_hex_string(&buf[0], 4, true, s);
+ printf("%9sh", s);
+
+ temp = ctrl->psd[i].flags;
+ printf("%4ub", ((unsigned char)temp & 0x02));
+ printf("%3ub", ((unsigned char)temp & 0x01));
+ vt_convert_data_buffer_to_hex_string(&buf[0], 2, true, s);
+ printf("%5sh", s);
+
+ vt_convert_data_buffer_to_hex_string(&buf[4], 4, true, s);
+ printf("%9sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[8], 4, true, s);
+ printf("%9sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[12], 4, true, s);
+ printf("%9sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[15], 1, true, s);
+ printf("%3sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[14], 1, true, s);
+ printf("%3sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[13], 1, true, s);
+ printf("%3sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[12], 1, true, s);
+ printf("%3sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[16], 4, true, s);
+ printf("%9sh", s);
+
+ temp = ctrl->psd[i].ips;
+ snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01));
+ printf("%3sb", s);
+
+ vt_convert_data_buffer_to_hex_string(&buf[16], 2, true, s);
+ printf("%5sh", s);
+ vt_convert_data_buffer_to_hex_string(&buf[20], 4, true, s);
+ printf("%9sh", s);
+
+ temp = ctrl->psd[i].apws;
+ snprintf(s, sizeof(s), "%u%u", (((unsigned char)temp >> 6) & 0x01), (((unsigned char)temp >> 7) & 0x01));
+ printf("%3sb", s);
+ snprintf(s, sizeof(s), "%u%u%u", (((unsigned char)temp) & 0x01), (((unsigned char)temp >> 1) & 0x01), (((unsigned char)temp >> 2) & 0x01));
+ printf("%4sb", s);
+
+ vt_convert_data_buffer_to_hex_string(&buf[20], 2, true, s);
+ printf("%5sh", s);
+ printf("\n");
+ }
+
+ printf(" \"}\n}\n");
+
+}
+
+static void vt_dump_hex_data(const unsigned char *pbuff, size_t pbuffsize)
+{
+ char textbuf[33];
+ unsigned long i, j;
+
+ textbuf[32] = '\0';
+ printf("[%08X] ", 0);
+ for (i = 0; i < pbuffsize; i++) {
+ printf("%02X ", pbuff[i]);
+
+ if (pbuff[i] >= ' ' && pbuff[i] <= '~')
+ textbuf[i % 32] = pbuff[i];
+ else
+ textbuf[i % 32] = '.';
+
+ if (!(((i + 1) % 8)) || ((i + 1) == pbuffsize)) {
+ printf(" ");
+ if (!((i + 1) % 32)) {
+ printf(" %s\n", textbuf);
+ if ((i + 1) != pbuffsize)
+ printf("[%08lX] ", (i + 1));
+ } else if (i + 1 == pbuffsize) {
+ textbuf[(i + 1) % 32] = '\0';
+ if (!((i + 1) % 8))
+ printf(" ");
+
+ for (j = ((i + 1) % 32); j < 32; j++) {
+ printf(" ");
+ if (!((j + 1) % 8))
+ printf(" ");
+ }
+
+ printf("%s\n", textbuf);
+ }
+ }
+ }
+}
+
+static void vt_parse_detail_identify(const struct nvme_id_ctrl *ctrl)
+{
+ unsigned char *buf;
+ unsigned int temp, pos;
+ char s[1024] = "";
+
+ const char *CMICtable[6] = {"0 = the NVM subsystem contains only a single NVM subsystem port",
+ "1 = the NVM subsystem may contain more than one subsystem ports",
+ "0 = the NVM subsystem contains only a single controller",
+ "1 = the NVM subsystem may contain two or more controllers (see section 1.4.1)",
+ "0 = the controller is associated with a PCI Function or a Fabrics connection",
+ "1 = the controller is associated with an SR-IOV Virtual Function"};
+
+ const char *OAEStable[20] = {"Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "0 = does not support sending the Namespace Attribute Notices event nor the associated Changed Namespace List log page",
+ "1 = supports sending the Namespace Attribute Notices & the associated Changed Namespace List log page",
+ "0 = does not support sending Firmware Activation Notices event",
+ "1 = supports sending Firmware Activation Notices"};
+
+ const char *CTRATTtable[4] = {"0 = does not support a 128-bit Host Identifier",
+ "1 = supports a 128-bit Host Identifier",
+ "0 = does not support Non-Operational Power State Permissive Mode",
+ "1 = supports Non-Operational Power State Permissive Mode"};
+
+ const char *OACStable[18] = {"0 = does not support the Security Send and Security Receive commands",
+ "1 = supports the Security Send and Security Receive commands",
+ "0 = does not support the Format NVM command",
+ "1 = supports the Format NVM command",
+ "0 = does not support the Firmware Commit and Firmware Image Download commands",
+ "1 = supports the Firmware Commit and Firmware Image Download commands",
+ "0 = does not support the Namespace Management capability",
+ "1 = supports the Namespace Management capability",
+ "0 = does not support the Device Self-test command",
+ "1 = supports the Device Self-test command",
+ "0 = does not support Directives",
+ "1 = supports Directive Send & Directive Receive commands",
+ "0 = does not support the NVMe-MI Send and NVMe-MI Receive commands",
+ "1 = supports the NVMe-MI Send and NVMe-MI Receive commands",
+ "0 = does not support the Virtualization Management command",
+ "1 = supports the Virtualization Management command",
+ "0 = does not support the Doorbell Buffer Config command",
+ "1 = supports the Doorbell Buffer Config command"};
+
+ const char *FRMWtable[10] = {"0 = the 1st firmware slot (slot 1) is read/write",
+ "1 = the 1st firmware slot (slot 1) is read only",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "0 = requires a reset for firmware to be activated",
+ "1 = supports firmware activation without a reset"};
+
+ const char *LPAtable[8] = {"0 = does not support the SMART / Health information log page on a per namespace basis",
+ "1 = supports the SMART / Health information log page on a per namespace basis",
+ "0 = does not support the Commands Supported & Effects log page",
+ "1 = supports the Commands Supported Effects log page",
+ "0 = does not support extended data for Get Log Page",
+ "1 = supports extended data for Get Log Page (including extended Number of Dwords and Log Page Offset fields)",
+ "0 = does not support the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and Telemetry Log Notices events",
+ "1 = supports the Telemetry Host-Initiated and Telemetry Controller-Initiated log pages and sending Telemetry Log Notices"};
+
+ const char *AVSCCtable[2] = {"0 = the format of all Admin Vendor Specific Commands are vendor specific",
+ "1 = all Admin Vendor Specific Commands use the format defined in NVM Express specification"};
+
+ const char *APSTAtable[2] = {"0 = does not support autonomous power state transitions",
+ "1 = supports autonomous power state transitions"};
+
+ const char *DSTOtable[2] = {"0 = the NVM subsystem supports one device self-test operation per controller at a time",
+ "1 = the NVM subsystem supports only one device self-test operation in progress at a time"};
+
+ const char *HCTMAtable[2] = {"0 = does not support host controlled thermal management",
+ "1 = supports host controlled thermal management. Supports Set Features & Get Features commands with the Feature Identifier field set to 10h"};
+
+ const char *SANICAPtable[6] = {"0 = does not support the Crypto Erase sanitize operation",
+ "1 = supports the Crypto Erase sanitize operation",
+ "0 = does not support the Block Erase sanitize operation",
+ "1 = supports the Block Erase sanitize operation",
+ "0 = does not support the Overwrite sanitize operation",
+ "1 = supports the Overwrite sanitize operation"};
+
+ const char *ONCStable[14] = {"0 = does not support the Compare command",
+ "1 = supports the Compare command",
+ "0 = does not support the Write Uncorrectable command",
+ "1 = supports the Write Uncorrectable command",
+ "0 = does not support the Dataset Management command",
+ "1 = supports the Dataset Management command",
+ "0 = does not support the Write Zeroes command",
+ "1 = supports the Write Zeroes command",
+ "0 = does not support the Save field set to a non-zero value in the Set Features and the Get Features commands",
+ "1 = supports the Save field set to a non-zero value in the Set Features and the Get Features commands",
+ "0 = does not support reservations",
+ "1 = supports reservations",
+ "0 = does not support the Timestamp feature (refer to section 5.21.1.14)",
+ "1 = supports the Timestamp feature"};
+
+ const char *FUSEStable[2] = {"0 = does not support the Compare and Write fused operation",
+ "1 = supports the Compare and Write fused operation"};
+
+ const char *FNAtable[6] = {"0 = supports format on a per namespace basis",
+ "1 = all namespaces shall be configured with the same attributes and a format (excluding secure erase) of any namespace results in a format of all namespaces in an NVM subsystem",
+ "0 = any secure erase performed as part of a format results in a secure erase of a particular namespace specified",
+ "1 = any secure erase performed as part of a format operation results in a secure erase of all namespaces in the NVM subsystem",
+ "0 = cryptographic erase is not supported",
+ "1 = cryptographic erase is supported as part of the secure erase functionality"};
+
+ const char *VWCtable[2] = {"0 = a volatile write cache is not present",
+ "1 = a volatile write cache is present"};
+
+ 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",
+ "01b = SGLs are supported. There is no alignment nor granularity requirement for Data Blocks",
+ "10b = SGLs are supported. There is a Dword alignment and granularity requirement for Data Blocks",
+ "11b = Reserved"};
+
+ const char *SGLStable[42] = {"Used",
+ "Used",
+ "Used",
+ "Used",
+ "0 = does not support the Keyed SGL Data Block descriptor",
+ "1 = supports the Keyed SGL Data Block descriptor",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "0 = the SGL Bit Bucket descriptor is not supported",
+ "1 = the SGL Bit Bucket descriptor is supported",
+ "0 = use of a byte aligned contiguous physical buffer of metadata is not supported",
+ "1 = use of a byte aligned contiguous physical buffer of metadata is supported",
+ "0 = the SGL length shall be equal to the amount of data to be transferred",
+ "1 = supports commands that contain a data or metadata SGL of a length larger than the amount of data to be transferred",
+ "0 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is not supported",
+ "1 = use of Metadata Pointer (MPTR) that contains an address of an SGL segment containing exactly one SGL Descriptor that is Qword aligned is supported",
+ "0 = the Address field specifying an offset is not supported",
+ "1 = supports the Address field in SGL Data Block, SGL Segment, and SGL Last Segment descriptor types specifying an offset"};
+
+ buf = (unsigned char *)(ctrl);
+
+ printf("{\n");
+ vt_convert_data_buffer_to_hex_string(buf, 2, true, s);
+ printf(" \"PCI Vendor ID\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[2], 2, true, s);
+ printf(" \"PCI Subsystem Vendor ID\":\"%sh\",\n", s);
+ printf(" \"Serial Number\":\"%s\",\n", ctrl->sn);
+ printf(" \"Model Number\":\"%s\",\n", ctrl->mn);
+ printf(" \"Firmware Revision\":\"%-.*s\",\n", (int)sizeof(ctrl->fr), ctrl->fr);
+ vt_convert_data_buffer_to_hex_string(&buf[72], 1, true, s);
+ printf(" \"Recommended Arbitration Burst\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[73], 3, true, s);
+ printf(" \"IEEE OUI Identifier\":\"%sh\",\n", s);
+
+ temp = ctrl->cmic;
+ printf(" \"Controller Multi-Path I/O and Namespace Sharing Capabilities\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[76], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 3, CMICtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[77], 1, true, s);
+ printf(" \"Maximum Data Transfer Size\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[78], 2, true, s);
+ printf(" \"Controller ID\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[80], 4, true, s);
+ printf(" \"Version\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[84], 4, true, s);
+ printf(" \"RTD3 Resume Latency\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[88], 4, true, s);
+ printf(" \"RTD3 Entry Latency\":\"%sh\",\n", s);
+
+ temp = le32_to_cpu(ctrl->oaes);
+ printf(" \"Optional Asynchronous Events Supported\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[92], 4, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 8, 2, OAEStable, true);
+
+ temp = le32_to_cpu(ctrl->ctratt);
+ printf(" \"Controller Attributes\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[96], 4, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 2, CTRATTtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[122], 16, true, s);
+ printf(" \"FRU Globally Unique Identifier\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[240], 16, true, s);
+ printf(" \"NVMe Management Interface Specification\":\"%sh\",\n", s);
+
+ temp = le16_to_cpu(ctrl->oacs);
+ printf(" \"Optional Admin Command Support\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[256], 2, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 9, OACStable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[258], 1, true, s);
+ printf(" \"Abort Command Limit\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[259], 1, true, s);
+ printf(" \"Asynchronous Event Request Limit\":\"%sh\",\n", s);
+
+ temp = ctrl->frmw;
+ printf(" \"Firmware Updates\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[260], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, FRMWtable, false);
+ vt_convert_data_buffer_to_hex_string(&buf[260], 1, true, s);
+ printf(" \"Firmware Slot\":\"%uh\",\n", ((ctrl->frmw >> 1) & 0x07));
+ vt_build_identify_lv2(temp, 4, 1, FRMWtable, true);
+
+ temp = ctrl->lpa;
+ printf(" \"Log Page Attributes\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[261], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 4, LPAtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[262], 1, true, s);
+ printf(" \"Error Log Page Entries\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[263], 1, true, s);
+ printf(" \"Number of Power States Support\":\"%sh\",\n", s);
+
+ temp = ctrl->avscc;
+ printf(" \"Admin Vendor Specific Command Configuration\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[264], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, AVSCCtable, true);
+
+ temp = ctrl->apsta;
+ printf(" \"Autonomous Power State Transition Attributes\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[265], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, APSTAtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[266], 2, true, s);
+ printf(" \"Warning Composite Temperature Threshold\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[268], 2, true, s);
+ printf(" \"Critical Composite Temperature Threshold\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[270], 2, true, s);
+ printf(" \"Maximum Time for Firmware Activation\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[272], 4, true, s);
+ printf(" \"Host Memory Buffer Preferred Size\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[276], 4, true, s);
+ printf(" \"Host Memory Buffer Minimum Size\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[280], 16, true, s);
+ printf(" \"Total NVM Capacity\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[296], 16, true, s);
+ printf(" \"Unallocated NVM Capacity\":\"%sh\",\n", s);
+
+ temp = le32_to_cpu(ctrl->rpmbs);
+ printf(" \"Replay Protected Memory Block Support\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[312], 4, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ printf(" \"Number of RPMB Units\":\"%u\",\n", (temp & 0x00000003));
+ snprintf(s, sizeof(s), ((temp >> 3) & 0x00000007) ? "Reserved" : "HMAC SHA-256");
+ printf(" \"Authentication Method\":\"%u: %s\",\n", ((temp >> 3) & 0x00000007), s);
+ printf(" \"Total Size\":\"%u\",\n", ((temp >> 16) & 0x000000FF));
+ printf(" \"Access Size\":\"%u\",\n", ((temp >> 24) & 0x000000FF));
+ printf(" },\n");
+
+ vt_convert_data_buffer_to_hex_string(&buf[316], 2, true, s);
+ printf(" \"Extended Device Self-test Time\":\"%sh\",\n", s);
+
+ temp = ctrl->dsto;
+ printf(" \"Device Self-test Options\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[318], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, DSTOtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[319], 1, true, s);
+ printf(" \"Firmware Update Granularity\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[320], 1, true, s);
+ printf(" \"Keep Alive Support\":\"%sh\",\n", s);
+
+ temp = le16_to_cpu(ctrl->hctma);
+ printf(" \"Host Controlled Thermal Management Attributes\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[322], 2, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, HCTMAtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[324], 2, true, s);
+ printf(" \"Minimum Thermal Management Temperature\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[326], 2, true, s);
+ printf(" \"Maximum Thermal Management Temperature\":\"%sh\",\n", s);
+
+ temp = le16_to_cpu(ctrl->sanicap);
+ printf(" \"Sanitize Capabilities\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[328], 2, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 3, SANICAPtable, true);
+
+ temp = ctrl->sqes;
+ printf(" \"Submission Queue Entry Size\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[512], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ printf(" \"Maximum Size\":\"%u\",\n", (temp & 0x0000000F));
+ printf(" \"Required Size\":\"%u\",\n", ((temp >> 4) & 0x0000000F));
+ printf(" }\n");
+
+ temp = ctrl->cqes;
+ printf(" \"Completion Queue Entry Size\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[513], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ printf(" \"Maximum Size\":\"%u\",\n", (temp & 0x0000000F));
+ printf(" \"Required Size\":\"%u\",\n", ((temp >> 4) & 0x0000000F));
+ printf(" }\n");
+
+ vt_convert_data_buffer_to_hex_string(&buf[514], 2, true, s);
+ printf(" \"Maximum Outstanding Commands\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[516], 4, true, s);
+ printf(" \"Number of Namespaces\":\"%sh\",\n", s);
+
+ temp = le16_to_cpu(ctrl->oncs);
+ printf(" \"Optional NVM Command Support\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[520], 2, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 7, ONCStable, true);
+
+ temp = le16_to_cpu(ctrl->fuses);
+ printf(" \"Fused Operation Support\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[522], 2, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, FUSEStable, true);
+
+ temp = ctrl->fna;
+ printf(" \"Format NVM Attributes\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[524], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 3, FNAtable, true);
+
+ temp = ctrl->vwc;
+ printf(" \"Volatile Write Cache\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[525], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, VWCtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[526], 2, true, s);
+ printf(" \"Atomic Write Unit Normal\":\"%sh\",\n", s);
+ vt_convert_data_buffer_to_hex_string(&buf[528], 2, true, s);
+ printf(" \"Atomic Write Unit Power Fail\":\"%sh\",\n", s);
+
+ 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, ICSVSCCtable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[532], 2, true, s);
+ printf(" \"Atomic Compare 0 Write Unit\":\"%sh\",\n", s);
+
+ temp = le32_to_cpu(ctrl->sgls);
+ printf(" \"SGL Support\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[536], 4, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ pos = (temp & 0x00000003);
+ printf(" \"bit 1:0\":\"%s\",\n", SGLSSubtable[pos]);
+ vt_build_identify_lv2(temp, 2, 1, SGLStable, false);
+ vt_build_identify_lv2(temp, 16, 5, SGLStable, true);
+
+ vt_convert_data_buffer_to_hex_string(&buf[768], 256, false, s);
+ printf(" \"NVM Subsystem NVMe Qualified Name\":\"%s\",\n", s);
+ printf("}\n\n");
+
+ vt_build_power_state_descriptor(ctrl);
+
+
+ printf("\n{\n");
+ printf("\"Vendor Specific\":\"\n");
+ vt_dump_hex_data(&buf[3072], 1024);
+ printf("\"}\n");
+}
+
+static int vt_save_smart_to_vtview_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int ret, err = 0;
+ long total_time = 0;
+ long freq_time = 0;
+ long cur_time = 0;
+ long remain_time = 0;
+ long start_time = 0;
+ long end_time = 0;
+ char path[256] = "";
+ char *desc = "Save SMART data into log file with format that is easy to analyze (comma delimited). Maximum log file will be 4K.\n\n"
+ "Typical usages:\n\n"
+ "Temperature characterization:\n"
+ "\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=0.25 --test-name=burn-in-at-(-40)\n\n"
+ "Endurance testing :\n"
+ "\tvirtium save-smart-to-vtview-log /dev/yourDevice --run-time=100 --record-frequency=1 --test-name=Endurance-test-JEDEG-219-workload\n\n"
+ "Just logging :\n"
+ "\tvirtium save-smart-to-vtview-log /dev/yourDevice";
+
+ const char *run_time = "(optional) Number of hours to log data (default = 20 hours)";
+ const char *freq = "(optional) How often you want to log SMART data (0.25 = 15' , 0.5 = 30' , 1 = 1 hour, 2 = 2 hours, etc.). Default = 10 hours.";
+ const char *output_file = "(optional) Name of the log file (give it a name that easy for you to remember what the test is). You can leave it blank too, we will take care it for you.";
+ const char *test_name = "(optional) Name of the test you are doing. We use this as part of the name of the log file.";
+ struct nvme_dev *dev;
+
+ struct vtview_save_log_settings cfg = {
+ .run_time_hrs = 20,
+ .log_record_frequency_hrs = 10,
+ .output_file = NULL,
+ .test_name = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_DOUBLE("run-time", 'r', &cfg.run_time_hrs, run_time),
+ OPT_DOUBLE("freq", 'f', &cfg.log_record_frequency_hrs, freq),
+ OPT_FILE("output-file", 'o', &cfg.output_file, output_file),
+ OPT_STRING("test-name", 'n', "NAME", &cfg.test_name, test_name),
+ OPT_END()
+ };
+
+ vt_generate_vtview_log_file_name(vt_default_log_file_name);
+
+ if (argc >= 2) {
+ if (strlen(argv[1]) > sizeof(path) - 1) {
+ printf("Filename too long\n");
+ return -1;
+ }
+ strcpy(path, argv[1]);
+ }
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("Error parse and open (err = %d)\n", err);
+ return err;
+ }
+
+ printf("Running...\n");
+ printf("Collecting data for device %s\n", path);
+ printf("Running for %lf hour(s)\n", cfg.run_time_hrs);
+ printf("Logging SMART data for every %lf hour(s)\n", cfg.log_record_frequency_hrs);
+
+ ret = vt_update_vtview_log_header(dev_fd(dev), path, &cfg);
+ if (ret) {
+ err = EINVAL;
+ dev_close(dev);
+ return err;
+ }
+
+ total_time = cfg.run_time_hrs * (float)HOUR_IN_SECONDS;
+ freq_time = cfg.log_record_frequency_hrs * (float)HOUR_IN_SECONDS;
+
+ if (!freq_time)
+ freq_time = 1;
+
+ start_time = time(NULL);
+ end_time = start_time + total_time;
+
+ fflush(stdout);
+
+ while (1) {
+ cur_time = time(NULL);
+ if (cur_time >= end_time)
+ break;
+
+ ret = vt_add_entry_to_log(dev_fd(dev), path, &cfg);
+ if (ret) {
+ printf("Cannot update driver log\n");
+ break;
+ }
+
+ remain_time = end_time - cur_time;
+ freq_time = MIN2(freq_time, remain_time);
+ sleep(freq_time);
+ fflush(stdout);
+ }
+
+ dev_close(dev);
+ return err;
+}
+
+static int vt_show_identify(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int ret, err = 0;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_dev *dev;
+ char *desc = "Parse identify data to json format\n\n"
+ "Typical usages:\n\n"
+ "virtium show-identify /dev/yourDevice\n";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err) {
+ printf("Error parse and open (err = %d)\n", err);
+ return err;
+ }
+
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ printf("Cannot read identify device\n");
+ dev_close(dev);
+ return -1;
+ }
+
+ vt_process_string(ctrl.sn, sizeof(ctrl.sn));
+ vt_process_string(ctrl.mn, sizeof(ctrl.mn));
+ vt_parse_detail_identify(&ctrl);
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/virtium/virtium-nvme.h b/plugins/virtium/virtium-nvme.h
new file mode 100644
index 0000000..0a04a35
--- /dev/null
+++ b/plugins/virtium/virtium-nvme.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/virtium/virtium-nvme
+
+#if !defined(VIRTIUM_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define VIRTIUM_NVME
+
+#include "cmd.h"
+#include "plugin.h"
+
+PLUGIN(NAME("virtium", "Virtium vendor specific extensions", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("save-smart-to-vtview-log", "Periodically save smart attributes into a log file.\n\
+ The data in this log file can be analyzed using excel or using Virtium’s vtView.\n\
+ Visit vtView.virtium.com to see full potential uses of the data", vt_save_smart_to_vtview_log)
+ ENTRY("show-identify", "Shows detail features and current settings", vt_show_identify)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/wdc/wdc-nvme.c b/plugins/wdc/wdc-nvme.c
new file mode 100644
index 0000000..8cbcf2e
--- /dev/null
+++ b/plugins/wdc/wdc-nvme.c
@@ -0,0 +1,12486 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2015-2018 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * 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>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "util/cleanup.h"
+#include "util/types.h"
+#include "nvme-print.h"
+
+#define CREATE_CMD
+#include "wdc-nvme.h"
+#include "wdc-utils.h"
+
+#define WRITE_SIZE (sizeof(__u8) * 4096)
+
+#define WDC_NVME_SUBCMD_SHIFT 8
+
+#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
+#define WDC_NVME_SNDK_VID 0x15b7
+
+#define WDC_NVME_SN100_DEV_ID 0x0003
+#define WDC_NVME_SN200_DEV_ID 0x0023
+#define WDC_NVME_SN630_DEV_ID 0x2200
+#define WDC_NVME_SN630_DEV_ID_1 0x2201
+#define WDC_NVME_SN840_DEV_ID 0x2300
+#define WDC_NVME_SN840_DEV_ID_1 0x2500
+#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_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_SN650_DEV_ID_4 0x2721
+#define WDC_NVME_SN655_DEV_ID 0x2722
+#define WDC_NVME_SN860_DEV_ID 0x2730
+#define WDC_NVME_SN660_DEV_ID 0x2704
+#define WDC_NVME_SN560_DEV_ID_1 0x2712
+#define WDC_NVME_SN560_DEV_ID_2 0x2713
+#define WDC_NVME_SN560_DEV_ID_3 0x2714
+#define WDC_NVME_SN861_DEV_ID 0x2750
+#define WDC_NVME_SN861_DEV_ID_1 0x2751
+
+/* This id's are no longer supported, delete ?? */
+#define WDC_NVME_SN550_DEV_ID 0x2708
+
+#define WDC_NVME_SXSLCL_DEV_ID 0x2001
+#define WDC_NVME_SN520_DEV_ID 0x5003
+#define WDC_NVME_SN520_DEV_ID_1 0x5004
+#define WDC_NVME_SN520_DEV_ID_2 0x5005
+
+#define WDC_NVME_SN530_DEV_ID_1 0x5007
+#define WDC_NVME_SN530_DEV_ID_2 0x5008
+#define WDC_NVME_SN530_DEV_ID_3 0x5009
+#define WDC_NVME_SN530_DEV_ID_4 0x500b
+#define WDC_NVME_SN530_DEV_ID_5 0x501d
+
+#define WDC_NVME_SN350_DEV_ID 0x5019
+
+#define WDC_NVME_SN570_DEV_ID 0x501A
+
+#define WDC_NVME_SN850X_DEV_ID 0x5030
+
+#define WDC_NVME_SN5000_DEV_ID_1 0x5034
+#define WDC_NVME_SN5000_DEV_ID_2 0x5035
+#define WDC_NVME_SN5000_DEV_ID_3 0x5036
+#define WDC_NVME_SN5000_DEV_ID_4 0x504A
+
+#define WDC_NVME_SN7000S_DEV_ID_1 0x5039
+
+#define WDC_NVME_SN7150_DEV_ID_1 0x503b
+#define WDC_NVME_SN7150_DEV_ID_2 0x503c
+#define WDC_NVME_SN7150_DEV_ID_3 0x503d
+#define WDC_NVME_SN7150_DEV_ID_4 0x503e
+#define WDC_NVME_SN7150_DEV_ID_5 0x503f
+
+#define WDC_NVME_SN7100_DEV_ID_1 0x5043
+#define WDC_NVME_SN7100_DEV_ID_2 0x5044
+#define WDC_NVME_SN7100_DEV_ID_3 0x5045
+
+#define WDC_NVME_SN8000S_DEV_ID 0x5049
+
+#define WDC_NVME_SN720_DEV_ID 0x5002
+#define WDC_NVME_SN730_DEV_ID 0x5006
+#define WDC_NVME_SN740_DEV_ID 0x5015
+#define WDC_NVME_SN740_DEV_ID_1 0x5016
+#define WDC_NVME_SN740_DEV_ID_2 0x5017
+#define WDC_NVME_SN740_DEV_ID_3 0x5025
+#define WDC_NVME_SN340_DEV_ID 0x500d
+#define WDC_NVME_ZN350_DEV_ID 0x5010
+#define WDC_NVME_ZN350_DEV_ID_1 0x5018
+#define WDC_NVME_SN810_DEV_ID 0x5011
+#define WDC_NVME_SN820CL_DEV_ID 0x5037
+
+#define WDC_DRIVE_CAP_CAP_DIAG 0x0000000000000001
+#define WDC_DRIVE_CAP_INTERNAL_LOG 0x0000000000000002
+#define WDC_DRIVE_CAP_C1_LOG_PAGE 0x0000000000000004
+#define WDC_DRIVE_CAP_CA_LOG_PAGE 0x0000000000000008
+#define WDC_DRIVE_CAP_D0_LOG_PAGE 0x0000000000000010
+#define WDC_DRIVE_CAP_DRIVE_STATUS 0x0000000000000020
+#define WDC_DRIVE_CAP_CLEAR_ASSERT 0x0000000000000040
+#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_FW_ACTIVATE_HISTORY 0x0000000000002000
+#define WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY 0x0000000000004000
+#define WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG 0x0000000000008000
+#define WDC_DRIVE_CAP_REASON_ID 0x0000000000010000
+#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_HW_REV_LOG_PAGE 0x0000000010000000
+#define WDC_DRIVE_CAP_C3_LOG_PAGE 0x0000000020000000
+#define WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION 0x0000000040000000
+#define WDC_DRIVE_CAP_CLOUD_LOG_PAGE 0x0000000080000000
+
+#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_DUI 0x0000000800000000
+#define WDC_DRIVE_CAP_PURGE 0x0000001000000000
+#define WDC_DRIVE_CAP_OCP_C1_LOG_PAGE 0x0000002000000000
+#define WDC_DRIVE_CAP_OCP_C4_LOG_PAGE 0x0000004000000000
+#define WDC_DRIVE_CAP_OCP_C5_LOG_PAGE 0x0000008000000000
+#define WDC_DRIVE_CAP_DEVICE_WAF 0x0000010000000000
+#define WDC_DRIVE_CAP_SET_LATENCY_MONITOR 0x0000020000000000
+
+#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
+#define SN730_GET_KEY_LOG_LENGTH 0x00090009
+#define SN730_GET_COREDUMP_LOG_LENGTH 0x00120009
+#define SN730_GET_EXTENDED_LOG_LENGTH 0x00420009
+
+#define SN730_GET_FULL_LOG_SUBOPCODE 0x00010009
+#define SN730_GET_KEY_LOG_SUBOPCODE 0x00020009
+#define SN730_GET_CORE_LOG_SUBOPCODE 0x00030009
+#define SN730_GET_EXTEND_LOG_SUBOPCODE 0x00040009
+#define SN730_LOG_CHUNK_SIZE 0x1000
+
+/* Customer ID's */
+#define WDC_CUSTOMER_ID_GN 0x0001
+#define WDC_CUSTOMER_ID_GD 0x0101
+#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_INVALID_CUSTOMER_ID -1
+
+#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
+#define WDC_NVME_DRIVE_RESIZE_SUBCMD 0x01
+
+/* Namespace Resize */
+#define WDC_NVME_NAMESPACE_RESIZE_OPCODE 0xFB
+
+/* Drive Info */
+#define WDC_NVME_DRIVE_INFO_OPCODE 0xC6
+#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
+#define WDC_NVME_CAP_DIAG_CMD_OPCODE 0xC6
+#define WDC_NVME_CAP_DIAG_SUBCMD 0x00
+#define WDC_NVME_CAP_DIAG_CMD 0x00
+
+#define WDC_NVME_CRASH_DUMP_TYPE 1
+#define WDC_NVME_PFAIL_DUMP_TYPE 2
+
+/* Capture Device Unit Info */
+#define WDC_NVME_CAP_DUI_HEADER_SIZE 0x400
+#define WDC_NVME_CAP_DUI_OPCODE 0xFA
+#define WDC_NVME_CAP_DUI_DISABLE_IO 0x01
+#define WDC_NVME_DUI_MAX_SECTION 0x3A
+#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
+#define WDC_TELEMETRY_TYPE_HOST 0x1
+#define WDC_TELEMETRY_TYPE_CONTROLLER 0x2
+#define WDC_TELEMETRY_HEADER_LENGTH 512
+#define WDC_TELEMETRY_BLOCK_SIZE 512
+
+/* Crash dump */
+#define WDC_NVME_CRASH_DUMP_SIZE_DATA_LEN WDC_NVME_LOG_SIZE_DATA_LEN
+#define WDC_NVME_CRASH_DUMP_SIZE_NDT 0x02
+#define WDC_NVME_CRASH_DUMP_SIZE_CMD 0x20
+#define WDC_NVME_CRASH_DUMP_SIZE_SUBCMD 0x03
+
+#define WDC_NVME_CRASH_DUMP_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
+#define WDC_NVME_CRASH_DUMP_CMD 0x20
+#define WDC_NVME_CRASH_DUMP_SUBCMD 0x04
+
+/* PFail Crash dump */
+#define WDC_NVME_PF_CRASH_DUMP_SIZE_DATA_LEN WDC_NVME_LOG_SIZE_HDR_LEN
+#define WDC_NVME_PF_CRASH_DUMP_SIZE_NDT 0x02
+#define WDC_NVME_PF_CRASH_DUMP_SIZE_CMD 0x20
+#define WDC_NVME_PF_CRASH_DUMP_SIZE_SUBCMD 0x05
+
+#define WDC_NVME_PF_CRASH_DUMP_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
+#define WDC_NVME_PF_CRASH_DUMP_CMD 0x20
+#define WDC_NVME_PF_CRASH_DUMP_SUBCMD 0x06
+
+/* Drive Log */
+#define WDC_NVME_DRIVE_LOG_SIZE_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
+#define WDC_NVME_DRIVE_LOG_SIZE_DATA_LEN WDC_NVME_LOG_SIZE_DATA_LEN
+#define WDC_NVME_DRIVE_LOG_SIZE_NDT 0x02
+#define WDC_NVME_DRIVE_LOG_SIZE_CMD 0x20
+#define WDC_NVME_DRIVE_LOG_SIZE_SUBCMD 0x01
+
+#define WDC_NVME_DRIVE_LOG_OPCODE WDC_NVME_CAP_DIAG_CMD_OPCODE
+#define WDC_NVME_DRIVE_LOG_CMD 0x20
+#define WDC_NVME_DRIVE_LOG_SUBCMD 0x00
+
+/* Purge and Purge Monitor */
+#define WDC_NVME_PURGE_CMD_OPCODE 0xDD
+#define WDC_NVME_PURGE_MONITOR_OPCODE 0xDE
+#define WDC_NVME_PURGE_MONITOR_DATA_LEN 0x2F
+#define WDC_NVME_PURGE_MONITOR_CMD_CDW10 0x0000000C
+#define WDC_NVME_PURGE_MONITOR_TIMEOUT 0x7530
+#define WDC_NVME_PURGE_CMD_SEQ_ERR 0x0C
+#define WDC_NVME_PURGE_INT_DEV_ERR 0x06
+
+#define WDC_NVME_PURGE_STATE_IDLE 0x00
+#define WDC_NVME_PURGE_STATE_DONE 0x01
+#define WDC_NVME_PURGE_STATE_BUSY 0x02
+#define WDC_NVME_PURGE_STATE_REQ_PWR_CYC 0x03
+#define WDC_NVME_PURGE_STATE_PWR_CYC_PURGE 0x04
+
+/* Clear dumps */
+#define WDC_NVME_CLEAR_DUMP_OPCODE 0xFF
+#define WDC_NVME_CLEAR_CRASH_DUMP_CMD 0x03
+#define WDC_NVME_CLEAR_CRASH_DUMP_SUBCMD 0x05
+#define WDC_NVME_CLEAR_PF_CRASH_DUMP_SUBCMD 0x06
+
+/* Clear FW Activate History */
+#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
+#define WDC_NVME_ADD_LOG_OPCODE 0xC1
+#define WDC_GET_LOG_PAGE_SSD_PERFORMANCE 0x37
+#define WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME 0x0F
+
+/* C2 Log Page */
+#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID 0xC2
+#define WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8 0xC8
+#define WDC_C2_LOG_BUF_LEN 0x1000
+#define WDC_C2_LOG_PAGES_SUPPORTED_ID 0x08
+#define WDC_C2_CUSTOMER_ID_ID 0x15
+#define WDC_C2_THERMAL_THROTTLE_STATUS_ID 0x18
+#define WDC_C2_ASSERT_DUMP_PRESENT_ID 0x19
+#define WDC_C2_USER_EOL_STATUS_ID 0x1A
+#define WDC_C2_USER_EOL_STATE_ID 0x1C
+#define WDC_C2_SYSTEM_EOL_STATE_ID 0x1D
+#define WDC_C2_FORMAT_CORRUPT_REASON_ID 0x1E
+#define WDC_EOL_STATUS_NORMAL cpu_to_le32(0x00000000)
+#define WDC_EOL_STATUS_END_OF_LIFE cpu_to_le32(0x00000001)
+#define WDC_EOL_STATUS_READ_ONLY cpu_to_le32(0x00000002)
+#define WDC_ASSERT_DUMP_NOT_PRESENT cpu_to_le32(0x00000000)
+#define WDC_ASSERT_DUMP_PRESENT cpu_to_le32(0x00000001)
+#define WDC_THERMAL_THROTTLING_OFF cpu_to_le32(0x00000000)
+#define WDC_THERMAL_THROTTLING_ON cpu_to_le32(0x00000001)
+#define WDC_THERMAL_THROTTLING_UNAVAILABLE cpu_to_le32(0x00000002)
+#define WDC_FORMAT_NOT_CORRUPT cpu_to_le32(0x00000000)
+#define WDC_FORMAT_CORRUPT_FW_ASSERT cpu_to_le32(0x00000001)
+#define WDC_FORMAT_CORRUPT_UNKNOWN cpu_to_le32(0x000000FF)
+
+/* CA Log Page */
+#define WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE 0xCA
+#define WDC_FB_CA_LOG_BUF_LEN 0x80
+/* Added 4 padding bytes to resolve build warning messages */
+#define WDC_BD_CA_LOG_BUF_LEN 0xA0
+
+/* 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_ID 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
+#define WDC_C2_GUID_LENGTH 16
+
+/* C3 Latency Monitor Log Page */
+#define WDC_LATENCY_MON_LOG_BUF_LEN 0x200
+#define WDC_LATENCY_MON_LOG_ID 0xC3
+#define WDC_LATENCY_MON_VERSION 0x0001
+
+#define WDC_C3_GUID_LENGTH 16
+static __u8 wdc_lat_mon_guid[WDC_C3_GUID_LENGTH] = {
+ 0x92, 0x7a, 0xc0, 0x8c, 0xd0, 0x84, 0x6c, 0x9c,
+ 0x70, 0x43, 0xe6, 0xd4, 0x58, 0x5e, 0xd4, 0x85
+};
+
+/* D0 Smart Log Page */
+#define WDC_NVME_GET_VU_SMART_LOG_OPCODE 0xD0
+#define WDC_NVME_VU_SMART_LOG_LEN 0x200
+
+/* 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_ID
+#define WDC_LOG_ID_C3 0xC3
+#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_ID_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
+#define WDC_LOG_ID_DE 0xDE
+#define WDC_LOG_ID_F0 0xF0
+#define WDC_LOG_ID_F1 0xF1
+#define WDC_LOG_ID_F2 0xF2
+#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_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
+#define WDC_NVME_CLEAR_ASSERT_DUMP_SUBCMD 0x05
+
+#define WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID 0xD2
+
+/* Drive Essentials */
+#define WDC_DE_DEFAULT_NUMBER_OF_ERROR_ENTRIES 64
+#define WDC_DE_GENERIC_BUFFER_SIZE 80
+#define WDC_DE_GLOBAL_NSID 0xFFFFFFFF
+#define WDC_DE_DEFAULT_NAMESPACE_ID 0x01
+#define WDC_DE_PATH_SEPARATOR "/"
+#define WDC_DE_TAR_FILES "*.bin"
+#define WDC_DE_TAR_FILE_EXTN ".tar.gz"
+#define WDC_DE_TAR_CMD "tar -czf"
+
+/* VS NAND Stats */
+#define WDC_NVME_NAND_STATS_LOG_ID 0xFB
+#define WDC_NVME_NAND_STATS_SIZE 0x200
+
+/* 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
+#define WDC_DE_FILE_NAME_SIZE 32
+#define WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET 0x8000
+#define WDC_DE_READ_MAX_TRANSFER_SIZE 0x8000
+
+#define WDC_DE_MANUFACTURING_INFO_PAGE_FILE_NAME "manufacturing_info" /* Unique log entry page name. */
+#define WDC_DE_CORE_DUMP_FILE_NAME "core_dump"
+#define WDC_DE_EVENT_LOG_FILE_NAME "event_log"
+#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
+
+/* OCP Log Page Directory Data Structure */
+#define BYTE_TO_BIT(byte) ((byte) * 8)
+
+/* Set latency monitor feature */
+#define NVME_FEAT_OCP_LATENCY_MONITOR 0xC5
+
+enum _NVME_FEATURES_SELECT {
+ FS_CURRENT = 0,
+ FS_DEFAULT = 1,
+ FS_SAVED = 2,
+ FS_SUPPORTED_CAPBILITIES = 3
+};
+
+enum NVME_FEATURE_IDENTIFIERS {
+ FID_ARBITRATION = 0x01,
+ FID_POWER_MANAGEMENT = 0x02,
+ FID_LBA_RANGE_TYPE = 0x03,
+ FID_TEMPERATURE_THRESHOLD = 0x04,
+ FID_ERROR_RECOVERY = 0x05,
+ FID_VOLATILE_WRITE_CACHE = 0x06,
+ FID_NUMBER_OF_QUEUES = 0x07,
+ FID_INTERRUPT_COALESCING = 0x08,
+ FID_INTERRUPT_VECTOR_CONFIGURATION = 0x09,
+ FID_WRITE_ATOMICITY = 0x0A,
+ FID_ASYNCHRONOUS_EVENT_CONFIGURATION = 0x0B,
+ FID_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C,
+ /*Below FID's are NVM Command Set Specific*/
+ FID_SOFTWARE_PROGRESS_MARKER = 0x80,
+ FID_HOST_IDENTIFIER = 0x81,
+ FID_RESERVATION_NOTIFICATION_MASK = 0x82,
+ FID_RESERVATION_PERSISTENCE = 0x83
+};
+
+/* WDC UUID value */
+const uint8_t WDC_UUID[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0xb9, 0x8c, 0x52, 0x0c, 0x4c,
+ 0x5a, 0x15, 0xab, 0xe6, 0x33, 0x29, 0x9a, 0x70, 0xdf, 0xd0
+};
+
+/* WDC_UUID value for SN640_3 devices */
+const uint8_t WDC_UUID_SN640_3[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22
+};
+
+/* UUID field with value of 0 indicates end of UUID List*/
+const uint8_t UUID_END[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+enum WDC_DRIVE_ESSENTIAL_TYPE {
+ WDC_DE_TYPE_IDENTIFY = 0x1,
+ WDC_DE_TYPE_SMARTATTRIBUTEDUMP = 0x2,
+ WDC_DE_TYPE_EVENTLOG = 0x4,
+ WDC_DE_TYPE_DUMPTRACE = 0x8,
+ WDC_DE_TYPE_DUMPSNAPSHOT = 0x10,
+ WDC_DE_TYPE_ATA_LOGS = 0x20,
+ WDC_DE_TYPE_SMART_LOGS = 0x40,
+ WDC_DE_TYPE_SCSI_LOGS = 0x80,
+ WDC_DE_TYPE_SCSI_MODE_PAGES = 0x100,
+ WDC_DE_TYPE_NVMe_FEATURES = 0x200,
+ WDC_DE_TYPE_DUMPSMARTERRORLOG3 = 0x400,
+ WDC_DE_TYPE_DUMPLOG3E = 0x800,
+ WDC_DE_TYPE_DUMPSCRAM = 0x1000,
+ WDC_DE_TYPE_PCU_LOG = 0x2000,
+ WDC_DE_TYPE_DUMP_ERROR_LOGS = 0x4000,
+ WDC_DE_TYPE_FW_SLOT_LOGS = 0x8000,
+ WDC_DE_TYPE_MEDIA_SETTINGS = 0x10000,
+ WDC_DE_TYPE_SMART_DATA = 0x20000,
+ WDC_DE_TYPE_NVME_SETTINGS = 0x40000,
+ WDC_DE_TYPE_NVME_ERROR_LOGS = 0x80000,
+ WDC_DE_TYPE_NVME_LOGS = 0x100000,
+ WDC_DE_TYPE_UART_LOGS = 0x200000,
+ WDC_DE_TYPE_DLOGS_SPI = 0x400000,
+ WDC_DE_TYPE_DLOGS_RAM = 0x800000,
+ WDC_DE_TYPE_NVME_MANF_INFO = 0x2000000,
+ WDC_DE_TYPE_NONE = 0x1000000,
+ WDC_DE_TYPE_ALL = 0xFFFFFFF,
+};
+
+#define WDC_C0_GUID_LENGTH 16
+#define WDC_SCA_V1_NAND_STATS 0x1
+#define WDC_SCA_V1_ALL 0xF
+enum {
+ SCAO_V1_PMUWT = 0, /* Physical media units written TLC */
+ SCAO_V1_PMUWS = 16, /* Physical media units written SLC */
+ SCAO_V1_BUNBN = 32, /* Bad user nand blocks normalized */
+ SCAO_V1_BUNBR = 34, /* Bad user nand blocks raw */
+ SCAO_V1_XRC = 40, /* XOR recovery count */
+ SCAO_V1_UREC = 48, /* Uncorrectable read error count */
+ SCAO_V1_EECE = 56, /* End to end corrected errors */
+ SCAO_V1_EEDE = 64, /* End to end detected errors */
+ SCAO_V1_EEUE = 72, /* End to end uncorrected errors */
+ SCAO_V1_SDPU = 80, /* System data percent used */
+ SCAO_V1_MNUDEC = 84, /* Min User data erase counts (TLC) */
+ SCAO_V1_MXUDEC = 92, /* Max User data erase counts (TLC) */
+ SCAO_V1_AVUDEC = 100, /* Average User data erase counts (TLC) */
+ SCAO_V1_MNEC = 108, /* Min Erase counts (SLC) */
+ SCAO_V1_MXEC = 116, /* Max Erase counts (SLC) */
+ SCAO_V1_AVEC = 124, /* Average Erase counts (SLC) */
+ SCAO_V1_PFCN = 132, /* Program fail count normalized */
+ SCAO_V1_PFCR = 134, /* Program fail count raw */
+ SCAO_V1_EFCN = 140, /* Erase fail count normalized */
+ SCAO_V1_EFCR = 142, /* Erase fail count raw */
+ SCAO_V1_PCEC = 148, /* PCIe correctable error count */
+ SCAO_V1_PFBU = 156, /* Percent free blocks (User) */
+ SCAO_V1_SVN = 160, /* Security Version Number */
+ SCAO_V1_PFBS = 168, /* Percent free blocks (System) */
+ SCAO_V1_DCC = 172, /* Deallocate Commands Completed */
+ SCAO_V1_TNU = 188, /* Total Namespace Utilization */
+ SCAO_V1_FCC = 196, /* Format NVM Commands Completed */
+ SCAO_V1_BBPG = 198, /* Background Back-Pressure Gauge */
+ SCAO_V1_SEEC = 202, /* Soft ECC error count */
+ SCAO_V1_RFSC = 210, /* Refresh count */
+ SCAO_V1_BSNBN = 218, /* Bad system nand blocks normalized */
+ SCAO_V1_BSNBR = 220, /* Bad system nand blocks raw */
+ SCAO_V1_EEST = 226, /* Endurance estimate */
+ SCAO_V1_TTC = 242, /* Thermal throttling count */
+ SCAO_V1_UIO = 244, /* Unaligned I/O */
+ SCAO_V1_PMUR = 252, /* Physical media units read */
+ SCAO_V1_RTOC = 268, /* Read command timeout count */
+ SCAO_V1_WTOC = 272, /* Write command timeout count */
+ SCAO_V1_TTOC = 276, /* Trim command timeout count */
+ SCAO_V1_PLRC = 284, /* PCIe Link Retraining Count */
+ SCAO_V1_PSCC = 292, /* Power State Change Count */
+ SCAO_V1_MAVF = 300, /* Boot SSD major version field */
+ SCAO_V1_MIVF = 302, /* Boot SSD minor version field */
+ SCAO_V1_PVF = 304, /* Boot SSD point version field */
+ SCAO_V1_EVF = 306, /* Boot SSD errata version field */
+ SCAO_V1_FTLUS = 308, /* FTL Unit Size */
+ SCAO_V1_TCGOS = 312, /* TCG Ownership Status */
+
+ SCAO_V1_LPV = 494, /* Log page version - 0x0001 */
+ SCAO_V1_LPG = 496, /* Log page GUID */
+};
+
+static __u8 ext_smart_guid[WDC_C0_GUID_LENGTH] = {
+ 0x65, 0x43, 0x88, 0x78, 0xAC, 0xD8, 0x78, 0xA1,
+ 0x66, 0x42, 0x1E, 0x0F, 0x92, 0xD7, 0x6D, 0xC4
+};
+
+struct __packed wdc_nvme_ext_smart_log {
+ __u8 ext_smart_pmuwt[16]; /* 000 Physical media units written TLC */
+ __u8 ext_smart_pmuws[16]; /* 016 Physical media units written SLC */
+ __u8 ext_smart_bunbc[8]; /* 032 Bad user nand block count */
+ __u64 ext_smart_xrc; /* 040 XOR recovery count */
+ __u64 ext_smart_urec; /* 048 Uncorrectable read error count */
+ __u64 ext_smart_eece; /* 056 End to end corrected errors */
+ __u64 ext_smart_eede; /* 064 End to end detected errors */
+ __u64 ext_smart_eeue; /* 072 End to end uncorrected errors */
+ __u8 ext_smart_sdpu; /* 080 System data percent used */
+ __u8 ext_smart_rsvd1[3]; /* 081 reserved */
+ __u64 ext_smart_mnudec; /* 084 Min User data erase counts (TLC) */
+ __u64 ext_smart_mxudec; /* 092 Max User data erase counts (TLC) */
+ __u64 ext_smart_avudec; /* 100 Average User data erase counts (TLC) */
+ __u64 ext_smart_mnec; /* 108 Min Erase counts (SLC) */
+ __u64 ext_smart_mxec; /* 116 Max Erase counts (SLC) */
+ __u64 ext_smart_avec; /* 124 Average Erase counts (SLC) */
+ __u8 ext_smart_pfc[8]; /* 132 Program fail count */
+ __u8 ext_smart_efc[8]; /* 140 Erase fail count */
+ __u64 ext_smart_pcec; /* 148 PCIe correctable error count */
+ __u8 ext_smart_pfbu; /* 156 Percent free blocks (User) */
+ __u8 ext_smart_rsvd2[3]; /* 157 reserved */
+ __u64 ext_smart_svn; /* 160 Security Version Number */
+ __u8 ext_smart_pfbs; /* 168 Percent free blocks (System) */
+ __u8 ext_smart_rsvd3[3]; /* 169 reserved */
+ __u8 ext_smart_dcc[16]; /* 172 Deallocate Commands Completed */
+ __u64 ext_smart_tnu; /* 188 Total Namespace Utilization */
+ __u16 ext_smart_fcc; /* 196 Format NVM Commands Completed */
+ __u8 ext_smart_bbpg; /* 198 Background Back-Pressure Gauge */
+ __u8 ext_smart_rsvd4[3]; /* 199 reserved */
+ __u64 ext_smart_seec; /* 202 Soft ECC error count */
+ __u64 ext_smart_rfsc; /* 210 Refresh count */
+ __u8 ext_smart_bsnbc[8]; /* 218 Bad system nand block count */
+ __u8 ext_smart_eest[16]; /* 226 Endurance estimate */
+ __u16 ext_smart_ttc; /* 242 Thermal throttling count */
+ __u64 ext_smart_uio; /* 244 Unaligned I/O */
+ __u8 ext_smart_pmur[16]; /* 252 Physical media units read */
+ __u32 ext_smart_rtoc; /* 268 Read command timeout count */
+ __u32 ext_smart_wtoc; /* 272 Write command timeout count */
+ __u32 ext_smart_ttoc; /* 276 Trim command timeout count */
+ __u8 ext_smart_rsvd5[4]; /* 280 reserved */
+ __u64 ext_smart_plrc; /* 284 PCIe Link Retraining Count */
+ __u64 ext_smart_pscc; /* 292 Power State Change Count */
+ __u16 ext_smart_maj; /* 300 Boot SSD major version field */
+ __u16 ext_smart_min; /* 302 Boot SSD minor version field */
+ __u16 ext_smart_pt; /* 304 Boot SSD point version field */
+ __u16 ext_smart_err; /* 306 Boot SSD errata version field */
+ __u32 ext_smart_ftlus; /* 308 FTL Unit Size */
+ __u32 ext_smart_tcgos; /* 312 TCG Ownership Status */
+ __u8 ext_smart_rsvd6[178]; /* 316 reserved */
+ __u16 ext_smart_lpv; /* 494 Log page version - 0x0001 */
+ __u8 ext_smart_lpg[16]; /* 496 Log page GUID */
+};
+
+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_PSCC = 200, /* Power State Change Count */
+ SCAO_LPV = 494, /* Log page version */
+ SCAO_LPG = 496, /* Log page GUID */
+};
+
+struct ocp_bad_nand_block_count {
+ __u64 raw : 48;
+ __u16 normalized : 16;
+};
+
+struct ocp_e2e_correction_count {
+ __u32 detected;
+ __u32 corrected;
+};
+
+struct ocp_user_data_erase_count {
+ __u32 maximum;
+ __u32 minimum;
+};
+
+struct ocp_thermal_status {
+ __u8 num_events;
+ __u8 current_status;
+};
+
+struct __packed ocp_dssd_specific_ver {
+ __u8 errata_ver;
+ __u16 point_ver;
+ __u16 minor_ver;
+ __u8 major_ver;
+};
+
+struct ocp_cloud_smart_log {
+ __u8 physical_media_units_written[16];
+ __u8 physical_media_units_read[16];
+ struct ocp_bad_nand_block_count bad_user_nand_blocks;
+ struct ocp_bad_nand_block_count bad_system_nand_blocks;
+ __u64 xor_recovery_count;
+ __u64 uncorrectable_read_error_count;
+ __u64 soft_ecc_error_count;
+ struct ocp_e2e_correction_count e2e_correction_counts;
+ __u8 system_data_percent_used;
+ __u64 refresh_counts : 56;
+ struct ocp_user_data_erase_count user_data_erase_counts;
+ struct ocp_thermal_status thermal_status;
+ struct ocp_dssd_specific_ver dssd_specific_ver;
+ __u64 pcie_correctable_error_count;
+ __u32 incomplete_shutdowns;
+ __u8 rsvd116[4];
+ __u8 percent_free_blocks;
+ __u8 rsvd121[7];
+ __u16 capacitor_health;
+ __u8 nvme_errata_ver;
+ __u8 rsvd131[5];
+ __u64 unaligned_io;
+ __u64 security_version_number;
+ __u64 total_nuse;
+ __u8 plp_start_count[16];
+ __u8 endurance_estimate[16];
+ __u64 pcie_link_retraining_cnt;
+ __u64 power_state_change_cnt;
+ __u8 rsvd208[286];
+ __u16 log_page_version;
+ __u8 log_page_guid[16];
+};
+
+static __u8 scao_guid[WDC_C0_GUID_LENGTH] = {
+ 0xC5, 0xAF, 0x10, 0x28, 0xEA, 0xBF, 0xF2, 0xA4,
+ 0x9C, 0x4F, 0x6F, 0x7C, 0xC9, 0x14, 0xD5, 0xAF
+};
+
+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 */
+};
+
+#define WDC_NVME_C6_GUID_LENGTH 16
+#define WDC_NVME_GET_HW_REV_LOG_OPCODE 0xc6
+#define WDC_NVME_HW_REV_LOG_PAGE_LEN 512
+
+struct __packed wdc_nvme_hw_rev_log {
+ __u8 hw_rev_gdr; /* 0 Global Device HW Revision */
+ __u8 hw_rev_ar; /* 1 ASIC HW Revision */
+ __u8 hw_rev_pbc_mc; /* 2 PCB Manufacturer Code */
+ __u8 hw_rev_dram_mc; /* 3 DRAM Manufacturer Code */
+ __u8 hw_rev_nand_mc; /* 4 NAND Manufacturer Code */
+ __u8 hw_rev_pmic1_mc; /* 5 PMIC 1 Manufacturer Code */
+ __u8 hw_rev_pmic2_mc; /* 6 PMIC 2 Manufacturer Code */
+ __u8 hw_rev_c1_mc; /* 7 Other Component 1 Manf Code */
+ __u8 hw_rev_c2_mc; /* 8 Other Component 2 Manf Code */
+ __u8 hw_rev_c3_mc; /* 9 Other Component 3 Manf Code */
+ __u8 hw_rev_c4_mc; /* 10 Other Component 4 Manf Code */
+ __u8 hw_rev_c5_mc; /* 11 Other Component 5 Manf Code */
+ __u8 hw_rev_c6_mc; /* 12 Other Component 6 Manf Code */
+ __u8 hw_rev_c7_mc; /* 13 Other Component 7 Manf Code */
+ __u8 hw_rev_c8_mc; /* 14 Other Component 8 Manf Code */
+ __u8 hw_rev_c9_mc; /* 15 Other Component 9 Manf Code */
+ __u8 hw_rev_rsrvd1[48]; /* 16 Reserved 48 bytes */
+ __u8 hw_rev_dev_mdi[16]; /* 64 Device Manf Detailed Info */
+ __u8 hw_rev_asic_di[16]; /* 80 ASIC Detailed Info */
+ __u8 hw_rev_pcb_di[16]; /* 96 PCB Detailed Info */
+ __u8 hw_rev_dram_di[16]; /* 112 DRAM Detailed Info */
+ __u8 hw_rev_nand_di[16]; /* 128 NAND Detailed Info */
+ __u8 hw_rev_pmic1_di[16]; /* 144 PMIC1 Detailed Info */
+ __u8 hw_rev_pmic2_di[16]; /* 160 PMIC2 Detailed Info */
+ __u8 hw_rev_c1_di[16]; /* 176 Component 1 Detailed Info */
+ __u8 hw_rev_c2_di[16]; /* 192 Component 2 Detailed Info */
+ __u8 hw_rev_c3_di[16]; /* 208 Component 3 Detailed Info */
+ __u8 hw_rev_c4_di[16]; /* 224 Component 4 Detailed Info */
+ __u8 hw_rev_c5_di[16]; /* 240 Component 5 Detailed Info */
+ __u8 hw_rev_c6_di[16]; /* 256 Component 6 Detailed Info */
+ __u8 hw_rev_c7_di[16]; /* 272 Component 7 Detailed Info */
+ __u8 hw_rev_c8_di[16]; /* 288 Component 8 Detailed Info */
+ __u8 hw_rev_c9_di[16]; /* 304 Component 9 Detailed Info */
+ __u8 hw_rev_sn[32]; /* 320 Serial Number */
+ __u8 hw_rev_rsrvd2[142]; /* 352 Reserved 143 bytes */
+ __u16 hw_rev_version; /* 494 Log Page Version */
+ __u8 hw_rev_guid[16]; /* 496 Log Page GUID */
+};
+
+static __u8 hw_rev_log_guid[WDC_NVME_C6_GUID_LENGTH] = {
+ 0xAA, 0xB0, 0x05, 0xF5, 0x13, 0x5E, 0x48, 0x15,
+ 0xAB, 0x89, 0x05, 0xBA, 0x8B, 0xE2, 0xBF, 0x3C
+};
+
+struct __packed WDC_DE_VU_FILE_META_DATA {
+ __u8 fileName[WDC_DE_FILE_NAME_SIZE];
+ __u16 fileID;
+ __u64 fileSize;
+};
+
+struct WDC_DRIVE_ESSENTIALS {
+ struct __packed WDC_DE_VU_FILE_META_DATA metaData;
+ enum WDC_DRIVE_ESSENTIAL_TYPE essentialType;
+};
+
+struct WDC_DE_VU_LOG_DIRECTORY {
+ struct WDC_DRIVE_ESSENTIALS *logEntry; /* Caller to allocate memory */
+ __u32 maxNumLogEntries; /* Caller to input memory allocated */
+ __u32 numOfValidLogEntries; /* API will output this value */
+};
+
+struct WDC_DE_CSA_FEATURE_ID_LIST {
+ enum NVME_FEATURE_IDENTIFIERS featureId;
+ __u8 featureName[WDC_DE_GENERIC_BUFFER_SIZE];
+};
+
+struct tarfile_metadata {
+ char fileName[MAX_PATH_LEN];
+ int8_t bufferFolderPath[MAX_PATH_LEN];
+ char bufferFolderName[MAX_PATH_LEN];
+ char tarFileName[MAX_PATH_LEN];
+ char tarFiles[MAX_PATH_LEN];
+ char tarCmd[MAX_PATH_LEN+MAX_PATH_LEN];
+ char currDir[MAX_PATH_LEN];
+ UtilsTimeInfo timeInfo;
+ uint8_t *timeString[MAX_PATH_LEN];
+};
+
+static struct WDC_DE_CSA_FEATURE_ID_LIST deFeatureIdList[] = {
+ {0x00, "Dummy Placeholder"},
+ {FID_ARBITRATION, "Arbitration"},
+ {FID_POWER_MANAGEMENT, "PowerMgmnt"},
+ {FID_LBA_RANGE_TYPE, "LbaRangeType"},
+ {FID_TEMPERATURE_THRESHOLD, "TempThreshold"},
+ {FID_ERROR_RECOVERY, "ErrorRecovery"},
+ {FID_VOLATILE_WRITE_CACHE, "VolatileWriteCache"},
+ {FID_NUMBER_OF_QUEUES, "NumOfQueues"},
+ {FID_INTERRUPT_COALESCING, "InterruptCoalesing"},
+ {FID_INTERRUPT_VECTOR_CONFIGURATION, "InterruptVectorConfig"},
+ {FID_WRITE_ATOMICITY, "WriteAtomicity"},
+ {FID_ASYNCHRONOUS_EVENT_CONFIGURATION, "AsynEventConfig"},
+ {FID_AUTONOMOUS_POWER_STATE_TRANSITION, "AutonomousPowerState"},
+};
+
+enum NVME_VU_DE_LOGPAGE_NAMES {
+ NVME_DE_LOGPAGE_E3 = 0x01,
+ NVME_DE_LOGPAGE_C0 = 0x02
+};
+
+struct NVME_VU_DE_LOGPAGE_LIST {
+ enum NVME_VU_DE_LOGPAGE_NAMES logPageName;
+ __u32 logPageId;
+ __u32 logPageLen;
+ char logPageIdStr[5];
+};
+
+struct WDC_NVME_DE_VU_LOGPAGES {
+ enum NVME_VU_DE_LOGPAGE_NAMES vuLogPageReqd;
+ __u32 numOfVULogPages;
+};
+
+static struct NVME_VU_DE_LOGPAGE_LIST deVULogPagesList[] = {
+ { NVME_DE_LOGPAGE_E3, 0xE3, 1072, "0xe3"},
+ { NVME_DE_LOGPAGE_C0, 0xC0, 512, "0xc0"}
+};
+
+enum {
+ WDC_NVME_ADMIN_VUC_OPCODE_D2 = 0xD2,
+ WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2 = 0x0000010A,
+ WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2 = 0x00000105,
+};
+
+enum {
+ NVME_LOG_NS_BASE = 0x80,
+ NVME_LOG_VS_BASE = 0xC0,
+};
+
+/*drive_info struct*/
+struct ocp_drive_info {
+ __u32 hw_revision;
+ __u32 ftl_unit_size;
+};
+
+/*get log page directory struct*/
+struct log_page_directory {
+ __u64 supported_lid_bitmap;
+ __u64 rsvd;
+ __u64 supported_ns_lid_bitmap;
+ __u64 supported_vs_lid_bitmap;
+};
+
+/*set latency monitor feature */
+struct __packed feature_latency_monitor {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ __u8 reserved[4083];
+};
+
+static int wdc_get_serial_name(struct nvme_dev *dev, char *file, size_t len, const char *suffix);
+static int wdc_create_log_file(char *file, __u8 *drive_log_data, __u32 drive_log_length);
+static int wdc_do_clear_dump(struct nvme_dev *dev, __u8 opcode, __u32 cdw12);
+static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode, __u32 data_len, __u32 cdw12, char *file,
+ __u32 xfer_size);
+static int wdc_do_crash_dump(struct nvme_dev *dev, char *file, int type);
+static int wdc_crash_dump(struct nvme_dev *dev, char *file, int type);
+static int wdc_get_crash_dump(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_drive_log(struct nvme_dev *dev, char *file);
+static int wdc_drive_log(int argc, char **argv, struct command *command, struct plugin *plugin);
+static const char *wdc_purge_mon_status_to_string(__u32 status);
+static int wdc_purge(int argc, char **argv, struct command *command, struct plugin *plugin);
+static int wdc_purge_monitor(int argc, char **argv, struct command *command, struct plugin *plugin);
+static bool wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, __u8 log_id);
+static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev, char *dir, char *key);
+static int wdc_drive_essentials(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_drive_status(int argc, char **argv, struct command *command, struct plugin *plugin);
+static int wdc_clear_assert_dump(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_drive_resize(int argc, char **argv, struct command *command, struct plugin *plugin);
+static int wdc_do_drive_resize(struct nvme_dev *dev, uint64_t new_size);
+static int wdc_namespace_resize(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_namespace_resize(struct nvme_dev *dev, __u32 nsid, __u32 op_option);
+static int wdc_reason_identifier(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_get_reason_id(struct nvme_dev *dev, char *file, int log_id);
+static int wdc_save_reason_id(struct nvme_dev *dev, __u8 *rsn_ident, int size);
+static int wdc_clear_reason_id(struct nvme_dev *dev);
+static int wdc_log_page_directory(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_drive_info(struct nvme_dev *dev, __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(nvme_root_t r, struct nvme_dev *dev);
+static int wdc_enc_get_nic_log(struct nvme_dev *dev, __u8 log_id, __u32 xfer_size, __u32 data_len,
+ FILE *out);
+static int wdc_enc_submit_move_data(struct nvme_dev *dev, char *cmd, int len, int xfer_size,
+ FILE *out, int data_id, int cdw14, int cdw15);
+static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev, __u8 log_id,
+ void **cbs_data);
+static __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev);
+
+/* Drive log data size */
+struct wdc_log_size {
+ __le32 log_size;
+};
+
+/* E6 log header */
+struct wdc_e6_log_hdr {
+ __le32 eye_catcher;
+ __u8 log_size[4];
+};
+
+/* DUI log header */
+struct wdc_dui_log_section {
+ __le16 section_type;
+ __le16 reserved;
+ __le32 section_size;
+};
+
+/* DUI log header V2 */
+struct __packed wdc_dui_log_section_v2 {
+ __le16 section_type;
+ __le16 data_area_id;
+ __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;
+ __le16 section_count;
+ __le32 log_size;
+ struct wdc_dui_log_section log_section[WDC_NVME_DUI_MAX_SECTION];
+ __u8 log_data[40];
+};
+
+struct __packed wdc_dui_log_hdr_v2 {
+ __u8 telemetry_hdr[512];
+ __u8 hdr_version;
+ __u8 product_id;
+ __le16 section_count;
+ __le64 log_size;
+ struct wdc_dui_log_section_v2 log_section[WDC_NVME_DUI_MAX_SECTION_V2];
+ __u8 log_data[40];
+};
+
+struct __packed wdc_dui_log_hdr_v3 {
+ __u8 telemetry_hdr[512];
+ __u8 hdr_version;
+ __u8 product_id;
+ __le16 section_count;
+ __le64 log_size;
+ struct wdc_dui_log_section_v2 log_section[WDC_NVME_DUI_MAX_SECTION_V3];
+ __u8 securityNonce[36];
+ __u8 log_data[40];
+};
+
+struct __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;
+ __le16 rsvd2;
+ __le16 first_erase_failure_cnt;
+ __le16 second_erase_failure_cnt;
+ __le16 rsvd3;
+ __le16 programm_failure_cnt;
+ __le32 rsvd4;
+ __le32 rsvd5;
+ __le32 entire_progress_total;
+ __le32 entire_progress_current;
+ __u8 rsvd6[14];
+};
+
+/* Additional Smart Log */
+struct wdc_log_page_header {
+ uint8_t num_subpages;
+ uint8_t reserved;
+ __le16 total_log_size;
+};
+
+struct wdc_log_page_subpage_header {
+ uint8_t spcode;
+ uint8_t pcset;
+ __le16 subpage_length;
+};
+
+struct wdc_ssd_perf_stats {
+ __le64 hr_cmds; /* Host Read Commands */
+ __le64 hr_blks; /* Host Read Blocks */
+ __le64 hr_ch_cmds; /* Host Read Cache Hit Commands */
+ __le64 hr_ch_blks; /* Host Read Cache Hit Blocks */
+ __le64 hr_st_cmds; /* Host Read Stalled Commands */
+ __le64 hw_cmds; /* Host Write Commands */
+ __le64 hw_blks; /* Host Write Blocks */
+ __le64 hw_os_cmds; /* Host Write Odd Start Commands */
+ __le64 hw_oe_cmds; /* Host Write Odd End Commands */
+ __le64 hw_st_cmds; /* Host Write Commands Stalled */
+ __le64 nr_cmds; /* NAND Read Commands */
+ __le64 nr_blks; /* NAND Read Blocks */
+ __le64 nw_cmds; /* NAND Write Commands */
+ __le64 nw_blks; /* NAND Write Blocks */
+ __le64 nrbw; /* NAND Read Before Write */
+};
+
+/* Additional C2 Log Page */
+struct wdc_c2_log_page_header {
+ __le32 length;
+ __le32 version;
+};
+
+struct wdc_c2_log_subpage_header {
+ __le32 length;
+ __le32 entry_id;
+ __le32 data;
+};
+
+struct wdc_c2_cbs_data {
+ __le32 length;
+ __u8 data[];
+};
+
+struct __packed wdc_bd_ca_log_format {
+ __u8 field_id;
+ __u8 reserved1[2];
+ __u8 normalized_value;
+ __u8 raw_value[8];
+};
+
+#define LATENCY_LOG_BUCKET_READ 3
+#define LATENCY_LOG_BUCKET_WRITE 2
+#define LATENCY_LOG_BUCKET_TRIM 1
+#define LATENCY_LOG_BUCKET_RESERVED 0
+
+#define LATENCY_LOG_MEASURED_LAT_READ 2
+#define LATENCY_LOG_MEASURED_LAT_WRITE 1
+#define LATENCY_LOG_MEASURED_LAT_TRIM 0
+
+struct __packed wdc_ssd_latency_monitor_log {
+ __u8 feature_status; /* 0x00 */
+ __u8 rsvd1; /* 0x01 */
+ __le16 active_bucket_timer; /* 0x02 */
+ __le16 active_bucket_timer_threshold; /* 0x04 */
+ __u8 active_threshold_a; /* 0x06 */
+ __u8 active_threshold_b; /* 0x07 */
+ __u8 active_threshold_c; /* 0x08 */
+ __u8 active_threshold_d; /* 0x09 */
+ __le16 active_latency_config; /* 0x0A */
+ __u8 active_latency_min_window; /* 0x0C */
+ __u8 rsvd2[0x13]; /* 0x0D */
+
+ __le32 active_bucket_counter[4][4]; /* 0x20 - 0x5F */
+ __le64 active_latency_timestamp[4][3]; /* 0x60 - 0xBF */
+ __le16 active_measured_latency[4][3]; /* 0xC0 - 0xD7 */
+ __le16 active_latency_stamp_units; /* 0xD8 */
+ __u8 rsvd3[0x16]; /* 0xDA */
+
+ __le32 static_bucket_counter[4][4] ; /* 0xF0 - 0x12F */
+ __le64 static_latency_timestamp[4][3]; /* 0x130 - 0x18F */
+ __le16 static_measured_latency[4][3]; /* 0x190 - 0x1A7 */
+ __le16 static_latency_stamp_units; /* 0x1A8 */
+ __u8 rsvd4[0x16]; /* 0x1AA */
+
+ __le16 debug_log_trigger_enable; /* 0x1C0 */
+ __le16 debug_log_measured_latency; /* 0x1C2 */
+ __le64 debug_log_latency_stamp; /* 0x1C4 */
+ __le16 debug_log_ptr; /* 0x1CC */
+ __le16 debug_log_counter_trigger; /* 0x1CE */
+ __u8 debug_log_stamp_units; /* 0x1D0 */
+ __u8 rsvd5[0x1D]; /* 0x1D1 */
+
+ __le16 log_page_version; /* 0x1EE */
+ __u8 log_page_guid[0x10]; /* 0x1F0 */
+};
+
+struct __packed wdc_ssd_ca_perf_stats {
+ __le64 nand_bytes_wr_lo; /* 0x00 - NAND Bytes Written lo */
+ __le64 nand_bytes_wr_hi; /* 0x08 - NAND Bytes Written hi */
+ __le64 nand_bytes_rd_lo; /* 0x10 - NAND Bytes Read lo */
+ __le64 nand_bytes_rd_hi; /* 0x18 - NAND Bytes Read hi */
+ __le64 nand_bad_block; /* 0x20 - NAND Bad Block Count */
+ __le64 uncorr_read_count; /* 0x28 - Uncorrectable Read Count */
+ __le64 ecc_error_count; /* 0x30 - Soft ECC Error Count */
+ __le32 ssd_detect_count; /* 0x38 - SSD End to End Detection Count */
+ __le32 ssd_correct_count; /* 0x3C - SSD End to End Correction Count */
+ __u8 data_percent_used; /* 0x40 - System Data Percent Used */
+ __le32 data_erase_max; /* 0x41 - User Data Erase Counts */
+ __le32 data_erase_min; /* 0x45 - User Data Erase Counts */
+ __le64 refresh_count; /* 0x49 - Refresh Count */
+ __le64 program_fail; /* 0x51 - Program Fail Count */
+ __le64 user_erase_fail; /* 0x59 - User Data Erase Fail Count */
+ __le64 system_erase_fail; /* 0x61 - System Area Erase Fail Count */
+ __u8 thermal_throttle_status; /* 0x69 - Thermal Throttling Status */
+ __u8 thermal_throttle_count; /* 0x6A - Thermal Throttling Count */
+ __le64 pcie_corr_error; /* 0x6B - pcie Correctable Error Count */
+ __le32 incomplete_shutdown_count; /* 0x73 - Incomplete Shutdown Count */
+ __u8 percent_free_blocks; /* 0x77 - Percent Free Blocks */
+ __u8 rsvd[392]; /* 0x78 - Reserved bytes 120-511 */
+};
+
+struct __packed wdc_ssd_d0_smart_log {
+ __le32 smart_log_page_header; /* 0x00 - Smart Log Page Header */
+ __le32 lifetime_realloc_erase_block_count; /* 0x04 - Lifetime reallocated erase block count */
+ __le32 lifetime_power_on_hours; /* 0x08 - Lifetime power on hours */
+ __le32 lifetime_uecc_count; /* 0x0C - Lifetime UECC count */
+ __le32 lifetime_wrt_amp_factor; /* 0x10 - Lifetime write amplification factor */
+ __le32 trailing_hr_wrt_amp_factor; /* 0x14 - Trailing hour write amplification factor */
+ __le32 reserve_erase_block_count; /* 0x18 - Reserve erase block count */
+ __le32 lifetime_program_fail_count; /* 0x1C - Lifetime program fail count */
+ __le32 lifetime_block_erase_fail_count; /* 0x20 - Lifetime block erase fail count */
+ __le32 lifetime_die_failure_count; /* 0x24 - Lifetime die failure count */
+ __le32 lifetime_link_rate_downgrade_count; /* 0x28 - Lifetime link rate downgrade count */
+ __le32 lifetime_clean_shutdown_count; /* 0x2C - Lifetime clean shutdown count on power loss */
+ __le32 lifetime_unclean_shutdown_count; /* 0x30 - Lifetime unclean shutdowns on power loss */
+ __le32 current_temp; /* 0x34 - Current temperature */
+ __le32 max_recorded_temp; /* 0x38 - Max recorded temperature */
+ __le32 lifetime_retired_block_count; /* 0x3C - Lifetime retired block count */
+ __le32 lifetime_read_disturb_realloc_events; /* 0x40 - Lifetime read disturb reallocation events */
+ __le64 lifetime_nand_writes; /* 0x44 - Lifetime NAND write Lpages */
+ __le32 capacitor_health; /* 0x4C - Capacitor health */
+ __le64 lifetime_user_writes; /* 0x50 - Lifetime user writes */
+ __le64 lifetime_user_reads; /* 0x58 - Lifetime user reads */
+ __le32 lifetime_thermal_throttle_act; /* 0x60 - Lifetime thermal throttle activations */
+ __le32 percentage_pe_cycles_remaining; /* 0x64 - Percentage of P/E cycles remaining */
+ __u8 rsvd[408]; /* 0x68 - 408 Reserved bytes */
+};
+
+#define WDC_OCP_C1_GUID_LENGTH 16
+#define WDC_ERROR_REC_LOG_BUF_LEN 512
+#define WDC_ERROR_REC_LOG_ID 0xC1
+#define WDC_ERROR_REC_LOG_VERSION1 0001
+#define WDC_ERROR_REC_LOG_VERSION2 0002
+
+struct __packed wdc_ocp_c1_error_recovery_log {
+ __le16 panic_reset_wait_time; /* 000 - Panic Reset Wait Time */
+ __u8 panic_reset_action; /* 002 - Panic Reset Action */
+ __u8 dev_recovery_action1; /* 003 - Device Recovery Action 1 */
+ __le64 panic_id; /* 004 - Panic ID */
+ __le32 dev_capabilities; /* 012 - Device Capabilities */
+ __u8 vs_recovery_opc; /* 016 - Vendor Specific Recovery Opcode */
+ __u8 rsvd1[3]; /* 017 - 3 Reserved Bytes */
+ __le32 vs_cmd_cdw12; /* 020 - Vendor Specific Command CDW12 */
+ __le32 vs_cmd_cdw13; /* 024 - Vendor Specific Command CDW13 */
+ __u8 vs_cmd_to; /* 028 - Vendor Specific Command Timeout V2 */
+ __u8 dev_recovery_action2; /* 029 - Device Recovery Action 2 V2 */
+ __u8 dev_recovery_action2_to; /* 030 - Device Recovery Action 2 Timeout V2 */
+ __u8 rsvd2[463]; /* 031 - 463 Reserved Bytes */
+ __le16 log_page_version; /* 494 - Log Page Version */
+ __u8 log_page_guid[WDC_OCP_C1_GUID_LENGTH]; /* 496 - Log Page GUID */
+};
+
+static __u8 wdc_ocp_c1_guid[WDC_OCP_C1_GUID_LENGTH] = { 0x44, 0xD9, 0x31, 0x21, 0xFE, 0x30, 0x34, 0xAE,
+ 0xAB, 0x4D, 0xFD, 0x3D, 0xBA, 0x83, 0x19, 0x5A };
+
+/* NAND Stats */
+struct __packed wdc_nand_stats {
+ __u8 nand_write_tlc[16];
+ __u8 nand_write_slc[16];
+ __le32 nand_prog_failure;
+ __le32 nand_erase_failure;
+ __le32 bad_block_count;
+ __le64 nand_rec_trigger_event;
+ __le64 e2e_error_counter;
+ __le64 successful_ns_resize_event;
+ __u8 rsvd[442];
+ __u16 log_page_version;
+};
+
+struct __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 {
+ __le32 eye_catcher;
+ __u8 version;
+ __u8 reserved1;
+ __u8 num_entries;
+ __u8 reserved2;
+ __le32 entry_size;
+ __le32 reserved3;
+};
+
+struct wdc_fw_act_history_log_entry {
+ __le32 entry_num;
+ __le32 power_cycle_count;
+ __le64 power_on_seconds;
+ __le64 previous_fw_version;
+ __le64 new_fw_version;
+ __u8 slot_number;
+ __u8 commit_action_type;
+ __le16 result;
+ __u8 reserved[12];
+};
+
+struct __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 __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[WDC_MAX_NUM_ACT_HIST_ENTRIES];
+ __u8 reserved2[2790];
+ __le16 log_page_version;
+ __u8 log_page_guid[WDC_C2_GUID_LENGTH];
+};
+
+#define WDC_OCP_C4_GUID_LENGTH 16
+#define WDC_DEV_CAP_LOG_BUF_LEN 4096
+#define WDC_DEV_CAP_LOG_ID 0xC4
+#define WDC_DEV_CAP_LOG_VERSION 0001
+#define WDC_OCP_C4_NUM_PS_DESCR 127
+
+struct __packed wdc_ocp_C4_dev_cap_log {
+ __le16 num_pcie_ports; /* 0000 - Number of PCI Express Ports */
+ __le16 oob_mgmt_support; /* 0002 - OOB Management Interfaces Supported */
+ __le16 wrt_zeros_support; /* 0004 - Write Zeros Command Support */
+ __le16 sanitize_support; /* 0006 - Sanitize Command Support */
+ __le16 dsm_support; /* 0008 - Dataset Management Command Support */
+ __le16 wrt_uncor_support; /* 0010 - Write Uncorrectable Command Support */
+ __le16 fused_support; /* 0012 - Fused Operation Support */
+ __le16 min_dssd_ps; /* 0014 - Minimum Valid DSSD Power State */
+ __u8 rsvd1; /* 0016 - Reserved must be cleared to zero */
+ __u8 dssd_ps_descr[WDC_OCP_C4_NUM_PS_DESCR];/* 0017 - DSSD Power State Descriptors */
+ __u8 rsvd2[3934]; /* 0144 - Reserved must be cleared to zero */
+ __le16 log_page_version; /* 4078 - Log Page Version */
+ __u8 log_page_guid[WDC_OCP_C4_GUID_LENGTH]; /* 4080 - Log Page GUID */
+};
+
+static __u8 wdc_ocp_c4_guid[WDC_OCP_C4_GUID_LENGTH] = {
+ 0x97, 0x42, 0x05, 0x0D, 0xD1, 0xE1, 0xC9, 0x98,
+ 0x5D, 0x49, 0x58, 0x4B, 0x91, 0x3C, 0x05, 0xB7
+};
+
+#define WDC_OCP_C5_GUID_LENGTH 16
+#define WDC_UNSUPPORTED_REQS_LOG_BUF_LEN 4096
+#define WDC_UNSUPPORTED_REQS_LOG_ID 0xC5
+#define WDC_UNSUPPORTED_REQS_LOG_VERSION 0001
+#define WDC_NUM_UNSUPPORTED_REQ_ENTRIES 253
+
+struct __packed wdc_ocp_C5_unsupported_reqs {
+ __le16 unsupported_count; /* 0000 - Number of Unsupported Requirement IDs */
+ __u8 rsvd1[14]; /* 0002 - Reserved must be cleared to zero */
+ __u8 unsupported_req_list[WDC_NUM_UNSUPPORTED_REQ_ENTRIES][16]; /* 0016 - Unsupported Requirements List */
+ __u8 rsvd2[14]; /* 4064 - Reserved must be cleared to zero */
+ __le16 log_page_version; /* 4078 - Log Page Version */
+ __u8 log_page_guid[WDC_OCP_C5_GUID_LENGTH]; /* 4080 - Log Page GUID */
+};
+
+static __u8 wdc_ocp_c5_guid[WDC_OCP_C5_GUID_LENGTH] = { 0x2F, 0x72, 0x9C, 0x0E, 0x99, 0x23, 0x2C, 0xBB,
+ 0x63, 0x48, 0x32, 0xD0, 0xB7, 0x98, 0xBB, 0xC7 };
+
+#define WDC_REASON_INDEX_MAX 16
+#define WDC_REASON_ID_ENTRY_LEN 128
+#define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli"
+
+const char *log_page_name[256] = {
+ [NVME_LOG_LID_ERROR] = "Error Information",
+ [NVME_LOG_LID_SMART] = "SMART / Health Information",
+ [NVME_LOG_LID_FW_SLOT] = "Firmware Slot Information",
+ [NVME_LOG_LID_CHANGED_NS] = "Changed Namespace List",
+ [NVME_LOG_LID_CMD_EFFECTS] = "Command Supported and Effects",
+ [NVME_LOG_LID_TELEMETRY_HOST] = "Telemetry Host-Initiated",
+ [NVME_LOG_LID_TELEMETRY_CTRL] = "Telemetry Controller-Initiated",
+ [NVME_LOG_LID_SANITIZE] = "Sanitize Status",
+ [WDC_LOG_ID_C0] = "Extended SMART Information",
+ [WDC_LOG_ID_C2] = "Firmware Activation History",
+ [WDC_LOG_ID_C3] = "Latency Monitor",
+ [WDC_LOG_ID_C4] = "Device Capabilities",
+ [WDC_LOG_ID_C5] = "Unsupported Requirements",
+};
+
+static double safe_div_fp(double numerator, double denominator)
+{
+ return denominator ? numerator / denominator : 0;
+}
+
+static double calc_percent(uint64_t numerator, uint64_t denominator)
+{
+ return denominator ?
+ (uint64_t)(((double)numerator / (double)denominator) * 100) : 0;
+}
+
+static int wdc_get_pci_ids(nvme_root_t r, struct nvme_dev *dev,
+ uint32_t *device_id, uint32_t *vendor_id)
+{
+ char vid[256], did[256], id[32];
+ nvme_ctrl_t c = NULL;
+ nvme_ns_t n = NULL;
+ int fd, ret;
+
+ c = nvme_scan_ctrl(r, dev->name);
+ if (c) {
+ snprintf(vid, sizeof(vid), "%s/device/vendor",
+ nvme_ctrl_get_sysfs_dir(c));
+ snprintf(did, sizeof(did), "%s/device/device",
+ nvme_ctrl_get_sysfs_dir(c));
+ nvme_free_ctrl(c);
+ } else {
+ n = nvme_scan_namespace(dev->name);
+ if (!n) {
+ fprintf(stderr, "Unable to find %s\n", dev->name);
+ return -1;
+ }
+
+ snprintf(vid, sizeof(vid), "%s/device/device/vendor",
+ nvme_ns_get_sysfs_dir(n));
+ snprintf(did, sizeof(did), "%s/device/device/device",
+ nvme_ns_get_sysfs_dir(n));
+ nvme_free_ns(n);
+ }
+
+ fd = open(vid, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: WDC: %s : Open vendor file failed\n", __func__);
+ return -1;
+ }
+
+ ret = read(fd, id, 32);
+ close(fd);
+
+ if (ret < 0) {
+ fprintf(stderr, "%s: Read of pci vendor id failed\n", __func__);
+ return -1;
+ }
+ id[ret < 32 ? ret : 31] = '\0';
+ if (id[strlen(id) - 1] == '\n')
+ id[strlen(id) - 1] = '\0';
+
+ *vendor_id = strtol(id, NULL, 0);
+ ret = 0;
+
+ fd = open(did, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: WDC: %s : Open device file failed\n", __func__);
+ return -1;
+ }
+
+ ret = read(fd, id, 32);
+ close(fd);
+
+ if (ret < 0) {
+ fprintf(stderr, "%s: Read of pci device id failed\n", __func__);
+ return -1;
+ }
+ id[ret < 32 ? ret : 31] = '\0';
+ if (id[strlen(id) - 1] == '\n')
+ id[strlen(id) - 1] = '\0';
+
+ *device_id = strtol(id, NULL, 0);
+ return 0;
+}
+
+static int wdc_get_vendor_id(struct nvme_dev *dev, uint32_t *vendor_id)
+{
+ int ret;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &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_is_sn861(__u32 device_id)
+{
+ if ((device_id == WDC_NVME_SN861_DEV_ID) ||
+ (device_id == WDC_NVME_SN861_DEV_ID_1))
+ return true;
+ else
+ return false;
+}
+
+
+static bool wdc_is_sn640(__u32 device_id)
+{
+ if ((device_id == WDC_NVME_SN640_DEV_ID) ||
+ (device_id == WDC_NVME_SN640_DEV_ID_1) ||
+ (device_id == WDC_NVME_SN640_DEV_ID_2))
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn640_3(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN640_DEV_ID_3)
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn650_u2(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN650_DEV_ID_3)
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_is_sn650_e1l(__u32 device_id)
+{
+ if (device_id == WDC_NVME_SN650_DEV_ID_4)
+ return true;
+ else
+ return false;
+}
+
+static bool needs_c2_log_page_check(__u32 device_id)
+{
+ if ((wdc_is_sn640(device_id)) ||
+ (wdc_is_sn650_u2(device_id)) ||
+ (wdc_is_sn650_e1l(device_id)))
+ return true;
+ else
+ return false;
+}
+
+static bool wdc_check_power_of_2(int num)
+{
+ return num && (!(num & (num-1)));
+}
+
+static int wdc_get_model_number(struct nvme_dev *dev, char *model)
+{
+ int ret, i;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &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(nvme_root_t r, struct nvme_dev *dev)
+{
+ int ret;
+ bool supported;
+ uint32_t read_device_id = -1, read_vendor_id = -1;
+
+ ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id);
+ if (ret < 0) {
+ /* Use the identify nvme command to get vendor id due to NVMeOF device. */
+ if (wdc_get_vendor_id(dev, &read_vendor_id) < 0)
+ return false;
+ }
+
+ supported = false;
+
+ if (read_vendor_id == WDC_NVME_VID ||
+ read_vendor_id == WDC_NVME_VID_2 ||
+ read_vendor_id == WDC_NVME_SNDK_VID)
+ supported = true;
+ else
+ fprintf(stderr,
+ "ERROR: WDC: unsupported WDC device, Vendor ID = 0x%x, Device ID = 0x%x\n",
+ read_vendor_id, read_device_id);
+
+ return supported;
+}
+
+static bool wdc_enc_check_model(struct nvme_dev *dev)
+{
+ int ret;
+ bool supported;
+ char model[NVME_ID_CTRL_MODEL_NUMBER_SIZE+1];
+
+ ret = wdc_get_model_number(dev, 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))
+ supported = true;
+ else
+ fprintf(stderr, "ERROR: WDC: unsupported WDC enclosure, Model = %s\n", model);
+
+ return supported;
+}
+
+static __u64 wdc_get_drive_capabilities(nvme_root_t r, struct nvme_dev *dev)
+{
+ int ret;
+ uint32_t read_device_id = -1, read_vendor_id = -1;
+ __u64 capabilities = 0;
+ __u32 cust_id;
+
+ ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id);
+ if (ret < 0) {
+ if (wdc_get_vendor_id(dev, &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(r, dev);
+ return capabilities;
+ }
+
+ switch (read_vendor_id) {
+ case WDC_NVME_VID:
+ switch (read_device_id) {
+ case WDC_NVME_SN100_DEV_ID:
+ capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_C1_LOG_PAGE |
+ WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP |
+ WDC_DRIVE_CAP_PURGE);
+ break;
+
+ case WDC_NVME_SN200_DEV_ID:
+ capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG | WDC_DRIVE_CAP_CLEAR_PCIE |
+ WDC_DRIVE_CAP_DRIVE_LOG | WDC_DRIVE_CAP_CRASH_DUMP | WDC_DRIVE_CAP_PFAIL_DUMP |
+ WDC_DRIVE_CAP_PURGE);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xC1 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_ADD_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE;
+ break;
+
+ default:
+ capabilities = 0;
+ }
+ break;
+
+ case WDC_NVME_VID_2:
+ switch (read_device_id) {
+ case WDC_NVME_SN630_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN630_DEV_ID_1:
+ 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);
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_VU_SMART_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+ break;
+
+ case WDC_NVME_SN640_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN660_DEV_ID:
+ /* verify the 0xC0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID)
+ == 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 0xC1 (OCP Error Recovery) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_ERROR_REC_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C1_LOG_PAGE;
+
+ /* verify the 0xC3 (OCP Latency Monitor) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_LATENCY_MON_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE;
+
+ /* verify the 0xC4 (OCP Device Capabilities) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_DEV_CAP_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE;
+
+ /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_UNSUPPORTED_REQS_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C5_LOG_PAGE;
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_VU_SMART_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
+ return -1;
+ }
+
+ 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:
+ fallthrough;
+ case WDC_NVME_SN840_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN860_DEV_ID:
+ /* verify the 0xC0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_EOL_STATUS_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
+ fallthrough;
+ case WDC_NVME_ZN540_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN540_DEV_ID:
+ 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);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_VU_SMART_LOG_OPCODE))
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+ break;
+
+ case WDC_NVME_SN650_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_4:
+ fallthrough;
+ case WDC_NVME_SN655_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN550_DEV_ID:
+ /* verify the 0xC0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_C0_LOG_PAGE;
+
+ /* verify the 0xC1 (OCP Error Recovery) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_ERROR_REC_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C1_LOG_PAGE;
+
+ /* verify the 0xC3 (OCP Latency Monitor) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_LATENCY_MON_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE;
+
+ /* verify the 0xC4 (OCP Device Capabilities) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_DEV_CAP_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C4_LOG_PAGE;
+
+ /* verify the 0xC5 (OCP Unsupported Requirements) log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_UNSUPPORTED_REQS_LOG_ID))
+ capabilities |= WDC_DRIVE_CAP_OCP_C5_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);
+
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
+ return -1;
+ }
+
+ 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_SN861_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN861_DEV_ID_1:
+ capabilities |= (WDC_DRIVE_CAP_C0_LOG_PAGE |
+ WDC_DRIVE_CAP_C3_LOG_PAGE |
+ WDC_DRIVE_CAP_CA_LOG_PAGE |
+ WDC_DRIVE_CAP_OCP_C4_LOG_PAGE |
+ WDC_DRIVE_CAP_OCP_C5_LOG_PAGE |
+ WDC_DRIVE_CAP_INTERNAL_LOG |
+ WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_C2 |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_FW_ACT_HISTORY |
+ WDC_DRIVE_CAP_INFO |
+ WDC_DRIVE_CAP_CLOUD_SSD_VERSION |
+ WDC_DRIVE_CAP_LOG_PAGE_DIR |
+ WDC_DRIVE_CAP_SET_LATENCY_MONITOR);
+ break;
+
+ default:
+ capabilities = 0;
+ }
+ break;
+
+ case WDC_NVME_SNDK_VID:
+ switch (read_device_id) {
+ case WDC_NVME_SXSLCL_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DRIVE_ESSENTIALS;
+ break;
+
+ case WDC_NVME_SN520_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN520_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN520_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN810_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA;
+ break;
+
+ case WDC_NVME_SN820CL_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA |
+ WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION |
+ WDC_DRIVE_CAP_CLOUD_LOG_PAGE | WDC_DRIVE_CAP_C0_LOG_PAGE |
+ WDC_DRIVE_CAP_HW_REV_LOG_PAGE | WDC_DRIVE_CAP_INFO |
+ WDC_DRIVE_CAP_VU_FID_CLEAR_PCIE | WDC_DRIVE_CAP_NAND_STATS |
+ WDC_DRIVE_CAP_DEVICE_WAF | WDC_DRIVE_CAP_TEMP_STATS;
+ break;
+
+ case WDC_NVME_SN720_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS |
+ WDC_DRIVE_CAP_NS_RESIZE;
+ break;
+
+ case WDC_NVME_SN730_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI | WDC_DRIVE_CAP_NAND_STATS |
+ WDC_DRIVE_CAP_INFO | WDC_DRIVE_CAP_TEMP_STATS |
+ WDC_DRIVE_CAP_VUC_CLEAR_PCIE | WDC_DRIVE_CAP_PCIE_STATS;
+ break;
+
+ case WDC_NVME_SN530_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN530_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN530_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN530_DEV_ID_4:
+ fallthrough;
+ case WDC_NVME_SN530_DEV_ID_5:
+ fallthrough;
+ case WDC_NVME_SN350_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN570_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN850X_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN5000_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN5000_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN5000_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN5000_DEV_ID_4:
+ fallthrough;
+ case WDC_NVME_SN7000S_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN7150_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN7150_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN7150_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN7150_DEV_ID_4:
+ fallthrough;
+ case WDC_NVME_SN7150_DEV_ID_5:
+ fallthrough;
+ case WDC_NVME_SN7100_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN7100_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN7100_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN8000S_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN740_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN740_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN740_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN740_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN340_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI;
+ break;
+
+ case WDC_NVME_ZN350_DEV_ID:
+ fallthrough;
+ 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;
+ }
+ break;
+ default:
+ capabilities = 0;
+ }
+
+ return capabilities;
+}
+
+static __u64 wdc_get_enc_drive_capabilities(nvme_root_t r,
+ struct nvme_dev *dev)
+{
+ int ret;
+ uint32_t read_vendor_id;
+ __u64 capabilities = 0;
+ __u32 cust_id;
+
+ ret = wdc_get_vendor_id(dev, &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(r, dev, 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(r, dev, 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 0xC3 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_LATENCY_MON_LOG_ID) == true)
+ capabilities |= WDC_DRIVE_CAP_C3_LOG_PAGE;
+
+ /* verify the 0xCB log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, 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(r, dev, 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(r, dev, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
+ return -1;
+ }
+
+ 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(struct nvme_dev *dev, char *file, size_t len,
+ const char *suffix)
+{
+ int i;
+ int ret;
+ int res_len = 0;
+ char orig[PATH_MAX] = {0};
+ struct nvme_id_ctrl ctrl;
+ int ctrl_sn_len = sizeof(ctrl.sn);
+
+ i = sizeof(ctrl.sn) - 1;
+ strncpy(orig, file, PATH_MAX - 1);
+ memset(file, 0, len);
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret);
+ return -1;
+ }
+ /* Remove trailing spaces from the name */
+ while (i && ctrl.sn[i] == ' ') {
+ ctrl.sn[i] = '\0';
+ i--;
+ }
+ if (ctrl.sn[sizeof(ctrl.sn) - 1] == '\0')
+ ctrl_sn_len = strlen(ctrl.sn);
+
+ res_len = snprintf(file, len, "%s%.*s%s", orig, ctrl_sn_len, ctrl.sn, suffix);
+ if (len <= res_len) {
+ fprintf(stderr,
+ "ERROR: WDC: cannot format serial number due to data of unexpected length\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int wdc_create_log_file(char *file, __u8 *drive_log_data,
+ __u32 drive_log_length)
+{
+ int fd;
+ int ret;
+
+ if (!drive_log_length) {
+ fprintf(stderr, "ERROR: WDC: invalid log file length\n");
+ return -1;
+ }
+
+ fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
+ return -1;
+ }
+
+ while (drive_log_length > WRITE_SIZE) {
+ ret = write(fd, drive_log_data, WRITE_SIZE);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: write: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ drive_log_data += WRITE_SIZE;
+ drive_log_length -= WRITE_SIZE;
+ }
+
+ ret = write(fd, drive_log_data, drive_log_length);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: write: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (fsync(fd) < 0) {
+ fprintf(stderr, "ERROR: WDC: fsync: %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ 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) {
+ fprintf(stderr, "ERROR: WDC - %s: No ppLogEntry pointer.\n", __func__);
+ 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 - %s: Buffer is not large enough for the common header. BufSize: 0x%x HdrSize: %"PRIxPTR"\n",
+ __func__, 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 || log_entry_size > remaining_len) {
+ fprintf(stderr, "ERROR: WDC: %s: Detected unaligned end of the data. ",
+ __func__);
+ fprintf(stderr, "Data Offset: 0x%x Entry Size: 0x%x, ",
+ current_data_offset, log_entry_size);
+ fprintf(stderr, "Remaining Log Length: 0x%x Entry Id: 0x%x\n",
+ remaining_len, p_next_log_entry->entry_id);
+
+ /* Force the loop to end */
+ remaining_len = 0;
+ } else if (!p_next_log_entry->entry_id || p_next_log_entry->entry_id > 200) {
+ /* Invalid entry - fail the search */
+ fprintf(stderr, "ERROR: WDC: %s: Invalid entry found at offset: 0x%x ",
+ __func__, current_data_offset);
+ fprintf(stderr, "Entry Size: 0x%x, Remaining Log Length: 0x%x ",
+ log_entry_size, remaining_len);
+ fprintf(stderr, "Entry Id: 0x%x\n", p_next_log_entry->entry_id);
+
+ /* Force the loop to end */
+ remaining_len = 0;
+ valid_log = false;
+
+ /* The structure 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_mgmt_log_page_lid_data(struct nvme_dev *dev,
+ void **cbs_data,
+ __u8 lid,
+ __u8 log_id,
+ __u8 uuid_ix)
+{
+ void *data;
+ struct wdc_c2_log_page_header *hdr_ptr;
+ struct wdc_c2_log_subpage_header *sph;
+ __u32 length = 0;
+ int ret = 0;
+ bool found = false;
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_C2_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return false;
+ }
+
+ memset(data, 0, sizeof(__u8) * WDC_C2_LOG_BUF_LEN);
+
+ /* get the log page length */
+ struct nvme_get_log_args args_len = {
+ .args_size = sizeof(args_len),
+ .fd = dev_fd(dev),
+ .lid = lid,
+ .nsid = 0xFFFFFFFF,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_ix,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_C2_LOG_BUF_LEN,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args_len);
+ if (ret) {
+ fprintf(stderr,
+ "ERROR: WDC: Unable to get 0x%x Log Page length with uuid %d, ret = 0x%x\n",
+ lid, uuid_ix, ret);
+ goto end;
+ }
+
+ hdr_ptr = (struct wdc_c2_log_page_header *)data;
+ length = le32_to_cpu(hdr_ptr->length);
+
+ if (length > WDC_C2_LOG_BUF_LEN) {
+ /* Log Page buffer too small, free and reallocate the necessary size */
+ free(data);
+ data = calloc(length, sizeof(__u8));
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ goto end;
+ }
+
+ /* get the log page data with the increased length */
+ struct nvme_get_log_args args_data = {
+ .args_size = sizeof(args_data),
+ .fd = dev_fd(dev),
+ .lid = lid,
+ .nsid = 0xFFFFFFFF,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_ix,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = length,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args_data);
+
+ if (ret) {
+ fprintf(stderr,
+ "ERROR: WDC: Unable to read 0x%x Log Page data with uuid %d, ret = 0x%x\n",
+ lid, uuid_ix, 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(le32_to_cpu(hdr_ptr->length), log_id, hdr_ptr, &sph);
+ if (found) {
+ *cbs_data = calloc(le32_to_cpu(sph->length), sizeof(__u8));
+ if (!*cbs_data) {
+ fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
+ found = false;
+ goto end;
+ }
+ memcpy((void *)*cbs_data, (void *)&sph->data, le32_to_cpu(sph->length));
+ } else {
+ fprintf(stderr, "ERROR: WDC: C2 log id 0x%x not found with uuid index %d\n",
+ log_id, uuid_ix);
+ }
+
+end:
+ free(data);
+ return found;
+}
+
+static bool get_dev_mgment_cbs_data(nvme_root_t r, struct nvme_dev *dev,
+ __u8 log_id, void **cbs_data)
+{
+ int ret = -1;
+ bool found = false;
+ __u8 uuid_ix = 0;
+ __u8 lid = 0;
+ *cbs_data = NULL;
+ __u32 device_id, read_vendor_id;
+ bool uuid_present = false;
+ int index = 0, uuid_index = 0;
+ struct nvme_id_uuid_list uuid_list;
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+ if (ret == 0) {
+ if (device_id == WDC_NVME_ZN350_DEV_ID || device_id == WDC_NVME_ZN350_DEV_ID_1) {
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID_C8;
+ uuid_ix = 0;
+ } else {
+ lid = WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: get pci ids: %d\n", ret);
+ return false;
+ }
+
+ typedef struct nvme_id_uuid_list_entry *uuid_list_entry;
+
+ memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
+ if (wdc_CheckUuidListSupport(dev, &uuid_list)) {
+ uuid_list_entry uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[0];
+
+ while (index <= NVME_ID_UUID_LIST_MAX &&
+ !wdc_UuidEqual(uuid_list_entry_ptr, (uuid_list_entry)UUID_END)) {
+
+ if (wdc_UuidEqual(uuid_list_entry_ptr,
+ (uuid_list_entry)WDC_UUID)) {
+ uuid_present = true;
+ break;
+ } else if (wdc_UuidEqual(uuid_list_entry_ptr,
+ (uuid_list_entry)WDC_UUID_SN640_3) &&
+ wdc_is_sn640_3(device_id)) {
+ uuid_present = true;
+ break;
+ }
+ index++;
+ uuid_list_entry_ptr = (uuid_list_entry)&uuid_list.entry[index];
+ }
+ if (uuid_present)
+ uuid_index = index + 1;
+ }
+
+ if (!uuid_index && needs_c2_log_page_check(device_id)) {
+ /* In certain devices that don't support UUID lists, there are multiple
+ * definitions of the C2 logpage. In those cases, the code
+ * needs to try two UUID indexes and use an identification algorithm
+ * to determine which is returning the correct log page data.
+ */
+ uuid_ix = 1;
+ }
+
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+
+ if (!found) {
+ /* not found with uuid = 1 try with uuid = 0 */
+ uuid_ix = 0;
+ fprintf(stderr, "Not found, requesting log page with uuid_index %d\n", uuid_index);
+
+ found = get_dev_mgmt_log_page_lid_data(dev, cbs_data, lid, log_id, uuid_ix);
+ }
+
+ return found;
+}
+
+static bool wdc_nvme_check_supported_log_page(nvme_root_t r, struct nvme_dev *dev, __u8 log_id)
+{
+ int i;
+ bool found = false;
+ struct wdc_c2_cbs_data *cbs_data = NULL;
+
+ if (get_dev_mgment_cbs_data(r, dev, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) {
+ if (cbs_data) {
+ for (i = 0; i < le32_to_cpu(cbs_data->length); i++) {
+ if (log_id == cbs_data->data[i]) {
+ found = true;
+ break;
+ }
+ }
+
+#ifdef WDC_NVME_CLI_DEBUG
+ if (!found) {
+ fprintf(stderr, "ERROR: WDC: Log Page 0x%x not supported\n", log_id);
+ fprintf(stderr, "WDC: Supported Log Pages:\n");
+ /* print the supported pages */
+ d((__u8 *)cbs_data->data, le32_to_cpu(cbs_data->length), 16, 1);
+ }
+#endif
+ free(cbs_data);
+ } else {
+ fprintf(stderr, "ERROR: WDC: cbs_data ptr = NULL\n");
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n",
+ WDC_C2_LOG_PAGES_SUPPORTED_ID);
+ }
+
+ return found;
+}
+
+static bool wdc_nvme_get_dev_status_log_data(nvme_root_t r, struct nvme_dev *dev, __le32 *ret_data,
+ __u8 log_id)
+{
+ __u32 *cbs_data = NULL;
+
+ if (get_dev_mgment_cbs_data(r, dev, log_id, (void *)&cbs_data)) {
+ if (cbs_data) {
+ memcpy((void *)ret_data, (void *)cbs_data, 4);
+ free(cbs_data);
+
+ return true;
+ }
+ }
+
+ *ret_data = 0;
+ return false;
+}
+
+static int wdc_do_clear_dump(struct nvme_dev *dev, __u8 opcode, __u32 cdw12)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = opcode;
+ admin_cmd.cdw12 = cdw12;
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ if (ret)
+ fprintf(stdout, "ERROR: WDC: Crash dump erase failed\n");
+ nvme_show_status(ret);
+ return ret;
+}
+
+static __u32 wdc_dump_length(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, __u32 *dump_length)
+{
+ int ret;
+ __u8 buf[WDC_NVME_LOG_SIZE_DATA_LEN] = {0};
+ struct wdc_log_size *l;
+ struct nvme_passthru_cmd admin_cmd;
+
+ l = (struct wdc_log_size *) buf;
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = opcode;
+ admin_cmd.addr = (__u64)(uintptr_t)buf;
+ admin_cmd.data_len = WDC_NVME_LOG_SIZE_DATA_LEN;
+ admin_cmd.cdw10 = cdw10;
+ admin_cmd.cdw12 = cdw12;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (ret) {
+ l->log_size = 0;
+ ret = -1;
+ fprintf(stderr, "ERROR: WDC: reading dump length failed\n");
+ nvme_show_status(ret);
+ return ret;
+ }
+
+ if (opcode == WDC_NVME_CAP_DIAG_OPCODE)
+ *dump_length = buf[0x04] << 24 | buf[0x05] << 16 | buf[0x06] << 8 | buf[0x07];
+ else
+ *dump_length = le32_to_cpu(l->log_size);
+ return ret;
+}
+
+static __u32 wdc_dump_length_e6(int fd, __u32 opcode, __u32 cdw10, __u32 cdw12, struct wdc_e6_log_hdr *dump_hdr)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = opcode;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_hdr;
+ admin_cmd.data_len = WDC_NVME_LOG_SIZE_HDR_LEN;
+ admin_cmd.cdw10 = cdw10;
+ admin_cmd.cdw12 = cdw12;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: reading dump length failed\n");
+ nvme_show_status(ret);
+ }
+
+ return ret;
+}
+
+static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_data, bool last_xfer)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE;
+ admin_cmd.nsid = 0xFFFFFFFF;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data;
+ admin_cmd.data_len = dataLen;
+ admin_cmd.cdw10 = ((dataLen >> 2) - 1);
+ admin_cmd.cdw12 = offset;
+ if (last_xfer)
+ admin_cmd.cdw14 = 0;
+ else
+ admin_cmd.cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO;
+
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: reading DUI data failed\n");
+ nvme_show_status(ret);
+ }
+
+ return ret;
+}
+
+static __u32 wdc_dump_dui_data_v2(int fd, __u32 dataLen, __u64 offset, __u8 *dump_data, bool last_xfer)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+ __u64 offset_lo, offset_hi;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_CAP_DUI_OPCODE;
+ admin_cmd.nsid = 0xFFFFFFFF;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data;
+ admin_cmd.data_len = dataLen;
+ admin_cmd.cdw10 = ((dataLen >> 2) - 1);
+ 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
+ admin_cmd.cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: reading DUI data V2 failed\n");
+ nvme_show_status(ret);
+ }
+
+ return ret;
+}
+
+static int wdc_do_dump(struct nvme_dev *dev, __u32 opcode, __u32 data_len,
+ __u32 cdw12, char *file, __u32 xfer_size)
+{
+ int ret = 0;
+ __u8 *dump_data;
+ __u32 curr_data_offset, curr_data_len;
+ int i;
+ struct nvme_passthru_cmd admin_cmd;
+ __u32 dump_length = data_len;
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * dump_length);
+ if (!dump_data) {
+ 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_passthru_cmd));
+ curr_data_offset = 0;
+ curr_data_len = xfer_size;
+ i = 0;
+
+ admin_cmd.opcode = opcode;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data;
+ admin_cmd.data_len = curr_data_len;
+ admin_cmd.cdw10 = curr_data_len >> 2;
+ admin_cmd.cdw12 = cdw12;
+ admin_cmd.cdw13 = curr_data_offset;
+
+ while (curr_data_offset < data_len) {
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd,
+ NULL);
+ if (ret) {
+ nvme_show_status(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, (unsigned long)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;
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data + (__u64)curr_data_offset;
+ admin_cmd.data_len = curr_data_len;
+ admin_cmd.cdw10 = curr_data_len >> 2;
+ admin_cmd.cdw13 = curr_data_offset >> 2;
+ i++;
+ }
+
+ if (!ret) {
+ nvme_show_status(ret);
+ ret = wdc_create_log_file(file, dump_data, dump_length);
+ }
+ free(dump_data);
+ return ret;
+}
+
+static int wdc_do_dump_e6(int fd, __u32 opcode, __u32 data_len,
+ __u32 cdw12, char *file, __u32 xfer_size, __u8 *log_hdr)
+{
+ int ret = 0;
+ __u8 *dump_data;
+ __u32 curr_data_offset, log_size;
+ int i;
+ struct nvme_passthru_cmd admin_cmd;
+
+ /* if data_len is not 4 byte aligned */
+ if (data_len & 0x00000003) {
+ /* Round down to the next 4 byte aligned value */
+ fprintf(stderr, "%s: INFO: data_len 0x%x not 4 byte aligned.\n",
+ __func__, data_len);
+ fprintf(stderr, "%s: INFO: Round down to 0x%x.\n",
+ __func__, (data_len &= 0xFFFFFFFC));
+ data_len &= 0xFFFFFFFC;
+ }
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * data_len);
+
+ if (!dump_data) {
+ fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ memset(dump_data, 0, sizeof(__u8) * data_len);
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ curr_data_offset = WDC_NVME_LOG_SIZE_HDR_LEN;
+ i = 0;
+
+ /* copy the 8 byte header into the dump_data buffer */
+ memcpy(dump_data, log_hdr, WDC_NVME_LOG_SIZE_HDR_LEN);
+
+ admin_cmd.opcode = opcode;
+ admin_cmd.cdw12 = cdw12;
+
+ /* subtract off the header size since that was already copied into the buffer */
+ log_size = (data_len - curr_data_offset);
+ while (log_size > 0) {
+ xfer_size = min(xfer_size, log_size);
+
+ admin_cmd.addr = (__u64)(uintptr_t)dump_data + (__u64)curr_data_offset;
+ admin_cmd.data_len = xfer_size;
+ admin_cmd.cdw10 = xfer_size >> 2;
+ admin_cmd.cdw13 = curr_data_offset >> 2;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (ret) {
+ nvme_show_status(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, (unsigned long)admin_cmd.addr);
+ break;
+ }
+
+ log_size -= xfer_size;
+ curr_data_offset += xfer_size;
+ i++;
+ }
+
+ if (!ret) {
+ fprintf(stderr, "%s: INFO: ", __func__);
+ nvme_show_status(ret);
+ } else {
+ fprintf(stderr, "%s: FAILURE: ", __func__);
+ nvme_show_status(ret);
+ fprintf(stderr, "%s: Partial data may have been captured\n", __func__);
+ snprintf(file + strlen(file), PATH_MAX, "%s", "-PARTIAL");
+ }
+
+ ret = wdc_create_log_file(file, dump_data, data_len);
+
+ free(dump_data);
+ return ret;
+}
+
+static int wdc_do_cap_telemetry_log(struct nvme_dev *dev, char *file,
+ __u32 bs, int type, int data_area)
+{
+ struct nvme_telemetry_log *log;
+ size_t full_size = 0;
+ int err = 0, output;
+ __u32 host_gen = 1;
+ int ctrl_init = 0;
+ __u32 result;
+ void *buf = NULL;
+ __u8 *data_ptr = NULL;
+ int data_written = 0, data_remaining = 0;
+ struct nvme_id_ctrl ctrl;
+ __u64 capabilities = 0;
+ nvme_root_t r;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", err);
+ return err;
+ }
+
+ if (!(ctrl.lpa & 0x8)) {
+ fprintf(stderr, "Telemetry Host-Initiated and Telemetry Controller-Initiated log pages not supported\n");
+ return -EINVAL;
+ }
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (type == WDC_TELEMETRY_TYPE_HOST) {
+ host_gen = 1;
+ ctrl_init = 0;
+ } else if (type == WDC_TELEMETRY_TYPE_CONTROLLER) {
+ if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) {
+ /* Verify the Controller Initiated Option is enabled */
+ err = nvme_get_features_data(dev_fd(dev),
+ WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID,
+ 0, 4, buf, &result);
+ if (!err) {
+ if (!result) {
+ /* enabled */
+ host_gen = 0;
+ ctrl_init = 1;
+ } else {
+ fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__);
+ return -EINVAL;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: Get telemetry option feature failed.");
+ nvme_show_status(err);
+ return -EPERM;
+ }
+ } else {
+ host_gen = 0;
+ ctrl_init = 1;
+ }
+ } else {
+ fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type);
+ return -EINVAL;
+ }
+
+ if (!file) {
+ fprintf(stderr, "%s: Please provide an output file!\n", __func__);
+ return -EINVAL;
+ }
+
+ 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));
+ return output;
+ }
+
+ if (ctrl_init)
+ err = nvme_get_ctrl_telemetry(dev_fd(dev), true, &log,
+ data_area, &full_size);
+ else if (host_gen)
+ err = nvme_get_new_host_telemetry(dev_fd(dev), &log,
+ data_area, &full_size);
+ else
+ err = nvme_get_host_telemetry(dev_fd(dev), &log, data_area,
+ &full_size);
+
+ if (err < 0) {
+ perror("get-telemetry-log");
+ goto close_output;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "%s: Failed to acquire telemetry header!\n", __func__);
+ goto close_output;
+ }
+
+ /*
+ *Continuously pull data until the offset hits the end of the last
+ *block.
+ */
+ data_written = 0;
+ data_remaining = full_size;
+ data_ptr = (__u8 *)log;
+
+ while (data_remaining) {
+ data_written = write(output, data_ptr, data_remaining);
+
+ if (data_written < 0) {
+ data_remaining = data_written;
+ break;
+ } else if (data_written <= data_remaining) {
+ data_remaining -= data_written;
+ data_ptr += data_written;
+ } else {
+ /* Unexpected overwrite */
+ fprintf(stderr, "Failure: Unexpected telemetry log overwrite - data_remaining = 0x%x, data_written = 0x%x\n",
+ data_remaining, data_written);
+ break;
+ }
+ }
+
+ if (fsync(output) < 0) {
+ fprintf(stderr, "ERROR: %s: fsync: %s\n", __func__, strerror(errno));
+ err = -1;
+ }
+
+ free(log);
+close_output:
+ close(output);
+ return err;
+}
+
+static int wdc_do_cap_diag(nvme_root_t r, struct nvme_dev *dev, char *file,
+ __u32 xfer_size, int type, int data_area)
+{
+ int ret = -1;
+ __u32 e6_log_hdr_size = WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE;
+ struct wdc_e6_log_hdr *log_hdr;
+ __u32 cap_diag_length;
+
+ log_hdr = (struct wdc_e6_log_hdr *)malloc(e6_log_hdr_size);
+ if (!log_hdr) {
+ fprintf(stderr, "%s: ERROR: malloc: %s\n", __func__, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ memset(log_hdr, 0, e6_log_hdr_size);
+
+ if (type == WDC_TELEMETRY_TYPE_NONE) {
+ ret = wdc_dump_length_e6(dev_fd(dev),
+ WDC_NVME_CAP_DIAG_OPCODE,
+ WDC_NVME_CAP_DIAG_HEADER_TOC_SIZE>>2,
+ 0x00,
+ log_hdr);
+ if (ret == -1) {
+ ret = -1;
+ goto out;
+ }
+
+ cap_diag_length = (log_hdr->log_size[0] << 24 | log_hdr->log_size[1] << 16 |
+ log_hdr->log_size[2] << 8 | log_hdr->log_size[3]);
+
+ if (!cap_diag_length) {
+ fprintf(stderr, "INFO: WDC: Capture Diagnostics log is empty\n");
+ } else {
+ ret = wdc_do_dump_e6(dev_fd(dev),
+ WDC_NVME_CAP_DIAG_OPCODE,
+ cap_diag_length,
+ (WDC_NVME_CAP_DIAG_SUBCMD << WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_CAP_DIAG_CMD,
+ file, xfer_size, (__u8 *)log_hdr);
+
+ fprintf(stderr, "INFO: WDC: Capture Diagnostics log, length = 0x%x\n", cap_diag_length);
+ }
+ } else if ((type == WDC_TELEMETRY_TYPE_HOST) ||
+ (type == WDC_TELEMETRY_TYPE_CONTROLLER)) {
+ /* Get the desired telemetry log page */
+ ret = wdc_do_cap_telemetry_log(dev, file, xfer_size, type, data_area);
+ } else {
+ fprintf(stderr, "%s: ERROR: Invalid type : %d\n", __func__, type);
+ }
+
+out:
+ free(log_hdr);
+ return ret;
+}
+
+static int wdc_do_cap_dui_v1(int fd, char *file, __u32 xfer_size, int data_area, int verbose,
+ struct wdc_dui_log_hdr *log_hdr, __s64 *total_size)
+{
+ __s32 log_size = 0;
+ __u32 cap_dui_length = le32_to_cpu(log_hdr->log_size);
+ __u32 curr_data_offset = 0;
+ __u8 *buffer_addr;
+ __u8 *dump_data = NULL;
+ bool last_xfer = false;
+ int err;
+ int i;
+ int j;
+ int output;
+ int ret = 0;
+
+ 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: DUI section count = 0x%x\n", log_hdr->section_count);
+ fprintf(stderr, "INFO: WDC: DUI log size = 0x%x\n", log_hdr->log_size);
+ }
+
+ if (!cap_dui_length) {
+ fprintf(stderr, "INFO: WDC: Capture V1 Device Unit Info log is empty\n");
+ return 0;
+ }
+
+ /* 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 < log_hdr->section_count; j++) {
+ log_size += log_hdr->log_section[j].section_size;
+ if (verbose)
+ fprintf(stderr,
+ "%s: section size 0x%x, total size = 0x%x\n",
+ __func__,
+ (unsigned int)log_hdr->log_section[j].section_size,
+ (unsigned int)log_size);
+
+ }
+ } else {
+ log_size = cap_dui_length;
+ }
+
+ *total_size = log_size;
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size);
+ if (!dump_data) {
+ fprintf(stderr, "%s: ERROR: dump data V1 malloc failed : status %s, size = 0x%x\n",
+ __func__, strerror(errno), (unsigned int)xfer_size);
+ return -1;
+ }
+ 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));
+ free(dump_data);
+ return output;
+ }
+
+ /* 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) {
+ 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: ", __func__);
+ nvme_show_status(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);
+ ret = -1;
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size;
+ i++;
+ }
+
+free_mem:
+ close(output);
+ free(dump_data);
+ return ret;
+}
+
+static int wdc_do_cap_dui_v2_v3(int fd, char *file, __u32 xfer_size, int data_area, int verbose,
+ struct wdc_dui_log_hdr *log_hdr, __s64 *total_size, __u64 file_size,
+ __u64 offset)
+{
+ __u64 cap_dui_length_v3;
+ __u64 curr_data_offset = 0;
+ __s64 log_size = 0;
+ __u64 xfer_size_long = (__u64)xfer_size;
+ __u8 *buffer_addr;
+ __u8 *dump_data = NULL;
+ bool last_xfer = false;
+ int err;
+ int i;
+ int j;
+ int output;
+ int ret = 0;
+ struct wdc_dui_log_hdr_v3 *log_hdr_v3 = (struct wdc_dui_log_hdr_v3 *)log_hdr;
+
+ cap_dui_length_v3 = le64_to_cpu(log_hdr_v3->log_size);
+
+ if (verbose) {
+ 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->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) {
+ fprintf(stderr, "INFO: WDC: Capture V2 or V3 Device Unit Info log is empty\n");
+ return 0;
+ }
+
+ /* 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_V3; j++) {
+ if (log_hdr_v3->log_section[j].data_area_id <= data_area &&
+ log_hdr_v3->log_section[j].data_area_id) {
+ 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%"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%"PRIx64"\n",
+ __func__, (uint64_t)log_size);
+ break;
+ }
+ }
+ } else {
+ log_size = cap_dui_length_v3;
+ }
+
+ *total_size = log_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);
+ return -1;
+ }
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size_long);
+ if (!dump_data) {
+ fprintf(stderr,
+ "%s: ERROR: dump data v3 malloc failed : status %s, size = 0x%"PRIx64"\n",
+ __func__, strerror(errno), (uint64_t)xfer_size_long);
+ return -1;
+ }
+ memset(dump_data, 0, sizeof(__u8) * xfer_size_long);
+
+ 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));
+ free(dump_data);
+ return output;
+ }
+
+ curr_data_offset = 0;
+
+ if (file_size) {
+ /* 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;
+ }
+
+ i = 0;
+ buffer_addr = dump_data;
+
+ for (; log_size > 0; log_size -= xfer_size_long) {
+ xfer_size_long = min(xfer_size_long, log_size);
+
+ if (log_size <= xfer_size_long)
+ last_xfer = true;
+
+ ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr,
+ last_xfer);
+ if (ret) {
+ 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: ", __func__);
+ nvme_show_status(ret);
+ break;
+ }
+
+ /* 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%"PRIx64"\n",
+ __func__, i, err, (uint64_t)xfer_size_long);
+ ret = -1;
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size_long;
+ i++;
+ }
+
+free_mem:
+ close(output);
+ free(dump_data);
+ return ret;
+}
+
+static int wdc_do_cap_dui_v4(int fd, char *file, __u32 xfer_size, int data_area, int verbose,
+ struct wdc_dui_log_hdr *log_hdr, __s64 *total_size, __u64 file_size,
+ __u64 offset)
+{
+ __s64 log_size = 0;
+ __s64 section_size_bytes = 0;
+ __s64 xfer_size_long = (__s64)xfer_size;
+ __u64 cap_dui_length_v4;
+ __u64 curr_data_offset = 0;
+ __u8 *buffer_addr;
+ __u8 *dump_data = NULL;
+ int err;
+ int i;
+ int j;
+ int output;
+ int ret = 0;
+ bool last_xfer = false;
+ struct wdc_dui_log_hdr_v4 *log_hdr_v4 = (struct wdc_dui_log_hdr_v4 *)log_hdr;
+
+ 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 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_v4) {
+ fprintf(stderr, "INFO: WDC: Capture V4 Device Unit Info log is empty\n");
+ return 0;
+ }
+
+ /* 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_v4->log_section[j].data_area_id <= data_area &&
+ log_hdr_v4->log_section[j].data_area_id) {
+ 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 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%"PRIx64"\n", __func__, (uint64_t)log_size);
+ break;
+ }
+ }
+ } else {
+ log_size = cap_dui_length_v4;
+ }
+
+ *total_size = log_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);
+ return -1;
+ }
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * xfer_size_long);
+ if (!dump_data) {
+ fprintf(stderr, "%s: ERROR: dump data V4 malloc failed : status %s, size = 0x%x\n",
+ __func__, strerror(errno), (unsigned int)xfer_size_long);
+ return -1;
+ }
+ memset(dump_data, 0, sizeof(__u8) * xfer_size_long);
+
+ 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));
+ free(dump_data);
+ return output;
+ }
+
+ curr_data_offset = 0;
+
+ if (file_size) {
+ /* 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;
+ }
+
+ i = 0;
+ buffer_addr = dump_data;
+
+ for (; log_size > 0; log_size -= xfer_size_long) {
+ xfer_size_long = min(xfer_size_long, log_size);
+
+ if (log_size <= xfer_size_long)
+ last_xfer = true;
+
+ ret = wdc_dump_dui_data_v2(fd, (__u32)xfer_size_long, curr_data_offset, buffer_addr, last_xfer);
+ if (ret) {
+ 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:", __func__);
+ nvme_show_status(ret);
+ break;
+ }
+
+ /* 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_long = 0x%"PRIx64"\n",
+ __func__, i, err, (uint64_t)xfer_size_long);
+ ret = -1;
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size_long;
+ i++;
+ }
+
+free_mem:
+ close(output);
+ free(dump_data);
+ return ret;
+}
+
+static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area, int verbose,
+ __u64 file_size, __u64 offset)
+{
+ int ret = 0;
+ __u32 dui_log_hdr_size = WDC_NVME_CAP_DUI_HEADER_SIZE;
+ struct wdc_dui_log_hdr *log_hdr;
+ __s64 total_size = 0;
+ bool last_xfer = false;
+
+ log_hdr = (struct wdc_dui_log_hdr *)malloc(dui_log_hdr_size);
+ if (!log_hdr) {
+ fprintf(stderr, "%s: ERROR: log header malloc failed : status %s, size 0x%x\n",
+ __func__, strerror(errno), dui_log_hdr_size);
+ return -1;
+ }
+ memset(log_hdr, 0, dui_log_hdr_size);
+
+ /* get the dui telemetry and log headers */
+ ret = wdc_dump_dui_data(fd, WDC_NVME_CAP_DUI_HEADER_SIZE, 0x00, (__u8 *)log_hdr, last_xfer);
+ if (ret) {
+ fprintf(stderr, "%s: ERROR: WDC: Get DUI headers failed\n", __func__);
+ fprintf(stderr, "%s: ERROR: WDC: ", __func__);
+ nvme_show_status(ret);
+ goto out;
+ }
+
+ /* Check the Log Header version */
+ if ((log_hdr->hdr_version & 0xFF) == 0x00 || (log_hdr->hdr_version & 0xFF) == 0x01) {
+ ret = wdc_do_cap_dui_v1(fd, file, xfer_size, data_area, verbose, log_hdr,
+ &total_size);
+ if (ret)
+ goto out;
+ } else if ((log_hdr->hdr_version & 0xFF) == 0x02 ||
+ (log_hdr->hdr_version & 0xFF) == 0x03) {
+ /* Process Version 2 or 3 header */
+ ret = wdc_do_cap_dui_v2_v3(fd, file, xfer_size, data_area, verbose, log_hdr,
+ &total_size, file_size, offset);
+ if (ret)
+ goto out;
+ } else if ((log_hdr->hdr_version & 0xFF) == 0x04) {
+ ret = wdc_do_cap_dui_v4(fd, file, xfer_size, data_area, verbose, log_hdr,
+ &total_size, file_size, offset);
+ if (ret)
+ goto out;
+ } else {
+ fprintf(stderr, "INFO: WDC: Unsupported header version = 0x%x\n",
+ log_hdr->hdr_version);
+ goto out;
+ }
+
+ nvme_show_status(ret);
+ if (verbose)
+ fprintf(stderr, "INFO: WDC: Capture Device Unit Info log, length = 0x%"PRIx64"\n",
+ (uint64_t)total_size);
+
+out:
+ free(log_hdr);
+ return ret;
+}
+
+static int wdc_cap_diag(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ nvme_root_t r;
+ char *desc = "Capture Diagnostics Log.";
+ char *file = "Output file pathname.";
+ char *size = "Data retrieval transfer size.";
+ __u64 capabilities = 0;
+ char f[PATH_MAX] = {0};
+ struct nvme_dev *dev;
+ __u32 xfer_size = 0;
+ int ret = 0;
+
+ struct config {
+ char *file;
+ __u32 xfer_size;
+ };
+
+ struct config cfg = {
+ .file = NULL,
+ .xfer_size = 0x10000
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_UINT("transfer-size", 's', &cfg.xfer_size, size),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (cfg.file)
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ if (cfg.xfer_size)
+ xfer_size = cfg.xfer_size;
+ ret = wdc_get_serial_name(dev, f, PATH_MAX, "cap_diag");
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ goto out;
+ }
+ if (!cfg.file) {
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ strcat(f, ".bin");
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG)
+ ret = wdc_do_cap_diag(r, dev, f, xfer_size, 0, 0);
+ else
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_do_get_sn730_log_len(int fd, uint32_t *len_buf, uint32_t subopcode)
+{
+ int ret;
+ uint32_t *output = NULL;
+ struct nvme_passthru_cmd admin_cmd;
+
+ output = (uint32_t *)malloc(sizeof(uint32_t));
+ if (!output) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(output, 0, sizeof(uint32_t));
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+
+ admin_cmd.data_len = 8;
+ admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE;
+ admin_cmd.addr = (uintptr_t)output;
+ admin_cmd.cdw12 = subopcode;
+ admin_cmd.cdw10 = SN730_LOG_CHUNK_SIZE / 4;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (!ret)
+ *len_buf = *output;
+ free(output);
+ return ret;
+}
+
+static int wdc_do_get_sn730_log(int fd, void *log_buf, uint32_t offset, uint32_t subopcode)
+{
+ int ret;
+ uint8_t *output = NULL;
+ struct nvme_passthru_cmd admin_cmd;
+
+ output = (uint8_t *)calloc(SN730_LOG_CHUNK_SIZE, sizeof(uint8_t));
+ if (!output) {
+ fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.data_len = SN730_LOG_CHUNK_SIZE;
+ admin_cmd.opcode = SN730_NVME_GET_LOG_OPCODE;
+ admin_cmd.addr = (uintptr_t)output;
+ admin_cmd.cdw12 = subopcode;
+ admin_cmd.cdw13 = offset;
+ admin_cmd.cdw10 = SN730_LOG_CHUNK_SIZE / 4;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd, NULL);
+ if (!ret)
+ memcpy(log_buf, output, SN730_LOG_CHUNK_SIZE);
+ return ret;
+}
+
+static int get_sn730_log_chunks(int fd, uint8_t *log_buf, uint32_t log_len, uint32_t subopcode)
+{
+ int ret = 0;
+ uint8_t *chunk_buf = NULL;
+ int remaining = log_len;
+ int curr_offset = 0;
+
+ chunk_buf = (uint8_t *)malloc(sizeof(uint8_t) * SN730_LOG_CHUNK_SIZE);
+ if (!chunk_buf) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ while (remaining > 0) {
+ memset(chunk_buf, 0, SN730_LOG_CHUNK_SIZE);
+ ret = wdc_do_get_sn730_log(fd, chunk_buf, curr_offset, subopcode);
+ if (!ret) {
+ if (remaining >= SN730_LOG_CHUNK_SIZE) {
+ memcpy(log_buf + (curr_offset * SN730_LOG_CHUNK_SIZE),
+ chunk_buf, SN730_LOG_CHUNK_SIZE);
+ } else {
+ memcpy(log_buf + (curr_offset * SN730_LOG_CHUNK_SIZE),
+ chunk_buf, remaining);
+ }
+ remaining -= SN730_LOG_CHUNK_SIZE;
+ curr_offset += 1;
+ } else {
+ goto out;
+ }
+ }
+out:
+ free(chunk_buf);
+ return ret;
+}
+
+static int wdc_do_sn730_get_and_tar(int fd, char *outputName)
+{
+ int ret = 0;
+ void *retPtr;
+ uint8_t *full_log_buf = NULL;
+ uint8_t *key_log_buf = NULL;
+ uint8_t *core_dump_log_buf = NULL;
+ uint8_t *extended_log_buf = NULL;
+ uint32_t full_log_len = 0;
+ uint32_t key_log_len = 0;
+ uint32_t core_dump_log_len = 0;
+ uint32_t extended_log_len = 0;
+ struct tarfile_metadata *tarInfo = NULL;
+
+ tarInfo = (struct tarfile_metadata *)malloc(sizeof(struct tarfile_metadata));
+ if (!tarInfo) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ ret = -1;
+ goto free_buf;
+ }
+ memset(tarInfo, 0, sizeof(struct tarfile_metadata));
+
+ /* Create Logs directory */
+ wdc_UtilsGetTime(&tarInfo->timeInfo);
+ memset(tarInfo->timeString, 0, sizeof(tarInfo->timeString));
+ wdc_UtilsSnprintf((char *)tarInfo->timeString, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u",
+ tarInfo->timeInfo.year, tarInfo->timeInfo.month, tarInfo->timeInfo.dayOfMonth,
+ tarInfo->timeInfo.hour, tarInfo->timeInfo.minute, tarInfo->timeInfo.second);
+
+ wdc_UtilsSnprintf((char *)tarInfo->bufferFolderName, MAX_PATH_LEN, "%s",
+ (char *)outputName);
+
+ retPtr = getcwd((char *)tarInfo->currDir, MAX_PATH_LEN);
+ if (retPtr) {
+ wdc_UtilsSnprintf((char *)tarInfo->bufferFolderPath, MAX_PATH_LEN, "%s%s%s",
+ (char *)tarInfo->currDir, WDC_DE_PATH_SEPARATOR, (char *)tarInfo->bufferFolderName);
+ } else {
+ fprintf(stderr, "ERROR: WDC: get current working directory failed\n");
+ goto free_buf;
+ }
+
+ ret = wdc_UtilsCreateDir((char *)tarInfo->bufferFolderPath);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: create directory failed, ret = %d, dir = %s\n", ret, tarInfo->bufferFolderPath);
+ goto free_buf;
+ } else {
+ fprintf(stderr, "Stored log files in directory: %s\n", tarInfo->bufferFolderPath);
+ }
+
+ ret = wdc_do_get_sn730_log_len(fd, &full_log_len, SN730_GET_FULL_LOG_LENGTH);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &key_log_len, SN730_GET_KEY_LOG_LENGTH);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &core_dump_log_len, SN730_GET_COREDUMP_LOG_LENGTH);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &extended_log_len, SN730_GET_EXTENDED_LOG_LENGTH);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+
+ full_log_buf = (uint8_t *) calloc(full_log_len, sizeof(uint8_t));
+ key_log_buf = (uint8_t *) calloc(key_log_len, sizeof(uint8_t));
+ core_dump_log_buf = (uint8_t *) calloc(core_dump_log_len, sizeof(uint8_t));
+ extended_log_buf = (uint8_t *) calloc(extended_log_len, sizeof(uint8_t));
+
+ if (!full_log_buf || !key_log_buf || !core_dump_log_buf || !extended_log_buf) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ ret = -1;
+ goto free_buf;
+ }
+
+ /* Get the full log */
+ ret = get_sn730_log_chunks(fd, full_log_buf, full_log_len, SN730_GET_FULL_LOG_SUBOPCODE);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+
+ /* Get the key log */
+ ret = get_sn730_log_chunks(fd, key_log_buf, key_log_len, SN730_GET_KEY_LOG_SUBOPCODE);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+
+ /* Get the core dump log */
+ ret = get_sn730_log_chunks(fd, core_dump_log_buf, core_dump_log_len, SN730_GET_CORE_LOG_SUBOPCODE);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+
+ /* Get the extended log */
+ ret = get_sn730_log_chunks(fd, extended_log_buf, extended_log_len, SN730_GET_EXTEND_LOG_SUBOPCODE);
+ if (ret) {
+ nvme_show_status(ret);
+ goto free_buf;
+ }
+
+ /* Write log files */
+ wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "full_log", (char *)tarInfo->timeString);
+ wdc_WriteToFile(tarInfo->fileName, (char *)full_log_buf, full_log_len);
+
+ wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "key_log", (char *)tarInfo->timeString);
+ wdc_WriteToFile(tarInfo->fileName, (char *)key_log_buf, key_log_len);
+
+ wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "core_dump_log", (char *)tarInfo->timeString);
+ wdc_WriteToFile(tarInfo->fileName, (char *)core_dump_log_buf, core_dump_log_len);
+
+ wdc_UtilsSnprintf(tarInfo->fileName, MAX_PATH_LEN, "%s%s%s_%s.bin", (char *)tarInfo->bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "extended_log", (char *)tarInfo->timeString);
+ wdc_WriteToFile(tarInfo->fileName, (char *)extended_log_buf, extended_log_len);
+
+ /* Tar the log directory */
+ wdc_UtilsSnprintf(tarInfo->tarFileName, sizeof(tarInfo->tarFileName), "%s%s", (char *)tarInfo->bufferFolderPath, WDC_DE_TAR_FILE_EXTN);
+ wdc_UtilsSnprintf(tarInfo->tarFiles, sizeof(tarInfo->tarFiles), "%s%s%s", (char *)tarInfo->bufferFolderName, WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES);
+ wdc_UtilsSnprintf(tarInfo->tarCmd, sizeof(tarInfo->tarCmd), "%s %s %s", WDC_DE_TAR_CMD, (char *)tarInfo->tarFileName, (char *)tarInfo->tarFiles);
+
+ ret = system(tarInfo->tarCmd);
+
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Tar of log data failed, ret = %d\n", ret);
+
+free_buf:
+ free(tarInfo);
+ free(full_log_buf);
+ free(core_dump_log_buf);
+ free(key_log_buf);
+ free(extended_log_buf);
+ return ret;
+}
+
+static int dump_internal_logs(struct nvme_dev *dev, char *dir_name, int verbose)
+{
+ char file_path[128];
+ void *telemetry_log;
+ const size_t bs = 512;
+ struct nvme_telemetry_log *hdr;
+ size_t full_size, offset = bs;
+ int err, output;
+
+ if (verbose)
+ printf("NVMe Telemetry log...\n");
+
+ hdr = malloc(bs);
+ telemetry_log = malloc(bs);
+ if (!hdr || !telemetry_log) {
+ fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n", bs, strerror(errno));
+ err = -ENOMEM;
+ goto free_mem;
+ }
+ memset(hdr, 0, bs);
+
+ sprintf(file_path, "%s/telemetry.bin", dir_name);
+ output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ fprintf(stderr, "Failed to open output file %s: %s!\n", file_path, strerror(errno));
+ err = output;
+ goto free_mem;
+ }
+
+ struct nvme_get_log_args args = {
+ .lpo = 0,
+ .result = NULL,
+ .log = hdr,
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .lid = NVME_LOG_LID_TELEMETRY_HOST,
+ .len = bs,
+ .nsid = NVME_NSID_ALL,
+ .csi = NVME_CSI_NVM,
+ .lsi = NVME_LOG_LSI_NONE,
+ .lsp = NVME_LOG_TELEM_HOST_LSP_CREATE,
+ .uuidx = NVME_UUID_NONE,
+ .rae = true,
+ .ot = false,
+ };
+
+ err = nvme_get_log(&args);
+ if (err < 0)
+ perror("get-telemetry-log");
+ else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "Failed to acquire telemetry header %d!\n", err);
+ goto close_output;
+ }
+
+ err = write(output, (void *)hdr, bs);
+ if (err != bs) {
+ fprintf(stderr, "Failed to flush all data to file!\n");
+ goto close_output;
+ }
+
+ full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset;
+
+ while (offset != full_size) {
+ args.log = telemetry_log;
+ args.lpo = offset;
+ args.lsp = NVME_LOG_LSP_NONE;
+ err = nvme_get_log(&args);
+ if (err < 0) {
+ perror("get-telemetry-log");
+ break;
+ } else if (err > 0) {
+ fprintf(stderr, "Failed to acquire full telemetry log!\n");
+ nvme_show_status(err);
+ break;
+ }
+
+ err = write(output, (void *)telemetry_log, bs);
+ if (err != bs) {
+ fprintf(stderr, "Failed to flush all data to file!\n");
+ break;
+ }
+ err = 0;
+ offset += bs;
+ }
+
+close_output:
+ close(output);
+free_mem:
+ free(hdr);
+ free(telemetry_log);
+
+ return err;
+}
+
+static int wdc_vs_internal_fw_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ 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, 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 SN530, SN640, SN730, SN740, SN810, SN840 and ZN350 devices.";
+ char *verbose = "Display more debug messages.";
+ char f[PATH_MAX] = {0};
+ char fb[PATH_MAX/2] = {0};
+ char fileSuffix[PATH_MAX] = {0};
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ __u32 xfer_size = 0;
+ int telemetry_type = 0, telemetry_data_area = 0;
+ UtilsTimeInfo timeInfo;
+ __u8 timeStamp[MAX_PATH_LEN];
+ __u64 capabilities = 0;
+ __u32 device_id, read_vendor_id;
+ char file_path[PATH_MAX/2] = {0};
+ char cmd_buf[PATH_MAX] = {0};
+ int ret = -1;
+
+ struct config {
+ char *file;
+ __u32 xfer_size;
+ int data_area;
+ __u64 file_size;
+ __u64 offset;
+ char *type;
+ bool verbose;
+ };
+
+ struct config cfg = {
+ .file = NULL,
+ .xfer_size = 0x10000,
+ .data_area = 0,
+ .file_size = 0,
+ .offset = 0,
+ .type = NULL,
+ .verbose = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_UINT("transfer-size", 's', &cfg.xfer_size, size),
+ OPT_UINT("data-area", 'd', &cfg.data_area, data_area),
+ OPT_LONG("file-size", 'f', &cfg.file_size, file_size),
+ OPT_LONG("offset", 'e', &cfg.offset, offset),
+ OPT_FILE("type", 't', &cfg.type, type),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ if (!wdc_check_device(r, dev))
+ goto out;
+
+ if (cfg.xfer_size) {
+ xfer_size = cfg.xfer_size;
+ } else {
+ fprintf(stderr, "ERROR: WDC: Invalid length\n");
+ goto out;
+ }
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+
+ if (!wdc_is_sn861(device_id)) {
+ if (cfg.file) {
+ int verify_file;
+
+ /* verify file name and path is valid before getting dump data */
+ verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (verify_file < 0) {
+ fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
+ goto out;
+ }
+ close(verify_file);
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ } else {
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeStamp, 0, sizeof(timeStamp));
+ wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN,
+ "%02u%02u%02u_%02u%02u%02u", timeInfo.year,
+ timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute,
+ timeInfo.second);
+ snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp);
+
+ ret = wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ goto out;
+ }
+ }
+
+ if (!cfg.file) {
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ strcat(f, ".bin");
+ }
+ fprintf(stderr, "%s: filename = %s\n", __func__, f);
+
+ if (cfg.data_area) {
+ if (cfg.data_area > 5 || cfg.data_area < 1) {
+ fprintf(stderr, "ERROR: WDC: Data area must be 1-5\n");
+ ret = -1;
+ goto out;
+ }
+ }
+
+ if (!cfg.type || !strcmp(cfg.type, "NONE") || !strcmp(cfg.type, "none")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_NONE;
+ data_area = 0;
+ } else if (!strcmp(cfg.type, "HOST") || !strcmp(cfg.type, "host")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_HOST;
+ telemetry_data_area = cfg.data_area;
+ } else if (!strcmp(cfg.type, "CONTROLLER") || !strcmp(cfg.type, "controller")) {
+ telemetry_type = WDC_TELEMETRY_TYPE_CONTROLLER;
+ telemetry_data_area = cfg.data_area;
+ } else {
+ fprintf(stderr,
+ "ERROR: WDC: Invalid type - Must be NONE, HOST or CONTROLLER\n");
+ ret = -1;
+ goto out;
+ }
+ } else {
+ if (cfg.file) {
+ strncpy(fb, cfg.file, PATH_MAX/2 - 8);
+ } else {
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeStamp, 0, sizeof(timeStamp));
+ wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN,
+ "%02u%02u%02u_%02u%02u%02u", timeInfo.year,
+ timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute,
+ timeInfo.second);
+ snprintf(fileSuffix, PATH_MAX, "_internal_fw_log_%s", (char *)timeStamp);
+
+ ret = wdc_get_serial_name(dev, fb, PATH_MAX/2 - 7, fileSuffix);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ goto out;
+ }
+
+ if (strlen(fb) > PATH_MAX/2 - 7) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto out;
+ }
+ }
+ fprintf(stderr, "%s: filename = %s.tar.gz\n", __func__, fb);
+
+
+ memset(file_path, 0, sizeof(file_path));
+ if (snprintf(file_path, PATH_MAX/2 - 8, "%s.tar.gz", fb) >= PATH_MAX/2 - 8) {
+ fprintf(stderr, "File path is too long!\n");
+ ret = -1;
+ goto out;
+ }
+ if (access(file_path, F_OK) != -1) {
+ fprintf(stderr, "Output file already exists!\n");
+ ret = -EEXIST;
+ goto out;
+ }
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) {
+ if (!wdc_is_sn861(device_id)) {
+ /* Set the default DA to 3 if not specified */
+ if (!telemetry_data_area)
+ telemetry_data_area = 3;
+
+ ret = wdc_do_cap_diag(r, dev, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ } else {
+ if (cfg.verbose)
+ printf("Creating temp directory...\n");
+
+ ret = mkdir(fb, 0666);
+ if (ret) {
+ fprintf(stderr, "Failed to create directory!\n");
+ goto out;
+ }
+
+ ret = dump_internal_logs(dev, fb, cfg.verbose);
+ if (ret < 0)
+ perror("vs-internal-log");
+
+ if (cfg.verbose)
+ printf("Archiving...\n");
+
+ if (snprintf(cmd_buf, PATH_MAX,
+ "tar --remove-files -czf %s %s",
+ file_path, fb) >= PATH_MAX) {
+ fprintf(stderr, "Command buffer is too long!\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = system(cmd_buf);
+ if (ret)
+ fprintf(stderr, "Failed to create an archive file!\n");
+ }
+ goto out;
+ }
+ if ((capabilities & WDC_DRIVE_CAP_DUI) == WDC_DRIVE_CAP_DUI) {
+ if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) ||
+ (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) {
+ if (!telemetry_data_area)
+ telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
+ /* Get the desired telemetry log page */
+ ret = wdc_do_cap_telemetry_log(dev, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ goto out;
+ } else {
+ if (!cfg.data_area)
+ cfg.data_area = 1;
+
+ /* FW requirement - xfer size must be 256k for data area 4 */
+ if (cfg.data_area >= 4)
+ xfer_size = 0x40000;
+ ret = wdc_do_cap_dui(dev_fd(dev), f, xfer_size,
+ cfg.data_area,
+ cfg.verbose, cfg.file_size,
+ cfg.offset);
+ goto out;
+ }
+ }
+ if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA) {
+ if ((telemetry_type == WDC_TELEMETRY_TYPE_HOST) ||
+ (telemetry_type == WDC_TELEMETRY_TYPE_CONTROLLER)) {
+ if (!telemetry_data_area)
+ telemetry_data_area = 3; /* Set the default DA to 3 if not specified */
+ /* Get the desired telemetry log page */
+ ret = wdc_do_cap_telemetry_log(dev, f, xfer_size,
+ telemetry_type, telemetry_data_area);
+ goto out;
+ } else {
+ ret = wdc_do_cap_dui(dev_fd(dev), f, xfer_size,
+ WDC_NVME_DUI_MAX_DATA_AREA,
+ cfg.verbose, 0, 0);
+ goto out;
+ }
+ }
+ if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG) {
+ ret = wdc_do_sn730_get_and_tar(dev_fd(dev), f);
+ } else {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_do_crash_dump(struct nvme_dev *dev, char *file, int type)
+{
+ int ret;
+ __u32 crash_dump_length;
+ __u32 opcode;
+ __u32 cdw12;
+ __u32 cdw10_size;
+ __u32 cdw12_size;
+ __u32 cdw12_clear;
+
+ if (type == WDC_NVME_PFAIL_DUMP_TYPE) {
+ /* set parms to get the PFAIL Crash Dump */
+ opcode = WDC_NVME_PF_CRASH_DUMP_OPCODE;
+ cdw10_size = WDC_NVME_PF_CRASH_DUMP_SIZE_NDT;
+ cdw12_size = ((WDC_NVME_PF_CRASH_DUMP_SIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_PF_CRASH_DUMP_SIZE_CMD);
+
+ cdw12 = (WDC_NVME_PF_CRASH_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_PF_CRASH_DUMP_CMD;
+
+ cdw12_clear = ((WDC_NVME_CLEAR_PF_CRASH_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_CRASH_DUMP_CMD);
+
+ } else {
+ /* set parms to get the Crash Dump */
+ opcode = WDC_NVME_CRASH_DUMP_OPCODE;
+ cdw10_size = WDC_NVME_CRASH_DUMP_SIZE_NDT;
+ cdw12_size = ((WDC_NVME_CRASH_DUMP_SIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CRASH_DUMP_SIZE_CMD);
+
+ cdw12 = (WDC_NVME_CRASH_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CRASH_DUMP_CMD;
+
+ cdw12_clear = ((WDC_NVME_CLEAR_CRASH_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_CRASH_DUMP_CMD);
+ }
+
+ ret = wdc_dump_length(dev_fd(dev),
+ opcode,
+ cdw10_size,
+ cdw12_size,
+ &crash_dump_length);
+
+ if (ret == -1) {
+ if (type == WDC_NVME_PFAIL_DUMP_TYPE)
+ fprintf(stderr, "INFO: WDC: Pfail dump get size failed\n");
+ else
+ fprintf(stderr, "INFO: WDC: Crash dump get size failed\n");
+
+ return -1;
+ }
+
+ if (!crash_dump_length) {
+ if (type == WDC_NVME_PFAIL_DUMP_TYPE)
+ fprintf(stderr, "INFO: WDC: Pfail dump is empty\n");
+ else
+ fprintf(stderr, "INFO: WDC: Crash dump is empty\n");
+ } else {
+ ret = wdc_do_dump(dev,
+ opcode,
+ crash_dump_length,
+ cdw12,
+ file,
+ crash_dump_length);
+
+ if (!ret)
+ ret = wdc_do_clear_dump(dev, WDC_NVME_CLEAR_DUMP_OPCODE,
+ cdw12_clear);
+ }
+ return ret;
+}
+
+static int wdc_crash_dump(struct nvme_dev *dev, char *file, int type)
+{
+ char f[PATH_MAX] = {0};
+ const char *dump_type;
+ int ret;
+
+ if (file)
+ strncpy(f, file, PATH_MAX - 1);
+
+ if (type == WDC_NVME_PFAIL_DUMP_TYPE)
+ dump_type = "_pfail_dump";
+ else
+ dump_type = "_crash_dump";
+
+ ret = wdc_get_serial_name(dev, f, PATH_MAX, dump_type);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ else
+ ret = wdc_do_crash_dump(dev, f, type);
+ return ret;
+}
+
+static int wdc_do_drive_log(struct nvme_dev *dev, char *file)
+{
+ int ret;
+ __u8 *drive_log_data;
+ __u32 drive_log_length;
+ struct nvme_passthru_cmd admin_cmd;
+
+ ret = wdc_dump_length(dev_fd(dev), WDC_NVME_DRIVE_LOG_SIZE_OPCODE,
+ WDC_NVME_DRIVE_LOG_SIZE_NDT,
+ (WDC_NVME_DRIVE_LOG_SIZE_SUBCMD <<
+ WDC_NVME_SUBCMD_SHIFT | WDC_NVME_DRIVE_LOG_SIZE_CMD),
+ &drive_log_length);
+ if (ret == -1)
+ return -1;
+
+ drive_log_data = (__u8 *)malloc(sizeof(__u8) * drive_log_length);
+ if (!drive_log_data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(drive_log_data, 0, sizeof(__u8) * drive_log_length);
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_DRIVE_LOG_OPCODE;
+ admin_cmd.addr = (__u64)(uintptr_t)drive_log_data;
+ admin_cmd.data_len = drive_log_length;
+ admin_cmd.cdw10 = drive_log_length;
+ admin_cmd.cdw12 = ((WDC_NVME_DRIVE_LOG_SUBCMD <<
+ WDC_NVME_SUBCMD_SHIFT) | WDC_NVME_DRIVE_LOG_SIZE_CMD);
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ nvme_show_status(ret);
+ if (!ret)
+ ret = wdc_create_log_file(file, drive_log_data, drive_log_length);
+ free(drive_log_data);
+ return ret;
+}
+
+static int wdc_drive_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Capture Drive Log.";
+ const char *file = "Output file pathname.";
+ char f[PATH_MAX] = {0};
+ struct nvme_dev *dev;
+ int ret;
+ nvme_root_t r;
+ __u64 capabilities = 0;
+ struct config {
+ char *file;
+ };
+
+ struct config cfg = {
+ .file = NULL
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (!wdc_check_device(r, dev)) {
+ nvme_free_tree(r);
+ dev_close(dev);
+ return -1;
+ }
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_DRIVE_LOG)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ if (cfg.file)
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ ret = wdc_get_serial_name(dev, f, PATH_MAX, "drive_log");
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ else
+ ret = wdc_do_drive_log(dev, f);
+ }
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_crash_dump(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Get Crash Dump.";
+ const char *file = "Output file pathname.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ struct config {
+ char *file;
+ };
+
+ struct config cfg = {
+ .file = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (!wdc_check_device(r, dev)) {
+ nvme_free_tree(r);
+ dev_close(dev);
+ return -1;
+
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_CRASH_DUMP)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_crash_dump(dev, cfg.file, WDC_NVME_CRASH_DUMP_TYPE);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: failed to read crash dump\n");
+ }
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_pfail_dump(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Get Pfail Crash Dump.";
+ char *file = "Output file pathname.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ struct config {
+ char *file;
+ };
+ nvme_root_t r;
+ int ret;
+
+ struct config cfg = {
+ .file = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("output-file", 'o', &cfg.file, file),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (!wdc_check_device(r, dev)) {
+ nvme_free_tree(r);
+ dev_close(dev);
+ return -1;
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_PFAIL_DUMP)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_crash_dump(dev, cfg.file, WDC_NVME_PFAIL_DUMP_TYPE);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: failed to read pfail crash dump\n");
+ }
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static void wdc_do_id_ctrl(__u8 *vs, struct json_object *root)
+{
+ char vsn[24] = {0};
+ int base = 3072;
+ int vsn_start = 3081;
+
+ memcpy(vsn, &vs[vsn_start - base], sizeof(vsn));
+ if (root)
+ json_object_add_value_string(root, "wdc vsn", strlen(vsn) > 1 ? vsn : "NULL");
+ else
+ printf("wdc vsn: %s\n", strlen(vsn) > 1 ? vsn : "NULL");
+}
+
+static int wdc_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, wdc_do_id_ctrl);
+}
+
+static const char *wdc_purge_mon_status_to_string(__u32 status)
+{
+ const char *str;
+
+ switch (status) {
+ case WDC_NVME_PURGE_STATE_IDLE:
+ str = "Purge State Idle.";
+ break;
+ case WDC_NVME_PURGE_STATE_DONE:
+ str = "Purge State Done.";
+ break;
+ case WDC_NVME_PURGE_STATE_BUSY:
+ str = "Purge State Busy.";
+ break;
+ case WDC_NVME_PURGE_STATE_REQ_PWR_CYC:
+ str = "Purge Operation resulted in an error that requires power cycle.";
+ break;
+ case WDC_NVME_PURGE_STATE_PWR_CYC_PURGE:
+ str = "The previous purge operation was interrupted by a power cycle\n"
+ "or reset interruption. Other commands may be rejected until\n"
+ "Purge Execute is issued and completed.";
+ break;
+ default:
+ str = "Unknown.";
+ }
+ return str;
+}
+
+static int wdc_purge(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a Purge command.";
+ struct nvme_passthru_cmd admin_cmd;
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ char *err_str;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (!wdc_check_device(r, dev)) {
+ nvme_free_tree(r);
+ dev_close(dev);
+ return -1;
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_PURGE)) {
+ ret = -1;
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ } else {
+ err_str = "";
+ memset(&admin_cmd, 0, sizeof(admin_cmd));
+ admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd,
+ NULL);
+ if (ret > 0) {
+ switch (ret) {
+ case WDC_NVME_PURGE_CMD_SEQ_ERR:
+ err_str = "ERROR: WDC: Cannot execute purge, Purge operation is in progress.\n";
+ break;
+ case WDC_NVME_PURGE_INT_DEV_ERR:
+ err_str = "ERROR: WDC: Internal Device Error.\n";
+ break;
+ default:
+ err_str = "ERROR: WDC\n";
+ }
+ }
+
+ fprintf(stderr, "%s", err_str);
+ nvme_show_status(ret);
+ }
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_purge_monitor(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a Purge Monitor command.";
+ __u8 output[WDC_NVME_PURGE_MONITOR_DATA_LEN];
+ double progress_percent;
+ struct nvme_passthru_cmd admin_cmd;
+ struct wdc_nvme_purge_monitor_data *mon;
+ struct nvme_dev *dev;
+ __u64 capabilities;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ if (!wdc_check_device(r, dev)) {
+ nvme_free_tree(r);
+ dev_close(dev);
+ return -1;
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_PURGE)) {
+ ret = -1;
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ } else {
+ memset(output, 0, sizeof(output));
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE;
+ admin_cmd.addr = (__u64)(uintptr_t)output;
+ admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN;
+ admin_cmd.cdw10 = WDC_NVME_PURGE_MONITOR_CMD_CDW10;
+ admin_cmd.timeout_ms = WDC_NVME_PURGE_MONITOR_TIMEOUT;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd,
+ NULL);
+ if (!ret) {
+ mon = (struct wdc_nvme_purge_monitor_data *) output;
+ printf("Purge state = 0x%0x\n", admin_cmd.result);
+ printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result));
+ if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) {
+ progress_percent =
+ ((double)le32_to_cpu(mon->entire_progress_current) * 100) /
+ le32_to_cpu(mon->entire_progress_total);
+ printf("Purge Progress = %f%%\n", progress_percent);
+ }
+ }
+
+ nvme_show_status(ret);
+ }
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static void wdc_print_log_normal(struct wdc_ssd_perf_stats *perf)
+{
+ printf(" C1 Log Page Performance Statistics :-\n");
+ printf(" Host Read Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->hr_cmds));
+ printf(" Host Read Blocks %20"PRIu64"\n",
+ le64_to_cpu(perf->hr_blks));
+ printf(" Average Read Size %20lf\n",
+ safe_div_fp((le64_to_cpu(perf->hr_blks)), (le64_to_cpu(perf->hr_cmds))));
+ printf(" Host Read Cache Hit Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->hr_ch_cmds));
+ printf(" Host Read Cache Hit_Percentage %20"PRIu64"%%\n",
+ (uint64_t) calc_percent(le64_to_cpu(perf->hr_ch_cmds), le64_to_cpu(perf->hr_cmds)));
+ printf(" Host Read Cache Hit Blocks %20"PRIu64"\n",
+ le64_to_cpu(perf->hr_ch_blks));
+ printf(" Average Read Cache Hit Size %20f\n",
+ safe_div_fp((le64_to_cpu(perf->hr_ch_blks)), (le64_to_cpu(perf->hr_ch_cmds))));
+ printf(" Host Read Commands Stalled %20"PRIu64"\n",
+ le64_to_cpu(perf->hr_st_cmds));
+ printf(" Host Read Commands Stalled Percentage %20"PRIu64"%%\n",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hr_st_cmds)), le64_to_cpu(perf->hr_cmds)));
+ printf(" Host Write Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->hw_cmds));
+ printf(" Host Write Blocks %20"PRIu64"\n",
+ le64_to_cpu(perf->hw_blks));
+ printf(" Average Write Size %20f\n",
+ safe_div_fp((le64_to_cpu(perf->hw_blks)), (le64_to_cpu(perf->hw_cmds))));
+ printf(" Host Write Odd Start Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->hw_os_cmds));
+ printf(" Host Write Odd Start Commands Percentage %20"PRIu64"%%\n",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_os_cmds)), (le64_to_cpu(perf->hw_cmds))));
+ printf(" Host Write Odd End Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->hw_oe_cmds));
+ printf(" Host Write Odd End Commands Percentage %20"PRIu64"%%\n",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_oe_cmds)), (le64_to_cpu((perf->hw_cmds)))));
+ printf(" Host Write Commands Stalled %20"PRIu64"\n",
+ le64_to_cpu(perf->hw_st_cmds));
+ printf(" Host Write Commands Stalled Percentage %20"PRIu64"%%\n",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_st_cmds)), (le64_to_cpu(perf->hw_cmds))));
+ printf(" NAND Read Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->nr_cmds));
+ printf(" NAND Read Blocks Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->nr_blks));
+ printf(" Average NAND Read Size %20f\n",
+ safe_div_fp((le64_to_cpu(perf->nr_blks)), (le64_to_cpu((perf->nr_cmds)))));
+ printf(" Nand Write Commands %20"PRIu64"\n",
+ le64_to_cpu(perf->nw_cmds));
+ printf(" NAND Write Blocks %20"PRIu64"\n",
+ le64_to_cpu(perf->nw_blks));
+ printf(" Average NAND Write Size %20f\n",
+ safe_div_fp((le64_to_cpu(perf->nw_blks)), (le64_to_cpu(perf->nw_cmds))));
+ printf(" NAND Read Before Write %20"PRIu64"\n",
+ le64_to_cpu(perf->nrbw));
+}
+
+static void wdc_print_log_json(struct wdc_ssd_perf_stats *perf)
+{
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Host Read Commands", le64_to_cpu(perf->hr_cmds));
+ json_object_add_value_int(root, "Host Read Blocks", le64_to_cpu(perf->hr_blks));
+ json_object_add_value_int(root, "Average Read Size",
+ safe_div_fp((le64_to_cpu(perf->hr_blks)), (le64_to_cpu(perf->hr_cmds))));
+ json_object_add_value_int(root, "Host Read Cache Hit Commands",
+ le64_to_cpu(perf->hr_ch_cmds));
+ json_object_add_value_int(root, "Host Read Cache Hit Percentage",
+ (uint64_t) calc_percent(le64_to_cpu(perf->hr_ch_cmds), le64_to_cpu(perf->hr_cmds)));
+ json_object_add_value_int(root, "Host Read Cache Hit Blocks",
+ le64_to_cpu(perf->hr_ch_blks));
+ json_object_add_value_int(root, "Average Read Cache Hit Size",
+ safe_div_fp((le64_to_cpu(perf->hr_ch_blks)), (le64_to_cpu(perf->hr_ch_cmds))));
+ json_object_add_value_int(root, "Host Read Commands Stalled",
+ le64_to_cpu(perf->hr_st_cmds));
+ json_object_add_value_int(root, "Host Read Commands Stalled Percentage",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hr_st_cmds)), le64_to_cpu(perf->hr_cmds)));
+ json_object_add_value_int(root, "Host Write Commands",
+ le64_to_cpu(perf->hw_cmds));
+ json_object_add_value_int(root, "Host Write Blocks",
+ le64_to_cpu(perf->hw_blks));
+ json_object_add_value_int(root, "Average Write Size",
+ safe_div_fp((le64_to_cpu(perf->hw_blks)), (le64_to_cpu(perf->hw_cmds))));
+ json_object_add_value_int(root, "Host Write Odd Start Commands",
+ le64_to_cpu(perf->hw_os_cmds));
+ json_object_add_value_int(root, "Host Write Odd Start Commands Percentage",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_os_cmds)), (le64_to_cpu(perf->hw_cmds))));
+ json_object_add_value_int(root, "Host Write Odd End Commands",
+ le64_to_cpu(perf->hw_oe_cmds));
+ json_object_add_value_int(root, "Host Write Odd End Commands Percentage",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_oe_cmds)), (le64_to_cpu((perf->hw_cmds)))));
+ json_object_add_value_int(root, "Host Write Commands Stalled",
+ le64_to_cpu(perf->hw_st_cmds));
+ json_object_add_value_int(root, "Host Write Commands Stalled Percentage",
+ (uint64_t)calc_percent((le64_to_cpu(perf->hw_st_cmds)), (le64_to_cpu(perf->hw_cmds))));
+ json_object_add_value_int(root, "NAND Read Commands",
+ le64_to_cpu(perf->nr_cmds));
+ json_object_add_value_int(root, "NAND Read Blocks Commands",
+ le64_to_cpu(perf->nr_blks));
+ json_object_add_value_int(root, "Average NAND Read Size",
+ safe_div_fp((le64_to_cpu(perf->nr_blks)), (le64_to_cpu((perf->nr_cmds)))));
+ json_object_add_value_int(root, "Nand Write Commands",
+ le64_to_cpu(perf->nw_cmds));
+ json_object_add_value_int(root, "NAND Write Blocks",
+ le64_to_cpu(perf->nw_blks));
+ json_object_add_value_int(root, "Average NAND Write Size",
+ safe_div_fp((le64_to_cpu(perf->nw_blks)), (le64_to_cpu(perf->nw_cmds))));
+ json_object_add_value_int(root, "NAND Read Before Written",
+ le64_to_cpu(perf->nrbw));
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static int wdc_print_log(struct wdc_ssd_perf_stats *perf, int fmt)
+{
+ if (!perf) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_log_normal(perf);
+ break;
+ case JSON:
+ wdc_print_log_json(perf);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_latency_monitor_log_normal(struct nvme_dev *dev,
+ struct wdc_ssd_latency_monitor_log *log_data)
+{
+ printf("Latency Monitor/C3 Log Page Data\n");
+ printf(" Controller : %s\n", dev->name);
+ int err = -1, i, j;
+ struct nvme_id_ctrl ctrl;
+ char ts_buf[128];
+
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err) {
+ printf(" Serial Number: %-.*s\n", (int)sizeof(ctrl.sn), ctrl.sn);
+ } else {
+ fprintf(stderr, "ERROR: WDC: latency monitor read id ctrl failure, err = %d\n", err);
+ return err;
+ }
+
+ printf(" Feature Status 0x%x\n", log_data->feature_status);
+ printf(" Active Bucket Timer %d min\n", 5*le16_to_cpu(log_data->active_bucket_timer));
+ printf(" Active Bucket Timer Threshold %d min\n", 5*le16_to_cpu(log_data->active_bucket_timer_threshold));
+ printf(" Active Threshold A %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_a+1)));
+ printf(" Active Threshold B %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_b+1)));
+ printf(" Active Threshold C %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_c+1)));
+ printf(" Active Threshold D %d ms\n", 5*(le16_to_cpu(log_data->active_threshold_d+1)));
+ printf(" Active Latency Config 0x%x\n", le16_to_cpu(log_data->active_latency_config));
+ printf(" Active Latency Minimum Window %d ms\n", 100*log_data->active_latency_min_window);
+ printf(" Active Latency Stamp Units %d\n", le16_to_cpu(log_data->active_latency_stamp_units));
+ printf(" Static Latency Stamp Units %d\n", le16_to_cpu(log_data->static_latency_stamp_units));
+ printf(" Debug Log Trigger Enable %d\n", le16_to_cpu(log_data->debug_log_trigger_enable));
+
+ printf(" Read Write Deallocate/Trim\n");
+ for (i = 0; i <= 3; i++)
+ printf(" Active Bucket Counter: Bucket %d %27d %27d %27d\n",
+ i, le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_READ]),
+ le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]),
+ le32_to_cpu(log_data->active_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM]));
+
+ for (i = 3; i >= 0; i--)
+ printf(" Active Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
+ 3-i, le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]),
+ le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]),
+ le16_to_cpu(log_data->active_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM]));
+
+ for (i = 3; i >= 0; i--) {
+ printf(" Active Latency Time Stamp: Bucket %d ", 3-i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->active_latency_timestamp[i][j]) == -1) {
+ printf(" N/A ");
+ } else {
+ convert_ts(le64_to_cpu(log_data->active_latency_timestamp[i][j]), ts_buf);
+ printf("%s ", ts_buf);
+ }
+ }
+ printf("\n");
+ }
+
+ for (i = 0; i <= 3; i++)
+ printf(" Static Bucket Counter: Bucket %d %27d %27d %27d\n",
+ i, le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_READ]),
+ le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_WRITE]),
+ le32_to_cpu(log_data->static_bucket_counter[i][LATENCY_LOG_BUCKET_TRIM]));
+
+ for (i = 3; i >= 0; i--)
+ printf(" Static Measured Latency: Bucket %d %27d ms %27d ms %27d ms\n",
+ 3-i, le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_READ]),
+ le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_WRITE]),
+ le16_to_cpu(log_data->static_measured_latency[i][LATENCY_LOG_MEASURED_LAT_TRIM]));
+
+ for (i = 3; i >= 0; i--) {
+ printf(" Static Latency Time Stamp: Bucket %d ", 3-i);
+ for (j = 2; j >= 0; j--) {
+ if (le64_to_cpu(log_data->static_latency_timestamp[i][j]) == -1) {
+ printf(" N/A ");
+ } else {
+ convert_ts(le64_to_cpu(log_data->static_latency_timestamp[i][j]), ts_buf);
+ printf("%s ", ts_buf);
+ }
+ }
+ printf("\n");
+ }
+
+ return 0;
+}
+
+static void wdc_print_latency_monitor_log_json(struct wdc_ssd_latency_monitor_log *log_data)
+{
+ int i, j;
+ char buf[128];
+ char *operation[3] = {"Read", "Write", "Trim"};
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Feature Status", log_data->feature_status);
+ json_object_add_value_int(root, "Active Bucket Timer", 5*le16_to_cpu(log_data->active_bucket_timer));
+ json_object_add_value_int(root, "Active Bucket Timer Threshold", 5*le16_to_cpu(log_data->active_bucket_timer_threshold));
+ json_object_add_value_int(root, "Active Threshold A", 5*le16_to_cpu(log_data->active_threshold_a+1));
+ json_object_add_value_int(root, "Active Threshold B", 5*le16_to_cpu(log_data->active_threshold_b+1));
+ json_object_add_value_int(root, "Active Threshold C", 5*le16_to_cpu(log_data->active_threshold_c+1));
+ json_object_add_value_int(root, "Active Threshold D", 5*le16_to_cpu(log_data->active_threshold_d+1));
+ json_object_add_value_int(root, "Active Latency Config", le16_to_cpu(log_data->active_latency_config));
+ json_object_add_value_int(root, "Active Lantency Minimum Window", 100*log_data->active_latency_min_window);
+ json_object_add_value_int(root, "Active Latency Stamp Units", le16_to_cpu(log_data->active_latency_stamp_units));
+ json_object_add_value_int(root, "Static Latency Stamp Units", le16_to_cpu(log_data->static_latency_stamp_units));
+ json_object_add_value_int(root, "Debug Log Trigger Enable", le16_to_cpu(log_data->debug_log_trigger_enable));
+
+ for (i = 0; i <= 3; i++) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Active Bucket Counter: Bucket %d %s", i, operation[2-j]);
+ json_object_add_value_int(root, buf, le32_to_cpu(log_data->active_bucket_counter[i][j+1]));
+ }
+ }
+ for (i = 3; i >= 0; i--) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Active Measured Latency: Bucket %d %s", 3-i, operation[2-j]);
+ json_object_add_value_int(root, buf, le16_to_cpu(log_data->active_measured_latency[i][j]));
+ }
+ }
+ for (i = 3; i >= 0; i--) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Active Latency Time Stamp: Bucket %d %s", 3-i, operation[2-j]);
+ json_object_add_value_int(root, buf, le64_to_cpu(log_data->active_latency_timestamp[i][j]));
+ }
+ }
+ for (i = 0; i <= 3; i++) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Static Bucket Counter: Bucket %d %s", i, operation[2-j]);
+ json_object_add_value_int(root, buf, le32_to_cpu(log_data->static_bucket_counter[i][j+1]));
+ }
+ }
+ for (i = 3; i >= 0; i--) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Static Measured Latency: Bucket %d %s", 3-i, operation[2-j]);
+ json_object_add_value_int(root, buf, le16_to_cpu(log_data->static_measured_latency[i][j]));
+ }
+ }
+ for (i = 3; i >= 0; i--) {
+ for (j = 2; j >= 0; j--) {
+ sprintf(buf, "Static Latency Time Stamp: Bucket %d %s", 3-i, operation[2-j]);
+ json_object_add_value_int(root, buf, le64_to_cpu(log_data->static_latency_timestamp[i][j]));
+ }
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void wdc_print_error_rec_log_normal(struct wdc_ocp_c1_error_recovery_log *log_data)
+{
+ int j;
+
+ printf("Error Recovery/C1 Log Page Data\n");
+
+ printf(" Panic Reset Wait Time : 0x%x\n", le16_to_cpu(log_data->panic_reset_wait_time));
+ printf(" Panic Reset Action : 0x%x\n", log_data->panic_reset_action);
+ printf(" Device Recovery Action 1 : 0x%x\n", log_data->dev_recovery_action1);
+ printf(" Panic ID : 0x%" PRIu64 "\n", le64_to_cpu(log_data->panic_id));
+ printf(" Device Capabilities : 0x%x\n", le32_to_cpu(log_data->dev_capabilities));
+ printf(" Vendor Specific Recovery Opcode : 0x%x\n", log_data->vs_recovery_opc);
+ printf(" Vendor Specific Command CDW12 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw12));
+ printf(" Vendor Specific Command CDW13 : 0x%x\n", le32_to_cpu(log_data->vs_cmd_cdw13));
+ if (le16_to_cpu(log_data->log_page_version) == WDC_ERROR_REC_LOG_VERSION2) {
+ printf(" Vendor Specific Command Timeout : 0x%x\n", log_data->vs_cmd_to);
+ printf(" Device Recovery Action 2 : 0x%x\n", log_data->dev_recovery_action2);
+ printf(" Device Recovery Action 2 Timeout : 0x%x\n", log_data->dev_recovery_action2_to);
+ }
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (j = 0; j < WDC_OCP_C1_GUID_LENGTH; j++)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+}
+
+static void wdc_print_error_rec_log_json(struct wdc_ocp_c1_error_recovery_log *log_data)
+{
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Panic Reset Wait Time", le16_to_cpu(log_data->panic_reset_wait_time));
+ json_object_add_value_int(root, "Panic Reset Action", log_data->panic_reset_wait_time);
+ json_object_add_value_int(root, "Device Recovery Action 1", log_data->dev_recovery_action1);
+ json_object_add_value_int(root, "Panic ID", le64_to_cpu(log_data->panic_id));
+ json_object_add_value_int(root, "Device Capabilities", le32_to_cpu(log_data->dev_capabilities));
+ json_object_add_value_int(root, "Vendor Specific Recovery Opcode", log_data->vs_recovery_opc);
+ json_object_add_value_int(root, "Vendor Specific Command CDW12", le32_to_cpu(log_data->vs_cmd_cdw12));
+ json_object_add_value_int(root, "Vendor Specific Command CDW13", le32_to_cpu(log_data->vs_cmd_cdw13));
+ if (le16_to_cpu(log_data->log_page_version) == WDC_ERROR_REC_LOG_VERSION2) {
+ json_object_add_value_int(root, "Vendor Specific Command Timeout", log_data->vs_cmd_to);
+ json_object_add_value_int(root, "Device Recovery Action 2", log_data->dev_recovery_action2);
+ json_object_add_value_int(root, "Device Recovery Action 2 Timeout", log_data->dev_recovery_action2_to);
+ }
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+
+ char guid[40];
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void wdc_print_dev_cap_log_normal(struct wdc_ocp_C4_dev_cap_log *log_data)
+{
+ int j;
+
+ printf("Device Capabilities/C4 Log Page Data\n");
+
+ printf(" Number PCIE Ports : 0x%x\n", le16_to_cpu(log_data->num_pcie_ports));
+ printf(" Number OOB Management Interfaces : 0x%x\n", le16_to_cpu(log_data->oob_mgmt_support));
+ printf(" Write Zeros Command Support : 0x%x\n", le16_to_cpu(log_data->wrt_zeros_support));
+ printf(" Sanitize Command Support : 0x%x\n", le16_to_cpu(log_data->sanitize_support));
+ printf(" DSM Command Support : 0x%x\n", le16_to_cpu(log_data->dsm_support));
+ printf(" Write Uncorr Command Support : 0x%x\n", le16_to_cpu(log_data->wrt_uncor_support));
+ printf(" Fused Command Support : 0x%x\n", le16_to_cpu(log_data->fused_support));
+ printf(" Minimum DSSD Power State : 0x%x\n", le16_to_cpu(log_data->min_dssd_ps));
+
+ for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++)
+ printf(" DSSD Power State %d Descriptor : 0x%x\n", j, log_data->dssd_ps_descr[j]);
+
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (j = 0; j < WDC_OCP_C4_GUID_LENGTH; j++)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+}
+
+static void wdc_print_dev_cap_log_json(struct wdc_ocp_C4_dev_cap_log *log_data)
+{
+ int j;
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Number PCIE Ports", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Number OOB Management Interfaces", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Write Zeros Command Support", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Sanitize Command Support", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "DSM Command Support", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Write Uncorr Command Support", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Fused Command Support", le16_to_cpu(log_data->num_pcie_ports));
+ json_object_add_value_int(root, "Minimum DSSD Power State", le16_to_cpu(log_data->num_pcie_ports));
+
+ char dssd_descr_str[40];
+
+ memset((void *)dssd_descr_str, 0, 40);
+ for (j = 0; j < WDC_OCP_C4_NUM_PS_DESCR; j++) {
+ sprintf((char *)dssd_descr_str, "DSSD Power State %d Descriptor", j);
+ json_object_add_value_int(root, dssd_descr_str, log_data->dssd_ps_descr[j]);
+ }
+
+ json_object_add_value_int(root, "Log Page Version", le16_to_cpu(log_data->log_page_version));
+ char guid[40];
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void wdc_print_unsupported_reqs_log_normal(struct wdc_ocp_C5_unsupported_reqs *log_data)
+{
+ int j;
+
+ printf("Unsupported Requirements/C5 Log Page Data\n");
+
+ printf(" Number Unsupported Req IDs : 0x%x\n",
+ le16_to_cpu(log_data->unsupported_count));
+
+ for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++)
+ printf(" Unsupported Requirement List %d : %s\n", j,
+ log_data->unsupported_req_list[j]);
+
+ printf(" Log Page Version : 0x%x\n", le16_to_cpu(log_data->log_page_version));
+ printf(" Log page GUID : 0x");
+ for (j = 0; j < WDC_OCP_C5_GUID_LENGTH; j++)
+ printf("%x", log_data->log_page_guid[j]);
+ printf("\n");
+}
+
+static void wdc_print_unsupported_reqs_log_json(struct wdc_ocp_C5_unsupported_reqs *log_data)
+{
+ int j;
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Number Unsupported Req IDs", le16_to_cpu(log_data->unsupported_count));
+
+ char unsup_req_list_str[40];
+
+ memset((void *)unsup_req_list_str, 0, 40);
+ for (j = 0; j < le16_to_cpu(log_data->unsupported_count); j++) {
+ sprintf((char *)unsup_req_list_str, "Unsupported Requirement List %d", j);
+ json_object_add_value_string(root, unsup_req_list_str, (char *)log_data->unsupported_req_list[j]);
+ }
+
+ json_object_add_value_int(root, "Log Page Version",
+ le16_to_cpu(log_data->log_page_version));
+ char guid[40];
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data->log_page_guid[0]));
+ json_object_add_value_string(root, "Log page GUID", guid);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void wdc_print_fb_ca_log_normal(struct wdc_ssd_ca_perf_stats *perf)
+{
+ uint64_t converted = 0;
+
+ printf(" CA Log Page Performance Statistics :-\n");
+ printf(" NAND Bytes Written %20"PRIu64 "%20"PRIu64"\n",
+ le64_to_cpu(perf->nand_bytes_wr_hi), le64_to_cpu(perf->nand_bytes_wr_lo));
+ printf(" NAND Bytes Read %20"PRIu64 "%20"PRIu64"\n",
+ le64_to_cpu(perf->nand_bytes_rd_hi), le64_to_cpu(perf->nand_bytes_rd_lo));
+
+ converted = le64_to_cpu(perf->nand_bad_block);
+ printf(" NAND Bad Block Count (Normalized) %20"PRIu64"\n",
+ converted & 0xFFFF);
+ printf(" NAND Bad Block Count (Raw) %20"PRIu64"\n",
+ converted >> 16);
+
+ printf(" Uncorrectable Read Count %20"PRIu64"\n",
+ le64_to_cpu(perf->uncorr_read_count));
+ printf(" Soft ECC Error Count %20"PRIu64"\n",
+ le64_to_cpu(perf->ecc_error_count));
+ printf(" SSD End to End Detected Correction Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->ssd_detect_count));
+ printf(" SSD End to End Corrected Correction Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->ssd_correct_count));
+ printf(" System Data Percent Used %20"PRIu32"%%\n",
+ perf->data_percent_used);
+ printf(" User Data Erase Counts Max %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->data_erase_max));
+ printf(" User Data Erase Counts Min %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->data_erase_min));
+ printf(" Refresh Count %20"PRIu64"\n",
+ le64_to_cpu(perf->refresh_count));
+
+ converted = le64_to_cpu(perf->program_fail);
+ printf(" Program Fail Count (Normalized) %20"PRIu64"\n",
+ converted & 0xFFFF);
+ printf(" Program Fail Count (Raw) %20"PRIu64"\n",
+ converted >> 16);
+
+ converted = le64_to_cpu(perf->user_erase_fail);
+ printf(" User Data Erase Fail Count (Normalized) %20"PRIu64"\n",
+ converted & 0xFFFF);
+ printf(" User Data Erase Fail Count (Raw) %20"PRIu64"\n",
+ converted >> 16);
+
+ converted = le64_to_cpu(perf->system_erase_fail);
+ printf(" System Area Erase Fail Count (Normalized) %20"PRIu64"\n",
+ converted & 0xFFFF);
+ printf(" System Area Erase Fail Count (Raw) %20"PRIu64"\n",
+ converted >> 16);
+
+ printf(" Thermal Throttling Status %20"PRIu8"\n",
+ perf->thermal_throttle_status);
+ printf(" Thermal Throttling Count %20"PRIu8"\n",
+ perf->thermal_throttle_count);
+ printf(" PCIe Correctable Error Count %20"PRIu64"\n",
+ le64_to_cpu(perf->pcie_corr_error));
+ printf(" Incomplete Shutdown Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->incomplete_shutdown_count));
+ printf(" Percent Free Blocks %20"PRIu32"%%\n",
+ perf->percent_free_blocks);
+}
+
+static void wdc_print_fb_ca_log_json(struct wdc_ssd_ca_perf_stats *perf)
+{
+ struct json_object *root = json_create_object();
+ uint64_t converted = 0;
+
+ json_object_add_value_int(root, "NAND Bytes Written Hi", le64_to_cpu(perf->nand_bytes_wr_hi));
+ json_object_add_value_int(root, "NAND Bytes Written Lo", le64_to_cpu(perf->nand_bytes_wr_lo));
+ json_object_add_value_int(root, "NAND Bytes Read Hi", le64_to_cpu(perf->nand_bytes_rd_hi));
+ json_object_add_value_int(root, "NAND Bytes Read Lo", le64_to_cpu(perf->nand_bytes_rd_lo));
+
+ converted = le64_to_cpu(perf->nand_bad_block);
+ json_object_add_value_int(root, "NAND Bad Block Count (Normalized)",
+ converted & 0xFFFF);
+ json_object_add_value_int(root, "NAND Bad Block Count (Raw)",
+ converted >> 16);
+
+ json_object_add_value_int(root, "Uncorrectable Read Count", le64_to_cpu(perf->uncorr_read_count));
+ json_object_add_value_int(root, "Soft ECC Error Count", le64_to_cpu(perf->ecc_error_count));
+ json_object_add_value_int(root, "SSD End to End Detected Correction Count",
+ le32_to_cpu(perf->ssd_detect_count));
+ json_object_add_value_int(root, "SSD End to End Corrected Correction Count",
+ le32_to_cpu(perf->ssd_correct_count));
+ json_object_add_value_int(root, "System Data Percent Used",
+ perf->data_percent_used);
+ json_object_add_value_int(root, "User Data Erase Counts Max",
+ le32_to_cpu(perf->data_erase_max));
+ json_object_add_value_int(root, "User Data Erase Counts Min",
+ le32_to_cpu(perf->data_erase_min));
+ json_object_add_value_int(root, "Refresh Count", le64_to_cpu(perf->refresh_count));
+
+ converted = le64_to_cpu(perf->program_fail);
+ json_object_add_value_int(root, "Program Fail Count (Normalized)",
+ converted & 0xFFFF);
+ json_object_add_value_int(root, "Program Fail Count (Raw)",
+ converted >> 16);
+
+ converted = le64_to_cpu(perf->user_erase_fail);
+ json_object_add_value_int(root, "User Data Erase Fail Count (Normalized)",
+ converted & 0xFFFF);
+ json_object_add_value_int(root, "User Data Erase Fail Count (Raw)",
+ converted >> 16);
+
+ converted = le64_to_cpu(perf->system_erase_fail);
+ json_object_add_value_int(root, "System Area Erase Fail Count (Normalized)",
+ converted & 0xFFFF);
+ json_object_add_value_int(root, "System Area Erase Fail Count (Raw)",
+ converted >> 16);
+
+ json_object_add_value_int(root, "Thermal Throttling Status",
+ perf->thermal_throttle_status);
+ json_object_add_value_int(root, "Thermal Throttling Count",
+ perf->thermal_throttle_count);
+ json_object_add_value_int(root, "PCIe Correctable Error", le64_to_cpu(perf->pcie_corr_error));
+ json_object_add_value_int(root, "Incomplete Shutdown Counte", le32_to_cpu(perf->incomplete_shutdown_count));
+ json_object_add_value_int(root, "Percent Free Blocks", perf->percent_free_blocks);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void wdc_print_bd_ca_log_normal(struct nvme_dev *dev, void *data)
+{
+ struct wdc_bd_ca_log_format *bd_data = (struct wdc_bd_ca_log_format *)data;
+ __u64 *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[0];
+ printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", dev->name,
+ 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[0];
+ 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_raw1 = (__u16 *)&bd_data->raw_value[1];
+ word_raw2 = (__u16 *)&bd_data->raw_value[3];
+ word_raw3 = (__u16 *)&bd_data->raw_value[5];
+ 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[0];
+ 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[0];
+ 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[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[0];
+ 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[0];
+ 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[1];
+ dword_raw = (__u32 *)&bd_data->raw_value[2];
+ 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[0];
+ 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[0];
+ 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[0];
+ printf("nand_bytes_written : %3"PRIu8"%% sectors: %.f\n",
+ bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0C) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ printf("host_bytes_written : %3"PRIu8"%% sectors: %.f\n",
+ bd_data->normalized_value, safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ } else {
+ goto invalid_id;
+ }
+
+ goto done;
+
+invalid_id:
+ printf(" Invalid Field ID = %d\n", bd_data->field_id);
+
+done:
+ return;
+
+}
+
+static void wdc_print_bd_ca_log_json(void *data)
+{
+ struct wdc_bd_ca_log_format *bd_data = (struct wdc_bd_ca_log_format *)data;
+ __u64 *raw;
+ __u16 *word_raw;
+ __u32 *dword_raw;
+ __u8 *byte_raw;
+ struct json_object *root = json_create_object();
+
+ if (bd_data->field_id == 0x00) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "program_fail_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "program_fail_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x01) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "erase_fail_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "erase_fail_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x02) {
+ word_raw = (__u16 *)&bd_data->raw_value[1];
+ json_object_add_value_int(root, "wear_leveling normalized", bd_data->normalized_value);
+ json_object_add_value_int(root, "wear_leveling min", le16_to_cpu(*word_raw));
+ word_raw = (__u16 *)&bd_data->raw_value[3];
+ json_object_add_value_int(root, "wear_leveling max", le16_to_cpu(*word_raw));
+ word_raw = (__u16 *)&bd_data->raw_value[5];
+ json_object_add_value_int(root, "wear_leveling avg", le16_to_cpu(*word_raw));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x03) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "end_to_end_error_detection_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "end_to_end_error_detection_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x04) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "crc_error_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "crc_error_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x05) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "timed_workload_media_wear normalized",
+ bd_data->normalized_value);
+ json_object_add_value_double(root, "timed_workload_media_wear raw",
+ 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[0];
+ json_object_add_value_int(root, "timed_workload_host_reads normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "timed_workload_host_reads raw",
+ le64_to_cpu(*raw & 0x00000000000000FF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x07) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "timed_workload_timer normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "timed_workload_timer",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x08) {
+ byte_raw = (__u8 *)&bd_data->raw_value[1];
+ json_object_add_value_int(root, "thermal_throttle_status normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "thermal_throttle_status", *byte_raw);
+ dword_raw = (__u32 *)&bd_data->raw_value[2];
+ json_object_add_value_int(root, "thermal_throttle_cnt", le32_to_cpu(*dword_raw));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x09) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "retry_buffer_overflow_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "retry_buffer_overflow_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0A) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "pll_lock_loss_count normalized",
+ bd_data->normalized_value);
+ json_object_add_value_int(root, "pll_lock_loss_count raw",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0B) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "nand_bytes_written normalized",
+ bd_data->normalized_value);
+ json_object_add_value_double(root, "nand_bytes_written raw",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0C) {
+ raw = (__u64 *)&bd_data->raw_value[0];
+ json_object_add_value_int(root, "host_bytes_written normalized",
+ bd_data->normalized_value);
+ json_object_add_value_double(root, "host_bytes_written raw",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ } else {
+ goto invalid_id;
+ }
+
+ goto done;
+
+invalid_id:
+ printf(" Invalid Field ID = %d\n", bd_data->field_id);
+
+done:
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+
+ return;
+
+}
+
+static void wdc_print_d0_log_normal(struct wdc_ssd_d0_smart_log *perf)
+{
+ printf(" D0 Smart Log Page Statistics :-\n");
+ printf(" Lifetime Reallocated Erase Block Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_realloc_erase_block_count));
+ printf(" Lifetime Power on Hours %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_power_on_hours));
+ printf(" Lifetime UECC Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_uecc_count));
+ printf(" Lifetime Write Amplification Factor %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_wrt_amp_factor));
+ printf(" Trailing Hour Write Amplification Factor %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->trailing_hr_wrt_amp_factor));
+ printf(" Reserve Erase Block Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->reserve_erase_block_count));
+ printf(" Lifetime Program Fail Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_program_fail_count));
+ printf(" Lifetime Block Erase Fail Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_block_erase_fail_count));
+ printf(" Lifetime Die Failure Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_die_failure_count));
+ printf(" Lifetime Link Rate Downgrade Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_link_rate_downgrade_count));
+ printf(" Lifetime Clean Shutdown Count on Power Loss %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_clean_shutdown_count));
+ printf(" Lifetime Unclean Shutdowns on Power Loss %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_unclean_shutdown_count));
+ printf(" Current Temperature %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->current_temp));
+ printf(" Max Recorded Temperature %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->max_recorded_temp));
+ printf(" Lifetime Retired Block Count %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_retired_block_count));
+ printf(" Lifetime Read Disturb Reallocation Events %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_read_disturb_realloc_events));
+ printf(" Lifetime NAND Writes %20"PRIu64"\n",
+ le64_to_cpu(perf->lifetime_nand_writes));
+ printf(" Capacitor Health %20"PRIu32"%%\n",
+ (uint32_t)le32_to_cpu(perf->capacitor_health));
+ printf(" Lifetime User Writes %20"PRIu64"\n",
+ le64_to_cpu(perf->lifetime_user_writes));
+ printf(" Lifetime User Reads %20"PRIu64"\n",
+ le64_to_cpu(perf->lifetime_user_reads));
+ printf(" Lifetime Thermal Throttle Activations %20"PRIu32"\n",
+ (uint32_t)le32_to_cpu(perf->lifetime_thermal_throttle_act));
+ printf(" Percentage of P/E Cycles Remaining %20"PRIu32"%%\n",
+ (uint32_t)le32_to_cpu(perf->percentage_pe_cycles_remaining));
+}
+
+static void wdc_print_d0_log_json(struct wdc_ssd_d0_smart_log *perf)
+{
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_int(root, "Lifetime Reallocated Erase Block Count",
+ le32_to_cpu(perf->lifetime_realloc_erase_block_count));
+ json_object_add_value_int(root, "Lifetime Power on Hours",
+ le32_to_cpu(perf->lifetime_power_on_hours));
+ json_object_add_value_int(root, "Lifetime UECC Count",
+ le32_to_cpu(perf->lifetime_uecc_count));
+ json_object_add_value_int(root, "Lifetime Write Amplification Factor",
+ le32_to_cpu(perf->lifetime_wrt_amp_factor));
+ json_object_add_value_int(root, "Trailing Hour Write Amplification Factor",
+ le32_to_cpu(perf->trailing_hr_wrt_amp_factor));
+ json_object_add_value_int(root, "Reserve Erase Block Count",
+ le32_to_cpu(perf->reserve_erase_block_count));
+ json_object_add_value_int(root, "Lifetime Program Fail Count",
+ le32_to_cpu(perf->lifetime_program_fail_count));
+ json_object_add_value_int(root, "Lifetime Block Erase Fail Count",
+ le32_to_cpu(perf->lifetime_block_erase_fail_count));
+ json_object_add_value_int(root, "Lifetime Die Failure Count",
+ le32_to_cpu(perf->lifetime_die_failure_count));
+ json_object_add_value_int(root, "Lifetime Link Rate Downgrade Count",
+ le32_to_cpu(perf->lifetime_link_rate_downgrade_count));
+ json_object_add_value_int(root, "Lifetime Clean Shutdown Count on Power Loss",
+ le32_to_cpu(perf->lifetime_clean_shutdown_count));
+ json_object_add_value_int(root, "Lifetime Unclean Shutdowns on Power Loss",
+ le32_to_cpu(perf->lifetime_unclean_shutdown_count));
+ json_object_add_value_int(root, "Current Temperature",
+ le32_to_cpu(perf->current_temp));
+ json_object_add_value_int(root, "Max Recorded Temperature",
+ le32_to_cpu(perf->max_recorded_temp));
+ json_object_add_value_int(root, "Lifetime Retired Block Count",
+ le32_to_cpu(perf->lifetime_retired_block_count));
+ json_object_add_value_int(root, "Lifetime Read Disturb Reallocation Events",
+ le32_to_cpu(perf->lifetime_read_disturb_realloc_events));
+ json_object_add_value_int(root, "Lifetime NAND Writes",
+ le64_to_cpu(perf->lifetime_nand_writes));
+ json_object_add_value_int(root, "Capacitor Health",
+ le32_to_cpu(perf->capacitor_health));
+ json_object_add_value_int(root, "Lifetime User Writes",
+ le64_to_cpu(perf->lifetime_user_writes));
+ json_object_add_value_int(root, "Lifetime User Reads",
+ le64_to_cpu(perf->lifetime_user_reads));
+ json_object_add_value_int(root, "Lifetime Thermal Throttle Activations",
+ le32_to_cpu(perf->lifetime_thermal_throttle_act));
+ json_object_add_value_int(root, "Percentage of P/E Cycles Remaining",
+ le32_to_cpu(perf->percentage_pe_cycles_remaining));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void wdc_get_commit_action_bin(__u8 commit_action_type, char *action_bin)
+{
+
+ switch (commit_action_type) {
+ case 0:
+ strcpy(action_bin, "000b");
+ break;
+ case 1:
+ strcpy(action_bin, "001b");
+ break;
+ case 2:
+ strcpy(action_bin, "010b");
+ break;
+ case 3:
+ strcpy(action_bin, "011b");
+ break;
+ case 4:
+ strcpy(action_bin, "100b");
+ break;
+ case 5:
+ strcpy(action_bin, "101b");
+ break;
+ case 6:
+ strcpy(action_bin, "110b");
+ break;
+ case 7:
+ strcpy(action_bin, "111b");
+ break;
+ default:
+ strcpy(action_bin, "INVALID");
+ }
+
+}
+
+static void wdc_print_fw_act_history_log_normal(__u8 *data, int num_entries,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
+{
+ int i, j;
+ char previous_fw[9];
+ char new_fw[9];
+ char commit_action_bin[8];
+ char time_str[11];
+ __u16 oldestEntryIdx = 0, entryIdx = 0;
+ char *null_fw = "--------";
+
+ 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 ||
+ vendor_id == WDC_NVME_SNDK_VID ||
+ wdc_is_sn861(device_id)) {
+ 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);
+
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
+ /* find lowest/oldest entry */
+ for (i = 0; i < num_entries; i++) {
+ j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
+ if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
+ le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
+ oldestEntryIdx = j;
+ break;
+ }
+ }
+ }
+ 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->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 if (vendor_id == WDC_NVME_SNDK_VID) {
+ printf(" ");
+ uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
+
+ memset((void *)time_str, 0, 9);
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60),
+ (int)((timestamp/1000)%60));
+ printf("%s", time_str);
+ printf(" ");
+ } else if (wdc_is_sn861(device_id)) {
+ printf(" ");
+ char timestamp[20];
+ __u64 hour;
+ __u8 min;
+ __u8 sec;
+ __u64 timestamp_sec;
+
+ timestamp_sec =
+ le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
+ / 1000;
+ hour = timestamp_sec / 3600;
+ min = (timestamp_sec % 3600) / 60;
+ sec = timestamp_sec % 60;
+
+ sprintf(timestamp,
+ "%"PRIu64":%02"PRIu8":%02"PRIu8,
+ (uint64_t)hour, min, sec);
+ printf("%-11s", timestamp);
+ printf(" ");
+ } else {
+ printf(" ");
+ uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
+
+ printf("%16"PRIu64"", timestamp);
+ printf(" ");
+ }
+
+ 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))
+ 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));
+
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ 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++) {
+ 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))
+ 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(__u8 *data, int num_entries,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
+{
+ struct json_object *root = json_create_object();
+ int i, j;
+ char previous_fw[9];
+ char new_fw[9];
+ char commit_action_bin[8];
+ char fail_str[32];
+ char time_str[11];
+ char ext_time_str[20];
+
+ memset((void *)previous_fw, 0, 9);
+ memset((void *)new_fw, 0, 9);
+ memset((void *)commit_action_bin, 0, 8);
+ memset((void *)time_str, 0, 11);
+ memset((void *)ext_time_str, 0, 20);
+ memset((void *)fail_str, 0, 11);
+ char *null_fw = "--------";
+ __u16 oldestEntryIdx = 0, entryIdx = 0;
+
+ 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);
+
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ if (num_entries == WDC_MAX_NUM_ACT_HIST_ENTRIES) {
+ /* find lowest/oldest entry */
+ for (i = 0; i < num_entries; i++) {
+ j = (i+1 == WDC_MAX_NUM_ACT_HIST_ENTRIES) ? 0 : i+1;
+ if (le16_to_cpu(fw_act_history_entry->entry[i].fw_act_hist_entries) >
+ le16_to_cpu(fw_act_history_entry->entry[j].fw_act_hist_entries)) {
+ oldestEntryIdx = j;
+ 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->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 if (vendor_id == WDC_NVME_SNDK_VID) {
+ uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
+
+ sprintf((char *)time_str, "%04d:%02d:%02d", (int)((timestamp/(3600*1000))%24), (int)((timestamp/(1000*60))%60),
+ (int)((timestamp/1000)%60));
+ json_object_add_value_string(root, "Power on Hour", time_str);
+ } else if (wdc_is_sn861(device_id)) {
+ __u64 timestamp_sec =
+ le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp)
+ / 1000;
+
+ sprintf((char *)ext_time_str,
+ "%"PRIu64":%02"PRIu8":%02"PRIu8,
+ (uint64_t)(__u64)(timestamp_sec/3600),
+ (__u8)((timestamp_sec%3600)/60),
+ (__u8)(timestamp_sec%60));
+ json_object_add_value_string(root, "Power on Hour", ext_time_str);
+ } else {
+ uint64_t timestamp = (0x0000FFFFFFFFFFFF & le64_to_cpu(fw_act_history_entry->entry[entryIdx].timestamp));
+
+ json_object_add_value_uint64(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)) {
+ 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);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ 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));
+
+ oldestEntryIdx = WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ 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)) {
+ 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);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ entryIdx++;
+ if (entryIdx >= WDC_MAX_NUM_ACT_HIST_ENTRIES)
+ entryIdx = 0;
+ }
+ }
+
+ json_free_object(root);
+}
+
+static int nvme_get_ext_smart_cloud_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id)
+{
+ int ret, i;
+ __u8 *log_ptr = NULL;
+
+ log_ptr = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
+ if (!log_ptr) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (!ret) {
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_C0_GUID_LENGTH; i++) {
+ if (ext_smart_guid[i] != *&log_ptr[SCAO_V1_LPG + i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C0 Log Page V1 data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < WDC_C0_GUID_LENGTH; j++)
+ fprintf(stderr, "%x", ext_smart_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < WDC_C0_GUID_LENGTH; j++)
+ fprintf(stderr, "%x", *&log_ptr[SCAO_V1_LPG + j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ *data = log_ptr;
+
+ return ret;
+}
+
+
+static int nvme_get_hw_rev_log(int fd, __u8 **data, int uuid_index, __u32 namespace_id)
+{
+ int ret, i;
+ struct wdc_nvme_hw_rev_log *log_ptr = NULL;
+
+ log_ptr = (struct wdc_nvme_hw_rev_log *)malloc(sizeof(__u8) * WDC_NVME_HW_REV_LOG_PAGE_LEN);
+ if (!log_ptr) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = fd,
+ .lid = WDC_NVME_GET_HW_REV_LOG_OPCODE,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_HW_REV_LOG_PAGE_LEN,
+ .log = log_ptr,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (!ret) {
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_NVME_C6_GUID_LENGTH; i++) {
+ if (hw_rev_log_guid[i] != log_ptr->hw_rev_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in HW Revision Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++)
+ fprintf(stderr, "%x", hw_rev_log_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < WDC_NVME_C6_GUID_LENGTH; j++)
+ fprintf(stderr, "%x", log_ptr->hw_rev_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+ *data = (__u8 *)log_ptr;
+
+ return ret;
+}
+
+
+static void wdc_print_hw_rev_log_normal(void *data)
+{
+ int i;
+ struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data;
+
+ printf(" Hardware Revision Log:-\n");
+
+ printf(" Global Device HW Revision : %d\n",
+ log_data->hw_rev_gdr);
+ printf(" ASIC HW Revision : %d\n",
+ log_data->hw_rev_ar);
+ printf(" PCB Manufacturer Code : %d\n",
+ log_data->hw_rev_pbc_mc);
+ printf(" DRAM Manufacturer Code : %d\n",
+ log_data->hw_rev_dram_mc);
+ printf(" NAND Manufacturer Code : %d\n",
+ log_data->hw_rev_nand_mc);
+ printf(" PMIC 1 Manufacturer Code : %d\n",
+ log_data->hw_rev_pmic1_mc);
+ printf(" PMIC 2 Manufacturer Code : %d\n",
+ log_data->hw_rev_pmic2_mc);
+ printf(" Other Component 1 Manf Code : %d\n",
+ log_data->hw_rev_c1_mc);
+ printf(" Other Component 2 Manf Code : %d\n",
+ log_data->hw_rev_c2_mc);
+ printf(" Other Component 3 Manf Code : %d\n",
+ log_data->hw_rev_c3_mc);
+ printf(" Other Component 4 Manf Code : %d\n",
+ log_data->hw_rev_c4_mc);
+ printf(" Other Component 5 Manf Code : %d\n",
+ log_data->hw_rev_c5_mc);
+ printf(" Other Component 6 Manf Code : %d\n",
+ log_data->hw_rev_c6_mc);
+ printf(" Other Component 7 Manf Code : %d\n",
+ log_data->hw_rev_c7_mc);
+ printf(" Other Component 8 Manf Code : %d\n",
+ log_data->hw_rev_c8_mc);
+ printf(" Other Component 9 Manf Code : %d\n",
+ log_data->hw_rev_c9_mc);
+
+ printf(" Device Manf Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_dev_mdi[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" ASIC Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_asic_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PCB Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pcb_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" DRAM Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_dram_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" NAND Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_nand_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PMIC 1 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pmic1_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" PMIC 2 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_pmic2_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 1 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c1_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 2 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c2_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 3 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c3_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 4 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c4_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 5 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c5_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 6 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c6_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 7 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c7_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 8 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c8_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Component 9 Detailed Info : 0x");
+ for (i = 0; i < 16; i++) {
+ printf("%02x", log_data->hw_rev_c9_di[i]);
+ if (i == 7)
+ printf(" 0x");
+ }
+ printf("\n");
+ printf(" Serial Number : 0x");
+ for (i = 0; i < 32; i++) {
+ if ((i > 1) & !(i % 8))
+ printf(" 0x");
+ printf("%02x", log_data->hw_rev_sn[i]);
+ }
+ printf("\n");
+
+ printf(" Log Page Version : %d\n", log_data->hw_rev_version);
+ printf(" Log page GUID : 0x");
+ printf("%"PRIx64"%"PRIx64"\n", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0]));
+ printf("\n");
+}
+
+static void wdc_print_hw_rev_log_json(void *data)
+{
+ struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data;
+ struct json_object *root = json_create_object();
+ char json_data[80];
+
+ json_object_add_value_uint(root, "Global Device HW Revision",
+ log_data->hw_rev_gdr);
+ json_object_add_value_uint(root, "ASIC HW Revision",
+ log_data->hw_rev_ar);
+ json_object_add_value_uint(root, "PCB Manufacturer Code",
+ log_data->hw_rev_pbc_mc);
+ json_object_add_value_uint(root, "DRAM Manufacturer Code",
+ log_data->hw_rev_dram_mc);
+ json_object_add_value_uint(root, "NAND Manufacturer Code",
+ log_data->hw_rev_nand_mc);
+ json_object_add_value_uint(root, "PMIC 1 Manufacturer Code",
+ log_data->hw_rev_pmic1_mc);
+ json_object_add_value_uint(root, "PMIC 2 Manufacturer Code",
+ log_data->hw_rev_pmic2_mc);
+ json_object_add_value_uint(root, "Other Component 1 Manf Code",
+ log_data->hw_rev_c1_mc);
+ json_object_add_value_uint(root, "Other Component 2 Manf Code",
+ log_data->hw_rev_c2_mc);
+ json_object_add_value_uint(root, "Other Component 3 Manf Code",
+ log_data->hw_rev_c3_mc);
+ json_object_add_value_uint(root, "Other Component 4 Manf Code",
+ log_data->hw_rev_c4_mc);
+ json_object_add_value_uint(root, "Other Component 5 Manf Code",
+ log_data->hw_rev_c5_mc);
+ json_object_add_value_uint(root, "Other Component 6 Manf Code",
+ log_data->hw_rev_c6_mc);
+ json_object_add_value_uint(root, "Other Component 7 Manf Code",
+ log_data->hw_rev_c7_mc);
+ json_object_add_value_uint(root, "Other Component 8 Manf Code",
+ log_data->hw_rev_c8_mc);
+ json_object_add_value_uint(root, "Other Component 9 Manf Code",
+ log_data->hw_rev_c9_mc);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dev_mdi[0]));
+ json_object_add_value_string(root, "Device Manf Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_asic_di[0]));
+ json_object_add_value_string(root, "ASIC Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pcb_di[0]));
+ json_object_add_value_string(root, "PCB Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_dram_di[0]));
+ json_object_add_value_string(root, "DRAM Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_nand_di[0]));
+ json_object_add_value_string(root, "NAND Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic1_di[0]));
+ json_object_add_value_string(root, "PMIC 1 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_pmic2_di[0]));
+ json_object_add_value_string(root, "PMIC 2 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c1_di[0]));
+ json_object_add_value_string(root, "Component 1 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c2_di[0]));
+ json_object_add_value_string(root, "Component 2 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c3_di[0]));
+ json_object_add_value_string(root, "Component 3 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c4_di[0]));
+ json_object_add_value_string(root, "Component 4 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c5_di[0]));
+ json_object_add_value_string(root, "Component 5 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c6_di[0]));
+ json_object_add_value_string(root, "Component 6 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c7_di[0]));
+ json_object_add_value_string(root, "Component 7 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c8_di[0]));
+ json_object_add_value_string(root, "Component 8 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_c9_di[0]));
+ json_object_add_value_string(root, "Component 9 Detailed Info", json_data);
+
+ memset((void *)json_data, 0, 80);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"%"PRIx64"%"PRIx64"",
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[0]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[16]), le64_to_cpu(*(uint64_t *)&log_data->hw_rev_sn[24]));
+ json_object_add_value_string(root, "Serial Number", json_data);
+
+ json_object_add_value_uint(root, "Log Page Version",
+ le16_to_cpu(log_data->hw_rev_version));
+
+ memset((void *)json_data, 0, 40);
+ sprintf((char *)json_data, "0x%"PRIx64"%"PRIx64"", le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[8]),
+ le64_to_cpu(*(uint64_t *)&log_data->hw_rev_guid[0]));
+ json_object_add_value_string(root, "Log Page GUID", json_data);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void wdc_print_ext_smart_cloud_log_normal(void *data, int mask)
+{
+ int i;
+ struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data;
+
+ if (mask == WDC_SCA_V1_NAND_STATS)
+ printf(" NAND Statistics :-\n");
+ else
+ printf(" SMART Cloud Attributes :-\n");
+
+ printf(" Physical Media Units Written TLC (Bytes): %s\n",
+ uint128_t_to_string(le128_to_cpu(
+ ext_smart_log_ptr->ext_smart_pmuwt)));
+ printf(" Physical Media Units Written SLC (Bytes): %s\n",
+ uint128_t_to_string(le128_to_cpu(
+ ext_smart_log_ptr->ext_smart_pmuws)));
+ printf(" Bad User NAND Block Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc));
+ printf(" Bad User NAND Block Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000));
+ printf(" XOR Recovery Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc));
+ printf(" Uncorrectable Read Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_urec));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" SSD End to End correction counts (Corrected Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eece));
+ printf(" SSD End to End correction counts (Detected Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eede));
+ printf(" SSD End to End correction counts (Uncorrected E2E Errors) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue));
+ printf(" System Data %% life-used : %d %%\n",
+ ext_smart_log_ptr->ext_smart_sdpu);
+ }
+ printf(" User data erase counts (Minimum TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec));
+ printf(" User data erase counts (Maximum TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec));
+ printf(" User data erase counts (Minimum SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec));
+ printf(" User data erase counts (Maximum SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec));
+ printf(" User data erase counts (Average SLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avec));
+ printf(" User data erase counts (Average TLC) (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec));
+ printf(" Program Fail Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc));
+ printf(" Program Fail Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000));
+ printf(" Erase Fail Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc));
+ printf(" Erase Fail Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" PCIe Correctable Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec));
+ printf(" %% Free Blocks (User) (Int) : %d %%\n",
+ ext_smart_log_ptr->ext_smart_pfbu);
+ printf(" Security Version Number (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_svn));
+ printf(" %% Free Blocks (System) (Int) : %d %%\n",
+ ext_smart_log_ptr->ext_smart_pfbs);
+ printf(" NVMe Stats (# Data Set Management/TRIM Commands Completed) (Int): %s\n",
+ uint128_t_to_string(le128_to_cpu(
+ ext_smart_log_ptr->ext_smart_dcc)));
+ printf(" Total Namespace Utilization (nvme0n1 NUSE) (Bytes) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu));
+ printf(" NVMe Stats (# NVMe Format Commands Completed) (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc));
+ printf(" Background Back-Pressure Gauge(%%) (Int) : %d\n",
+ ext_smart_log_ptr->ext_smart_bbpg);
+ }
+ printf(" Total # of Soft ECC Error Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_seec));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Total # of Read Refresh Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc));
+ }
+ printf(" Bad System NAND Block Count (Normalized) (Int) : %d\n",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc));
+ printf(" Bad System NAND Block Count (Raw) (Int) : %"PRIu64"\n",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000));
+ printf(" Endurance Estimate (Total Writable Lifetime Bytes) (Bytes) : %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_eest)));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Thermal Throttling Status & Count (Number of thermal throttling events) (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc));
+ printf(" Total # Unaligned I/O (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_uio));
+ }
+ printf(" Total Physical Media Units Read (Bytes) (Int) : %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_pmur)));
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" Command Timeout (# of READ Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc));
+ printf(" Command Timeout (# of WRITE Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc));
+ printf(" Command Timeout (# of TRIM Commands > 5 Seconds) (Int) : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc));
+ printf(" Total PCIe Link Retraining Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc));
+ printf(" Active Power State Change Count (Int) : %"PRIu64"\n",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc));
+ }
+ printf(" Cloud Boot SSD Spec Version (Int) : %d.%d.%d.%d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_maj),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_min),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_pt),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_err));
+ printf(" Cloud Boot SSD HW Revision (Int) : %d.%d.%d.%d\n",
+ 0, 0, 0, 0);
+ if (mask == WDC_SCA_V1_ALL) {
+ printf(" FTL Unit Size : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus));
+ printf(" TCG Ownership Status : %"PRIu32"\n",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos));
+ printf(" Log Page Version (Int) : %d\n",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv));
+ printf(" Log page GUID (Hex) : 0x");
+ for (i = WDC_C0_GUID_LENGTH; i > 0; i--)
+ printf("%02x", ext_smart_log_ptr->ext_smart_lpg[i-1]);
+ printf("\n");
+ }
+ printf("\n");
+}
+
+static void wdc_print_ext_smart_cloud_log_json(void *data, int mask)
+{
+ struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr =
+ (struct __packed wdc_nvme_ext_smart_log *)data;
+ struct json_object *root = json_create_object();
+
+ json_object_add_value_uint128(root, "physical_media_units_bytes_tlc",
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_pmuwt));
+ json_object_add_value_uint128(root, "physical_media_units_bytes_slc",
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_pmuws));
+ json_object_add_value_uint(root, "bad_user_blocks_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bunbc));
+ json_object_add_value_uint64(root, "bad_user_blocks_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bunbc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_uint64(root, "xor_recovery_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_xrc));
+ json_object_add_value_uint64(root, "uncorrectable_read_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_urec));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint64(root, "corrected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eece));
+ json_object_add_value_uint64(root, "detected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eede));
+ json_object_add_value_uint64(root, "uncorrected_e2e_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_eeue));
+ json_object_add_value_uint(root, "system_data_life_used_pct",
+ (__u8)ext_smart_log_ptr->ext_smart_sdpu);
+ }
+ json_object_add_value_uint64(root, "min_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnec));
+ json_object_add_value_uint64(root, "min_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mnudec));
+ json_object_add_value_uint64(root, "max_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxec));
+ json_object_add_value_uint64(root, "max_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_mxudec));
+ json_object_add_value_uint64(root, "avg_slc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avec));
+ json_object_add_value_uint64(root, "avg_tlc_user_data_erase_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_avudec));
+ json_object_add_value_uint(root, "program_fail_count_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_pfc));
+ json_object_add_value_uint64(root, "program_fail_count_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_pfc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_uint(root, "erase_fail_count_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_efc));
+ json_object_add_value_uint64(root, "erase_fail_count_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_efc & 0xFFFFFFFFFFFF0000));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint64(root, "pcie_correctable_errors",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pcec));
+ json_object_add_value_uint(root, "pct_free_blocks_user",
+ (__u8)ext_smart_log_ptr->ext_smart_pfbu);
+ json_object_add_value_uint64(root, "security_version",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_svn));
+ json_object_add_value_uint(root, "pct_free_blocks_system",
+ (__u8)ext_smart_log_ptr->ext_smart_pfbs);
+ json_object_add_value_uint128(root, "num_of_trim_commands",
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_dcc));
+ json_object_add_value_uint64(root, "total_nuse_bytes",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_tnu));
+ json_object_add_value_uint(root, "num_of_format_commands",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_fcc));
+ json_object_add_value_uint(root, "background_pressure_gauge",
+ (__u8)ext_smart_log_ptr->ext_smart_bbpg);
+ }
+ json_object_add_value_uint64(root, "soft_ecc_error_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_seec));
+ if (mask == WDC_SCA_V1_ALL)
+ json_object_add_value_uint64(root, "read_refresh_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_rfsc));
+ json_object_add_value_uint(root, "bad_system_block_normalized",
+ le16_to_cpu(*(uint16_t *)ext_smart_log_ptr->ext_smart_bsnbc));
+ json_object_add_value_uint64(root, "bad_system_block_raw",
+ le64_to_cpu(*(uint64_t *)ext_smart_log_ptr->ext_smart_bsnbc & 0xFFFFFFFFFFFF0000));
+ json_object_add_value_uint128(root, "endurance_est_bytes",
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_eest));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "num_throttling_events",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_ttc));
+ json_object_add_value_uint64(root, "total_unaligned_io",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_uio));
+ }
+ json_object_add_value_uint128(root, "physical_media_units_read_bytes",
+ le128_to_cpu(ext_smart_log_ptr->ext_smart_pmur));
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "num_read_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_rtoc));
+ json_object_add_value_uint(root, "num_write_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_wtoc));
+ json_object_add_value_uint(root, "num_trim_timeouts",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ttoc));
+ json_object_add_value_uint64(root, "pcie_link_retrain_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_plrc));
+ json_object_add_value_uint64(root, "active_power_state_change_count",
+ le64_to_cpu(ext_smart_log_ptr->ext_smart_pscc));
+ }
+ char vers_str[40];
+
+ memset((void *)vers_str, 0, 40);
+ sprintf((char *)vers_str, "%d.%d.%d.%d",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_maj),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_min),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_pt),
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_err));
+ json_object_add_value_string(root, "cloud_boot_ssd_spec_ver", vers_str);
+ memset((void *)vers_str, 0, 40);
+ sprintf((char *)vers_str, "%d.%d.%d.%d", 0, 0, 0, 0);
+ json_object_add_value_string(root, "cloud_boot_ssd_hw_ver", vers_str);
+
+ if (mask == WDC_SCA_V1_ALL) {
+ json_object_add_value_uint(root, "ftl_unit_size",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus));
+ json_object_add_value_uint(root, "tcg_ownership_status",
+ le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos));
+ json_object_add_value_uint(root, "log_page_ver",
+ le16_to_cpu(ext_smart_log_ptr->ext_smart_lpv));
+ char guid[40];
+
+ memset((void *)guid, 0, 40);
+ sprintf((char *)guid, "0x%"PRIx64"%"PRIx64"",
+ le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[8]),
+ le64_to_cpu(*(uint64_t *)&ext_smart_log_ptr->ext_smart_lpg[0]));
+ json_object_add_value_string(root, "log_page_guid", guid);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+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 : %s\n",
+ uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PMUW])));
+ printf(" Physical media units read : %s\n",
+ uint128_t_to_string(le128_to_cpu(&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 : %s\n",
+ uint128_t_to_string(le128_to_cpu(&log_data[SCAO_PSC])));
+ printf(" Endurance estimate : %s\n",
+ uint128_t_to_string(le128_to_cpu(&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("%"PRIx64"%"PRIx64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
+ if (smart_log_ver > 2) {
+ printf(" Errata Version Field : %d\n",
+ (__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]));
+ }
+ if (smart_log_ver > 3) {
+ printf(" Power State Change Count : %"PRIu64"\n",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
+ printf("\n");
+}
+
+static void wdc_print_smart_cloud_attr_C0_json(void *data)
+{
+ __u8 *log_data = (__u8 *)data;
+ struct json_object *root = json_create_object();
+ uint16_t smart_log_ver = 0;
+
+ json_object_add_value_uint128(root, "Physical media units written",
+ le128_to_cpu(&log_data[SCAO_PMUW]));
+ json_object_add_value_uint128(root, "Physical media units read",
+ le128_to_cpu(&log_data[SCAO_PMUR]));
+ json_object_add_value_uint64(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_uint64(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_uint64(root, "XOR recovery count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_XRC]));
+ json_object_add_value_uint64(root, "Uncorrectable read error count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UREC]));
+ json_object_add_value_uint64(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_uint64(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_uint64(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_uint64(root, "Unaligned I/O",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_UIO]));
+ json_object_add_value_uint64(root, "Security Version Number",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_SVN]));
+ json_object_add_value_uint64(root, "NUSE - Namespace utilization",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_NUSE]));
+ json_object_add_value_uint128(root, "PLP start count",
+ le128_to_cpu(&log_data[SCAO_PSC]));
+ json_object_add_value_uint128(root, "Endurance estimate",
+ le128_to_cpu(&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%"PRIx64"%"PRIx64"",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG + 8]),
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_LPG]));
+ 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_uint64(root, "PCIe Link Retraining Count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PLRC]));
+ }
+ if (smart_log_ver > 3) {
+ json_object_add_value_uint64(root, "Power State Change Count",
+ (uint64_t)le64_to_cpu(*(uint64_t *)&log_data[SCAO_PSCC]));
+ }
+ 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 = 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_ext_smart_cloud_log(void *data, int fmt)
+{
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read 0xC0 V1 log\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_ALL);
+ break;
+ case JSON:
+ wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_ALL);
+ break;
+ }
+ return 0;
+}
+
+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_sn_customer_id_0x100X(struct nvme_dev *dev, int uuid_index,
+ char *format, __u32 namespace_id, int fmt)
+{
+ int ret;
+ __u8 *data;
+ int i;
+
+ if (!uuid_index) {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (namespace_id == NVME_NSID_ALL) {
+ ret = nvme_get_nsid(dev_fd(dev), &namespace_id);
+ if (ret < 0)
+ namespace_id = NVME_NSID_ALL;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* 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)
+ /* 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) {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
+ .nsid = NVME_NSID_ALL,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_EOL_STATUS_LOG_LEN,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* 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;
+ }
+
+ return ret;
+}
+
+static int wdc_get_c0_log_page_sn(nvme_root_t r, struct nvme_dev *dev, int uuid_index, char *format,
+ __u32 namespace_id, int fmt)
+{
+ int ret = 0;
+ __u32 cust_id;
+ __u8 *data;
+
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
+ return -1;
+ }
+
+ if ((cust_id == WDC_CUSTOMER_ID_0x1004) || (cust_id == WDC_CUSTOMER_ID_0x1008) ||
+ (cust_id == WDC_CUSTOMER_ID_0x1005)) {
+ ret = wdc_get_c0_log_page_sn_customer_id_0x100X(dev, uuid_index, format,
+ namespace_id, fmt);
+ } else {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_EOL_STATUS_LOG_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_EOL_STATUS_LOG_OPCODE,
+ WDC_NVME_EOL_STATUS_LOG_LEN,
+ data);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* 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);
+ }
+
+ return ret;
+}
+
+static int wdc_get_c0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format, int uuid_index,
+ __u32 namespace_id)
+{
+ uint32_t device_id, read_vendor_id;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ __u8 log_id;
+ __u32 length;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+
+ switch (device_id) {
+ case WDC_NVME_SN640_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN840_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN840_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN860_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN560_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN550_DEV_ID:
+ ret = wdc_get_c0_log_page_sn(r, dev, uuid_index, format, namespace_id, fmt);
+ break;
+
+ case WDC_NVME_SN650_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN650_DEV_ID_4:
+ fallthrough;
+ case WDC_NVME_SN655_DEV_ID:
+ if (uuid_index == 0) {
+ log_id = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID;
+ length = WDC_NVME_SMART_CLOUD_ATTR_LEN;
+ } else {
+ log_id = WDC_NVME_GET_EOL_STATUS_LOG_OPCODE;
+ length = WDC_NVME_EOL_STATUS_LOG_LEN;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * length);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (namespace_id == NVME_NSID_ALL) {
+ ret = nvme_get_nsid(dev_fd(dev), &namespace_id);
+ if (ret < 0)
+ namespace_id = NVME_NSID_ALL;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = log_id,
+ .nsid = namespace_id,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = length,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ if (uuid_index == 0)
+ wdc_print_c0_cloud_attr_log(data, fmt);
+ else
+ wdc_print_c0_eol_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page data ");
+ fprintf(stderr, "with uuid index %d\n", uuid_index);
+ ret = -1;
+ }
+ free(data);
+ break;
+
+ case WDC_NVME_ZN350_DEV_ID:
+ fallthrough;
+ case WDC_NVME_ZN350_DEV_ID_1:
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ /* Get the 0xC0 log data */
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ WDC_NVME_SMART_CLOUD_ATTR_LEN, data);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* 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;
+ case WDC_NVME_SN820CL_DEV_ID:
+ /* Get the 0xC0 Extended Smart Cloud Attribute log data */
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data,
+ uuid_index, namespace_id);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ wdc_print_ext_smart_cloud_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page V1 data\n");
+ ret = -1;
+ }
+
+ if (data)
+ 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_latency_monitor_log(struct nvme_dev *dev,
+ struct wdc_ssd_latency_monitor_log *log_data,
+ int fmt)
+{
+ if (!log_data) {
+ fprintf(stderr, "ERROR: WDC: Invalid C3 log data buffer\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_latency_monitor_log_normal(dev, log_data);
+ break;
+ case JSON:
+ wdc_print_latency_monitor_log_json(log_data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_error_rec_log(struct wdc_ocp_c1_error_recovery_log *log_data, int fmt)
+{
+ if (!log_data) {
+ fprintf(stderr, "ERROR: WDC: Invalid C1 log data buffer\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_error_rec_log_normal(log_data);
+ break;
+ case JSON:
+ wdc_print_error_rec_log_json(log_data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_dev_cap_log(struct wdc_ocp_C4_dev_cap_log *log_data, int fmt)
+{
+ if (!log_data) {
+ fprintf(stderr, "ERROR: WDC: Invalid C4 log data buffer\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_dev_cap_log_normal(log_data);
+ break;
+ case JSON:
+ wdc_print_dev_cap_log_json(log_data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_unsupported_reqs_log(struct wdc_ocp_C5_unsupported_reqs *log_data, int fmt)
+{
+ if (!log_data) {
+ fprintf(stderr, "ERROR: WDC: Invalid C5 log data buffer\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_unsupported_reqs_log_normal(log_data);
+ break;
+ case JSON:
+ wdc_print_unsupported_reqs_log_json(log_data);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_fb_ca_log(struct wdc_ssd_ca_perf_stats *perf, int fmt)
+{
+ if (!perf) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_fb_ca_log_normal(perf);
+ break;
+ case JSON:
+ wdc_print_fb_ca_log_json(perf);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_bd_ca_log(struct nvme_dev *dev, void *bd_data, int fmt)
+{
+ if (!bd_data) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read data\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_bd_ca_log_normal(dev, bd_data);
+ break;
+ case JSON:
+ wdc_print_bd_ca_log_json(bd_data);
+ break;
+ default:
+ fprintf(stderr, "ERROR: WDC: Unknown format - %d\n", fmt);
+ return -1;
+ }
+ return 0;
+}
+
+static int wdc_print_d0_log(struct wdc_ssd_d0_smart_log *perf, int fmt)
+{
+ if (!perf) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read perf stats\n");
+ return -1;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_d0_log_normal(perf);
+ break;
+ case JSON:
+ wdc_print_d0_log_json(perf);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_print_fw_act_history_log(__u8 *data, int num_entries, int fmt,
+ __u32 cust_id, __u32 vendor_id,
+ __u32 device_id)
+{
+ 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(data, num_entries, cust_id,
+ vendor_id, device_id);
+ break;
+ case JSON:
+ wdc_print_fw_act_history_log_json(data, num_entries, cust_id,
+ vendor_id, device_id);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_get_ca_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ uint32_t read_device_id, read_vendor_id;
+ struct wdc_ssd_ca_perf_stats *perf;
+ enum nvme_print_flags fmt;
+ __u32 cust_id;
+ __u8 *data;
+ int ret;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == false) {
+ fprintf(stderr, "ERROR: WDC: 0xCA Log Page not supported\n");
+ return -1;
+ }
+
+ /* get the FW customer id */
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid customer id\n", __func__);
+ return -1;
+ }
+
+ ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id);
+
+ switch (read_device_id) {
+ case WDC_NVME_SN200_DEV_ID:
+ if (cust_id == WDC_CUSTOMER_ID_0x1005) {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ WDC_FB_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ perf = (struct wdc_ssd_ca_perf_stats *)(data);
+ ret = wdc_print_fb_ca_log(perf, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read CA Log Page data\n");
+ ret = -1;
+ }
+ } else {
+
+ fprintf(stderr, "ERROR: WDC: Unsupported Customer id, id = 0x%x\n", cust_id);
+ return -1;
+ }
+ break;
+ case WDC_NVME_SN640_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_2:
+ fallthrough;
+ case WDC_NVME_SN640_DEV_ID_3:
+ fallthrough;
+ case WDC_NVME_SN840_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN840_DEV_ID_1:
+ fallthrough;
+ case WDC_NVME_SN860_DEV_ID:
+ if (cust_id == WDC_CUSTOMER_ID_0x1005) {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof(__u8) * WDC_FB_CA_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ WDC_FB_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ perf = (struct wdc_ssd_ca_perf_stats *)(data);
+ ret = wdc_print_fb_ca_log(perf, fmt);
+ } else {
+ 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) ||
+ (cust_id == WDC_CUSTOMER_ID_BD)) {
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_BD_CA_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof(__u8) * WDC_BD_CA_LOG_BUF_LEN);
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ WDC_BD_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ ret = wdc_print_bd_ca_log(dev, data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read CA Log Page data\n");
+ ret = -1;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unsupported Customer id, id = 0x%x\n", cust_id);
+ return -1;
+ }
+ break;
+ default:
+ fprintf(stderr, "ERROR: WDC: Log page 0xCA not supported for this device\n");
+ return -1;
+ }
+
+ free(data);
+ return ret;
+}
+
+static int wdc_get_c1_log_page(nvme_root_t r, struct nvme_dev *dev,
+ char *format, uint8_t interval)
+{
+ struct wdc_log_page_subpage_header *sph;
+ struct wdc_ssd_perf_stats *perf;
+ struct wdc_log_page_header *l;
+ enum nvme_print_flags fmt;
+ int total_subpages;
+ int skip_cnt = 4;
+ __u8 *data;
+ __u8 *p;
+ int i;
+ int ret;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ if (interval < 1 || interval > 15) {
+ fprintf(stderr, "ERROR: WDC: interval out of range [1-15]\n");
+ return -1;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_ADD_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_ADD_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_ADD_LOG_OPCODE,
+ WDC_ADD_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+ if (!ret) {
+ l = (struct wdc_log_page_header *)data;
+ total_subpages = l->num_subpages + WDC_NVME_GET_STAT_PERF_INTERVAL_LIFETIME - 1;
+ for (i = 0, p = data + skip_cnt; i < total_subpages; i++, p += skip_cnt) {
+ sph = (struct wdc_log_page_subpage_header *)p;
+ if (sph->spcode == WDC_GET_LOG_PAGE_SSD_PERFORMANCE) {
+ if (sph->pcset == interval) {
+ perf = (struct wdc_ssd_perf_stats *)(p + 4);
+ ret = wdc_print_log(perf, fmt);
+ break;
+ }
+ }
+ skip_cnt = le16_to_cpu(sph->subpage_length) + 4;
+ }
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Unable to read data from buffer\n");
+ }
+ free(data);
+ return ret;
+}
+
+static int wdc_get_c3_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ struct wdc_ssd_latency_monitor_log *log_data;
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int ret;
+ int i;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_LATENCY_MON_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_LATENCY_MON_LOG_ID,
+ WDC_LATENCY_MON_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+ if (!ret) {
+ log_data = (struct wdc_ssd_latency_monitor_log *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != WDC_LATENCY_MON_VERSION) {
+ fprintf(stderr, "ERROR: WDC: invalid latency monitor version\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* check log page guid */
+ /* Verify GUID matches */
+ for (i = 0; i < 16; i++) {
+ if (wdc_lat_mon_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C3 Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", wdc_lat_mon_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* parse the data */
+ wdc_print_latency_monitor_log(dev, log_data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C3 data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+
+}
+
+static int wdc_get_ocp_c1_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ struct wdc_ocp_c1_error_recovery_log *log_data;
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int ret;
+ int i;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_ERROR_REC_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_ERROR_REC_LOG_ID,
+ WDC_ERROR_REC_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+ if (!ret) {
+ log_data = (struct wdc_ocp_c1_error_recovery_log *)data;
+
+ /* check log page version */
+ if ((log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION1) &&
+ (log_data->log_page_version != WDC_ERROR_REC_LOG_VERSION2)) {
+ fprintf(stderr, "ERROR: WDC: invalid error recovery log version - %d\n", log_data->log_page_version);
+ ret = -1;
+ goto out;
+ }
+
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_OCP_C1_GUID_LENGTH; i++) {
+ if (wdc_ocp_c1_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C1 Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", wdc_ocp_c1_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* parse the data */
+ wdc_print_error_rec_log(log_data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read error recovery (C1) data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int wdc_get_ocp_c4_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ struct wdc_ocp_C4_dev_cap_log *log_data;
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int ret;
+ int i;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_DEV_CAP_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_DEV_CAP_LOG_ID,
+ WDC_DEV_CAP_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+ if (!ret) {
+ log_data = (struct wdc_ocp_C4_dev_cap_log *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != WDC_DEV_CAP_LOG_VERSION) {
+ fprintf(stderr, "ERROR: WDC: invalid device capabilities log version - %d\n", log_data->log_page_version);
+ ret = -1;
+ goto out;
+ }
+
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_OCP_C4_GUID_LENGTH; i++) {
+ if (wdc_ocp_c4_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C4 Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", wdc_ocp_c4_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* parse the data */
+ wdc_print_dev_cap_log(log_data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read device capabilities (C4) data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int wdc_get_ocp_c5_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ struct wdc_ocp_C5_unsupported_reqs *log_data;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+ int i;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_UNSUPPORTED_REQS_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_UNSUPPORTED_REQS_LOG_ID,
+ WDC_UNSUPPORTED_REQS_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret, false), ret);
+
+ if (!ret) {
+ log_data = (struct wdc_ocp_C5_unsupported_reqs *)data;
+
+ /* check log page version */
+ if (log_data->log_page_version != WDC_UNSUPPORTED_REQS_LOG_VERSION) {
+ fprintf(stderr, "ERROR: WDC: invalid unsupported requirements log version - %d\n", log_data->log_page_version);
+ ret = -1;
+ goto out;
+ }
+
+ /* Verify GUID matches */
+ for (i = 0; i < WDC_OCP_C5_GUID_LENGTH; i++) {
+ if (wdc_ocp_c5_guid[i] != log_data->log_page_guid[i]) {
+ fprintf(stderr, "ERROR: WDC: Unknown GUID in C5 Log Page data\n");
+ int j;
+
+ fprintf(stderr, "ERROR: WDC: Expected GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", wdc_ocp_c5_guid[j]);
+ fprintf(stderr, "\nERROR: WDC: Actual GUID: 0x");
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "%x", log_data->log_page_guid[j]);
+ fprintf(stderr, "\n");
+
+ ret = -1;
+ goto out;
+ }
+ }
+
+ /* parse the data */
+ wdc_print_unsupported_reqs_log(log_data, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read unsupported requirements (C5) data from buffer\n");
+ }
+
+out:
+ free(data);
+ return ret;
+}
+
+static int wdc_get_d0_log_page(nvme_root_t r, struct nvme_dev *dev, char *format)
+{
+ struct wdc_ssd_d0_smart_log *perf;
+ enum nvme_print_flags fmt;
+ int ret = 0;
+ __u8 *data;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == false) {
+ fprintf(stderr, "ERROR: WDC: 0xD0 Log Page not supported\n");
+ return -1;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_VU_SMART_LOG_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+ memset(data, 0, sizeof(__u8) * WDC_NVME_VU_SMART_LOG_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_VU_SMART_LOG_OPCODE,
+ WDC_NVME_VU_SMART_LOG_LEN, data);
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ perf = (struct wdc_ssd_d0_smart_log *)(data);
+ ret = wdc_print_d0_log(perf, fmt);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read D0 Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ return ret;
+}
+
+static long double le_to_float(__u8 *data, int byte_len)
+{
+ long double result = 0;
+ int i;
+
+ for (i = 0; i < byte_len; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+
+ return result;
+}
+
+static void stringify_log_page_guid(__u8 *guid, char *buf)
+{
+ char *ptr = buf;
+ int i;
+
+ memset(buf, 0, sizeof(char) * 19);
+
+ ptr += sprintf(ptr, "0x");
+ for (i = 0; i < 16; i++)
+ ptr += sprintf(ptr, "%x", guid[15 - i]);
+}
+
+static const char *const cloud_smart_log_thermal_status[] = {
+ [0x00] = "unthrottled",
+ [0x01] = "first_level",
+ [0x02] = "second_level",
+ [0x03] = "third_level",
+};
+
+static const char *stringify_cloud_smart_log_thermal_status(__u8 status)
+{
+ if (status < ARRAY_SIZE(cloud_smart_log_thermal_status) &&
+ cloud_smart_log_thermal_status[status])
+ return cloud_smart_log_thermal_status[status];
+ return "unrecognized";
+}
+
+static void show_cloud_smart_log_json(struct ocp_cloud_smart_log *log)
+{
+ struct json_object *root;
+ struct json_object *bad_user_nand_blocks;
+ struct json_object *bad_system_nand_blocks;
+ struct json_object *e2e_correction_counts;
+ struct json_object *user_data_erase_counts;
+ struct json_object *thermal_status;
+ struct json_object *dssd_specific_ver;
+ char buf[2 * sizeof(log->log_page_guid) + 3];
+
+ bad_user_nand_blocks = json_create_object();
+ json_object_add_value_uint(bad_user_nand_blocks, "normalized",
+ le16_to_cpu(log->bad_user_nand_blocks.normalized));
+ json_object_add_value_uint(bad_user_nand_blocks, "raw",
+ le64_to_cpu(log->bad_user_nand_blocks.raw));
+
+ bad_system_nand_blocks = json_create_object();
+ json_object_add_value_uint(bad_system_nand_blocks, "normalized",
+ le16_to_cpu(log->bad_system_nand_blocks.normalized));
+ json_object_add_value_uint(bad_system_nand_blocks, "raw",
+ le64_to_cpu(log->bad_system_nand_blocks.raw));
+
+ e2e_correction_counts = json_create_object();
+ json_object_add_value_uint(e2e_correction_counts, "corrected",
+ le32_to_cpu(log->e2e_correction_counts.corrected));
+ json_object_add_value_uint(e2e_correction_counts, "detected",
+ le32_to_cpu(log->e2e_correction_counts.detected));
+
+ user_data_erase_counts = json_create_object();
+ json_object_add_value_uint(user_data_erase_counts, "minimum",
+ le32_to_cpu(log->user_data_erase_counts.minimum));
+ json_object_add_value_uint(user_data_erase_counts, "maximum",
+ le32_to_cpu(log->user_data_erase_counts.maximum));
+
+ thermal_status = json_create_object();
+ json_object_add_value_string(thermal_status, "current_status",
+ stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status));
+ json_object_add_value_uint(thermal_status, "num_events",
+ log->thermal_status.num_events);
+
+ dssd_specific_ver = json_create_object();
+ json_object_add_value_uint(dssd_specific_ver, "major_ver",
+ log->dssd_specific_ver.major_ver);
+ json_object_add_value_uint(dssd_specific_ver, "minor_ver",
+ le16_to_cpu(log->dssd_specific_ver.minor_ver));
+ json_object_add_value_uint(dssd_specific_ver, "point_ver",
+ le16_to_cpu(log->dssd_specific_ver.point_ver));
+ json_object_add_value_uint(dssd_specific_ver, "errata_ver",
+ log->dssd_specific_ver.errata_ver);
+
+ root = json_create_object();
+ json_object_add_value_uint64(root, "physical_media_units_written",
+ le_to_float(log->physical_media_units_written, 16));
+ json_object_add_value_uint64(root, "physical_media_units_read",
+ le_to_float(log->physical_media_units_read, 16));
+ json_object_add_value_object(root, "bad_user_nand_blocks",
+ bad_user_nand_blocks);
+ json_object_add_value_object(root, "bad_system_nand_blocks",
+ bad_system_nand_blocks);
+ json_object_add_value_uint(root, "xor_recovery_count",
+ le64_to_cpu(log->xor_recovery_count));
+ json_object_add_value_uint(root, "uncorrectable_read_error_count",
+ le64_to_cpu(log->uncorrectable_read_error_count));
+ json_object_add_value_uint(root, "soft_ecc_error_count",
+ le64_to_cpu(log->soft_ecc_error_count));
+ json_object_add_value_object(root, "e2e_correction_counts",
+ e2e_correction_counts);
+ json_object_add_value_uint(root, "system_data_percent_used",
+ log->system_data_percent_used);
+ json_object_add_value_uint(root, "refresh_counts",
+ le64_to_cpu(log->refresh_counts));
+ json_object_add_value_object(root, "user_data_erase_counts",
+ user_data_erase_counts);
+ json_object_add_value_object(root, "thermal_status", thermal_status);
+ json_object_add_value_object(root, "dssd_specific_ver",
+ dssd_specific_ver);
+ json_object_add_value_uint(root, "pcie_correctable_error_count",
+ le64_to_cpu(log->pcie_correctable_error_count));
+ json_object_add_value_uint(root, "incomplete_shutdowns",
+ le32_to_cpu(log->incomplete_shutdowns));
+ json_object_add_value_uint(root, "percent_free_blocks",
+ log->percent_free_blocks);
+ json_object_add_value_uint(root, "capacitor_health",
+ le16_to_cpu(log->capacitor_health));
+ sprintf(buf, "%c", log->nvme_errata_ver);
+ json_object_add_value_string(root, "nvme_errata_version", buf);
+ json_object_add_value_uint(root, "unaligned_io",
+ le64_to_cpu(log->unaligned_io));
+ json_object_add_value_uint(root, "security_version_number",
+ le64_to_cpu(log->security_version_number));
+ json_object_add_value_uint(root, "total_nuse",
+ le64_to_cpu(log->total_nuse));
+ json_object_add_value_uint64(root, "plp_start_count",
+ le_to_float(log->plp_start_count, 16));
+ json_object_add_value_uint64(root, "endurance_estimate",
+ le_to_float(log->endurance_estimate, 16));
+ json_object_add_value_uint(root, "pcie_link_retraining_count",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ json_object_add_value_uint(root, "power_state_change_count",
+ le64_to_cpu(log->power_state_change_cnt));
+ json_object_add_value_uint(root, "log_page_version",
+ le16_to_cpu(log->log_page_version));
+ stringify_log_page_guid(log->log_page_guid, buf);
+ json_object_add_value_string(root, "log_page_guid", buf);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void show_cloud_smart_log_normal(struct ocp_cloud_smart_log *log, struct nvme_dev *dev)
+{
+ char buf[2 * sizeof(log->log_page_guid) + 3];
+
+ printf("Smart Extended Log for NVME device:%s\n", dev->name);
+ printf("Physical Media Units Written : %'.0Lf\n",
+ le_to_float(log->physical_media_units_written, 16));
+ printf("Physical Media Units Read : %'.0Lf\n",
+ le_to_float(log->physical_media_units_read, 16));
+ printf("Bad User NAND Blocks (Normalized) : %" PRIu16 "%%\n",
+ le16_to_cpu(log->bad_user_nand_blocks.normalized));
+ printf("Bad User NAND Blocks (Raw) : %" PRIu64 "\n",
+ le64_to_cpu(log->bad_user_nand_blocks.raw));
+ printf("Bad System NAND Blocks (Normalized) : %" PRIu16 "%%\n",
+ le16_to_cpu(log->bad_system_nand_blocks.normalized));
+ printf("Bad System NAND Blocks (Raw) : %" PRIu64 "\n",
+ le64_to_cpu(log->bad_system_nand_blocks.raw));
+ printf("XOR Recovery Count : %" PRIu64 "\n",
+ le64_to_cpu(log->xor_recovery_count));
+ printf("Uncorrectable Read Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->uncorrectable_read_error_count));
+ printf("Soft ECC Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->soft_ecc_error_count));
+ printf("End to End Correction Counts (Corrected) : %" PRIu32 "\n",
+ le32_to_cpu(log->e2e_correction_counts.corrected));
+ printf("End to End Correction Counts (Detected) : %" PRIu32 "\n",
+ le32_to_cpu(log->e2e_correction_counts.detected));
+ printf("System Data %% Used : %" PRIu8 "%%\n",
+ log->system_data_percent_used);
+ printf("Refresh Counts : %" PRIu64 "\n",
+ le64_to_cpu(log->refresh_counts));
+ printf("User Data Erase Counts (Minimum) : %" PRIu32 "\n",
+ le32_to_cpu(log->user_data_erase_counts.minimum));
+ printf("User Data Erase Counts (Maximum) : %" PRIu32 "\n",
+ le32_to_cpu(log->user_data_erase_counts.maximum));
+ printf("Thermal Throttling Status (Current Status) : %s\n",
+ stringify_cloud_smart_log_thermal_status(log->thermal_status.current_status));
+ printf("Thermal Throttling Status (Number of Events) : %" PRIu8 "\n",
+ log->thermal_status.num_events);
+ printf("NVMe Major Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.major_ver);
+ printf(" Minor Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.minor_ver));
+ printf(" Point Version : %" PRIu16 "\n",
+ le16_to_cpu(log->dssd_specific_ver.point_ver));
+ printf(" Errata Version : %" PRIu8 "\n",
+ log->dssd_specific_ver.errata_ver);
+ printf("PCIe Correctable Error Count : %" PRIu64 "\n",
+ le64_to_cpu(log->pcie_correctable_error_count));
+ printf("Incomplete Shutdowns : %" PRIu32 "\n",
+ le32_to_cpu(log->incomplete_shutdowns));
+ printf("%% Free Blocks : %" PRIu8 "%%\n",
+ log->percent_free_blocks);
+ printf("Capacitor Health : %" PRIu16 "%%\n",
+ le16_to_cpu(log->capacitor_health));
+ printf("NVMe Errata Version : %c\n",
+ log->nvme_errata_ver);
+ printf("Unaligned IO : %" PRIu64 "\n",
+ le64_to_cpu(log->unaligned_io));
+ printf("Security Version Number : %" PRIu64 "\n",
+ le64_to_cpu(log->security_version_number));
+ printf("Total NUSE : %" PRIu64 "\n",
+ le64_to_cpu(log->total_nuse));
+ printf("PLP Start Count : %'.0Lf\n",
+ le_to_float(log->plp_start_count, 16));
+ printf("Endurance Estimate : %'.0Lf\n",
+ le_to_float(log->endurance_estimate, 16));
+ printf("PCIe Link Retraining Count : %" PRIu64 "\n",
+ le64_to_cpu(log->pcie_link_retraining_cnt));
+ printf("Power State Change Count : %" PRIu64 "\n",
+ le64_to_cpu(log->power_state_change_cnt));
+ printf("Log Page Version : %" PRIu16 "\n",
+ le16_to_cpu(log->log_page_version));
+ stringify_log_page_guid(log->log_page_guid, buf);
+ printf("Log Page GUID : %s\n", buf);
+ printf("\n\n");
+}
+
+static int wdc_vs_smart_add_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve additional performance statistics.";
+ const char *interval = "Interval to read the statistics from [1, 15].";
+ 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";
+ const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret = 0;
+ int uuid_index = 0;
+ int page_mask = 0, num, i;
+ int log_page_list[16];
+ __u64 capabilities = 0;
+ __u32 device_id, read_vendor_id;
+
+ struct config {
+ uint8_t interval;
+ char *output_format;
+ __u8 log_page_version;
+ char *log_page_mask;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .interval = 14,
+ .output_format = "normal",
+ .log_page_version = 0,
+ .log_page_mask = "",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("interval", 'i', &cfg.interval, interval),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ 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_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ if (!cfg.log_page_version) {
+ 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) {
+ 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)
+ fprintf(stderr, "ERROR: WDC: Unknown log page mask - %s\n", cfg.log_page_mask);
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &read_vendor_id);
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ 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. */
+ if (!wdc_is_sn861(device_id)) {
+ ret = wdc_get_c0_log_page(r, dev, cfg.output_format,
+ uuid_index, cfg.namespace_id);
+ if (ret)
+ fprintf(stderr,
+ "ERROR: WDC: Failure reading the C0 Log Page, ret = %d\n",
+ ret);
+ } else {
+ struct ocp_cloud_smart_log log;
+ char buf[2 * sizeof(log.log_page_guid) + 3];
+
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "Invalid output format: %s\n", cfg.output_format);
+ goto out;
+ }
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ sizeof(log), &log);
+ if (!ret) {
+ char *ptr = buf;
+ int i;
+ __u8 *guid = log.log_page_guid;
+
+ memset(buf, 0, sizeof(char) * 19);
+
+ ptr += sprintf(ptr, "0x");
+ for (i = 0; i < 16; i++)
+ ptr += sprintf(ptr, "%x", guid[15 - i]);
+ if (strcmp(buf, "0xafd514c97c6f4f9ca4f2bfea2810afc5"))
+ fprintf(stderr, "Invalid GUID: %s\n", buf);
+ else {
+ if (fmt == BINARY)
+ d_raw((unsigned char *)&log, sizeof(log));
+ else if (fmt == JSON)
+ show_cloud_smart_log_json(&log);
+ else
+ show_cloud_smart_log_normal(&log, dev);
+ }
+ } else if (ret > 0) {
+ nvme_show_status(ret);
+ } else {
+ perror("vs-smart-add-log");
+ }
+ }
+ }
+ if (((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) &&
+ (page_mask & WDC_CA_PAGE_MASK) &&
+ (!wdc_is_sn861(device_id))) {
+ /* Get the CA Log Page */
+ ret = wdc_get_ca_log_page(r, dev, 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) &&
+ (page_mask & WDC_C1_PAGE_MASK)) {
+ /* Get the C1 Log Page */
+ ret = wdc_get_c1_log_page(r, dev, 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) &&
+ (page_mask & WDC_D0_PAGE_MASK)) {
+ /* Get the D0 Log Page */
+ ret = wdc_get_d0_log_page(r, dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the D0 Log Page, ret = %d\n", ret);
+ }
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_vs_cloud_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Cloud Log Smart/Health Information";
+ const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+ __u8 *data;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0,
+ cfg.namespace_id);
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
+ } else {
+ /* parse the data */
+ wdc_print_ext_smart_cloud_log(data, fmt);
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read C0 Log Page V1 data\n");
+ ret = -1;
+ }
+
+ if (data)
+ free(data);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_vs_hw_rev_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Hardware Revision Log Information";
+ const char *namespace_id = "desired namespace id";
+ enum nvme_print_flags fmt;
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ int ret;
+ __u8 *data = NULL;
+ nvme_root_t r;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_hw_rev_log(dev_fd(dev), &data, 0, cfg.namespace_id);
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
+ goto free_buf;
+ }
+
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: Invalid buffer to read Hardware Revision log\n");
+ ret = -1;
+ goto out;
+ }
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_hw_rev_log_normal(data);
+ break;
+ case JSON:
+ wdc_print_hw_rev_log_json(data);
+ break;
+ default:
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read Hardware Revision Log Page data\n");
+ ret = -1;
+ }
+
+free_buf:
+ if (data)
+ free(data);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_vs_device_waf(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Device Write Amplication Factor";
+ const char *namespace_id = "desired namespace id";
+ struct nvme_smart_log smart_log;
+ enum nvme_print_flags fmt;
+ struct nvme_dev *dev;
+ __u8 *data;
+ nvme_root_t r;
+ int ret = 0;
+ __u64 capabilities = 0;
+ struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr;
+ long double data_units_written = 0,
+ phys_media_units_written_tlc = 0,
+ phys_media_units_written_slc = 0;
+ struct json_object *root = NULL;
+ char tlc_waf_str[32] = { 0 },
+ slc_waf_str[32] = { 0 };
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_DEVICE_WAF)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* get data units written from the smart log page */
+ ret = nvme_get_log_smart(dev_fd(dev), cfg.namespace_id, false,
+ &smart_log);
+ if (!ret) {
+ data_units_written = int128_to_double(smart_log.data_units_written);
+ } else if (ret > 0) {
+ nvme_show_status(ret);
+ ret = -1;
+ goto out;
+ } else {
+ fprintf(stderr, "smart log: %s\n", nvme_strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ /* get Physical Media Units Written from extended smart/C0 log page */
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0,
+ cfg.namespace_id);
+
+ if (!ret) {
+ ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data;
+ phys_media_units_written_tlc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuwt);
+ phys_media_units_written_slc = int128_to_double(ext_smart_log_ptr->ext_smart_pmuws);
+
+ if (data)
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR: WDC %s: get smart cloud log failure\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (strcmp(cfg.output_format, "json"))
+ nvme_show_status(ret);
+
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC %s: invalid output format\n", __func__);
+ goto out;
+ }
+
+ if (!data_units_written) {
+ fprintf(stderr, "ERROR: WDC %s: 0 data units written\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (fmt == NORMAL) {
+ printf("Device Write Amplification Factor TLC : %4.2Lf\n",
+ (phys_media_units_written_tlc/data_units_written));
+ printf("Device Write Amplification Factor SLC : %4.2Lf\n",
+ (phys_media_units_written_slc/data_units_written));
+ } else if (fmt == JSON) {
+ root = json_create_object();
+ sprintf(tlc_waf_str, "%4.2Lf", (phys_media_units_written_tlc/data_units_written));
+ sprintf(slc_waf_str, "%4.2Lf", (phys_media_units_written_slc/data_units_written));
+
+ json_object_add_value_string(root, "Device Write Amplification Factor TLC", tlc_waf_str);
+ json_object_add_value_string(root, "Device Write Amplification Factor SLC", slc_waf_str);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_latency_monitor_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve latency monitor log data.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = wdc_get_c3_log_page(r, dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the Latency Monitor (C3) Log Page, ret = %d\n", ret);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_error_recovery_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve error recovery log data.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = wdc_get_ocp_c1_log_page(r, dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the Error Recovery (C1) Log Page, ret = 0x%x\n", ret);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_dev_capabilities_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve device capabilities log data.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = wdc_get_ocp_c4_log_page(r, dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the Device Capabilities (C4) Log Page, ret = 0x%x\n", ret);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_unsupported_reqs_log(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve unsupported requirements log data.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = wdc_get_ocp_c5_log_page(r, dev, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the Unsupported Requirements (C5) Log Page, ret = 0x%x\n", ret);
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ 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, NULL);
+ nvme_show_status(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, NULL);
+ nvme_show_status(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_features_simple(fd, WDC_NVME_CLEAR_PCIE_CORR_FEATURE_ID, 0, value,
+ false, &result);
+
+ nvme_show_status(ret);
+ return ret;
+}
+
+static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Clear PCIE Correctable Errors.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ if (!wdc_check_device(r, dev)) {
+ ret = -1;
+ goto out;
+ }
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_CLEAR_PCIE_MASK)) {
+ 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(dev_fd(dev));
+ else if (capabilities & WDC_DRIVE_CAP_VUC_CLEAR_PCIE)
+ ret = wdc_do_clear_pcie_correctable_errors_vuc(dev_fd(dev));
+ else
+ ret = wdc_do_clear_pcie_correctable_errors_fid(dev_fd(dev));
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_drive_status(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Get Drive Status.";
+ struct nvme_dev *dev;
+ int ret = 0;
+ nvme_root_t r;
+ __le32 system_eol_state;
+ __le32 user_eol_state;
+ __le32 format_corrupt_reason = cpu_to_le32(0xFFFFFFFF);
+ __le32 eol_status;
+ __le32 assert_status = cpu_to_le32(0xFFFFFFFF);
+ __le32 thermal_status = cpu_to_le32(0xFFFFFFFF);
+ __u64 capabilities = 0;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_DRIVE_STATUS) != WDC_DRIVE_CAP_DRIVE_STATUS) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* verify the 0xC2 Device Manageability log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev,
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID) == false) {
+ fprintf(stderr, "ERROR: WDC: 0xC2 Log Page not supported\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Get the assert dump present status */
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &assert_status,
+ WDC_C2_ASSERT_DUMP_PRESENT_ID))
+ fprintf(stderr, "ERROR: WDC: Get Assert Status Failed\n");
+
+ /* Get the thermal throttling status */
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &thermal_status,
+ WDC_C2_THERMAL_THROTTLE_STATUS_ID))
+ fprintf(stderr, "ERROR: WDC: Get Thermal Throttling Status Failed\n");
+
+ /* Get EOL status */
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &eol_status,
+ WDC_C2_USER_EOL_STATUS_ID)) {
+ fprintf(stderr, "ERROR: WDC: Get User EOL Status Failed\n");
+ eol_status = cpu_to_le32(-1);
+ }
+
+ /* Get Customer EOL state */
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &user_eol_state,
+ WDC_C2_USER_EOL_STATE_ID))
+ fprintf(stderr, "ERROR: WDC: Get User EOL State Failed\n");
+
+ /* Get System EOL state*/
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &system_eol_state,
+ WDC_C2_SYSTEM_EOL_STATE_ID))
+ fprintf(stderr, "ERROR: WDC: Get System EOL State Failed\n");
+
+ /* Get format corrupt reason*/
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &format_corrupt_reason,
+ WDC_C2_FORMAT_CORRUPT_REASON_ID))
+ fprintf(stderr, "ERROR: WDC: Get Format Corrupt Reason Failed\n");
+
+ printf(" Drive Status :-\n");
+ if ((int)le32_to_cpu(eol_status) >= 0)
+ printf(" Percent Used: %"PRIu32"%%\n",
+ le32_to_cpu(eol_status));
+ else
+ printf(" Percent Used: Unknown\n");
+ if (system_eol_state == WDC_EOL_STATUS_NORMAL && user_eol_state == WDC_EOL_STATUS_NORMAL)
+ printf(" Drive Life Status: Normal\n");
+ else if (system_eol_state == WDC_EOL_STATUS_END_OF_LIFE ||
+ user_eol_state == WDC_EOL_STATUS_END_OF_LIFE)
+ printf(" Drive Life Status: End Of Life\n");
+ else if (system_eol_state == WDC_EOL_STATUS_READ_ONLY ||
+ user_eol_state == WDC_EOL_STATUS_READ_ONLY)
+ printf(" Drive Life Status: Read Only\n");
+ else
+ printf(" Drive Life Status: Unknown : 0x%08x/0x%08x\n",
+ le32_to_cpu(user_eol_state), le32_to_cpu(system_eol_state));
+
+ if (assert_status == WDC_ASSERT_DUMP_PRESENT)
+ printf(" Assert Dump Status: Present\n");
+ else if (assert_status == WDC_ASSERT_DUMP_NOT_PRESENT)
+ printf(" Assert Dump Status: Not Present\n");
+ else
+ printf(" Assert Dump Status: Unknown : 0x%08x\n", le32_to_cpu(assert_status));
+
+ if (thermal_status == WDC_THERMAL_THROTTLING_OFF)
+ printf(" Thermal Throttling Status: Off\n");
+ else if (thermal_status == WDC_THERMAL_THROTTLING_ON)
+ printf(" Thermal Throttling Status: On\n");
+ else if (thermal_status == WDC_THERMAL_THROTTLING_UNAVAILABLE)
+ printf(" Thermal Throttling Status: Unavailable\n");
+ else
+ printf(" Thermal Throttling Status: Unknown : 0x%08x\n", le32_to_cpu(thermal_status));
+
+ if (format_corrupt_reason == WDC_FORMAT_NOT_CORRUPT)
+ printf(" Format Corrupt Reason: Format Not Corrupted\n");
+ else if (format_corrupt_reason == WDC_FORMAT_CORRUPT_FW_ASSERT)
+ printf(" Format Corrupt Reason: Format Corrupt due to FW Assert\n");
+ else if (format_corrupt_reason == WDC_FORMAT_CORRUPT_UNKNOWN)
+ printf(" Format Corrupt Reason: Format Corrupt for Unknown Reason\n");
+ else
+ printf(" Format Corrupt Reason: Unknown : 0x%08x\n", le32_to_cpu(format_corrupt_reason));
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_clear_assert_dump(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Clear Assert Dump Present Status.";
+ struct nvme_dev *dev;
+ int ret = -1;
+ nvme_root_t r;
+ __le32 assert_status = cpu_to_le32(0xFFFFFFFF);
+ __u64 capabilities = 0;
+ struct nvme_passthru_cmd admin_cmd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_CLEAR_ASSERT) != WDC_DRIVE_CAP_CLEAR_ASSERT) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+ if (!wdc_nvme_get_dev_status_log_data(r, dev, &assert_status,
+ WDC_C2_ASSERT_DUMP_PRESENT_ID)) {
+ fprintf(stderr, "ERROR: WDC: Get Assert Status Failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Get the assert dump present status */
+ if (assert_status == WDC_ASSERT_DUMP_PRESENT) {
+ memset(&admin_cmd, 0, sizeof(admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_ASSERT_DUMP_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_ASSERT_DUMP_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_ASSERT_DUMP_CMD);
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd,
+ NULL);
+ nvme_show_status(ret);
+ } else
+ fprintf(stderr, "INFO: WDC: No Assert Dump Present\n");
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_fw_act_history(nvme_root_t r, struct nvme_dev *dev,
+ char *format)
+{
+ struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
+ enum nvme_print_flags fmt;
+ int ret;
+ __u8 *data;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ /* verify the FW Activate History log page is supported */
+ if (!wdc_nvme_check_supported_log_page(r, dev, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID)) {
+ fprintf(stderr, "ERROR: WDC: %d Log Page not supported\n",
+ WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID);
+ return -1;
+ }
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ return -1;
+ }
+
+ memset(data, 0, sizeof(__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN);
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID,
+ WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data);
+
+ if ((fw_act_history_hdr->num_entries > 0) &&
+ (fw_act_history_hdr->num_entries <= WDC_MAX_NUM_ACT_HIST_ENTRIES)) {
+ ret = wdc_print_fw_act_history_log(data, fw_act_history_hdr->num_entries,
+ fmt, 0, 0, 0);
+ } else if (!fw_act_history_hdr->num_entries) {
+ 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 __u32 wdc_get_fw_cust_id(nvme_root_t r, struct nvme_dev *dev)
+{
+
+ __u32 cust_id = WDC_INVALID_CUSTOMER_ID;
+ __u32 *cust_id_ptr = NULL;
+
+ if (!get_dev_mgment_cbs_data(r, dev, WDC_C2_CUSTOMER_ID_ID, (void *)&cust_id_ptr))
+ fprintf(stderr, "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n",
+ __func__, WDC_C2_CUSTOMER_ID_ID);
+ else
+ cust_id = *cust_id_ptr;
+
+ free(cust_id_ptr);
+ return cust_id;
+}
+
+static int wdc_get_fw_act_history_C2(nvme_root_t r, struct nvme_dev *dev,
+ char *format)
+{
+ struct wdc_fw_act_history_log_format_c2 *fw_act_history_log;
+ __u32 tot_entries = 0, num_entries = 0;
+ __u32 vendor_id = 0, device_id = 0;
+ __u32 cust_id = 0;
+ enum nvme_print_flags fmt;
+ __u8 *data;
+ int ret;
+
+ if (!wdc_check_device(r, dev))
+ return -1;
+
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ return ret;
+ }
+
+ ret = wdc_get_pci_ids(r, dev, &device_id, &vendor_id);
+
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN);
+ if (!data) {
+ 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_simple(dev_fd(dev),
+ WDC_NVME_GET_FW_ACT_HISTORY_C2_LOG_ID,
+ WDC_FW_ACT_HISTORY_C2_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ nvme_show_status(ret);
+
+ if (!ret) {
+ /* parse the data */
+ fw_act_history_log = (struct wdc_fw_act_history_log_format_c2 *)(data);
+ tot_entries = le32_to_cpu(fw_act_history_log->num_entries);
+
+ if (tot_entries > 0) {
+ /* get the FW customer id */
+ if (!wdc_is_sn861(device_id)) {
+ cust_id = wdc_get_fw_cust_id(r, dev);
+ if (cust_id == WDC_INVALID_CUSTOMER_ID) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: invalid customer id\n",
+ __func__);
+ ret = -1;
+ goto freeData;
+ }
+ }
+ num_entries = (tot_entries < WDC_MAX_NUM_ACT_HIST_ENTRIES) ? tot_entries :
+ WDC_MAX_NUM_ACT_HIST_ENTRIES;
+ ret = wdc_print_fw_act_history_log(data, num_entries,
+ fmt, cust_id, vendor_id, device_id);
+ } else {
+ fprintf(stderr, "INFO: WDC: No FW Activate History entries found.\n");
+ ret = 0;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read FW Activate History Log Page data\n");
+ ret = -1;
+ }
+
+freeData:
+ free(data);
+ return ret;
+}
+
+static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve FW activate history table.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY_MASK)) {
+ 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
+ * retrieve fw activate history data
+ */
+ data = (__u8 *)malloc(sizeof(__u8) * WDC_NVME_SMART_CLOUD_ATTR_LEN);
+ if (!data) {
+ fprintf(stderr, "ERROR: WDC: malloc: %s\n", strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ /* Get the 0xC0 log data */
+ struct nvme_get_log_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .lid = WDC_NVME_GET_SMART_CLOUD_ATTR_LOG_ID,
+ .nsid = 0xFFFFFFFF,
+ .lpo = 0,
+ .lsp = NVME_LOG_LSP_NONE,
+ .lsi = 0,
+ .rae = false,
+ .uuidx = uuid_index,
+ .csi = NVME_CSI_NVM,
+ .ot = false,
+ .len = WDC_NVME_SMART_CLOUD_ATTR_LEN,
+ .log = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ ret = nvme_get_log(&args);
+
+ if (!ret) {
+ /* 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(r, dev, cfg.output_format);
+ else
+ ret = wdc_get_fw_act_history(r, dev, cfg.output_format);
+ } else {
+ ret = wdc_get_fw_act_history_C2(r, dev, cfg.output_format);
+ }
+
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading the FW Activate History, ret = %d\n", ret);
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ 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, NULL);
+ nvme_show_status(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_features_simple(fd, WDC_NVME_CLEAR_FW_ACT_HIST_VU_FID, 0, value,
+ false, &result);
+
+ nvme_show_status(ret);
+ return ret;
+}
+
+static int wdc_clear_fw_activate_history(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Clear FW activate history table.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if (!(capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY_MASK)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY)
+ ret = wdc_do_clear_fw_activate_history_vuc(dev_fd(dev));
+ else
+ ret = wdc_do_clear_fw_activate_history_fid(dev_fd(dev));
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_vs_telemetry_controller_option(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Disable/Enable Controller Option of the Telemetry Log Page.";
+ char *disable = "Disable controller option of the telemetry log page.";
+ char *enable = "Enable controller option of the telemetry log page.";
+ char *status = "Displays the current state of the controller initiated log page.";
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ __u32 result;
+ int ret = -1;
+
+
+ struct config {
+ bool disable;
+ bool enable;
+ bool status;
+ };
+
+ struct config cfg = {
+ .disable = false,
+ .enable = false,
+ .status = false,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("disable", 'd', &cfg.disable, disable),
+ OPT_FLAG("enable", 'e', &cfg.enable, enable),
+ OPT_FLAG("status", 's', &cfg.status, status),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) != WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* allow only one option at a time */
+ if ((cfg.disable + cfg.enable + cfg.status) > 1) {
+
+ fprintf(stderr, "ERROR: WDC: Invalid option\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (cfg.disable) {
+ ret = nvme_set_features_simple(dev_fd(dev),
+ WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID,
+ 0, 1, false, &result);
+
+ wdc_clear_reason_id(dev);
+ } else {
+ if (cfg.enable) {
+ ret = nvme_set_features_simple(dev_fd(dev),
+ WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID,
+ 0, 0, false, &result);
+ } else if (cfg.status) {
+ ret = nvme_get_features_simple(dev_fd(dev),
+ WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID,
+ 0, &result);
+ if (!ret) {
+ if (result)
+ fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n");
+ else
+ fprintf(stderr, "Controller Option Telemetry Log Page State: Enabled\n");
+ } else {
+ nvme_show_status(ret);
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: unsupported option for this command\n");
+ fprintf(stderr, "Please provide an option, -d, -e or -s\n");
+ ret = -1;
+ goto out;
+ }
+ }
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+
+static int wdc_get_serial_and_fw_rev(struct nvme_dev *dev, char *sn, char *fw_rev)
+{
+ int i;
+ int ret;
+ struct nvme_id_ctrl ctrl;
+
+ i = sizeof(ctrl.sn) - 1;
+ memset(sn, 0, WDC_SERIAL_NO_LEN);
+ memset(fw_rev, 0, WDC_NVME_FIRMWARE_REV_LEN);
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret);
+ return -1;
+ }
+ /* Remove trailing spaces from the name */
+ while (i && ctrl.sn[i] == ' ') {
+ ctrl.sn[i] = '\0';
+ i--;
+ }
+ snprintf(sn, WDC_SERIAL_NO_LEN, "%s", ctrl.sn);
+ snprintf(fw_rev, WDC_NVME_FIRMWARE_REV_LEN, "%s", ctrl.fr);
+
+ return 0;
+}
+
+static int wdc_get_max_transfer_len(struct nvme_dev *dev, __u32 *maxTransferLen)
+{
+ int ret = 0;
+ struct nvme_id_ctrl ctrl;
+
+ __u32 maxTransferLenDevice = 0;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret);
+ return -1;
+ }
+
+ maxTransferLenDevice = (1 << ctrl.mdts) * getpagesize();
+ *maxTransferLen = maxTransferLenDevice;
+
+ return ret;
+}
+
+static int wdc_de_VU_read_size(struct nvme_dev *dev, __u32 fileId, __u16 spiDestn, __u32 *logSize)
+{
+ int ret = WDC_STATUS_FAILURE;
+ struct nvme_passthru_cmd cmd;
+
+ if (!dev || !logSize) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ memset(&cmd, 0, sizeof(struct nvme_passthru_cmd));
+ cmd.opcode = WDC_DE_VU_READ_SIZE_OPCODE;
+ cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID;
+ cmd.cdw13 = fileId << 16;
+ cmd.cdw14 = spiDestn;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+
+ if (!ret && logSize)
+ *logSize = cmd.result;
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: VUReadSize() failed, ");
+ nvme_show_status(ret);
+ }
+
+end:
+ return ret;
+}
+
+static int wdc_de_VU_read_buffer(struct nvme_dev *dev, __u32 fileId, __u16 spiDestn,
+ __u32 offsetInDwords, __u8 *dataBuffer, __u32 *bufferSize)
+{
+ int ret = WDC_STATUS_FAILURE;
+ struct nvme_passthru_cmd cmd;
+ __u32 noOfDwordExpected = 0;
+
+ if (!dev || !dataBuffer || !bufferSize) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ memset(&cmd, 0, sizeof(struct nvme_passthru_cmd));
+ noOfDwordExpected = *bufferSize / sizeof(__u32);
+ cmd.opcode = WDC_DE_VU_READ_BUFFER_OPCODE;
+ cmd.nsid = WDC_DE_DEFAULT_NAMESPACE_ID;
+ cmd.cdw10 = noOfDwordExpected;
+ cmd.cdw13 = fileId << 16;
+ cmd.cdw14 = spiDestn;
+ cmd.cdw15 = offsetInDwords;
+
+ cmd.addr = (__u64)(__u64)(uintptr_t)dataBuffer;
+ cmd.data_len = *bufferSize;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &cmd, NULL);
+
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: VUReadBuffer() failed, ");
+ nvme_show_status(ret);
+ }
+
+end:
+ return ret;
+}
+
+static int wdc_get_log_dir_max_entries(struct nvme_dev *dev, __u32 *maxNumOfEntries)
+{
+ int ret = WDC_STATUS_FAILURE;
+ __u32 headerPayloadSize = 0;
+ __u8 *fileIdOffsetsBuffer = NULL;
+ __u32 fileIdOffsetsBufferSize = 0;
+ __u32 fileNum = 0;
+ __u16 fileOffset = 0;
+
+
+ if (!dev || !maxNumOfEntries) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+ /* 1.Get log directory first four bytes */
+ ret = wdc_de_VU_read_size(dev, 0, 5, (__u32 *)&headerPayloadSize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr,
+ "ERROR: WDC: %s: Failed to get headerPayloadSize from file directory 0x%x\n",
+ __func__, ret);
+ return ret;
+ }
+
+ fileIdOffsetsBufferSize =
+ WDC_DE_FILE_HEADER_SIZE + (headerPayloadSize * WDC_DE_FILE_OFFSET_SIZE);
+ fileIdOffsetsBuffer = (__u8 *)calloc(1, fileIdOffsetsBufferSize);
+
+ /* 2.Read to get file offsets */
+ ret = wdc_de_VU_read_buffer(dev, 0, 5, 0, fileIdOffsetsBuffer, &fileIdOffsetsBufferSize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr,
+ "ERROR: WDC: %s: Failed to get fileIdOffsets from file directory 0x%x\n",
+ __func__, ret);
+ goto end;
+ }
+ /* 3.Determine valid entries */
+ for (fileNum = 0;
+ fileNum < (headerPayloadSize - WDC_DE_FILE_HEADER_SIZE) / WDC_DE_FILE_OFFSET_SIZE;
+ fileNum++) {
+ fileOffset = (fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE +
+ (fileNum * WDC_DE_FILE_OFFSET_SIZE)] << 8) +
+ fileIdOffsetsBuffer[WDC_DE_FILE_HEADER_SIZE +
+ (fileNum * WDC_DE_FILE_OFFSET_SIZE) + 1];
+ if (!fileOffset)
+ continue;
+ (*maxNumOfEntries)++;
+ }
+
+end:
+ free(fileIdOffsetsBuffer);
+ return ret;
+}
+
+static enum WDC_DRIVE_ESSENTIAL_TYPE wdc_get_essential_type(__u8 fileName[])
+{
+ enum WDC_DRIVE_ESSENTIAL_TYPE essentialType = WDC_DE_TYPE_NONE;
+
+ if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_CORE_DUMP_FILE_NAME))
+ essentialType = WDC_DE_TYPE_DUMPSNAPSHOT;
+ else if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_EVENT_LOG_FILE_NAME))
+ essentialType = WDC_DE_TYPE_EVENTLOG;
+ else if (!wdc_UtilsStrCompare((char *)fileName, WDC_DE_MANUFACTURING_INFO_PAGE_FILE_NAME))
+ essentialType = WDC_DE_TYPE_NVME_MANF_INFO;
+
+ return essentialType;
+}
+
+static int wdc_fetch_log_directory(struct nvme_dev *dev, struct WDC_DE_VU_LOG_DIRECTORY *directory)
+{
+ int ret = WDC_STATUS_FAILURE;
+ __u8 *fileOffset = NULL;
+ __u8 *fileDirectory = NULL;
+ __u32 headerSize = 0;
+ __u32 fileNum = 0, startIdx = 0;
+ __u16 fileOffsetTemp = 0;
+ __u32 entryId = 0;
+ __u32 fileDirectorySize = 0;
+
+ if (!dev || !directory) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ ret = wdc_de_VU_read_size(dev, 0, 5, &fileDirectorySize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr,
+ "ERROR: WDC: %s: Failed to get filesystem directory size, ret = %d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ fileDirectory = (__u8 *)calloc(1, fileDirectorySize);
+ ret = wdc_de_VU_read_buffer(dev, 0, 5, 0, fileDirectory, &fileDirectorySize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: %s: Failed to get filesystem directory, ret = %d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ /* First four bytes of header directory is headerSize */
+ memcpy(&headerSize, fileDirectory, WDC_DE_FILE_HEADER_SIZE);
+
+ /* minimum buffer for 1 entry is required */
+ if (!directory->maxNumLogEntries) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ for (fileNum = 0;
+ fileNum < (headerSize - WDC_DE_FILE_HEADER_SIZE) / WDC_DE_FILE_OFFSET_SIZE;
+ fileNum++) {
+ if (entryId >= directory->maxNumLogEntries)
+ break;
+
+ startIdx = WDC_DE_FILE_HEADER_SIZE + (fileNum * WDC_DE_FILE_OFFSET_SIZE);
+ memcpy(&fileOffsetTemp, fileDirectory + startIdx, sizeof(fileOffsetTemp));
+ fileOffset = fileDirectory + fileOffsetTemp;
+
+ if (!fileOffsetTemp)
+ continue;
+
+ memset(&directory->logEntry[entryId], 0, sizeof(struct WDC_DRIVE_ESSENTIALS));
+ memcpy(&directory->logEntry[entryId].metaData, fileOffset, sizeof(struct __packed WDC_DE_VU_FILE_META_DATA));
+ directory->logEntry[entryId].metaData.fileName[WDC_DE_FILE_NAME_SIZE - 1] = '\0';
+ wdc_UtilsDeleteCharFromString((char *)directory->logEntry[entryId].metaData.fileName,
+ WDC_DE_FILE_NAME_SIZE, ' ');
+ if (!directory->logEntry[entryId].metaData.fileID)
+ continue;
+
+ directory->logEntry[entryId].essentialType = wdc_get_essential_type(directory->logEntry[entryId].metaData.fileName);
+ entryId++;
+ }
+
+ directory->numOfValidLogEntries = entryId;
+
+end:
+ if (fileDirectory)
+ free(fileDirectory);
+ return ret;
+}
+
+static int wdc_fetch_log_file_from_device(struct nvme_dev *dev, __u32 fileId,
+ __u16 spiDestn, __u64 fileSize, __u8 *dataBuffer)
+{
+ int ret = WDC_STATUS_FAILURE;
+ __u32 chunckSize = WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET;
+ __u32 maximumTransferLength = 0;
+ __u32 buffSize = 0;
+ __u64 offsetIdx = 0;
+
+ if (!dev || !dataBuffer || !fileSize) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ if (wdc_get_max_transfer_len(dev, &maximumTransferLength) < 0) {
+ ret = WDC_STATUS_FAILURE;
+ goto end;
+ }
+
+ /* Fetch Log File Data */
+ if ((fileSize >= maximumTransferLength) || (fileSize > 0xFFFFFFFF)) {
+ chunckSize = WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET;
+ if (maximumTransferLength < WDC_DE_VU_READ_BUFFER_STANDARD_OFFSET)
+ chunckSize = maximumTransferLength;
+
+ buffSize = chunckSize;
+ for (offsetIdx = 0; (offsetIdx * chunckSize) < fileSize; offsetIdx++) {
+ if (((offsetIdx * chunckSize) + buffSize) > fileSize)
+ buffSize = (__u32)(fileSize - (offsetIdx * chunckSize));
+ /* Limitation in VU read buffer - offsetIdx and bufferSize are not greater than u32 */
+ ret = wdc_de_VU_read_buffer(dev, fileId, spiDestn,
+ (__u32)((offsetIdx * chunckSize) / sizeof(__u32)), dataBuffer + (offsetIdx * chunckSize), &buffSize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n",
+ __func__, ret, fileId, (unsigned long)fileSize);
+ break;
+ }
+ }
+ } else {
+ buffSize = (__u32)fileSize;
+ ret = wdc_de_VU_read_buffer(dev, fileId, spiDestn,
+ (__u32)((offsetIdx * chunckSize) / sizeof(__u32)),
+ dataBuffer, &buffSize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_buffer failed with ret = %d, fileId = 0x%x, fileSize = 0x%lx\n",
+ __func__, ret, fileId, (unsigned long)fileSize);
+ }
+ }
+
+end:
+ return ret;
+}
+
+static int wdc_de_get_dump_trace(struct nvme_dev *dev, char *filePath, __u16 binFileNameLen, char *binFileName)
+{
+ int ret = WDC_STATUS_FAILURE;
+ __u8 *readBuffer = NULL;
+ __u32 readBufferLen = 0;
+ __u32 lastPktReadBufferLen = 0;
+ __u32 maxTransferLen = 0;
+ __u32 dumptraceSize = 0;
+ __u32 chunkSize = 0;
+ __u32 chunks = 0;
+ __u32 offset = 0;
+ __u8 loop = 0;
+ __u16 i = 0;
+ __u32 maximumTransferLength = 0;
+
+ if (!dev || !binFileName || !filePath) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+
+ if (wdc_get_max_transfer_len(dev, &maximumTransferLength) < 0)
+ return WDC_STATUS_FAILURE;
+
+ do {
+ /* Get dumptrace size */
+ ret = wdc_de_VU_read_size(dev, 0, WDC_DE_DUMPTRACE_DESTINATION, &dumptraceSize);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_size failed with ret = %d\n",
+ __func__, ret);
+ break;
+ }
+
+ /* Make sure the size requested is greater than dword */
+ if (dumptraceSize < 4) {
+ ret = WDC_STATUS_FAILURE;
+ fprintf(stderr, "ERROR: WDC: %s: wdc_de_VU_read_size failed, read size is less than 4 bytes, dumptraceSize = 0x%x\n",
+ __func__, dumptraceSize);
+ break;
+ }
+
+ /* Choose the least max transfer length */
+ maxTransferLen = maximumTransferLength < WDC_DE_READ_MAX_TRANSFER_SIZE ? maximumTransferLength : WDC_DE_READ_MAX_TRANSFER_SIZE;
+
+ /* Comment from FW Team:
+ * The max non - block transfer size is 0xFFFF (16 bits allowed as the block size).Use 0x8000
+ * to keep it on a word - boundary.
+ * max_xfer = int(pow(2, id_data['MDTS'])) * 4096 # 4k page size as reported in pcie capabiltiies
+ */
+ chunkSize = dumptraceSize < maxTransferLen ? dumptraceSize : maxTransferLen;
+ chunks = (dumptraceSize / maxTransferLen) + ((dumptraceSize % maxTransferLen) ? 1 : 0);
+
+ readBuffer = (unsigned char *)calloc(dumptraceSize, sizeof(unsigned char));
+ readBufferLen = chunkSize;
+ lastPktReadBufferLen = (dumptraceSize % maxTransferLen) ? (dumptraceSize % maxTransferLen) : chunkSize;
+
+ if (!readBuffer) {
+ fprintf(stderr, "ERROR: WDC: %s: readBuffer calloc failed\n", __func__);
+ ret = WDC_STATUS_INSUFFICIENT_MEMORY;
+ break;
+ }
+
+ for (i = 0; i < chunks; i++) {
+ offset = ((i*chunkSize) / 4);
+
+ /* Last loop call, Assign readBufferLen to read only left over bytes */
+ if (i == (chunks - 1))
+ readBufferLen = lastPktReadBufferLen;
+
+ ret = wdc_de_VU_read_buffer(dev, 0, WDC_DE_DUMPTRACE_DESTINATION, 0,
+ readBuffer + offset, &readBufferLen);
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr,
+ "ERROR: WDC: %s: wdc_de_VU_read_buffer failed, ret = %d on offset 0x%x\n",
+ __func__, ret, offset);
+ break;
+ }
+ }
+ } while (loop);
+
+ if (ret == WDC_STATUS_SUCCESS) {
+ ret = wdc_WriteToFile(binFileName, (char *)readBuffer, dumptraceSize);
+ if (ret != WDC_STATUS_SUCCESS)
+ fprintf(stderr, "ERROR: WDC: %s: wdc_WriteToFile failed, ret = %d\n",
+ __func__, ret);
+ } else {
+ fprintf(stderr, "ERROR: WDC: %s: Read Buffer Loop failed, ret = %d\n", __func__,
+ ret);
+ }
+
+ if (readBuffer)
+ free(readBuffer);
+
+ return ret;
+}
+
+int wdc_fetch_vu_file_directory(struct nvme_dev *dev,
+ struct WDC_DE_VU_LOG_DIRECTORY deEssentialsList,
+ __s8 *bufferFolderPath, __u8 *serialNo, __u8 *timeString)
+{
+ int ret = wdc_fetch_log_directory(dev, &deEssentialsList);
+ __u32 listIdx;
+ char *dataBuffer;
+ char fileName[MAX_PATH_LEN];
+
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "WDC: wdc_fetch_log_directory failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ /* Get Debug Data Files */
+ for (listIdx = 0; listIdx < deEssentialsList.numOfValidLogEntries; listIdx++) {
+ if (!deEssentialsList.logEntry[listIdx].metaData.fileSize) {
+ fprintf(stderr, "ERROR: WDC: File Size for %s is 0\n",
+ deEssentialsList.logEntry[listIdx].metaData.fileName);
+ ret = WDC_STATUS_FILE_SIZE_ZERO;
+ } else {
+ /* Fetch Log File Data */
+ dataBuffer = (char *)calloc(1, (size_t)deEssentialsList.logEntry[listIdx].metaData.fileSize);
+ ret = wdc_fetch_log_file_from_device(dev,
+ deEssentialsList.logEntry[listIdx].metaData.fileID,
+ WDC_DE_DESTN_SPI,
+ deEssentialsList.logEntry[listIdx].metaData.fileSize,
+ (__u8 *)dataBuffer);
+
+ /* Write databuffer to file */
+ if (ret == WDC_STATUS_SUCCESS) {
+ memset(fileName, 0, sizeof(fileName));
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ deEssentialsList.logEntry[listIdx].metaData.fileName, serialNo, timeString);
+ if (deEssentialsList.logEntry[listIdx].metaData.fileSize > 0xFFFFFFFF) {
+ wdc_WriteToFile(fileName, dataBuffer, 0xFFFFFFFF);
+ wdc_WriteToFile(fileName, dataBuffer + 0xFFFFFFFF, (__u32)(deEssentialsList.logEntry[listIdx].metaData.fileSize - 0xFFFFFFFF));
+ } else {
+ wdc_WriteToFile(fileName, dataBuffer, (__u32)deEssentialsList.logEntry[listIdx].metaData.fileSize);
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: wdc_fetch_log_file_from_device: %s failed, ret = %d\n",
+ deEssentialsList.logEntry[listIdx].metaData.fileName, ret);
+ }
+ free(dataBuffer);
+ }
+ }
+
+ return ret;
+}
+
+int wdc_read_debug_directory(struct nvme_dev *dev, __s8 *bufferFolderPath, __u8 *serialNo,
+ __u8 *timeString)
+{
+ __u32 maxNumOfVUFiles = 0;
+ int ret = wdc_get_log_dir_max_entries(dev, &maxNumOfVUFiles);
+ struct WDC_DE_VU_LOG_DIRECTORY deEssentialsList;
+
+ if (ret != WDC_STATUS_SUCCESS) {
+ fprintf(stderr, "WDC: wdc_get_log_dir_max_entries failed, ret = %d\n", ret);
+ return ret;
+ }
+
+ memset(&deEssentialsList, 0, sizeof(deEssentialsList));
+ deEssentialsList.logEntry =
+ (struct WDC_DRIVE_ESSENTIALS *)calloc(1, sizeof(struct WDC_DRIVE_ESSENTIALS) * maxNumOfVUFiles);
+ deEssentialsList.maxNumLogEntries = maxNumOfVUFiles;
+
+ ret = wdc_fetch_vu_file_directory(dev, deEssentialsList, bufferFolderPath, serialNo,
+ timeString);
+
+ free(deEssentialsList.logEntry);
+ deEssentialsList.logEntry = NULL;
+
+ return ret;
+}
+
+static int wdc_do_drive_essentials(nvme_root_t r, struct nvme_dev *dev,
+ char *dir, char *key)
+{
+ int ret = 0;
+ void *retPtr;
+ char fileName[MAX_PATH_LEN];
+ __s8 bufferFolderPath[MAX_PATH_LEN];
+ char bufferFolderName[MAX_PATH_LEN];
+ char tarFileName[MAX_PATH_LEN];
+ char tarFiles[MAX_PATH_LEN];
+ char tarCmd[MAX_PATH_LEN+MAX_PATH_LEN];
+ UtilsTimeInfo timeInfo;
+ __u8 timeString[MAX_PATH_LEN];
+ __u8 serialNo[WDC_SERIAL_NO_LEN];
+ __u8 firmwareRevision[WDC_NVME_FIRMWARE_REV_LEN];
+ __u8 idSerialNo[WDC_SERIAL_NO_LEN];
+ __u8 idFwRev[WDC_NVME_FIRMWARE_REV_LEN];
+ __u8 featureIdBuff[4];
+ char currDir[MAX_PATH_LEN];
+ char *dataBuffer = NULL;
+ __u32 elogNumEntries, elogBufferSize;
+ __u32 dataBufferSize;
+ __u32 listIdx = 0;
+ __u32 vuLogIdx = 0;
+ __u32 result;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_id_ns ns;
+ struct nvme_error_log_page *elogBuffer;
+ struct nvme_smart_log smart_log;
+ struct nvme_firmware_slot fw_log;
+ struct WDC_NVME_DE_VU_LOGPAGES *vuLogInput = NULL;
+
+ memset(bufferFolderPath, 0, sizeof(bufferFolderPath));
+ memset(bufferFolderName, 0, sizeof(bufferFolderName));
+ memset(tarFileName, 0, sizeof(tarFileName));
+ memset(tarFiles, 0, sizeof(tarFiles));
+ memset(tarCmd, 0, sizeof(tarCmd));
+ memset(&timeInfo, 0, sizeof(timeInfo));
+
+ if (wdc_get_serial_and_fw_rev(dev, (char *)idSerialNo, (char *)idFwRev)) {
+ fprintf(stderr, "ERROR: WDC: get serial # and fw revision failed\n");
+ return -1;
+ }
+
+ fprintf(stderr, "Get Drive Essentials Data for device serial #: %s and fw revision: %s\n",
+ idSerialNo, idFwRev);
+
+ /* Create Drive Essentials directory */
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeString, 0, sizeof(timeString));
+ wdc_UtilsSnprintf((char *)timeString, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u",
+ timeInfo.year, timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute, timeInfo.second);
+
+ wdc_UtilsSnprintf((char *)serialNo, WDC_SERIAL_NO_LEN, (char *)idSerialNo);
+ /* Remove any space form serialNo */
+ wdc_UtilsDeleteCharFromString((char *)serialNo, WDC_SERIAL_NO_LEN, ' ');
+
+ memset(firmwareRevision, 0, sizeof(firmwareRevision));
+ wdc_UtilsSnprintf((char *)firmwareRevision, WDC_NVME_FIRMWARE_REV_LEN, (char *)idFwRev);
+ /* Remove any space form FirmwareRevision */
+ wdc_UtilsDeleteCharFromString((char *)firmwareRevision, WDC_NVME_FIRMWARE_REV_LEN, ' ');
+
+ wdc_UtilsSnprintf((char *)bufferFolderName, MAX_PATH_LEN, "%s_%s_%s_%s",
+ "DRIVE_ESSENTIALS", (char *)serialNo, (char *)firmwareRevision, (char *)timeString);
+
+ if (dir) {
+ wdc_UtilsSnprintf((char *)bufferFolderPath, MAX_PATH_LEN, "%s%s%s",
+ (char *)dir, WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName);
+ } else {
+ retPtr = getcwd((char *)currDir, MAX_PATH_LEN);
+ if (retPtr) {
+ wdc_UtilsSnprintf((char *)bufferFolderPath, MAX_PATH_LEN, "%s%s%s",
+ (char *)currDir, WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName);
+ } else {
+ fprintf(stderr, "ERROR: WDC: get current working directory failed\n");
+ return -1;
+ }
+ }
+
+ ret = wdc_UtilsCreateDir((char *)bufferFolderPath);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: create directory failed, ret = %d, dir = %s\n", ret, bufferFolderPath);
+ return -1;
+ }
+
+ fprintf(stderr, "Store Drive Essentials bin files in directory: %s\n", bufferFolderPath);
+
+ /* Get Identify Controller Data */
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed, ret = %d\n", ret);
+ return -1;
+ }
+
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath,
+ WDC_DE_PATH_SEPARATOR, "IdentifyController", (char *)serialNo,
+ (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)&ctrl, sizeof(struct nvme_id_ctrl));
+
+ memset(&ns, 0, sizeof(struct nvme_id_ns));
+ ret = nvme_identify_ns(dev_fd(dev), 1, &ns);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ns() failed, ret = %d\n", ret);
+ } else {
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "IdentifyNamespace", (char *)serialNo, (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)&ns, sizeof(struct nvme_id_ns));
+ }
+
+ /* Get Log Pages (0x01, 0x02, 0x03, 0xC0 and 0xE3) */
+ elogNumEntries = WDC_DE_DEFAULT_NUMBER_OF_ERROR_ENTRIES;
+ elogBufferSize = elogNumEntries*sizeof(struct nvme_error_log_page);
+ dataBuffer = calloc(1, elogBufferSize);
+ elogBuffer = (struct nvme_error_log_page *)dataBuffer;
+
+ ret = nvme_get_log_error(dev_fd(dev), elogNumEntries, false,
+ elogBuffer);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_error_log() failed, ret = %d\n", ret);
+ } else {
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "ErrorLog", (char *)serialNo, (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)elogBuffer, elogBufferSize);
+ }
+
+ free(dataBuffer);
+ dataBuffer = NULL;
+
+ /* Get Smart log page */
+ memset(&smart_log, 0, sizeof(struct nvme_smart_log));
+ ret = nvme_get_log_smart(dev_fd(dev), NVME_NSID_ALL, false,
+ &smart_log);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_smart_log() failed, ret = %d\n", ret);
+ } else {
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "SmartLog", (char *)serialNo, (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)&smart_log, sizeof(struct nvme_smart_log));
+ }
+
+ /* Get FW Slot log page */
+ memset(&fw_log, 0, sizeof(struct nvme_firmware_slot));
+ ret = nvme_get_log_fw_slot(dev_fd(dev), false, &fw_log);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_fw_log() failed, ret = %d\n", ret);
+ } else {
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "FwSLotLog", (char *)serialNo, (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)&fw_log, sizeof(struct nvme_firmware_slot));
+ }
+
+ /* Get VU log pages */
+ /* define inputs for vendor unique log pages */
+ vuLogInput = (struct WDC_NVME_DE_VU_LOGPAGES *)calloc(1, sizeof(struct WDC_NVME_DE_VU_LOGPAGES));
+ vuLogInput->numOfVULogPages = ARRAY_SIZE(deVULogPagesList);
+
+ for (vuLogIdx = 0; vuLogIdx < vuLogInput->numOfVULogPages; vuLogIdx++) {
+ dataBufferSize = deVULogPagesList[vuLogIdx].logPageLen;
+ dataBuffer = calloc(1, dataBufferSize);
+ memset(dataBuffer, 0, dataBufferSize);
+
+ ret = nvme_get_log_simple(dev_fd(dev),
+ deVULogPagesList[vuLogIdx].logPageId,
+ dataBufferSize, dataBuffer);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_get_log() for log page 0x%x failed, ret = %d\n",
+ deVULogPagesList[vuLogIdx].logPageId, ret);
+ } else {
+ wdc_UtilsDeleteCharFromString((char *)deVULogPagesList[vuLogIdx].logPageIdStr, 4, ' ');
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "LogPage", (char *)&deVULogPagesList[vuLogIdx].logPageIdStr, (char *)serialNo, (char *)timeString);
+ wdc_WriteToFile(fileName, (char *)dataBuffer, dataBufferSize);
+ }
+
+ free(dataBuffer);
+ dataBuffer = NULL;
+ }
+
+ free(vuLogInput);
+
+ /* Get NVMe Features (0x01, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C) */
+ for (listIdx = 1; listIdx < ARRAY_SIZE(deFeatureIdList); listIdx++) {
+ memset(featureIdBuff, 0, sizeof(featureIdBuff));
+ /* skipping LbaRangeType as it is an optional nvme command and not supported */
+ if (deFeatureIdList[listIdx].featureId == FID_LBA_RANGE_TYPE)
+ continue;
+ ret = nvme_get_features_data(dev_fd(dev),
+ (enum nvme_features_id)deFeatureIdList[listIdx].featureId,
+ WDC_DE_GLOBAL_NSID,
+ sizeof(featureIdBuff),
+ &featureIdBuff, &result);
+
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_get_feature id 0x%x failed, ret = %d\n",
+ deFeatureIdList[listIdx].featureId, ret);
+ } else {
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s0x%x_%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR,
+ "FEATURE_ID_", deFeatureIdList[listIdx].featureId,
+ deFeatureIdList[listIdx].featureName, serialNo, timeString);
+ wdc_WriteToFile(fileName, (char *)featureIdBuff, sizeof(featureIdBuff));
+ }
+ }
+
+ ret = wdc_read_debug_directory(dev, bufferFolderPath, serialNo, timeString);
+
+ /* Get Dump Trace Data */
+ wdc_UtilsSnprintf(fileName, MAX_PATH_LEN, "%s%s%s_%s_%s.bin", (char *)bufferFolderPath, WDC_DE_PATH_SEPARATOR, "dumptrace", serialNo, timeString);
+ ret = wdc_de_get_dump_trace(dev, (char *)bufferFolderPath, 0, fileName);
+ if (ret != WDC_STATUS_SUCCESS)
+ fprintf(stderr, "ERROR: WDC: wdc_de_get_dump_trace failed, ret = %d\n", ret);
+
+ /* Tar the Drive Essentials directory */
+ wdc_UtilsSnprintf(tarFileName, sizeof(tarFileName), "%s%s", (char *)bufferFolderPath, WDC_DE_TAR_FILE_EXTN);
+ if (dir)
+ wdc_UtilsSnprintf(tarFiles, sizeof(tarFiles), "%s%s%s%s%s", (char *)dir,
+ WDC_DE_PATH_SEPARATOR, (char *)bufferFolderName,
+ WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES);
+ else
+ wdc_UtilsSnprintf(tarFiles, sizeof(tarFiles), "%s%s%s", (char *)bufferFolderName,
+ WDC_DE_PATH_SEPARATOR, WDC_DE_TAR_FILES);
+ wdc_UtilsSnprintf(tarCmd, sizeof(tarCmd), "%s %s %s", WDC_DE_TAR_CMD, (char *)tarFileName, (char *)tarFiles);
+
+ ret = system(tarCmd);
+
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Tar of Drive Essentials data failed, ret = %d\n",
+ ret);
+
+ fprintf(stderr, "Get of Drive Essentials data successful\n");
+ nvme_free_tree(r);
+ return 0;
+}
+
+static int wdc_drive_essentials(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Capture Drive Essentials.";
+ char *dirName = "Output directory pathname.";
+ char d[PATH_MAX] = {0};
+ char k[PATH_MAX] = {0};
+ __u64 capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ char *d_ptr;
+ int ret;
+
+ struct config {
+ char *dirName;
+ };
+
+ struct config cfg = {
+ .dirName = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("dir-name", 'd', "DIRECTORY", &cfg.dirName, dirName),
+ OPT_END()
+ };
+
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS) != WDC_DRIVE_CAP_DRIVE_ESSENTIALS) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ if (cfg.dirName) {
+ strncpy(d, cfg.dirName, PATH_MAX - 1);
+ d_ptr = d;
+ } else {
+ d_ptr = NULL;
+ }
+
+ ret = wdc_do_drive_essentials(r, dev, d_ptr, k);
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_do_drive_resize(struct nvme_dev *dev, uint64_t new_size)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_DRIVE_RESIZE_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_DRIVE_RESIZE_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_DRIVE_RESIZE_CMD);
+ admin_cmd.cdw13 = new_size;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ return ret;
+}
+
+static int wdc_do_namespace_resize(struct nvme_dev *dev, __u32 nsid, __u32 op_option)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_NAMESPACE_RESIZE_OPCODE;
+ admin_cmd.nsid = nsid;
+ admin_cmd.cdw10 = op_option;
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+ return ret;
+}
+
+static int wdc_do_drive_info(struct nvme_dev *dev, __u32 *result)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_cmd));
+ admin_cmd.opcode = WDC_NVME_DRIVE_INFO_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_DRIVE_INFO_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_DRIVE_INFO_CMD);
+
+ ret = nvme_submit_admin_passthru(dev_fd(dev), &admin_cmd, NULL);
+
+ if (!ret && result)
+ *result = admin_cmd.result;
+
+ return ret;
+}
+
+static int wdc_drive_resize(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a Resize command.";
+ const char *size = "The new size (in GB) to resize the drive to.";
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ struct config {
+ uint64_t size;
+ };
+
+ struct config cfg = {
+ .size = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("size", 's', &cfg.size, size),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_RESIZE) == WDC_DRIVE_CAP_RESIZE) {
+ ret = wdc_do_drive_resize(dev, cfg.size);
+ } else {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+
+ if (!ret)
+ printf("New size: %" PRIu64 " GB\n", cfg.size);
+
+ nvme_show_status(ret);
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_namespace_resize(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a Namespace Resize command.";
+ const char *namespace_id = "The namespace id to resize.";
+ const char *op_option = "The over provisioning option to set for namespace.";
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 op_option;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0x1,
+ .op_option = 0xF,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("op-option", 'o', &cfg.op_option, op_option),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ if ((cfg.op_option != 0x1) && (cfg.op_option != 0x2) && (cfg.op_option != 0x3) &&
+ (cfg.op_option != 0xF)) {
+ fprintf(stderr, "ERROR: WDC: unsupported OP option parameter\n");
+ dev_close(dev);
+ return -1;
+ }
+
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_NS_RESIZE) == WDC_DRIVE_CAP_NS_RESIZE) {
+ ret = wdc_do_namespace_resize(dev, cfg.namespace_id,
+ cfg.op_option);
+
+ if (ret)
+ printf("ERROR: WDC: Namespace Resize of namespace id 0x%x, op option 0x%x failed\n", cfg.namespace_id, cfg.op_option);
+ } else {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+
+ nvme_show_status(ret);
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_reason_identifier(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Retrieve telemetry log reason identifier.";
+ const char *log_id = "Log ID to retrieve - host - 7 or controller - 8";
+ const char *fname = "File name to save raw binary identifier";
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+ uint64_t capabilities = 0;
+ char f[PATH_MAX] = {0};
+ char fileSuffix[PATH_MAX] = {0};
+ UtilsTimeInfo timeInfo;
+ __u8 timeStamp[MAX_PATH_LEN];
+
+
+ struct config {
+ int log_id;
+ char *file;
+ };
+ struct config cfg = {
+ .log_id = 7,
+ .file = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-id", 'i', &cfg.log_id, log_id),
+ OPT_FILE("file", 'o', &cfg.file, fname),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+
+ if (cfg.log_id != NVME_LOG_LID_TELEMETRY_HOST &&
+ cfg.log_id != NVME_LOG_LID_TELEMETRY_CTRL) {
+ fprintf(stderr, "ERROR: WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n");
+ ret = -1;
+ goto close_dev;
+ }
+
+ if (cfg.file) {
+ int verify_file;
+
+ /* verify the passed in file name and path is valid before getting the dump data */
+ verify_file = open(cfg.file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (verify_file < 0) {
+ fprintf(stderr, "ERROR: WDC: open: %s\n", strerror(errno));
+ ret = -1;
+ goto close_dev;
+ }
+ close(verify_file);
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ } else {
+ wdc_UtilsGetTime(&timeInfo);
+ memset(timeStamp, 0, sizeof(timeStamp));
+ wdc_UtilsSnprintf((char *)timeStamp, MAX_PATH_LEN, "%02u%02u%02u_%02u%02u%02u",
+ timeInfo.year, timeInfo.month, timeInfo.dayOfMonth,
+ timeInfo.hour, timeInfo.minute, timeInfo.second);
+ if (cfg.log_id == NVME_LOG_LID_TELEMETRY_CTRL)
+ snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_ctlr_%s", (char *)timeStamp);
+ else
+ snprintf(fileSuffix, PATH_MAX, "_error_reason_identifier_host_%s", (char *)timeStamp);
+
+ if (wdc_get_serial_name(dev, f, PATH_MAX, fileSuffix) == -1) {
+ fprintf(stderr, "ERROR: WDC: failed to generate file name\n");
+ ret = -1;
+ goto close_dev;
+ }
+ if (strlen(f) > PATH_MAX - 5) {
+ fprintf(stderr, "ERROR: WDC: file name overflow\n");
+ ret = -1;
+ goto close_dev;
+ }
+ strcat(f, ".bin");
+ }
+
+ fprintf(stderr, "%s: filename = %s\n", __func__, f);
+
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_REASON_ID) == WDC_DRIVE_CAP_REASON_ID) {
+ ret = wdc_do_get_reason_id(dev, f, cfg.log_id);
+ } else {
+ fprintf(stderr, "ERROR: WDC:unsupported device for this command\n");
+ ret = -1;
+ }
+
+ nvme_show_status(ret);
+
+close_dev:
+ dev_close(dev);
+ nvme_free_tree(r);
+ return ret;
+}
+
+static const char *nvme_log_id_to_string(__u8 log_id)
+{
+ switch (log_id) {
+ case NVME_LOG_LID_ERROR:
+ return "Error Information Log ID";
+ case NVME_LOG_LID_SMART:
+ return "Smart/Health Information Log ID";
+ case NVME_LOG_LID_FW_SLOT:
+ return "Firmware Slot Information Log ID";
+ case NVME_LOG_LID_CHANGED_NS:
+ return "Namespace Changed Log ID";
+ case NVME_LOG_LID_CMD_EFFECTS:
+ return "Commamds Supported and Effects Log ID";
+ case NVME_LOG_LID_DEVICE_SELF_TEST:
+ return "Device Self Test Log ID";
+ case NVME_LOG_LID_TELEMETRY_HOST:
+ return "Telemetry Host Initiated Log ID";
+ case NVME_LOG_LID_TELEMETRY_CTRL:
+ return "Telemetry Controller Generated Log ID";
+ case NVME_LOG_LID_ENDURANCE_GROUP:
+ return "Endurance Group Log ID";
+ case NVME_LOG_LID_ANA:
+ return "ANA Log ID";
+ case NVME_LOG_LID_PERSISTENT_EVENT:
+ return "Persistent Event Log ID";
+ case NVME_LOG_LID_DISCOVER:
+ return "Discovery Log ID";
+ case NVME_LOG_LID_RESERVATION:
+ return "Reservation Notification Log ID";
+ case NVME_LOG_LID_SANITIZE:
+ return "Sanitize Status Log ID";
+ case WDC_LOG_ID_C0:
+ return "WDC Vendor Unique Log ID C0";
+ case WDC_LOG_ID_C1:
+ return "WDC Vendor Unique Log ID C1";
+ case WDC_LOG_ID_C2:
+ return "WDC Vendor Unique Log ID C2";
+ case WDC_LOG_ID_C3:
+ return "WDC Vendor Unique Log ID C3";
+ case WDC_LOG_ID_C4:
+ return "WDC Vendor Unique Log ID C4";
+ case WDC_LOG_ID_C5:
+ return "WDC Vendor Unique Log ID C5";
+ case WDC_LOG_ID_C6:
+ return "WDC Vendor Unique Log ID C6";
+ case WDC_LOG_ID_C8:
+ return "WDC Vendor Unique Log ID C8";
+ case WDC_LOG_ID_CA:
+ return "WDC Vendor Unique Log ID CA";
+ case WDC_LOG_ID_CB:
+ return "WDC Vendor Unique Log ID CB";
+ case WDC_LOG_ID_D0:
+ return "WDC Vendor Unique Log ID D0";
+ case WDC_LOG_ID_D1:
+ return "WDC Vendor Unique Log ID D1";
+ case WDC_LOG_ID_D6:
+ return "WDC Vendor Unique Log ID D6";
+ case WDC_LOG_ID_D7:
+ return "WDC Vendor Unique Log ID D7";
+ case WDC_LOG_ID_D8:
+ return "WDC Vendor Unique Log ID D8";
+ case WDC_LOG_ID_DE:
+ return "WDC Vendor Unique Log ID DE";
+ case WDC_LOG_ID_F0:
+ return "WDC Vendor Unique Log ID F0";
+ case WDC_LOG_ID_F1:
+ return "WDC Vendor Unique Log ID F1";
+ case WDC_LOG_ID_F2:
+ return "WDC Vendor Unique Log ID F2";
+ case WDC_LOG_ID_FA:
+ return "WDC Vendor Unique Log ID FA";
+ default:
+ return "Unknown Log ID";
+ }
+}
+
+static void __json_log_page_directory(struct log_page_directory *directory)
+{
+ __u32 bitmap_idx;
+ __u8 log_id;
+ struct json_object *root;
+ struct json_object *entries;
+
+ root = json_create_object();
+
+ entries = json_create_array();
+ json_object_add_value_array(root, "Entries", entries);
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = NVME_LOG_NS_BASE + bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ log_id = NVME_LOG_VS_BASE + bitmap_idx;
+ if (!log_page_name[log_id])
+ continue;
+ if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) {
+ struct json_object *json_entry = json_create_object();
+
+ json_object_add_value_uint(json_entry, "Log ID", log_id);
+ json_object_add_value_string(json_entry, "Log Page Name",
+ log_page_name[log_id]);
+
+ json_array_add_value_object(entries, json_entry);
+ }
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+
+static void __show_log_page_directory(struct log_page_directory *directory)
+{
+ __u32 bitmap_idx;
+ __u8 log_id;
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_ns_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = NVME_LOG_NS_BASE + bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+
+ for (bitmap_idx = 0; bitmap_idx < BYTE_TO_BIT(sizeof(__u64)); bitmap_idx++) {
+ if (directory->supported_vs_lid_bitmap & (1ULL << bitmap_idx)) {
+ log_id = NVME_LOG_VS_BASE + bitmap_idx;
+ if (log_page_name[log_id])
+ printf("0x%02X: %s\n", log_id, log_page_name[log_id]);
+ }
+ }
+}
+
+static int wdc_log_page_directory(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve Log Page Directory.";
+ enum nvme_print_flags fmt;
+ struct nvme_dev *dev;
+ int ret = 0;
+ nvme_root_t r;
+ __u64 capabilities = 0;
+ struct wdc_c2_cbs_data *cbs_data = NULL;
+ int i;
+ __u8 log_id = 0;
+ __u32 device_id, read_vendor_id;
+ bool uuid_supported = false;
+ struct nvme_id_uuid_list uuid_list;
+
+ 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|binary"),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "%s: ERROR: WDC: invalid output format\n", __func__);
+ dev_close(dev);
+ return ret;
+ }
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+
+ memset(&uuid_list, 0, sizeof(struct nvme_id_uuid_list));
+ if (wdc_CheckUuidListSupport(dev, &uuid_list))
+ uuid_supported = true;
+
+ if (uuid_supported)
+ fprintf(stderr, "WDC: UUID lists supported\n");
+ else
+ fprintf(stderr, "WDC: UUID lists NOT supported\n");
+
+
+ ret = wdc_get_pci_ids(r, dev, &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_ID_C8 :
+ WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_ID;
+
+ if (!wdc_is_sn861(device_id)) {
+ /* verify the 0xC2 Device Manageability log page is supported */
+ if (wdc_nvme_check_supported_log_page(r, dev, log_id) == false) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: 0x%x Log Page not supported\n",
+ __func__, log_id);
+ ret = -1;
+ goto out;
+ }
+
+ if (!get_dev_mgment_cbs_data(r, dev,
+ WDC_C2_LOG_PAGES_SUPPORTED_ID,
+ (void *)&cbs_data)) {
+ fprintf(stderr,
+ "%s: ERROR: WDC: 0xC2 Log Page entry ID 0x%x not found\n",
+ __func__, WDC_C2_LOG_PAGES_SUPPORTED_ID);
+ ret = -1;
+ goto out;
+ }
+ if (!cbs_data) {
+ fprintf(stderr, "%s: ERROR: WDC: NULL_data ptr\n", __func__);
+ ret = -1;
+ goto out;
+ }
+ printf("Log Page Directory\n");
+ /* print the supported pages */
+ if (!strcmp(cfg.output_format, "normal")) {
+ for (i = 0; i < le32_to_cpu(cbs_data->length); i++)
+ printf("0x%x - %s\n", cbs_data->data[i],
+ nvme_log_id_to_string(cbs_data->data[i]));
+ } else if (!strcmp(cfg.output_format, "binary")) {
+ d((__u8 *)cbs_data->data,
+ le32_to_cpu(cbs_data->length), 16, 1);
+ } else if (!strcmp(cfg.output_format, "json")) {
+ struct json_object *root = json_create_object();
+
+ for (i = 0; i < le32_to_cpu(cbs_data->length); i++) {
+ json_object_add_value_int(root,
+ nvme_log_id_to_string(cbs_data->data[i]),
+ cbs_data->data[i]);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ } else {
+ fprintf(stderr,
+ "%s: ERROR: WDC: Invalid format, format = %s\n",
+ __func__, cfg.output_format);
+ }
+
+ free(cbs_data);
+ } else {
+ struct log_page_directory *dir;
+ void *data = NULL;
+ __u32 result;
+
+ if (posix_memalign(&data, getpagesize(), 512)) {
+ fprintf(stderr,
+ "can not allocate log page directory payload\n");
+ ret = ENOMEM;
+ goto out;
+ }
+
+ dir = (struct log_page_directory *)data;
+ ret = nvme_admin_passthru(dev_fd(dev), WDC_NVME_ADMIN_VUC_OPCODE_D2, 0, 0,
+ 0, 0, 0, 8,
+ 0, WDC_VUC_SUBOPCODE_LOG_PAGE_DIR_D2, 0, 0, 0,
+ 32, data, 0, NULL,
+ 0, &result);
+
+ if (!ret) {
+ switch (fmt) {
+ case BINARY:
+ d_raw((unsigned char *)data, 32);
+ break;
+ case JSON:
+ __json_log_page_directory(dir);
+ break;
+ default:
+ __show_log_page_directory(dir);
+ }
+ } else {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(ret, false), ret);
+ }
+ }
+ }
+
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_get_drive_reason_id(struct nvme_dev *dev, char *drive_reason_id, size_t len)
+{
+ int i, j;
+ int ret;
+ int res_len = 0;
+ struct nvme_id_ctrl ctrl;
+ char *reason_id_str = "reason_id";
+
+ i = sizeof(ctrl.sn) - 1;
+ j = sizeof(ctrl.mn) - 1;
+ memset(drive_reason_id, 0, len);
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", ret);
+ return -1;
+ }
+ /* Remove trailing spaces from the sn and mn */
+ while (i && ctrl.sn[i] == ' ') {
+ ctrl.sn[i] = '\0';
+ i--;
+ }
+
+ while (j && ctrl.mn[j] == ' ') {
+ ctrl.mn[j] = '\0';
+ j--;
+ }
+
+ res_len = snprintf(drive_reason_id, len, "%s_%s_%s", ctrl.sn, ctrl.mn, reason_id_str);
+ if (len <= res_len) {
+ fprintf(stderr,
+ "ERROR: WDC: cannot format serial number due to data of unexpected length\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int wdc_save_reason_id(struct nvme_dev *dev, __u8 *rsn_ident, int size)
+{
+ int ret = 0;
+ char *reason_id_file;
+ char drive_reason_id[PATH_MAX] = {0};
+ char reason_id_path[PATH_MAX] = WDC_REASON_ID_PATH_NAME;
+ struct stat st = {0};
+
+ if (wdc_get_drive_reason_id(dev, drive_reason_id, PATH_MAX) == -1) {
+ fprintf(stderr, "%s: ERROR: failed to get drive reason id\n", __func__);
+ return -1;
+ }
+
+ /* make the nvmecli dir in /usr/local if it doesn't already exist */
+ if (stat(reason_id_path, &st) == -1) {
+ if (mkdir(reason_id_path, 0700) < 0) {
+ fprintf(stderr, "%s: ERROR: failed to mkdir %s: %s\n",
+ __func__, reason_id_path, strerror(errno));
+ return -1;
+ }
+ }
+
+ if (asprintf(&reason_id_file, "%s/%s%s", reason_id_path,
+ drive_reason_id, ".bin") < 0)
+ return -ENOMEM;
+
+ fprintf(stderr, "%s: reason id file = %s\n", __func__, reason_id_file);
+
+ /* save off the error reason identifier to a file in /usr/local/nvmecli */
+ ret = wdc_create_log_file(reason_id_file, rsn_ident, WDC_REASON_ID_ENTRY_LEN);
+ free(reason_id_file);
+
+ return ret;
+}
+
+static int wdc_clear_reason_id(struct nvme_dev *dev)
+{
+ int ret = -1;
+ int verify_file;
+ char *reason_id_file;
+ char drive_reason_id[PATH_MAX] = {0};
+
+ if (wdc_get_drive_reason_id(dev, drive_reason_id, PATH_MAX) == -1) {
+ fprintf(stderr, "%s: ERROR: failed to get drive reason id\n", __func__);
+ return -1;
+ }
+
+ if (asprintf(&reason_id_file, "%s/%s%s", WDC_REASON_ID_PATH_NAME,
+ drive_reason_id, ".bin") < 0)
+ return -ENOMEM;
+
+ /* verify the drive reason id file name and path is valid */
+ verify_file = open(reason_id_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (verify_file < 0) {
+ ret = -1;
+ goto free;
+ }
+ close(verify_file);
+
+ /* remove the reason id file */
+ ret = remove(reason_id_file);
+
+free:
+ free(reason_id_file);
+
+ return ret;
+}
+
+static int wdc_dump_telemetry_hdr(struct nvme_dev *dev, int log_id, struct nvme_telemetry_log *log_hdr)
+{
+ int ret = 0;
+
+ if (log_id == NVME_LOG_LID_TELEMETRY_HOST)
+ ret = nvme_get_log_create_telemetry_host(dev_fd(dev), log_hdr);
+ else
+ ret = nvme_get_log_telemetry_ctrl(dev_fd(dev), false, 0, 512,
+ (void *)log_hdr);
+
+ if (ret < 0) {
+ perror("get-telemetry-log");
+ } else if (ret > 0) {
+ nvme_show_status(ret);
+ fprintf(stderr, "%s: ERROR: Failed to acquire telemetry header, ret = %d!\n", __func__, ret);
+ }
+
+ return ret;
+}
+
+static int wdc_do_get_reason_id(struct nvme_dev *dev, char *file, int log_id)
+{
+ int ret;
+ struct nvme_telemetry_log *log_hdr;
+ __u32 log_hdr_size = sizeof(struct nvme_telemetry_log);
+ __u32 reason_id_size = 0;
+
+ log_hdr = (struct nvme_telemetry_log *)malloc(log_hdr_size);
+ if (!log_hdr) {
+ fprintf(stderr, "%s: ERROR: malloc failed, size : 0x%x, status: %s\n", __func__, log_hdr_size, strerror(errno));
+ ret = -1;
+ goto out;
+ }
+ memset(log_hdr, 0, log_hdr_size);
+
+ ret = wdc_dump_telemetry_hdr(dev, log_id, log_hdr);
+ if (ret) {
+ fprintf(stderr, "%s: ERROR: get telemetry header failed, ret : %d\n", __func__, ret);
+ ret = -1;
+ goto out;
+ }
+
+ reason_id_size = sizeof(log_hdr->rsnident);
+
+ if (log_id == NVME_LOG_LID_TELEMETRY_CTRL)
+ wdc_save_reason_id(dev, log_hdr->rsnident, reason_id_size);
+
+ ret = wdc_create_log_file(file, (__u8 *)log_hdr->rsnident, reason_id_size);
+
+out:
+ free(log_hdr);
+ return ret;
+}
+
+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) %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(nand_stats->nand_write_tlc)));
+ printf(" NAND Writes SLC (Bytes) %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(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 %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(nand_stats_v3->nand_write_tlc)));
+ printf(" SLC Units Written %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(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 %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(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 %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(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 %s\n",
+ uint128_t_to_string(
+ le128_to_cpu(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(__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 = json_create_object();
+ __u64 temp_raw;
+ __u16 temp_norm;
+ __u64 *temp_ptr = NULL;
+
+ switch (version) {
+ case 0:
+ json_object_add_value_uint128(root, "NAND Writes TLC (Bytes)",
+ le128_to_cpu(nand_stats->nand_write_tlc));
+ json_object_add_value_uint128(root, "NAND Writes SLC (Bytes)",
+ le128_to_cpu(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_uint64(root, "NAND XOR/RAID Recovery Trigger Events",
+ le64_to_cpu(nand_stats->nand_rec_trigger_event));
+ json_object_add_value_uint64(root, "E2E Error Counter",
+ le64_to_cpu(nand_stats->e2e_error_counter));
+ json_object_add_value_uint64(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_uint128(root, "NAND Writes TLC (Bytes)",
+ le128_to_cpu(nand_stats_v3->nand_write_tlc));
+ json_object_add_value_uint128(root, "NAND Writes SLC (Bytes)",
+ le128_to_cpu(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_uint64(root, "Bad NAND Blocks Count - Raw",
+ le64_to_cpu(temp_raw));
+ json_object_add_value_uint64(root, "NAND XOR Recovery count",
+ le64_to_cpu(nand_stats_v3->xor_recovery_count));
+ json_object_add_value_uint64(root, "UECC Read Error count",
+ le64_to_cpu(nand_stats_v3->uecc_read_error_count));
+ json_object_add_value_uint64(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_uint64(root, "User Data Erase Counts - SLC Min",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[0]));
+ json_object_add_value_uint64(root, "User Data Erase Counts - SLC Max",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[1]));
+ json_object_add_value_uint64(root, "User Data Erase Counts - TLC Min",
+ le64_to_cpu(nand_stats_v3->user_data_erase_counts[2]));
+ json_object_add_value_uint64(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_uint64(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_uint64(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_uint64(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_uint128(root, "Data Set Management Commands",
+ le128_to_cpu(nand_stats_v3->trim_completions));
+ json_object_add_value_uint64(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_uint64(root, "Soft ECC Error Count",
+ le64_to_cpu(nand_stats_v3->soft_ecc_error_count));
+ json_object_add_value_uint64(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_uint64(root, "Bad System Nand Block Count - Raw",
+ le64_to_cpu(temp_raw));
+ json_object_add_value_uint128(root, "Endurance Estimate",
+ le128_to_cpu(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_uint64(root, "Unaligned I/O",
+ le64_to_cpu(nand_stats_v3->unaligned_IO));
+ json_object_add_value_uint128(root, "Physical Media Units Read",
+ le128_to_cpu(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 = json_create_object();
+
+ json_object_add_value_uint64(root, "Unsupported Request Error Counter",
+ le64_to_cpu(pcie_stats->unsupportedRequestErrorCount));
+ json_object_add_value_uint64(root, "ECRC Error Status Counter",
+ le64_to_cpu(pcie_stats->ecrcErrorStatusCount));
+ json_object_add_value_uint64(root, "Malformed TLP Status Counter",
+ le64_to_cpu(pcie_stats->malformedTlpStatusCount));
+
+ json_object_add_value_uint64(root, "Receiver Overflow Status Counter",
+ le64_to_cpu(pcie_stats->receiverOverflowStatusCount));
+ json_object_add_value_uint64(root, "Unexpected Completion Status Counter",
+ le64_to_cpu(pcie_stats->unexpectedCmpltnStatusCount));
+ json_object_add_value_uint64(root, "Complete Abort Status Counter",
+ le64_to_cpu(pcie_stats->completeAbortStatusCount));
+ json_object_add_value_uint64(root, "Completion Timeout Status Counter",
+ le64_to_cpu(pcie_stats->cmpltnTimoutStatusCount));
+ json_object_add_value_uint64(root, "Flow Control Error Status Counter",
+ le64_to_cpu(pcie_stats->flowControlErrorStatusCount));
+ json_object_add_value_uint64(root, "Poisoned TLP Status Counter",
+ le64_to_cpu(pcie_stats->poisonedTlpStatusCount));
+ json_object_add_value_uint64(root, "Dlink Protocol Error Status Counter",
+ le64_to_cpu(pcie_stats->dLinkPrtclErrorStatusCount));
+ json_object_add_value_uint64(root, "Advisory Non Fatal Error Status Counter",
+ le64_to_cpu(pcie_stats->advsryNFatalErrStatusCount));
+ json_object_add_value_uint64(root, "Replay Timer TO Status Counter",
+ le64_to_cpu(pcie_stats->replayTimerToStatusCount));
+ json_object_add_value_uint64(root, "Replay Number Rollover Status Counter",
+ le64_to_cpu(pcie_stats->replayNumRolloverStCount));
+ json_object_add_value_uint64(root, "Bad DLLP Status Counter",
+ le64_to_cpu(pcie_stats->badDllpStatusCount));
+ json_object_add_value_uint64(root, "Bad TLP Status Counter",
+ le64_to_cpu(pcie_stats->badTlpStatusCount));
+ json_object_add_value_uint64(root, "Receiver Error Status Counter",
+ le64_to_cpu(pcie_stats->receiverErrStatusCount));
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static int wdc_do_vs_nand_stats_sn810_2(struct nvme_dev *dev, char *format)
+{
+ enum nvme_print_flags fmt;
+ uint8_t *data = NULL;
+ int ret;
+
+ data = NULL;
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0,
+ NVME_NSID_ALL);
+
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve NAND stats\n", __func__);
+ goto out;
+ } else {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: %s : invalid output format\n", __func__);
+ goto out;
+ }
+
+ /* parse the data */
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_ext_smart_cloud_log_normal(data, WDC_SCA_V1_NAND_STATS);
+ break;
+ case JSON:
+ wdc_print_ext_smart_cloud_log_json(data, WDC_SCA_V1_NAND_STATS);
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ if (data)
+ free(data);
+ return ret;
+}
+
+static int wdc_do_vs_nand_stats(struct nvme_dev *dev, char *format)
+{
+ enum nvme_print_flags fmt;
+ uint8_t *output = NULL;
+ __u16 version = 0;
+ int ret;
+
+ output = (uint8_t *)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t));
+ if (!output) {
+ fprintf(stderr, "ERROR: WDC: calloc: %s\n", strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_log_simple(dev_fd(dev), WDC_NVME_NAND_STATS_LOG_ID,
+ WDC_NVME_NAND_STATS_SIZE, (void *)output);
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC: %s : Failed to retrieve NAND stats\n", __func__);
+ goto out;
+ } else {
+ ret = validate_output_format(format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ goto out;
+ }
+
+ version = output[WDC_NVME_NAND_STATS_SIZE - 2];
+
+ /* parse the data */
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_nand_stats_normal(version, output);
+ break;
+ case JSON:
+ wdc_print_nand_stats_json(version, output);
+ break;
+ default:
+ break;
+ }
+ }
+
+out:
+ free(output);
+ return ret;
+}
+
+static int wdc_vs_nand_stats(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve NAND statistics.";
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ __u64 capabilities = 0;
+ uint32_t read_device_id = 0, read_vendor_id = 0;
+ int ret;
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_NAND_STATS)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret);
+ return -1;
+ }
+
+ switch (read_device_id) {
+ case WDC_NVME_SN820CL_DEV_ID:
+ ret = wdc_do_vs_nand_stats_sn810_2(dev,
+ cfg.output_format);
+ break;
+ default:
+ ret = wdc_do_vs_nand_stats(dev, cfg.output_format);
+ break;
+ }
+ }
+
+ if (ret)
+ fprintf(stderr, "ERROR: WDC: Failure reading NAND statistics, ret = %d\n", ret);
+
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_do_vs_pcie_stats(struct nvme_dev *dev,
+ struct wdc_vs_pcie_stats *pcieStatsPtr)
+{
+ int ret;
+ struct nvme_passthru_cmd admin_cmd;
+ int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats);
+
+ memset(&admin_cmd, 0, sizeof(struct nvme_passthru_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(dev_fd(dev), &admin_cmd, NULL);
+
+ return ret;
+}
+
+static int wdc_vs_pcie_stats(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Retrieve PCIE statistics.";
+ enum nvme_print_flags fmt;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+ __u64 capabilities = 0;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+ struct wdc_vs_pcie_stats *pcieStatsPtr = NULL;
+ int pcie_stats_size = sizeof(struct wdc_vs_pcie_stats);
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ goto out;
+ }
+
+ pcieStatsPtr = nvme_alloc_huge(pcie_stats_size, &mh);
+ if (!pcieStatsPtr) {
+ 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(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_PCIE_STATS)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_do_vs_pcie_stats(dev, 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;
+ default:
+ break;
+ }
+ }
+ }
+out:
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+static int wdc_vs_drive_info(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Send a vs-drive-info command.";
+ enum nvme_print_flags fmt;
+ nvme_root_t r;
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ int ret;
+ __le32 result;
+ __u16 size;
+ double rev;
+ struct nvme_id_ctrl ctrl;
+ char vsData[32] = {0};
+ char major_rev = 0, minor_rev = 0;
+ __u8 *data = NULL;
+ __u32 ftl_unit_size = 0, tcg_dev_ownership = 0;
+ __u16 boot_spec_major = 0, boot_spec_minor = 0;
+ struct json_object *root = NULL;
+ char formatter[41] = { 0 };
+ char rev_str[16] = { 0 };
+ uint32_t read_device_id = -1, read_vendor_id = -1;
+ struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = NULL;
+ struct ocp_drive_info info;
+ __u32 data_len = 0;
+ unsigned int num_dwords = 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC %s invalid output format\n", __func__);
+ dev_close(dev);
+ return ret;
+ }
+
+ /* get the id ctrl data used to fill in drive info below */
+ ret = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+
+ if (ret) {
+ fprintf(stderr, "ERROR: WDC %s: Identify Controller failed\n", __func__);
+ dev_close(dev);
+ return ret;
+ }
+
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) {
+ ret = wdc_get_pci_ids(r, dev, &read_device_id, &read_vendor_id);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: %s: failure to get pci ids, ret = %d\n", __func__, ret);
+ goto out;
+ }
+
+ switch (read_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_SN650_DEV_ID:
+ case WDC_NVME_SN650_DEV_ID_1:
+ case WDC_NVME_SN650_DEV_ID_2:
+ case WDC_NVME_SN650_DEV_ID_3:
+ case WDC_NVME_SN650_DEV_ID_4:
+ case WDC_NVME_SN655_DEV_ID:
+ case WDC_NVME_SN560_DEV_ID_1:
+ case WDC_NVME_SN560_DEV_ID_2:
+ case WDC_NVME_SN560_DEV_ID_3:
+ case WDC_NVME_SN550_DEV_ID:
+ case WDC_NVME_ZN350_DEV_ID:
+ case WDC_NVME_ZN350_DEV_ID_1:
+ ret = wdc_do_drive_info(dev, &result);
+
+ if (!ret) {
+ size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
+ rev = (double)(cpu_to_le32(result) & 0x0000ffff);
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revision: %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 Revision", 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);
+ }
+ }
+ break;
+ case WDC_NVME_SN730_DEV_ID:
+ 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);
+ }
+ break;
+ case WDC_NVME_SN820CL_DEV_ID:
+ /* Get the Drive HW Rev from the C6 Log page */
+ ret = nvme_get_hw_rev_log(dev_fd(dev), &data, 0,
+ NVME_NSID_ALL);
+ if (!ret) {
+ struct wdc_nvme_hw_rev_log *log_data = (struct wdc_nvme_hw_rev_log *)data;
+
+ major_rev = log_data->hw_rev_gdr;
+
+ free(data);
+ data = NULL;
+ } else {
+ fprintf(stderr, "ERROR: WDC: %s: failure to get hw revision log\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Get the Smart C0 log page */
+ if (!(capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data,
+ 0, NVME_NSID_ALL);
+
+ if (!ret) {
+ ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data;
+
+ /* Set the FTL Unit size */
+ ftl_unit_size = le32_to_cpu(ext_smart_log_ptr->ext_smart_ftlus);
+
+ /* Set the Boot Spec Version */
+ boot_spec_major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj);
+ boot_spec_minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min);
+
+ /* Set the Drive Ownership Status */
+ tcg_dev_ownership = le32_to_cpu(ext_smart_log_ptr->ext_smart_tcgos);
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR: WDC: %s: failure to get extended smart cloud log\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (fmt == NORMAL) {
+ printf("Drive HW Revision: %2d\n", major_rev);
+ printf("FTL Unit Size: %d\n", ftl_unit_size);
+ printf("HyperScale Boot Version Spec: %d.%d\n", boot_spec_major, boot_spec_minor);
+ printf("TCG Device Ownership Status: %2d\n", tcg_dev_ownership);
+
+ } else if (fmt == JSON) {
+ root = json_create_object();
+
+ json_object_add_value_int(root, "Drive HW Revison", major_rev);
+ json_object_add_value_int(root, "FTL Unit Size", ftl_unit_size);
+ sprintf(rev_str, "%d.%d", boot_spec_major, boot_spec_minor);
+ json_object_add_value_string(root, "HyperScale Boot Version Spec", rev_str);
+ json_object_add_value_int(root, "TCG Device Ownership Status", tcg_dev_ownership);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+ }
+
+ break;
+ case WDC_NVME_SN861_DEV_ID:
+ fallthrough;
+ case WDC_NVME_SN861_DEV_ID_1:
+ data_len = sizeof(info);
+ num_dwords = data_len / 4;
+ if (data_len % 4 != 0)
+ num_dwords += 1;
+
+ ret = nvme_admin_passthru(dev_fd(dev),
+ WDC_NVME_ADMIN_VUC_OPCODE_D2,
+ 0, 0, 0, 0, 0, num_dwords, 0,
+ WDC_VUC_SUBOPCODE_VS_DRIVE_INFO_D2,
+ 0, 0, 0, data_len, &info, 0,
+ NULL, 0, NULL);
+
+ if (!ret) {
+ __u16 hw_rev_major, hw_rev_minor;
+
+ hw_rev_major = le32_to_cpu(info.hw_revision) / 10;
+ hw_rev_minor = le32_to_cpu(info.hw_revision) % 10;
+ if (fmt == NORMAL) {
+ printf("HW Revision : %" PRIu32 ".%" PRIu32 "\n",
+ hw_rev_major, hw_rev_minor);
+ printf("FTL Unit Size : %" PRIu32 "\n",
+ le32_to_cpu(info.ftl_unit_size));
+ } else if (fmt == JSON) {
+ char buf[20];
+
+ root = json_create_object();
+
+ memset((void *)buf, 0, 20);
+ sprintf(buf, "%" PRIu32 ".%" PRIu32,
+ hw_rev_major, hw_rev_minor);
+
+ json_object_add_value_string(root,
+ "hw_revision", buf);
+ json_object_add_value_uint(root,
+ "ftl_unit_size",
+ le32_to_cpu(info.ftl_unit_size));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ break;
+ }
+ } else {
+ fprintf(stderr, "ERROR: WDC: capability not supported by this device\n");
+ ret = -1;
+ }
+
+out:
+ nvme_show_status(ret);
+ nvme_free_tree(r);
+ dev_close(dev);
+ 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;
+ enum nvme_print_flags fmt;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ uint64_t capabilities = 0;
+ __u32 hctm_tmt;
+ int temperature, temp_tmt1, temp_tmt2;
+ int ret;
+
+ 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()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ r = nvme_scan(NULL);
+ ret = validate_output_format(cfg.output_format, &fmt);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: WDC: invalid output format\n");
+ goto out;
+ }
+
+ /* check if command is supported */
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+ if ((capabilities & WDC_DRIVE_CAP_TEMP_STATS) != WDC_DRIVE_CAP_TEMP_STATS) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* get the temperature stats or report errors */
+ ret = nvme_identify_ctrl(dev_fd(dev), &id_ctrl);
+ if (ret)
+ goto out;
+ ret = nvme_get_log_smart(dev_fd(dev), NVME_NSID_ALL, false,
+ &smart_log);
+ if (ret)
+ goto out;
+
+ /* convert from kelvins to degrees Celsius */
+ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]) - 273;
+
+ /* retrieve HCTM Thermal Management Temperatures */
+ nvme_get_features_simple(dev_fd(dev), 0x10, 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",
+ dev->name, 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__);
+ }
+
+out:
+ nvme_show_status(ret);
+ nvme_free_tree(r);
+ dev_close(dev);
+ 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;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ /* print command and supported status */
+ printf("WDC Plugin Capabilities for NVME device:%s\n", dev->name);
+ 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 : %s\n",
+ capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported");
+ printf("purge-monitor : %s\n",
+ capabilities & WDC_DRIVE_CAP_PURGE ? "Supported" : "Not Supported");
+ printf("vs-internal-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_INTERNAL_LOG_MASK ? "Supported" : "Not Supported");
+ printf("vs-nand-stats : %s\n",
+ 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("--C3 Log Page : %s\n",
+ capabilities & WDC_DRIVE_CAP_C3_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 ? "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("get-error-recovery-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_OCP_C1_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("get-dev-capabilities-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_OCP_C4_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("get-unsupported-reqs-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_OCP_C5_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("get-latency-monitor-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_C3_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("cloud-boot-SSD-version : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION ? "Supported" : "Not Supported");
+ printf("vs-cloud-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_CLOUD_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("vs-hw-rev-log : %s\n",
+ capabilities & WDC_DRIVE_CAP_HW_REV_LOG_PAGE ? "Supported" : "Not Supported");
+ printf("vs-device_waf : %s\n",
+ capabilities & WDC_DRIVE_CAP_DEVICE_WAF ? "Supported" : "Not Supported");
+ printf("set-latency-monitor-feature : %s\n",
+ capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR ? "Supported" : "Not Supported");
+ printf("capabilities : Supported\n");
+ nvme_free_tree(r);
+ dev_close(dev);
+ 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;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ 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");
+ }
+
+ nvme_free_tree(r);
+ dev_close(dev);
+ return 0;
+}
+
+static int wdc_cloud_boot_SSD_version(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ const char *desc = "Get Cloud Boot SSD Version command.";
+ const char *namespace_id = "desired namespace id";
+ nvme_root_t r;
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ int ret;
+ int major = 0, minor = 0;
+ __u8 *data = NULL;
+ struct __packed wdc_nvme_ext_smart_log * ext_smart_log_ptr = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if ((capabilities & WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION) == WDC_DRIVE_CAP_CLOUD_BOOT_SSD_VERSION) {
+ /* Get the 0xC0 Smart Cloud Attribute V1 log data */
+ ret = nvme_get_ext_smart_cloud_log(dev_fd(dev), &data, 0,
+ cfg.namespace_id);
+
+ ext_smart_log_ptr = (struct __packed wdc_nvme_ext_smart_log *)data;
+ if (!ret) {
+ major = le16_to_cpu(ext_smart_log_ptr->ext_smart_maj);
+ minor = le16_to_cpu(ext_smart_log_ptr->ext_smart_min);
+
+ /* print the version returned from the log page */
+ printf("HyperScale Boot Version: %d.%d\n", major, minor);
+ } else {
+ fprintf(stderr, "ERROR: WDC: Unable to read Extended Smart/C0 Log Page data\n");
+ ret = -1;
+ }
+
+ if (data)
+ free(data);
+ } else {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ }
+
+ nvme_free_tree(r);
+ dev_close(dev);
+ return ret;
+}
+
+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.";
+ struct nvme_dev *dev;
+ FILE *output_fd;
+ int xfer_size = 0;
+ int len;
+ int err = 0;
+
+ 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 = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ goto ret;
+
+ if (!wdc_enc_check_model(dev)) {
+ 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) {
+ 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 ? 0 : strlen(cfg.file);
+ if (len > 0) {
+ output_fd = fopen(cfg.file, "wb");
+ if (!output_fd) {
+ 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(dev, 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(dev, 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:
+ dev_close(dev);
+ret:
+ return err;
+}
+
+static int wdc_enc_submit_move_data(struct nvme_dev *dev, 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) {
+ 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_passthru_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");
+ printf("opcode: 0x%02x, flags: 0x%02x, rsvd: 0x%04x, nsid: 0x%08x, cdw2: 0x%08x, ",
+ nvme_cmd.opcode, nvme_cmd.flags, nvme_cmd.rsvd1, nvme_cmd.nsid, nvme_cmd.cdw2);
+ printf("cdw3: 0x%08x, metadata_len: 0x%08x, data_len: 0x%08x, cdw10: 0x%08x, "
+ nvme_cmd.cdw3, nvme_cmd.metadata_len, nvme_cmd.data_len, nvme_cmd.cdw10);
+ printf("cdw11: 0x%08x, cdw12: 0x%08x, cdw13: 0x%08x, cdw14: 0x%08x, cdw15: 0x%08x, "
+ nvme_cmd.cdw11, nvme_cmd.cdw12, nvme_cmd.cdw13, nvme_cmd.cdw14, nvme_cmd.cdw15);
+ printf("timeout_ms: 0x%08x, result: 0x%08x, metadata: %s, data: %s\n",
+ nvme_cmd.timeout_ms, nvme_cmd.result, md, d);
+#endif
+ nvme_cmd.result = 0;
+ err = nvme_submit_admin_passthru(dev_fd(dev), &nvme_cmd, NULL);
+ if (nvme_status_equals(err, NVME_STATUS_TYPE_NVME, NVME_SC_INTERNAL)) {
+ fprintf(stderr, "%s: WARNING : WDC: No log ID:x%x available\n", __func__, log_id);
+ } else if (err) {
+ fprintf(stderr, "%s: ERROR: WDC: NVMe Snd Mgmt\n", __func__);
+ nvme_show_status(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_admin_passthru(dev_fd(dev),
+ &nvme_cmd, NULL);
+ if (err) {
+ more = 0;
+ fprintf(stderr, "%s: ERROR: WDC: NVMe Rcv Mgmt ", __func__);
+ nvme_show_status(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(struct nvme_dev *dev, __u8 log_id, __u32 xfer_size, __u32 data_len, FILE *out)
+{
+ __u8 *dump_data;
+ __u32 curr_data_offset, curr_data_len;
+ int i, ret = -1;
+ struct nvme_passthru_cmd admin_cmd;
+ __u32 dump_length = data_len;
+ __u32 numd;
+ __u16 numdu, numdl;
+
+ dump_data = (__u8 *)malloc(sizeof(__u8) * dump_length);
+ if (!dump_data) {
+ 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_passthru_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(dev_fd(dev), &admin_cmd, NULL);
+ if (ret) {
+ nvme_show_status(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, (unsigned long)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;
+}
+
+//------------------------------------------------------------------------------------
+// Description: set latency monitor feature
+//
+int wdc_set_latency_monitor_feature(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ const char *desc = "Set Latency Monitor feature.";
+
+ uint64_t capabilities = 0;
+ struct nvme_dev *dev;
+ nvme_root_t r;
+ int ret;
+ __u32 result;
+ struct feature_latency_monitor buf = {0,};
+
+ const char *active_bucket_timer_threshold =
+ "This is the value that loads the Active Bucket Timer Threshold.";
+ const char *active_threshold_a =
+ "This is the value that loads into the Active Threshold A.";
+ const char *active_threshold_b =
+ "This is the value that loads into the Active Threshold B.";
+ const char *active_threshold_c =
+ "This is the value that loads into the Active Threshold C.";
+ const char *active_threshold_d =
+ "This is the value that loads into the Active Threshold D.";
+ const char *active_latency_config =
+ "This is the value that loads into the Active Latency Configuration.";
+ const char *active_latency_minimum_window =
+ "This is the value that loads into the Active Latency Minimum Window.";
+ const char *debug_log_trigger_enable =
+ "This is the value that loads into the Debug Log Trigger Enable.";
+ const char *discard_debug_log = "Discard Debug Log.";
+ const char *latency_monitor_feature_enable = "Latency Monitor Feature Enable.";
+
+ struct config {
+ __u16 active_bucket_timer_threshold;
+ __u8 active_threshold_a;
+ __u8 active_threshold_b;
+ __u8 active_threshold_c;
+ __u8 active_threshold_d;
+ __u16 active_latency_config;
+ __u8 active_latency_minimum_window;
+ __u16 debug_log_trigger_enable;
+ __u8 discard_debug_log;
+ __u8 latency_monitor_feature_enable;
+ };
+
+ struct config cfg = {
+ .active_bucket_timer_threshold = 0x7E0,
+ .active_threshold_a = 0x5,
+ .active_threshold_b = 0x13,
+ .active_threshold_c = 0x1E,
+ .active_threshold_d = 0x2E,
+ .active_latency_config = 0xFFF,
+ .active_latency_minimum_window = 0xA,
+ .debug_log_trigger_enable = 0,
+ .discard_debug_log = 0,
+ .latency_monitor_feature_enable = 0x7,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("active_bucket_timer_threshold", 't',
+ &cfg.active_bucket_timer_threshold,
+ active_bucket_timer_threshold),
+ OPT_UINT("active_threshold_a", 'a', &cfg.active_threshold_a,
+ active_threshold_a),
+ OPT_UINT("active_threshold_b", 'b', &cfg.active_threshold_b,
+ active_threshold_b),
+ OPT_UINT("active_threshold_c", 'c', &cfg.active_threshold_c,
+ active_threshold_c),
+ OPT_UINT("active_threshold_d", 'd', &cfg.active_threshold_d,
+ active_threshold_d),
+ OPT_UINT("active_latency_config", 'f',
+ &cfg.active_latency_config, active_latency_config),
+ OPT_UINT("active_latency_minimum_window", 'w',
+ &cfg.active_latency_minimum_window,
+ active_latency_minimum_window),
+ OPT_UINT("debug_log_trigger_enable", 'r',
+ &cfg.debug_log_trigger_enable, debug_log_trigger_enable),
+ OPT_UINT("discard_debug_log", 'l', &cfg.discard_debug_log,
+ discard_debug_log),
+ OPT_UINT("latency_monitor_feature_enable", 'e',
+ &cfg.latency_monitor_feature_enable,
+ latency_monitor_feature_enable),
+ OPT_END()
+ };
+
+ ret = parse_and_open(&dev, argc, argv, desc, opts);
+
+ if (ret < 0)
+ return ret;
+
+ /* get capabilities */
+ r = nvme_scan(NULL);
+ wdc_check_device(r, dev);
+ capabilities = wdc_get_drive_capabilities(r, dev);
+
+ if (!(capabilities & WDC_DRIVE_CAP_SET_LATENCY_MONITOR)) {
+ fprintf(stderr, "ERROR: WDC: unsupported device for this command\n");
+ return -1;
+ }
+
+ memset(&buf, 0, sizeof(struct feature_latency_monitor));
+
+ buf.active_bucket_timer_threshold = cfg.active_bucket_timer_threshold;
+ buf.active_threshold_a = cfg.active_threshold_a;
+ buf.active_threshold_b = cfg.active_threshold_b;
+ buf.active_threshold_c = cfg.active_threshold_c;
+ buf.active_threshold_d = cfg.active_threshold_d;
+ buf.active_latency_config = cfg.active_latency_config;
+ buf.active_latency_minimum_window = cfg.active_latency_minimum_window;
+ buf.debug_log_trigger_enable = cfg.debug_log_trigger_enable;
+ buf.discard_debug_log = cfg.discard_debug_log;
+ buf.latency_monitor_feature_enable = cfg.latency_monitor_feature_enable;
+
+ struct nvme_set_features_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .fid = NVME_FEAT_OCP_LATENCY_MONITOR,
+ .nsid = 0,
+ .cdw12 = 0,
+ .save = 1,
+ .data_len = sizeof(struct feature_latency_monitor),
+ .data = (void *)&buf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ ret = nvme_set_features(&args);
+
+ if (ret < 0) {
+ perror("set-feature");
+ } else if (!ret) {
+ printf("NVME_FEAT_OCP_LATENCY_MONITOR: 0x%02x\n",
+ NVME_FEAT_OCP_LATENCY_MONITOR);
+ printf("active bucket timer threshold: 0x%x\n",
+ buf.active_bucket_timer_threshold);
+ printf("active threshold a: 0x%x\n", buf.active_threshold_a);
+ printf("active threshold b: 0x%x\n", buf.active_threshold_b);
+ printf("active threshold c: 0x%x\n", buf.active_threshold_c);
+ printf("active threshold d: 0x%x\n", buf.active_threshold_d);
+ printf("active latency config: 0x%x\n", buf.active_latency_config);
+ printf("active latency minimum window: 0x%x\n",
+ buf.active_latency_minimum_window);
+ printf("debug log trigger enable: 0x%x\n",
+ buf.debug_log_trigger_enable);
+ printf("discard debug log: 0x%x\n", buf.discard_debug_log);
+ printf("latency monitor feature enable: 0x%x\n",
+ buf.latency_monitor_feature_enable);
+ } else if (ret > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(ret, false), ret);
+
+ return ret;
+}
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
new file mode 100644
index 0000000..d3692bc
--- /dev/null
+++ b/plugins/wdc/wdc-nvme.h
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/wdc/wdc-nvme
+
+#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define WDC_NVME
+
+#define WDC_PLUGIN_VERSION "2.7.0"
+#include "cmd.h"
+
+PLUGIN(NAME("wdc", "Western Digital vendor specific extensions", WDC_PLUGIN_VERSION),
+ COMMAND_LIST(
+ ENTRY("cap-diag", "WDC Capture-Diagnostics", wdc_cap_diag)
+ ENTRY("drive-log", "WDC Drive Log", wdc_drive_log)
+ ENTRY("get-crash-dump", "WDC Crash Dump", wdc_get_crash_dump)
+ ENTRY("get-pfail-dump", "WDC Pfail Dump", wdc_get_pfail_dump)
+ ENTRY("id-ctrl", "WDC identify controller", wdc_id_ctrl)
+ ENTRY("purge", "WDC Purge", wdc_purge)
+ ENTRY("purge-monitor", "WDC Purge Monitor", wdc_purge_monitor)
+ ENTRY("vs-internal-log", "WDC Internal Firmware Log",
+ wdc_vs_internal_fw_log)
+ ENTRY("vs-nand-stats", "WDC NAND Statistics", wdc_vs_nand_stats)
+ ENTRY("vs-smart-add-log", "WDC Additional Smart Log",
+ wdc_vs_smart_add_log)
+ ENTRY("clear-pcie-correctable-errors",
+ "WDC Clear PCIe Correctable Error Count",
+ wdc_clear_pcie_correctable_errors)
+ ENTRY("drive-essentials", "WDC Drive Essentials",
+ wdc_drive_essentials)
+ ENTRY("get-drive-status", "WDC Get Drive Status",
+ wdc_drive_status)
+ ENTRY("clear-assert-dump", "WDC Clear Assert Dump",
+ wdc_clear_assert_dump)
+ 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)
+ ENTRY("get-latency-monitor-log",
+ "WDC Get Latency Monitor Log Page",
+ wdc_get_latency_monitor_log)
+ ENTRY("get-error-recovery-log",
+ "WDC Get Error Recovery Log Page",
+ wdc_get_error_recovery_log)
+ ENTRY("get-dev-capabilities-log",
+ "WDC Get Device Capabilities Log Page",
+ wdc_get_dev_capabilities_log)
+ ENTRY("get-unsupported-reqs-log",
+ "WDC Get Unsupported Requirements Log Page",
+ wdc_get_unsupported_reqs_log)
+ ENTRY("cloud-boot-SSD-version",
+ "WDC Get the Cloud Boot SSD Version",
+ wdc_cloud_boot_SSD_version)
+ ENTRY("vs-cloud-log", "WDC Get the Cloud Log Page",
+ wdc_vs_cloud_log)
+ ENTRY("vs-hw-rev-log", "WDC Get the Hardware Revision Log Page",
+ wdc_vs_hw_rev_log)
+ ENTRY("vs-device-waf",
+ "WDC Calculate Device Write Amplication Factor",
+ wdc_vs_device_waf)
+ ENTRY("set-latency-monitor-feature",
+ "WDC set Latency Monitor feature",
+ wdc_set_latency_monitor_feature)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/wdc/wdc-utils.c b/plugins/wdc/wdc-utils.c
new file mode 100644
index 0000000..414a06a
--- /dev/null
+++ b/plugins/wdc/wdc-utils.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017-2018 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Jeff Lien <jeff.lien@wdc.com>,
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "wdc-utils.h"
+
+int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *format, ...)
+{
+ int res = 0;
+ va_list vArgs;
+
+ va_start(vArgs, format);
+ res = vsnprintf(buffer, sizeOfBuffer, format, vArgs);
+ va_end(vArgs);
+
+ return res;
+}
+
+void wdc_UtilsDeleteCharFromString(char *buffer, int buffSize, char charToRemove)
+{
+ int i = 0;
+ int count = 0;
+
+ if (!buffer || !buffSize)
+ return;
+
+ /*
+ * Traverse the given string. If current character is not charToRemove,
+ * then place it at index count++
+ */
+ for (i = 0; ((i < buffSize) && (buffer[i] != '\0')); i++) {
+ if (buffer[i] != charToRemove)
+ buffer[count++] = buffer[i];
+ }
+ buffer[count] = '\0';
+}
+
+int wdc_UtilsGetTime(PUtilsTimeInfo timeInfo)
+{
+ time_t currTime;
+ struct tm currTimeInfo;
+
+ if (!timeInfo)
+ return WDC_STATUS_INVALID_PARAMETER;
+
+ tzset();
+ time(&currTime);
+ localtime_r(&currTime, &currTimeInfo);
+
+ timeInfo->year = currTimeInfo.tm_year + 1900;
+ timeInfo->month = currTimeInfo.tm_mon + 1;
+ timeInfo->dayOfWeek = currTimeInfo.tm_wday;
+ timeInfo->dayOfMonth = currTimeInfo.tm_mday;
+ timeInfo->hour = currTimeInfo.tm_hour;
+ timeInfo->minute = currTimeInfo.tm_min;
+ timeInfo->second = currTimeInfo.tm_sec;
+ timeInfo->msecs = 0;
+ timeInfo->isDST = currTimeInfo.tm_isdst;
+#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
+ timeInfo->zone = -currTimeInfo.tm_gmtoff / 60;
+#else
+ timeInfo->zone = -1 * (timezone / SECONDS_IN_MIN);
+#endif
+
+ return WDC_STATUS_SUCCESS;
+}
+
+int wdc_UtilsCreateDir(char *path)
+{
+ int retStatus;
+ int status = WDC_STATUS_SUCCESS;
+
+ if (!path)
+ return WDC_STATUS_INVALID_PARAMETER;
+
+ retStatus = mkdir(path, 0x999);
+ if (retStatus < 0) {
+ if (errno == EEXIST)
+ status = WDC_STATUS_DIR_ALREADY_EXISTS;
+ else if (errno == ENOENT)
+ status = WDC_STATUS_PATH_NOT_FOUND;
+ else
+ status = WDC_STATUS_CREATE_DIRECTORY_FAILED;
+ }
+
+ return status;
+}
+
+int wdc_WriteToFile(char *fileName, char *buffer, unsigned int bufferLen)
+{
+ int status = WDC_STATUS_SUCCESS;
+ FILE *file;
+ size_t bytesWritten = 0;
+
+ file = fopen(fileName, "ab+");
+ if (!file) {
+ status = WDC_STATUS_UNABLE_TO_OPEN_FILE;
+ goto end;
+ }
+
+ bytesWritten = fwrite(buffer, 1, bufferLen, file);
+ if (bytesWritten != bufferLen)
+ status = WDC_STATUS_UNABLE_TO_WRITE_ALL_DATA;
+
+end:
+ if (file)
+ fclose(file);
+ return status;
+}
+
+/**
+ * Compares the strings ignoring their cases.
+ *
+ * @param pcSrc Points to a null terminated string for comparing.
+ * @param pcDst Points to a null terminated string for comparing.
+ *
+ * @returns zero if the string matches or
+ * 1 if the pcSrc string is lexically higher than pcDst or
+ * -1 if the pcSrc string is lexically lower than pcDst.
+ */
+int wdc_UtilsStrCompare(char *pcSrc, char *pcDst)
+{
+ while ((toupper(*pcSrc) == toupper(*pcDst)) && (*pcSrc != '\0')) {
+ pcSrc++;
+ 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--;
+ }
+}
+
+bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list)
+{
+ int err;
+ struct nvme_id_ctrl ctrl;
+
+ memset(&ctrl, 0, sizeof(struct nvme_id_ctrl));
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR: WDC: nvme_identify_ctrl() failed 0x%x\n", err);
+ return false;
+ }
+
+ if ((ctrl.ctratt & NVME_CTRL_CTRATT_UUID_LIST) == NVME_CTRL_CTRATT_UUID_LIST) {
+ err = nvme_identify_uuid(dev_fd(dev), uuid_list);
+ if (!err)
+ return true;
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ nvme_show_error("identify UUID list: %s", nvme_strerror(errno));
+ }
+
+ return false;
+}
+
+bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2)
+{
+ return !memcmp(entry1, entry2, NVME_UUID_LEN);
+}
diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h
new file mode 100644
index 0000000..3fc47ca
--- /dev/null
+++ b/plugins/wdc/wdc-utils.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2017-2018 Western Digital Corporation or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Jeff Lien <jeff.lien@wdc.com>,
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Create Dir Command Status */
+#define WDC_STATUS_SUCCESS 0
+#define WDC_STATUS_FAILURE -1
+#define WDC_STATUS_INSUFFICIENT_MEMORY -2
+#define WDC_STATUS_INVALID_PARAMETER -3
+#define WDC_STATUS_FILE_SIZE_ZERO -27
+#define WDC_STATUS_UNABLE_TO_WRITE_ALL_DATA -34
+#define WDC_STATUS_DIR_ALREADY_EXISTS -36
+#define WDC_STATUS_PATH_NOT_FOUND -37
+#define WDC_STATUS_CREATE_DIRECTORY_FAILED -38
+#define WDC_STATUS_DELETE_DIRECTORY_FAILED -39
+#define WDC_STATUS_UNABLE_TO_OPEN_FILE -40
+#define WDC_STATUS_UNABLE_TO_OPEN_ZIP_FILE -41
+#define WDC_STATUS_UNABLE_TO_ARCHIVE_EXCEEDED_FILES_LIMIT -256
+#define WDC_STATUS_NO_DATA_FILE_AVAILABLE_TO_ARCHIVE -271
+
+#define WDC_NVME_FIRMWARE_REV_LEN 9 /* added 1 for end delimiter */
+#define WDC_SERIAL_NO_LEN 20
+#define SECONDS_IN_MIN 60
+#define MAX_PATH_LEN 256
+
+typedef struct _UtilsTimeInfo
+{
+ unsigned int year;
+ unsigned int month;
+ unsigned int dayOfWeek;
+ unsigned int dayOfMonth;
+ unsigned int hour;
+ unsigned int minute;
+ unsigned int second;
+ unsigned int msecs;
+ unsigned char isDST; /*0 or 1 */
+ int zone; /* Zone value like +530 or -300 */
+} UtilsTimeInfo, *PUtilsTimeInfo;
+
+int wdc_UtilsSnprintf(char *buffer, unsigned int sizeOfBuffer, const char *format, ...);
+void wdc_UtilsDeleteCharFromString(char* buffer, int buffSize, char charToRemove);
+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);
+bool wdc_CheckUuidListSupport(struct nvme_dev *dev, struct nvme_id_uuid_list *uuid_list);
+bool wdc_UuidEqual(struct nvme_id_uuid_list_entry *entry1, struct nvme_id_uuid_list_entry *entry2);
diff --git a/plugins/ymtc/ymtc-nvme.c b/plugins/ymtc/ymtc-nvme.c
new file mode 100644
index 0000000..5568c80
--- /dev/null
+++ b/plugins/ymtc/ymtc-nvme.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "nvme.h"
+#include "libnvme.h"
+#include "plugin.h"
+#include "linux/types.h"
+#include "nvme-print.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(struct nvme_dev *dev, __u32 nsid,
+ 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));
+
+ if (!nm) {
+ if (raw)
+ free(raw);
+ return -1;
+ }
+ if (!raw) {
+ free(nm);
+ return -1;
+ }
+ err = nvme_identify_ctrl(dev_fd(dev), &ctrl);
+ if (err) {
+ free(nm);
+ free(raw);
+ 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",
+ dev->name, nsid);
+ /* Column 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,
+ *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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%% %"PRIu32"\n", *nm, *(uint32_t *)raw);
+ /* 08 SI_VD_THERMAL_THROTTLE_STATUS */
+ get_ymtc_smart_info(smart, SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
+ printf("thermal_throttle_status : %3d%% %d%%, cnt: %"PRIu32"\n", *nm,
+ *raw, *(uint32_t *)(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,
+ *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(int16_t *)(raw+4)-273);
+ /* 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,
+ *(uint16_t *)raw, *(uint16_t *)(raw+2), *(uint16_t *)(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,
+ *(uint16_t *)raw-273, *(uint16_t *)(raw+2)-273, *(uint16_t *)(raw+4)-273);
+ /* 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%% %u, time: %"PRIu32"\n", *nm,
+ *raw, *(uint32_t *)(raw+1));
+ /* 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;
+ 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 nvme_dev *dev;
+ struct config {
+ __u32 namespace_id;
+ bool raw_binary;
+ };
+ int err;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return err;
+
+ err = nvme_get_nsid_log(dev_fd(dev), false, 0xca, cfg.namespace_id,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ err = show_ymtc_smart_log(dev, cfg.namespace_id, &smart_log);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ if (err > 0)
+ nvme_show_status(err);
+
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/ymtc/ymtc-nvme.h b/plugins/ymtc/ymtc-nvme.h
new file mode 100644
index 0000000..df5d598
--- /dev/null
+++ b/plugins/ymtc/ymtc-nvme.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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", NVME_VERSION),
+ 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..e9a3572
--- /dev/null
+++ b/plugins/ymtc/ymtc-utils.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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
+
+/* Additional 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..a7a3766
--- /dev/null
+++ b/plugins/zns/zns.c
@@ -0,0 +1,1274 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#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 "common.h"
+#include "nvme.h"
+#include "libnvme.h"
+#include "nvme-print.h"
+#include "util/cleanup.h"
+
+#define CREATE_CMD
+#include "zns.h"
+
+static const char *namespace_id = "Namespace identifier to use";
+static const char dash[100] = { [0 ... 99] = '-' };
+
+static int detect_zns(nvme_ns_t ns, int *out_supported)
+{
+ int err = 0;
+ char *zoned;
+
+ *out_supported = 0;
+
+ zoned = nvme_get_attr(nvme_ns_get_sysfs_dir(ns), "queue/zoned");
+ if (!zoned) {
+ *out_supported = 0;
+ return err;
+ }
+
+ *out_supported = strcmp("host-managed", zoned) == 0;
+ free(zoned);
+
+ return err;
+}
+
+static int print_zns_list_ns(nvme_ns_t ns)
+{
+ int supported;
+ int err = 0;
+
+ err = detect_zns(ns, &supported);
+ if (err) {
+ perror("Failed to enumerate namespace");
+ return err;
+ }
+
+ if (supported)
+ nvme_show_list_item(ns);
+
+ return err;
+}
+
+static int print_zns_list(nvme_root_t nvme_root)
+{
+ int err = 0;
+ nvme_host_t h;
+ nvme_subsystem_t s;
+ nvme_ctrl_t c;
+ nvme_ns_t n;
+
+ nvme_for_each_host(nvme_root, h) {
+ nvme_for_each_subsystem(h, s) {
+ nvme_subsystem_for_each_ns(s, n) {
+ err = print_zns_list_ns(n);
+ if (err)
+ return err;
+ }
+
+ nvme_subsystem_for_each_ctrl(s, c) {
+ nvme_ctrl_for_each_ns(c, n) {
+ err = print_zns_list_ns(n);
+ if (err)
+ return err;
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+static int list(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+ nvme_root_t nvme_root;
+
+ printf("%-21s %-20s %-40s %-9s %-26s %-16s %-8s\n", "Node", "SN",
+ "Model", "Namespace", "Usage", "Format", "FW Rev");
+ printf("%-.21s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash,
+ dash, dash, dash, dash, dash);
+
+ nvme_root = nvme_scan(NULL);
+ if (nvme_root) {
+ err = print_zns_list(nvme_root);
+ nvme_free_tree(nvme_root);
+ } else {
+ fprintf(stderr, "Failed to scan nvme subsystems\n");
+ err = -errno;
+ }
+
+ return err;
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a ZNS specific Identify Controller command to\n"
+ "the given device and report information about the specified\n"
+ "controller in various formats.";
+
+ enum nvme_print_flags flags;
+ struct nvme_zns_id_ctrl ctrl;
+ struct nvme_dev *dev;
+ int 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
+
+ err = nvme_zns_identify_ctrl(dev_fd(dev), &ctrl);
+ if (!err)
+ nvme_show_zns_id_ctrl(&ctrl, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns identify controller");
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
+static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a ZNS specific Identify Namespace command to\n"
+ "the given device and report information about the specified\n"
+ "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;
+ struct nvme_dev *dev;
+ int err = -1;
+
+ struct config {
+ char *output_format;
+ __u32 namespace_id;
+ bool human_readable;
+ bool 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
+ if (cfg.vendor_specific)
+ flags |= VS;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &id_ns);
+ if (err) {
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ err = nvme_zns_identify_ns(dev_fd(dev), 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_dev:
+ dev_close(dev);
+ 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";
+ const char *timeout = "timeout value, in milliseconds";
+ struct nvme_dev *dev;
+ int err, zcapc = 0;
+ char *command;
+ __u32 result;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ bool select_all;
+ __u32 timeout;
+ };
+
+ struct config cfg = {};
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-lba", 's', &cfg.zslba, zslba),
+ OPT_FLAG("select-all", 'a', &cfg.select_all, select_all),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ goto ret;
+
+ err = asprintf(&command, "%s-%s", plugin->name, cmd->name);
+ if (err < 0)
+ goto close_dev;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto free;
+ }
+ }
+
+ struct nvme_zns_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.zslba,
+ .zsa = zsa,
+ .select_all = cfg.select_all,
+ .zsaso = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = cfg.timeout,
+ .result = &result,
+ };
+ err = nvme_zns_mgmt_send(&args);
+ if (!err) {
+ if (zsa == NVME_ZNS_ZSA_RESET)
+ zcapc = result & 0x1;
+
+ printf("%s: Success, action:%d zone:%"PRIx64" all:%d zcapc:%u nsid:%d\n",
+ command, zsa, (uint64_t)cfg.zslba, (int)cfg.select_all,
+ zcapc, cfg.namespace_id);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else {
+ perror(desc);
+ }
+free:
+ free(command);
+close_dev:
+ dev_close(dev);
+ret:
+ return err;
+}
+
+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, &id_ns);
+ if (err > 0) {
+ nvme_show_status(err);
+ return -1;
+ } else if (err < 0) {
+ perror("identify namespace");
+ return -1;
+ }
+
+ err = nvme_zns_identify_ns(fd, nsid, &ns);
+ if (err > 0) {
+ nvme_show_status(err);
+ return -1;
+ } else if (err < 0) {
+ perror("zns identify namespace");
+ return -1;
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf);
+ 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(for flush action, last lba to flush)";
+ const char *zsaso = "Zone Send Action Specific Option";
+ 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)";
+ const char *timeout = "timeout value, in milliseconds";
+
+ int ffd = STDIN_FILENO, err = -1;
+ struct nvme_dev *dev;
+ void *buf = NULL;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ bool zsaso;
+ bool select_all;
+ __u8 zsa;
+ int data_len;
+ char *file;
+ __u32 timeout;
+ };
+
+ 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("zsaso", 'o', &cfg.zsaso, zsaso),
+ OPT_FLAG("select-all", 'a', &cfg.select_all, select_all),
+ OPT_BYTE("zsa", 'z', &cfg.zsa, zsa),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ if (!cfg.zsa) {
+ fprintf(stderr, "zone send action must be specified\n");
+ err = -EINVAL;
+ goto close_dev;
+ }
+
+ if (cfg.zsa == NVME_ZNS_ZSA_SET_DESC_EXT) {
+ if (!cfg.data_len) {
+ int data_len = get_zdes_bytes(dev_fd(dev),
+ cfg.namespace_id);
+
+ if (data_len == 0) {
+ fprintf(stderr, "Zone Descriptor Extensions are not supported\n");
+ goto close_dev;
+ } else if (data_len < 0) {
+ err = data_len;
+ goto close_dev;
+ }
+ cfg.data_len = data_len;
+ }
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ goto close_dev;
+ }
+ 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_dev;
+ }
+ }
+
+ struct nvme_zns_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.zslba,
+ .zsa = cfg.zsa,
+ .select_all = cfg.select_all,
+ .zsaso = cfg.zsaso,
+ .data_len = cfg.data_len,
+ .data = buf,
+ .timeout = cfg.timeout,
+ .result = NULL,
+ };
+ err = nvme_zns_mgmt_send(&args);
+ 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_dev:
+ dev_close(dev);
+ return err;
+}
+
+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";
+ const char *zslba = "starting LBA of the zone for this command";
+ const char *zrwaa = "Allocate Zone Random Write Area to zone";
+ const char *select_all = "send command to all zones";
+ const char *timeout = "timeout value, in milliseconds";
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u64 zslba;
+ __u32 namespace_id;
+ bool zrwaa;
+ bool select_all;
+ __u32 timeout;
+ };
+
+ 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("zrwaa", 'r', &cfg.zrwaa, zrwaa),
+ OPT_FLAG("select-all", 'a', &cfg.select_all, select_all),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ struct nvme_zns_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.zslba,
+ .zsa = NVME_ZNS_ZSA_OPEN,
+ .select_all = cfg.select_all,
+ .zsaso = cfg.zrwaa,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = cfg.timeout,
+ .result = NULL,
+ };
+ err = nvme_zns_mgmt_send(&args);
+ if (!err)
+ printf("zns-open-zone: Success zone slba:%"PRIx64" nsid:%d\n",
+ (uint64_t)cfg.zslba, cfg.namespace_id);
+ else
+ nvme_show_status(err);
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
+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 *zrwaa = "Allocate Zone Random Write Area to zone";
+ const char *data = "optional file for zone extension data (default stdin)";
+ const char *timeout = "timeout value, in milliseconds";
+
+ int ffd = STDIN_FILENO, err;
+ struct nvme_dev *dev;
+ void *buf = NULL;
+ int data_len;
+
+ struct config {
+ __u64 zslba;
+ bool zrwaa;
+ __u32 namespace_id;
+ char *file;
+ __u32 timeout;
+ };
+
+ 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("zrwaa", 'r', &cfg.zrwaa, zrwaa),
+ OPT_FILE("data", 'd', &cfg.file, data),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ data_len = get_zdes_bytes(dev_fd(dev), cfg.namespace_id);
+
+ if (!data_len || data_len < 0) {
+ fprintf(stderr,
+ "zone format does not provide descriptor extension\n");
+ errno = EINVAL;
+ err = -1;
+ goto close_dev;
+ }
+
+ buf = calloc(1, data_len);
+ if (!buf) {
+ perror("could not alloc memory for zone desc");
+ err = -ENOMEM;
+ goto close_dev;
+ }
+
+ 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;
+ }
+
+ struct nvme_zns_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.zslba,
+ .zsa = NVME_ZNS_ZSA_SET_DESC_EXT,
+ .select_all = 0,
+ .zsaso = cfg.zrwaa,
+ .data_len = data_len,
+ .data = buf,
+ .timeout = cfg.timeout,
+ .result = NULL,
+ };
+ err = nvme_zns_mgmt_send(&args);
+ 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_dev:
+ dev_close(dev);
+ return err;
+}
+
+
+static int zrwa_flush_zone(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Flush Explicit ZRWA Range";
+ const char *slba = "LBA to flush up to";
+ const char *timeout = "timeout value, in milliseconds";
+ struct nvme_dev *dev;
+ int err;
+
+ struct config {
+ __u64 lba;
+ __u32 namespace_id;
+ __u32 timeout;
+ };
+
+ struct config cfg = {};
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("lba", 'l', &cfg.lba, slba),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ struct nvme_zns_mgmt_send_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.lba,
+ .zsa = NVME_ZNS_ZSA_ZRWA_FLUSH,
+ .select_all = 0,
+ .zsaso = 0,
+ .data_len = 0,
+ .data = NULL,
+ .timeout = cfg.timeout,
+ .result = NULL,
+ };
+ err = nvme_zns_mgmt_send(&args);
+ if (!err)
+ printf("zrwa-flush-zone: Success, lba:%"PRIx64" nsid:%d\n",
+ (uint64_t)cfg.lba, cfg.namespace_id);
+ else
+ nvme_show_status(err);
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
+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;
+ struct nvme_dev *dev;
+ void *data = NULL;
+ int err = -1;
+
+ 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ 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_dev;
+ }
+ 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_dev;
+ }
+ }
+
+ struct nvme_zns_mgmt_recv_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .slba = cfg.zslba,
+ .zra = cfg.zra,
+ .zrasf = cfg.zrasf,
+ .zras_feat = cfg.partial,
+ .data_len = cfg.data_len,
+ .data = data,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = NULL,
+ };
+ err = nvme_zns_mgmt_recv(&args);
+ 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_dev:
+ dev_close(dev);
+ return err;
+}
+
+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 *verbose = "show report zones verbosity";
+
+ enum nvme_print_flags flags;
+ int zdes = 0, err = -1;
+ struct nvme_dev *dev;
+ __u32 report_size;
+ struct nvme_zone_report *report, *buff;
+ _cleanup_huge_ struct nvme_mem_huge mh = { 0, };
+
+ unsigned int nr_zones_chunks = 1024, /* 1024 entries * 64 bytes per entry = 64k byte transfer */
+ nr_zones_retrieved = 0,
+ nr_zones,
+ log_len;
+ __u64 offset;
+ int total_nr_zones = 0;
+ struct nvme_zns_id_ns id_zns;
+ struct nvme_id_ns id_ns;
+ uint8_t lbaf;
+ __le64 zsze;
+ struct json_object *zone_list = NULL;
+
+ struct config {
+ char *output_format;
+ __u64 zslba;
+ __u32 namespace_id;
+ int num_descs;
+ int state;
+ bool verbose;
+ 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("verbose", 'v', &cfg.verbose, verbose),
+ OPT_FLAG("extended", 'e', &cfg.extended, ext),
+ OPT_FLAG("partial", 'p', &cfg.partial, part),
+ OPT_END()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
+ if (cfg.verbose)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ if (cfg.extended) {
+ zdes = get_zdes_bytes(dev_fd(dev), cfg.namespace_id);
+ if (zdes < 0) {
+ err = zdes;
+ goto close_dev;
+ }
+ }
+
+ err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &id_ns);
+ if (err) {
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ err = nvme_zns_identify_ns(dev_fd(dev), cfg.namespace_id, &id_zns);
+ if (!err) {
+ /* get zsze field from zns id ns data - needed for offset calculation */
+ nvme_id_ns_flbas_to_lbaf_inuse(id_ns.flbas, &lbaf);
+ zsze = le64_to_cpu(id_zns.lbafe[lbaf].zsze);
+ } else {
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ log_len = sizeof(struct nvme_zone_report);
+ buff = calloc(1, log_len);
+ if (!buff) {
+ err = -ENOMEM;
+ goto close_dev;
+ }
+
+ err = nvme_zns_report_zones(dev_fd(dev), cfg.namespace_id, 0,
+ cfg.state, false, false,
+ log_len, buff,
+ NVME_DEFAULT_IOCTL_TIMEOUT, NULL);
+ if (err > 0) {
+ nvme_show_status(err);
+ goto free_buff;
+ } else if (err < 0) {
+ perror("zns report-zones");
+ goto free_buff;
+ }
+
+ total_nr_zones = le64_to_cpu(buff->nr_zones);
+
+ if (cfg.num_descs == -1)
+ cfg.num_descs = total_nr_zones;
+
+ nr_zones = cfg.num_descs;
+ if (nr_zones < nr_zones_chunks)
+ nr_zones_chunks = nr_zones;
+
+ log_len = sizeof(struct nvme_zone_report) + ((sizeof(struct nvme_zns_desc) * nr_zones_chunks) + (nr_zones_chunks * zdes));
+ report_size = log_len;
+
+ report = nvme_alloc_huge(report_size, &mh);
+ if (!report) {
+ perror("alloc");
+ err = -ENOMEM;
+ goto close_dev;
+ }
+
+ offset = cfg.zslba;
+
+ nvme_zns_start_zone_list(total_nr_zones, &zone_list, flags);
+
+ while (nr_zones_retrieved < nr_zones) {
+ if (nr_zones_retrieved >= nr_zones)
+ break;
+
+ if (nr_zones_retrieved + nr_zones_chunks > nr_zones) {
+ nr_zones_chunks = nr_zones - nr_zones_retrieved;
+ log_len = sizeof(struct nvme_zone_report) + ((sizeof(struct nvme_zns_desc) * nr_zones_chunks) + (nr_zones_chunks * zdes));
+ }
+
+ err = nvme_zns_report_zones(dev_fd(dev), cfg.namespace_id,
+ offset,
+ cfg.state, cfg.extended,
+ cfg.partial, log_len, report,
+ NVME_DEFAULT_IOCTL_TIMEOUT, NULL);
+ if (err > 0) {
+ nvme_show_status(err);
+ break;
+ }
+
+ if (!err)
+ nvme_show_zns_report_zones(report, nr_zones_chunks,
+ zdes, log_len, zone_list, flags);
+
+ nr_zones_retrieved += nr_zones_chunks;
+ offset = le64_to_cpu(report->entries[nr_zones_chunks-1].zslba) + zsze;
+ }
+
+ nvme_zns_finish_zone_list(total_nr_zones, zone_list, flags);
+
+free_buff:
+ free(buff);
+close_dev:
+ dev_close(dev);
+ return err;
+}
+
+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\n"
+ "using the slba of the zone, and the write will be appended from the\n"
+ "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, dfd = STDIN_FILENO, mfd = STDIN_FILENO;
+ unsigned int lba_size, meta_size;
+ void *buf = NULL, *mbuf = NULL;
+ __u16 nblocks, control = 0;
+ struct nvme_dev *dev;
+ __u64 result;
+ __u8 lba_index;
+ 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;
+ bool limited_retry;
+ bool fua;
+ __u32 namespace_id;
+ __u64 ref_tag;
+ __u16 lbat;
+ __u16 lbatm;
+ __u8 prinfo;
+ bool piremap;
+ bool 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_SUFFIX("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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ if (!cfg.data_size) {
+ fprintf(stderr, "Append size not provided\n");
+ errno = EINVAL;
+ goto close_dev;
+ }
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ err = nvme_identify_ns(dev_fd(dev), cfg.namespace_id, &ns);
+ if (err) {
+ nvme_show_status(err);
+ goto close_dev;
+ }
+
+ nvme_id_ns_flbas_to_lbaf_inuse(ns.flbas, &lba_index);
+ lba_size = 1 << ns.lbaf[lba_index].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_dev;
+ }
+
+ meta_size = ns.lbaf[lba_index].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_dev;
+ }
+
+ if (cfg.prinfo > 0xf) {
+ fprintf(stderr, "Invalid value for prinfo:%#x\n", cfg.prinfo);
+ errno = EINVAL;
+ goto close_dev;
+ }
+
+ if (cfg.data) {
+ dfd = open(cfg.data, O_RDONLY);
+ if (dfd < 0) {
+ perror(cfg.data);
+ goto close_dev;
+ }
+ }
+
+ 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 free_data;
+ }
+ }
+
+ 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_IO_LR;
+ if (cfg.fua)
+ control |= NVME_IO_FUA;
+ if (cfg.piremap)
+ control |= NVME_IO_ZNS_APPEND_PIREMAP;
+
+ struct nvme_zns_append_args args = {
+ .args_size = sizeof(args),
+ .fd = dev_fd(dev),
+ .nsid = cfg.namespace_id,
+ .zslba = cfg.zslba,
+ .nlb = nblocks,
+ .control = control,
+ .ilbrt_u64 = cfg.ref_tag,
+ .lbat = cfg.lbat,
+ .lbatm = cfg.lbatm,
+ .data_len = cfg.data_size,
+ .data = buf,
+ .metadata_len = cfg.metadata_size,
+ .metadata = mbuf,
+ .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
+ .result = &result,
+ };
+
+ gettimeofday(&start_time, NULL);
+ err = nvme_zns_append(&args);
+ 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_dev:
+ dev_close(dev);
+ return err;
+}
+
+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;
+ struct nvme_dev *dev;
+ int 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()
+ };
+
+ err = parse_and_open(&dev, argc, argv, desc, opts);
+ if (err)
+ return errno;
+
+ err = validate_output_format(cfg.output_format, &flags);
+ if (err < 0)
+ goto close_dev;
+
+ if (!cfg.namespace_id) {
+ err = nvme_get_nsid(dev_fd(dev), &cfg.namespace_id);
+ if (err < 0) {
+ perror("get-namespace-id");
+ goto close_dev;
+ }
+ }
+
+ err = nvme_get_log_zns_changed_zones(dev_fd(dev), cfg.namespace_id,
+ cfg.rae, &log);
+ if (!err)
+ nvme_show_zns_changed(&log, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("zns changed-zone-list");
+
+close_dev:
+ dev_close(dev);
+ return err;
+}
diff --git a/plugins/zns/zns.h b/plugins/zns/zns.h
new file mode 100644
index 0000000..43c4ecd
--- /dev/null
+++ b/plugins/zns/zns.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#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", NVME_VERSION),
+ COMMAND_LIST(
+ ENTRY("list", "List all NVMe devices with Zoned Namespace Command Set support", list)
+ ENTRY("id-ctrl", "Send NVMe Identify Zoned Namespace Controller, display structure", id_ctrl)
+ ENTRY("id-ns", "Send NVMe Identify Zoned Namespace Namespace, display structure", id_ns)
+ ENTRY("report-zones", "Report zones associated to a Zoned Namespace", report_zones)
+ ENTRY("reset-zone", "Reset one or more zones", reset_zone)
+ ENTRY("close-zone", "Close one or more zones", close_zone)
+ ENTRY("finish-zone", "Finish one or more zones", finish_zone)
+ ENTRY("open-zone", "Open one or more zones", open_zone)
+ ENTRY("offline-zone", "Offline one or more zones", offline_zone)
+ ENTRY("set-zone-desc", "Attach zone descriptor extension data to a zone", set_zone_desc)
+ ENTRY("zrwa-flush-zone", "Flush LBAs associated with a ZRWA to a zone.", zrwa_flush_zone)
+ ENTRY("changed-zone-list", "Retrieve the changed zone list log", changed_zone_list)
+ ENTRY("zone-mgmt-recv", "Send the zone management receive command", zone_mgmt_recv)
+ ENTRY("zone-mgmt-send", "Send the zone management send command", zone_mgmt_send)
+ ENTRY("zone-append", "Append data and metadata (if applicable) to a zone", zone_append)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/scripts/build.sh b/scripts/build.sh
new file mode 100755
index 0000000..470f39a
--- /dev/null
+++ b/scripts/build.sh
@@ -0,0 +1,230 @@
+#!/bin/bash
+set -e
+
+usage() {
+ echo "Usage: build.sh [-b [release|debug]] "
+ echo " [-c [gcc|clang]]"
+ echo " [-m [meson|muon]"
+ echo " [config]"
+ echo ""
+ echo "CI build script."
+ echo ""
+ echo " -b [release]|debug build type"
+ echo " -c [gcc]|clang compiler to use"
+ echo " -m [meson]|muon use meson or muon"
+ echo " -t [arm]|ppc64le|s390x cross compile target"
+ echo ""
+ echo "configs with meson:"
+ echo " [default] default settings"
+ echo " fallback download all dependencies"
+ echo " and build them as shared libraries"
+ echo " cross use cross toolchain to build"
+ echo " coverage build coverage report"
+ echo " appimage build AppImage target"
+ echo ""
+ echo "configs with muon:"
+ echo " [default] minimal static build"
+}
+
+BUILDTOOL=meson
+MESON=meson
+BUILDTYPE=release
+CROSS_TARGET=arm
+CC=${CC:-"gcc"}
+
+while getopts "b:c:m:t:" o; do
+ case "${o}" in
+ b)
+ BUILDTYPE="${OPTARG}"
+ ;;
+ c)
+ CC="${OPTARG}"
+ ;;
+ m)
+ BUILDTOOL="${OPTARG}"
+ ;;
+ t)
+ CROSS_TARGET="${OPTARG}"
+ ;;
+ *)
+ usage
+ exit 1
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+CONFIG=${1:-"default"}
+
+cd "$(git rev-parse --show-toplevel)" || exit 1
+
+BUILDDIR="$(pwd)/.build-ci"
+TOOLDIR="$(pwd)/.build-tools"
+
+fn_exists() { declare -F "$1" > /dev/null; }
+
+config_meson_default() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --force-fallback-for=libnvme \
+ -Dlibnvme:werror=false \
+ "${BUILDDIR}"
+}
+
+config_meson_fallback() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --wrap-mode=forcefallback \
+ --default-library=both \
+ -Dlibnvme:werror=false \
+ -Dopenssl:werror=false \
+ "${BUILDDIR}"
+}
+
+config_meson_cross() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --cross-file=.github/cross/ubuntu-cross-${CROSS_TARGET}.txt \
+ --force-fallback-for=libnvme \
+ -Dlibnvme:werror=false \
+ -Dlibnvme:python=disabled \
+ -Dlibnvme:openssl=disabled \
+ "${BUILDDIR}"
+}
+
+config_meson_coverage() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --force-fallback-for=libnvme \
+ -Dlibnvme:werror=false \
+ -Db_coverage=true \
+ "${BUILDDIR}"
+}
+
+config_meson_appimage() {
+ CC="${CC}" "${MESON}" setup \
+ --werror \
+ --buildtype="${BUILDTYPE}" \
+ --force-fallback-for=libnvme \
+ --prefix=/usr \
+ -Dlibnvme:werror=false \
+ "${BUILDDIR}"
+}
+
+build_meson() {
+ "${MESON}" compile \
+ -C "${BUILDDIR}"
+}
+
+test_meson() {
+ "${MESON}" test \
+ -C "${BUILDDIR}"
+}
+
+test_meson_coverage() {
+ "${MESON}" test \
+ -C "${BUILDDIR}"
+ ninja -C "${BUILDDIR}" coverage --verbose
+}
+
+install_meson_appimage() {
+ "${MESON}" install \
+ -C "${BUILDDIR}"
+}
+
+tools_build_samurai() {
+ if [ ! -d "${TOOLDIR}"/samurai ]; then
+ git clone --depth 1 https://github.com/michaelforney/samurai.git \
+ "${TOOLDIR}/samurai"
+ fi
+
+ if [[ -f "${TOOLDIR}/samurai/samu" ]]; then
+ return
+ fi
+
+ pushd "${TOOLDIR}/samurai" || exit 1
+ CC="${CC}" make
+ popd || exit 1
+}
+
+tools_build_muon() {
+ if [ ! -d "${TOOLDIR}/muon" ]; then
+ git clone --depth 1 https://git.sr.ht/~lattis/muon \
+ "${TOOLDIR}/muon"
+ fi
+
+ if [[ -f "${TOOLDIR}/build-muon/muon" ]]; then
+ return
+ fi
+
+ pushd "${TOOLDIR}/muon" || exit 1
+
+ CC="${CC}" CFLAGS="${CFLAGS} -std=c99" ninja="${SAMU}" ./bootstrap.sh stage1
+
+ CC="${CC}" ninja="${SAMU}" stage1/muon setup \
+ -Dprefix="${TOOLDIR}" \
+ -Ddocs=disabled \
+ -Dsamurai=disabled \
+ -Dbestline=disabled \
+ "${TOOLDIR}/build-muon"
+ "${SAMU}" -C "${TOOLDIR}/build-muon"
+ MUON="${BUILDDIR}/build-tools/.build-muon/muon"
+
+ # "${TOOLDIR}/build-muon/muon" \
+ # -C "${TOOLDIR}/build-muon" test
+
+ popd || exit 1
+}
+
+config_muon_default() {
+ # wrap_mode=forcefallback depends on git being available
+
+ CC="${CC}" CFLAGS="${CFLAGS}" ninja="${SAMU}" \
+ "${MUON}" setup \
+ -Ddefault_library=static \
+ -Dc_link_args="-static" \
+ -Dwrap_mode=forcefallback \
+ -Dlibnvme:json-c=disabled \
+ -Dlibnvme:python=disabled \
+ -Dlibnvme:openssl=disabled \
+ -Dlibnvme:keyutils=disabled \
+ -Djson-c=disabled \
+ "${BUILDDIR}"
+}
+
+build_muon() {
+ "${SAMU}" -C "${BUILDDIR}"
+}
+
+test_muon() {
+ ninja="${SAMU}" "${MUON}" -C "${BUILDDIR}" test
+ ldd "${BUILDDIR}/nvme" 2>&1 | grep 'not a dynamic executable' || exit 1
+}
+
+if [[ "${BUILDTOOL}" == "muon" ]]; then
+ SAMU="$(which samu 2> /dev/null)" || true
+ if [[ -z "${SAMU}" ]]; then
+ tools_build_samurai
+ SAMU="${TOOLDIR}/samurai/samu"
+ fi
+
+ MUON="$(which muon 2> /dev/null)" || true
+ if [[ -z "${MUON}" ]]; then
+ tools_build_muon
+ MUON="${TOOLDIR}/build-muon/muon"
+ fi
+fi
+
+echo "samu: ${SAMU}"
+echo "muon: ${MUON}"
+
+rm -rf "${BUILDDIR}"
+
+config_"${BUILDTOOL}"_"${CONFIG}"
+fn_exists "build_${BUILDTOOL}_${CONFIG}" && "build_${BUILDTOOL}_${CONFIG}" || build_"${BUILDTOOL}"
+fn_exists "test_${BUILDTOOL}_${CONFIG}" && "test_${BUILDTOOL}_${CONFIG}" || test_"${BUILDTOOL}"
+fn_exists "install_${BUILDTOOL}_${CONFIG}" && "install_${BUILDTOOL}_${CONFIG}" || true;
diff --git a/scripts/gen-hostnqn.sh b/scripts/gen-hostnqn.sh
new file mode 100644
index 0000000..b3edf14
--- /dev/null
+++ b/scripts/gen-hostnqn.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+nvme gen-hostnqn
diff --git a/scripts/latency b/scripts/latency
new file mode 100755
index 0000000..0a8cc48
--- /dev/null
+++ b/scripts/latency
@@ -0,0 +1,115 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2015 PMC-Sierra, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Stephen Bates <stephen.bates@pmcs.com>
+#
+# Description:
+# A shell script that calls the NVMe CLI multiple times to gather
+# latency data. Consider this a poor man's iometer or fio for QD=1
+# analysis. Of course this is below the file-system and block
+# layer so is a best case measurement.
+#
+
+DEVICE=
+WRITE=false
+COUNT=10
+DATA_SIZE=4096
+METADATA_SIZE=64
+
+RAND_BASE=temp.rand
+RAND_WFILE=${RAND_BASE}.write
+RAND_RFILE=${RAND_BASE}.read
+OUTPUT=latency.dat
+
+green=$(tput bold)$(tput setaf 2)
+red=$(tput bold)$(tput setaf 1)
+rst=$(tput sgr0)
+
+while getopts ":d:n:w" opt; do
+ case $opt in
+ d)
+ DEVICE=${OPTARG}
+ ;;
+ n)
+ COUNT=${OPTARG}
+ ;;
+ w)
+ echo "WARNING: Write mode enabled, this might trash your drive!"
+ WRITE=true
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ exit 1
+ ;;
+ :)
+ echo "Option -$OPTARG requires an argument." >&2
+ exit 1
+ ;;
+ esac
+done
+
+if [ "$COUNT" == "0" ]; then
+ echo "Count can not be 0"
+ exit 1
+fi
+
+if [ -z "$DEVICE" ]; then
+ echo "regress: You must specify a NVMe device using -d"
+ exit 1
+fi
+
+function run_test {
+ $* | grep -i latency >> ${OUTPUT} 2>&1
+ if (( $? )); then
+ echo ${red}"FAILED!"${rst}
+ echo "Failed running command: "
+ echo " $*"
+ exit 1
+ fi
+}
+
+rm -f ${OUTPUT} > /dev/null || exit -1
+make clean > /dev/null || exit -1
+make install > /dev/null || exit -1
+
+for i in `seq 1 ${COUNT}`;
+do
+ if $WRITE ; then
+ dd if=/dev/urandom of=${RAND_WFILE} bs=${DATA_SIZE} count=1
+ run_test nvme write ${DEVICE} --start-block=0 --block-count=0 \
+ --metadata-size=${METADATA_SIZE} --data-size=${DATA_SIZE} \
+ --data ${RAND_WFILE} --latency
+ rm ${RAND_WFILE} > /dev/null
+ else
+ run_test nvme read ${DEVICE} --start-block=0 --block-count=0 \
+ --metadata-size=${METADATA_SIZE} --data-size=${DATA_SIZE} \
+ --data ${RAND_RFILE} --latency
+ rm ${RAND_RFILE} > /dev/null
+ fi
+done
+
+# Calculate average latency
+SUM=0
+for i in `cat ${OUTPUT} | awk '{print $3}' | xargs`
+do
+ SUM=$(($SUM + $i))
+done
+AVERAGE=$(echo "scale=2; $SUM/$COUNT" | bc -l)
+echo "Average Latency: $AVERAGE us"
diff --git a/scripts/meson-vcs-tag.sh b/scripts/meson-vcs-tag.sh
new file mode 100755
index 0000000..8ce6924
--- /dev/null
+++ b/scripts/meson-vcs-tag.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+set -eu
+set -o pipefail
+
+dir="${1:?}"
+fallback="${2:?}"
+
+# Apparently git describe has a bug where it always considers the work-tree
+# dirty when invoked with --git-dir (even though 'git status' is happy). Work
+# around this issue by cd-ing to the source directory.
+cd "$dir"
+# Check that we have either .git/ (a normal clone) or a .git file (a work-tree)
+# and that we don't get confused if a tarball is extracted in a higher-level
+# git repository.
+[ -e .git ] && git describe --abbrev=7 --dirty=+ 2>/dev/null | sed 's/^v//' || echo "$fallback"
diff --git a/scripts/regress b/scripts/regress
new file mode 100755
index 0000000..302ff86
--- /dev/null
+++ b/scripts/regress
@@ -0,0 +1,113 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2015 PMC-Sierra, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Stephen Bates <stephen.bates@pmcs.com>
+#
+# Description:
+# Regression test-suite for the NVM Express CLI.
+#
+
+DEVICE=
+WRITE=false
+LIST=false
+
+RAND_BASE=temp.rand
+RAND_WFILE=${RAND_BASE}.write
+RAND_RFILE=${RAND_BASE}.read
+RAND_SIZE=4k
+
+green=$(tput bold)$(tput setaf 2)
+red=$(tput bold)$(tput setaf 1)
+rst=$(tput sgr0)
+
+while getopts ":d:wl" opt; do
+ case $opt in
+ d)
+ DEVICE=${OPTARG}
+ ;;
+ w)
+ echo "WARNING: Write mode enabled, this might trash your drive!"
+ WRITE=true
+ ;;
+ l)
+ LIST=true
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ exit 1
+ ;;
+ :)
+ echo "Option -$OPTARG requires an argument." >&2
+ exit 1
+ ;;
+ esac
+done
+
+if [ -z "$DEVICE" ]; then
+ echo "regress: You must specify a NVMe device using -d"
+ exit 1
+fi
+
+function print_pass_fail {
+ $* > /dev/null 2>&1
+ if (( $? )); then
+ echo ${red}"FAILED!"${rst}
+ echo "Failed running command: "
+ echo " $*"
+ exit 1
+ else
+ echo ${green}"PASSED!"${rst}
+ fi
+}
+
+function run_test {
+ LINE="$*"
+ printf " %-3s %-68s : " "RUN" "${LINE::67}"
+ print_pass_fail $*
+}
+
+make clean > /dev/null || exit -1
+make install > /dev/null || exit -1
+
+if $LIST ; then
+ run_test nvme list
+fi
+run_test nvme id-ctrl ${DEVICE}
+run_test nvme id-ns -raw-binary ${DEVICE}
+run_test nvme list-ns -n 1 ${DEVICE}
+run_test nvme get-ns-id ${DEVICE}
+run_test nvme get-log ${DEVICE} --log-id=2 --log-len=512
+run_test nvme fw-log ${DEVICE}
+run_test nvme fw-log ${DEVICE} -b
+run_test nvme smart-log ${DEVICE}
+run_test nvme error-log ${DEVICE}
+run_test nvme get-feature ${DEVICE} -f 7
+run_test nvme flush ${DEVICE}
+
+if $WRITE ; then
+ run_test dd if=/dev/urandom of=${RAND_WFILE} bs=${RAND_SIZE} count=1
+ run_test nvme write ${DEVICE} --start-block=0 --block-count=0 --data-size=${RAND_SIZE} --data ${RAND_WFILE}
+fi
+run_test nvme read ${DEVICE} --start-block=0 --block-count=0 --data-size=${RAND_SIZE} --data ${RAND_RFILE} --latency
+if $WRITE ; then
+ run_test diff ${RAND_RFILE} ${RAND_WFILE}
+ rm ${RAND_WFILE} > /dev/null
+fi
+rm ${RAND_RFILE} > /dev/null
diff --git a/scripts/release.sh b/scripts/release.sh
new file mode 100755
index 0000000..d2cbb08
--- /dev/null
+++ b/scripts/release.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+usage() {
+ echo "Usage: release.sh [-d] VERSION"
+ echo ""
+ echo "The script does all necessary steps to create a new release."
+ echo ""
+ echo " -d: no documentation update"
+ echo " -n: dry run"
+ echo ""
+ echo "Note: The version number needs to be exactly"
+ echo " '^v[\d]+.[\d]+(.[\d\]+(-rc[0-9]+)?$'"
+ echo ""
+ echo "example:"
+ echo " release.sh v2.1-rc0 # v2.1 release candidate 0"
+ echo " release.sh v2.1 # v2.1 release"
+}
+
+build_doc=true
+dry_run=false
+
+while getopts "dn" o; do
+ case "${o}" in
+ d)
+ build_doc=false
+ ;;
+ n)
+ dry_run=true
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+shift $((OPTIND-1))
+
+VERSION=${1:-}
+
+if [ -z "$VERSION" ] ; then
+ usage
+ exit 1
+fi
+
+# expected version regex
+re='^v([0-9]+\.[0-9]+(\.[0-9]+)?)(-rc[0-9]+)?$'
+
+# use the version string provided from the command line
+if [[ "$VERSION" =~ ${re} ]]; then
+ echo "valid version $VERSION string"
+
+ # remove the leading 'v'
+ ver="${VERSION#v}"
+else
+ echo "invalid version string $VERSION"
+ exit 1
+fi
+
+cd "$(git rev-parse --show-toplevel)" || exit 1
+
+if [[ -f subprojects/libnvme.wrap ]]; then
+ git -C subprojects/libnvme fetch --all
+
+ # extract the version string from libnvme by using the ref
+ # defined in libnvme.wrap.
+ libnvme_ref=$(sed -n "s/revision = \([0-9a-z]\+\)/\1/p" subprojects/libnvme.wrap)
+ libnvme_VERSION=$(git -C subprojects/libnvme describe "${libnvme_ref}")
+ if [[ "${libnvme_VERSION}" =~ ${re} ]]; then
+ echo "libnvme: valid version ${libnvme_VERSION} string"
+
+ # remove the leading 'v'
+ libnvme_ver="${libnvme_VERSION#v}"
+ else
+ echo "libnvme: invalid version string ${libnvme_VERSION}"
+ exit 1
+ fi
+fi
+
+if [[ -n $(git status -s) ]]; then
+ echo "tree is dirty."
+ if [[ "${dry_run}" = false ]]; then
+ exit 1
+ fi
+fi
+
+if [ "$(git rev-parse --abbrev-ref HEAD)" != "master" ] ; then
+ echo "currently not on master branch. abort."
+ exit 1
+fi
+
+# update all docs
+doc_dir=""
+if [ -d "Documentation" ]; then
+ doc_dir="Documentation"
+elif [ -d "doc" ]; then
+ doc_dir="doc"
+else
+ echo "documentation directory not found"
+ exit 1
+fi
+
+# update meson.build
+sed -i -e "0,/[ \t]version: /s/\([ \t]version: \).*/\1\'$ver\',/" meson.build
+if [[ -f subprojects/libnvme.wrap ]]; then
+ sed -i -e "s/\(dependency('libnvme', version: '>=\)\([\.1-9]\+\)/\1$libnvme_ver/" meson.build
+fi
+
+if [[ "${dry_run}" = false ]]; then
+ git add meson.build
+ git commit -s -m "build: Update version to $VERSION"
+fi
+
+if [ "$build_doc" = true ]; then
+ # update documentation
+ ./scripts/update-docs.sh
+ if [[ "${dry_run}" = false ]]; then
+ git add $doc_dir
+ git commit -s -m "doc: Regenerate all docs for $VERSION"
+ fi
+fi
+
+if [[ "${dry_run}" = true ]]; then
+ exit 0
+fi
+
+git tag -s -m "Release $VERSION" "$VERSION"
+git push --dry-run origin "$VERSION"^{}:master tag "$VERSION"
+
+read -p "All good? Ready to push changes to remote? [Yy]" -n 1 -r
+echo
+if [[ $REPLY =~ ^[Yy]$ ]]; then
+ git push origin "$VERSION"^{}:master tag "$VERSION"
+fi
diff --git a/scripts/update-docs.sh b/scripts/update-docs.sh
new file mode 100755
index 0000000..6fe1132
--- /dev/null
+++ b/scripts/update-docs.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+cd "$(git rev-parse --show-toplevel)" || exit 1
+
+BUILDDIR="$(mktemp -d)"
+trap 'rm -rf -- $BUILDDIR' EXIT
+
+meson setup \
+ -Ddocs=all \
+ -Ddocs-build=true \
+ --force-fallback-for=libnvme \
+ "${BUILDDIR}"
+meson compile -C "${BUILDDIR}"
+find "${BUILDDIR}/Documentation" -maxdepth 1 \
+ \( -name '*.1' -o -name '*.html' \) \
+ -exec cp {} Documentation/ \;
diff --git a/subprojects/json-c.wrap b/subprojects/json-c.wrap
new file mode 100644
index 0000000..569f78e
--- /dev/null
+++ b/subprojects/json-c.wrap
@@ -0,0 +1,13 @@
+[wrap-file]
+directory = json-c-0.17
+source_url = https://s3.amazonaws.com/json-c_releases/releases/json-c-0.17.tar.gz
+source_filename = json-c-0.17.tar.gz
+source_hash = 7550914d58fb63b2c3546f3ccfbe11f1c094147bd31a69dcd23714d7956159e6
+patch_filename = json-c_0.17-2_patch.zip
+patch_url = https://wrapdb.mesonbuild.com/v2/json-c_0.17-2/get_patch
+patch_hash = c1a9a7e2ea6bed89a59e13a5684be25899a5a510963154c4450c5a492b8f3984
+source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/json-c_0.17-2/json-c-0.17.tar.gz
+wrapdb_version = 0.17-2
+
+[provide]
+json-c = json_c_dep
diff --git a/subprojects/libnvme.wrap b/subprojects/libnvme.wrap
new file mode 100644
index 0000000..5bf470a
--- /dev/null
+++ b/subprojects/libnvme.wrap
@@ -0,0 +1,7 @@
+[wrap-git]
+url = https://github.com/linux-nvme/libnvme.git
+revision = bff7dda7e2a0f883d0b89e23fed725c916de3e61
+
+[provide]
+libnvme = libnvme_dep
+libnvme-mi = libnvme_mi_dep
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..a5fa708
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,98 @@
+nvmetests
+=========
+
+ This contains a NVMe tests framework. The purpose of this framework
+ to use nvme cli and test various supported commands and scenarios for
+ NVMe device.
+
+ In current implementation this framework uses nvme-cli to
+ interact with underlying controller/namespace.
+
+ Note these tests expect to run against real hardware and will
+ read and write data to /dev/nvme0!
+
+ DO NOT RUN THEM IF YOU DO NOT KNOW WHAT YOU ARE DOING!
+
+ You have been warned.
+
+1. Common Package Dependencies
+------------------------------
+
+ 1. Python(>= 3.3)
+ 2. nose2 (Installation guide http://nose2.readthedocs.io/)
+ 3. flake8 (https://pypi.python.org/pypi/flake8)
+ 4. mypy (https://pypi.org/project/mypy/)
+ 5. autopep8 (https://pypi.org/project/autopep8/)
+ 6. isort (https://pypi.org/project/isort/)
+
+ Python package management system pip can be used to install most of the
+ listed packages(https://pip.pypa.io/en/stable/installing/) :-
+ $ pip install nose2 flake8 mypy autopep8 isort
+
+2. Overview
+-----------
+
+ This framework follows simple class hierarchy. Each test file contains
+ one test. Each test is direct subclass or indirect subclass of TestNVMe
+ class which represents one testcase. To write a new testcase one can copy
+ existing template "nvme_simple_template_test.py" and start adding new
+ testcase specific functionality. For detailed information please look into
+ section 3.
+
+ For more information about tests, class hierarchy and code please refer :-
+
+ 1. Documentation :- html/
+ 2. Class Index :- html/index.html
+ 3. Class Hierarchy :- html/class-tree.html
+
+ For each testcase it will create log directory mentioned in
+ configuration file. This directory will be used for a temporary files
+ and storing execution logs of each testcases. Current implementation stores
+ stdout and stderr for each testcase under log directory, e.g. :-
+
+ $ tree nvmetests/
+ nvmetests/
+ ├── TestNVMeAttachDetachNSCmd
+ │   ├── stderr.log
+ │   └── stdout.log
+ ├── TestNVMeFlushCmd
+ │   ├── stderr.log
+ │   └── stdout.log
+ └── TestNVMeFormatCmd
+ ├── stderr.log
+ └── stdout.log
+ .
+ .
+ .
+
+3. Walk-Through Example for writing a new testcase
+--------------------------------------------------
+ 1. Copy simple test template file from current directory
+ with appropriate name, replace "simple_template" with testcase name
+ in new file name. Update config.json if necessary.
+ 2. Write a testcase main function, make sure its name is starting with
+ test_*.
+ 3. Based on the requirement one can inherit TestNVMe or TestNVMeIO
+ class.
+ 4. Write test precondition code into setUp. Make sure you are calling
+ super class setUp.
+ 5. Write test post condition code into tearDown. Make sure you are calling
+ super class tearDown.
+ 6. Before writing a new function have a look into TestNVMe to see if it
+ can be reused.
+ 7. Once testcase is ready make sure :-
+ a. Run flake8, mypy, autopep8 and isort on the testcase and fix
+ errors/warnings.
+ - Example "$ ninja -C .build lint-python" will run flake8 and
+ mypy on all the python files in current directory.
+ - Example "$ ninja -C .build format-python" will run autopep8 and
+ isort on all the python files in the current directory.
+
+4. Running testcases with framework
+-----------------------------------
+ 1. Running single testcase (in the source tree) with nose2 :-
+ $ nose2 --verbose --start-dir tests nvme_writezeros_test
+ $ nose2 --verbose --start-dir tests nvme_read_write_test
+
+ 2. Running all the testcases (in the build root directory) with ninja :-
+ $ ninja test -C .build
diff --git a/tests/TODO b/tests/TODO
new file mode 100644
index 0000000..69806a9
--- /dev/null
+++ b/tests/TODO
@@ -0,0 +1,14 @@
+nvmetests TODO List
+===================
+
+Feature list (with priority):-
+------------------------------
+ 1. PRE and POST section improvements :-
+ a. Add functionality to load and unload driver.
+ b. Make sure default namespace is present, if not create one before
+ any test begins. Read the default namespace size from config file.
+ 2. Add system statistics collection in PRE and POST section of testcase.
+ 3. Create execution summary file under log directory at the end of each
+ run.
+ 4. Add tracing functionality to track overall and current progress of the
+ testcase.
diff --git a/tests/config.json b/tests/config.json
new file mode 100644
index 0000000..098fba8
--- /dev/null
+++ b/tests/config.json
@@ -0,0 +1,5 @@
+{
+ "controller" : "/dev/nvme0",
+ "ns1": "/dev/nvme0n1",
+ "log_dir": "nvmetests/"
+}
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..f8c6aa2
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,99 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+infra = [
+ 'config.json',
+ 'nvme_test.py',
+ 'nvme_test_io.py',
+ 'nvme_test_logger.py',
+ 'nvme_simple_template_test.py',
+]
+
+tests = [
+ 'nvme_attach_detach_ns_test.py',
+ 'nvme_compare_test.py',
+ 'nvme_create_max_ns_test.py',
+ 'nvme_error_log_test.py',
+ 'nvme_flush_test.py',
+ 'nvme_format_test.py',
+ 'nvme_fw_log_test.py',
+ 'nvme_get_features_test.py',
+ 'nvme_id_ctrl_test.py',
+ 'nvme_id_ns_test.py',
+ 'nvme_read_write_test.py',
+ 'nvme_smart_log_test.py',
+ 'nvme_writeuncor_test.py',
+ 'nvme_writezeros_test.py',
+ 'nvme_copy_test.py',
+ 'nvme_dsm_test.py',
+ 'nvme_verify_test.py',
+ 'nvme_lba_status_log_test.py',
+ 'nvme_get_lba_status_test.py',
+ 'nvme_ctrl_reset_test.py',
+]
+
+runtests = find_program('nose2', required : false)
+
+if meson.version().version_compare('>= 0.56')
+ nvmecli_path = meson.project_build_root()
+else
+ nvmecli_path = meson.build_root()
+endif
+
+if runtests.found()
+ foreach file : infra + tests
+ configure_file(
+ input: file,
+ output: file,
+ copy: true)
+ endforeach
+
+ foreach t : tests
+ t_name = t.split('.')[0]
+ test(t_name, runtests,
+ args: ['--verbose', '--start-dir', meson.current_build_dir(), t_name],
+ env: ['PATH=' + nvmecli_path + ':/usr/bin:/usr/sbin'],
+ timeout: 500)
+ endforeach
+endif
+
+python_module = import('python')
+
+python = python_module.find_installation('python3')
+
+mypy = find_program(
+ 'mypy',
+ required : false,
+)
+flake8 = find_program(
+ 'flake8',
+ required : false,
+)
+linter_script = files('run_py_linters.py')
+
+if mypy.found() and flake8.found()
+ run_target(
+ 'lint-python',
+ command : [python, linter_script, 'lint'],
+ )
+else
+ message('Mypy or Flake8 not found. Python linting disabled')
+endif
+
+
+autopep8 = find_program(
+ 'autopep8',
+ required : false,
+)
+isort = find_program(
+ 'isort',
+ required : false,
+)
+
+if autopep8.found() and isort.found()
+ run_target(
+ 'format-python',
+ command : [python, linter_script, 'format'],
+ )
+else
+ message('autopep8 or isort not found. Python formatting disabled')
+endif
diff --git a/tests/nvme_attach_detach_ns_test.py b/tests/nvme_attach_detach_ns_test.py
new file mode 100644
index 0000000..075f211
--- /dev/null
+++ b/tests/nvme_attach_detach_ns_test.py
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Namespace Management Testcase:-
+
+ 1. Create Namespace and validate.
+ 2. Attach Namespace to controller.
+ 3. Run IOs on Namespace under test.
+ 4. Detach Namespace from controller.
+ 5. Delete Namespace.
+"""
+
+import time
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeAttachDetachNSCmd(TestNVMe):
+
+ """
+ Represents Attach, Detach namespace testcase.
+
+ - Attributes:
+ - dps : data protection information.
+ - flabs : LBA format information.
+ - nsze : namespace size.
+ - ncap : namespace capacity.
+ - ctrl_id : controller id.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeAttachDetachNSCmd """
+ super().setUp()
+ self.dps = 0
+ self.flbas = 0
+ self.nsze = 0x1400000
+ self.ncap = 0x1400000
+ self.setup_log_dir(self.__class__.__name__)
+ self.ctrl_id = self.get_ctrl_id()
+ self.delete_all_ns()
+ time.sleep(1)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeAttachDetachNSCmd
+
+ - Create primary namespace.
+ - Attach it to controller.
+ - Call super class's destructor.
+ """
+ self.assertEqual(self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps), 0)
+ self.attach_ns(self.ctrl_id, self.default_nsid)
+ super().tearDown()
+
+ def test_attach_detach_ns(self):
+ """ Testcase main """
+ err = self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps)
+ self.assertEqual(err, 0)
+ self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
+
+ self.run_ns_io(self.default_nsid, 0)
+
+ self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
+ self.nvme_reset_ctrl()
diff --git a/tests/nvme_compare_test.py b/tests/nvme_compare_test.py
new file mode 100644
index 0000000..8dfce04
--- /dev/null
+++ b/tests/nvme_compare_test.py
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Compare Command Testcase:-
+
+ 1. Create a data file 1 with pattern 1515 to write.
+ 2. Create a data file 2 with pattern 2525 to compare with.
+ 3. Write a block of data pattern using data file1.
+ 4. Compare written block to data file 2's pattern; shall fail.
+ 5. Compare written block to data file1's pattern; shall pass.
+
+"""
+
+from nvme_test_io import TestNVMeIO
+
+
+class TestNVMeCompareCmd(TestNVMeIO):
+
+ """
+ Represents Compare Testcase. Inherits TestNVMeIO class.
+
+ - Attributes:
+ - data_size : data size to perform IO.
+ - start_block : starting block of to perform IO.
+ - compare_file : data file to use in nvme compare command.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeCompareCmd """
+ super().setUp()
+ self.data_size = 1024
+ self.start_block = 1023
+ self.setup_log_dir(self.__class__.__name__)
+ self.compare_file = self.test_log_dir + "/" + "compare_file.txt"
+ self.write_file = self.test_log_dir + "/" + self.write_file
+ self.create_data_file(self.write_file, self.data_size, "15")
+ self.create_data_file(self.compare_file, self.data_size, "25")
+
+ def tearDown(self):
+ """ Post Section for TestNVMeCompareCmd """
+ super().tearDown()
+
+ def nvme_compare(self, cmp_file):
+ """ Wrapper for nvme compare command.
+ - Args:
+ - cmp_file : data file used in nvme compare command.
+ - Returns:
+ - return code of the nvme compare command.
+ """
+ compare_cmd = "nvme compare " + self.ns1 + " --start-block=" + \
+ str(self.start_block) + " --block-count=" + \
+ str(self.block_count) + " --data-size=" + \
+ str(self.data_size) + " --data=" + cmp_file
+ return self.exec_cmd(compare_cmd)
+
+ def test_nvme_compare(self):
+ """ Testcase main """
+ self.assertEqual(self.nvme_write(), 0)
+ self.assertNotEqual(self.nvme_compare(self.compare_file), 0)
+ self.assertEqual(self.nvme_compare(self.write_file), 0)
diff --git a/tests/nvme_copy_test.py b/tests/nvme_copy_test.py
new file mode 100644
index 0000000..a547231
--- /dev/null
+++ b/tests/nvme_copy_test.py
@@ -0,0 +1,113 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Authors: Arunpandian J <apj.arun@samsung.com>
+# Joy Gu <jgu@purestorage.com>
+
+"""
+NVMe Copy Testcase:-
+
+ 1. Issue copy command on set of block; shall pass.
+ 2. If cross-namespace copy formats are supported, enable and test
+ cross-namespace copy formats.
+
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeCopy(TestNVMe):
+
+ """
+ Represents NVMe Copy testcase.
+ - Attributes:
+ - ocfs : optional copy formats supported
+ - host_behavior_data : host behavior support data to restore during teardown
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeCopy """
+ super().setUp()
+ print("\nSetting up test...")
+ self.ocfs = self.get_ocfs()
+ cross_namespace_copy = self.ocfs & 0xc
+ if cross_namespace_copy:
+ # get host behavior support data
+ get_features_cmd = ["nvme", "get-feature", self.ctrl, "--feature-id=0x16", "--data-len=512", "-b"]
+ print("Running command:", " ".join(get_features_cmd))
+ self.host_behavior_data = subprocess.check_output(get_features_cmd)
+ # enable cross-namespace copy formats
+ if self.host_behavior_data[4] & cross_namespace_copy:
+ # skip if already enabled
+ print("Cross-namespace copy already enabled, skipping set-features")
+ self.host_behavior_data = None
+ else:
+ data = self.host_behavior_data[:4] + cross_namespace_copy.to_bytes(2, 'little') + self.host_behavior_data[6:]
+ set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"]
+ print("Running command:", " ".join(set_features_cmd))
+ proc = subprocess.Popen(set_features_cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ proc.communicate(input=data)
+ self.assertEqual(proc.returncode, 0, "Failed to enable cross-namespace copy formats")
+ get_ns_id_cmd = ["nvme", "get-ns-id", self.ns1]
+ print("Running command:", " ".join(get_ns_id_cmd))
+ output = subprocess.check_output(get_ns_id_cmd)
+ self.ns1_nsid = int(output.decode().strip().split(':')[-1])
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeCopy """
+ print("Tearing down test...")
+ if self.host_behavior_data:
+ # restore saved host behavior support data
+ set_features_cmd = ["nvme", "set-feature", self.ctrl, "--feature-id=0x16", "--data-len=512"]
+ print("Running command:", " ".join(set_features_cmd))
+ proc = subprocess.Popen(set_features_cmd,
+ stdout=subprocess.PIPE,
+ stdin=subprocess.PIPE)
+ proc.communicate(input=self.host_behavior_data)
+ super().tearDown()
+
+ def copy(self, sdlba, blocks, slbs, **kwargs):
+ """ Wrapper for nvme copy
+ - Args:
+ - sdlba : destination logical block address
+ - blocks : number of logical blocks (0-based)
+ - slbs : source range logical block address
+ - descriptor_format : copy descriptor format (optional)
+ - snsids : source namespace id (optional)
+ - sopts : source options (optional)
+ - Returns:
+ - None
+ """
+ # skip if descriptor format not supported (default format is 0)
+ desc_format = kwargs.get("descriptor_format", 0)
+ if not self.ocfs & (1 << desc_format):
+ print(f"Skip copy because descriptor format {desc_format} is not supported")
+ return
+ # build copy command
+ copy_cmd = f"nvme copy {self.ns1} --format={desc_format} --sdlba={sdlba} --blocks={blocks} --slbs={slbs}"
+ if "snsids" in kwargs:
+ copy_cmd += f" --snsids={kwargs['snsids']}"
+ if "sopts" in kwargs:
+ copy_cmd += f" --sopts={kwargs['sopts']}"
+ # run and assert success
+ print("Running command:", copy_cmd)
+ self.assertEqual(self.exec_cmd(copy_cmd), 0)
+
+ def test_copy(self):
+ """ Testcase main """
+ print("Running test...")
+ self.copy(0, 1, 2, descriptor_format=0)
+ self.copy(0, 1, 2, descriptor_format=1)
+ self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid)
+ self.copy(0, 1, 2, descriptor_format=2, snsids=self.ns1_nsid, sopts=0)
+ self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid)
+ self.copy(0, 1, 2, descriptor_format=3, snsids=self.ns1_nsid, sopts=0)
diff --git a/tests/nvme_create_max_ns_test.py b/tests/nvme_create_max_ns_test.py
new file mode 100644
index 0000000..bda93e1
--- /dev/null
+++ b/tests/nvme_create_max_ns_test.py
@@ -0,0 +1,100 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Namespace Management Testcase:-
+
+ 1. Create Maximum number of Namespaces and validate.
+ 2. Attach all Namespaces to controller.
+ 3. Run IOs on Namespace under test.
+ 4. Detach Maximum number of Namespaces from controller.
+ 5. Delete all Namespaces.
+"""
+
+import time
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeCreateMaxNS(TestNVMe):
+
+ """
+ Represents Attach, Detach namespace testcase.
+
+ - Attributes:
+ - dps : data protection information.
+ - flbas : LBA format information.
+ - nsze : namespace size.
+ - ncap : namespace capacity.
+ - ctrl_id : controller id.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeAttachDetachNSCmd """
+ super().setUp()
+ self.dps = 0
+ self.flbas = 0
+ self.nsze = int(self.get_ncap() /
+ self.get_format() / self.get_max_ns())
+ self.ncap = self.nsze
+ self.setup_log_dir(self.__class__.__name__)
+ self.max_ns = self.get_max_ns()
+ self.ctrl_id = self.get_ctrl_id()
+ self.delete_all_ns()
+ time.sleep(1)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeAttachDetachNSCmd
+
+ - Create primary namespace.
+ - Attach it to controller.
+ - Call super class's destructor.
+ """
+ self.assertEqual(self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps), 0)
+ self.attach_ns(self.ctrl_id, self.default_nsid)
+ super.tearDown()
+
+ def test_attach_detach_ns(self):
+ """ Testcase main """
+ for nsid in range(1, self.max_ns):
+ print("##### Creating " + str(nsid))
+ err = self.create_and_validate_ns(nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps)
+ self.assertEqual(err, 0)
+ print("##### Attaching " + str(nsid))
+ self.assertEqual(self.attach_ns(self.ctrl_id, nsid), 0)
+ print("##### Running IOs in " + str(nsid))
+ self.run_ns_io(nsid, 0)
+
+ for nsid in range(1, self.max_ns):
+ print("##### Detaching " + str(nsid))
+ self.assertEqual(self.detach_ns(self.ctrl_id, nsid), 0)
+ print("#### Deleting " + str(nsid))
+ self.assertEqual(self.delete_and_validate_ns(nsid), 0)
+ self.nvme_reset_ctrl()
diff --git a/tests/nvme_ctrl_reset_test.py b/tests/nvme_ctrl_reset_test.py
new file mode 100644
index 0000000..b8b3c3b
--- /dev/null
+++ b/tests/nvme_ctrl_reset_test.py
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Author: Arunpandian J <arun.j@samsung.com>
+
+"""
+NVMe controller reset Testcase:-
+
+ 1. Execute nvme controller reset.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeCtrlReset(TestNVMe):
+
+ """
+ Represents NVMe Controller reset testcase.
+ - Attributes:
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeCtrlReset """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeCtrlReset """
+ super().tearDown()
+
+ def ctrl_reset(self):
+ """ Wrapper for nvme controller reset
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme controller reset.
+ """
+ ctrl_reset_cmd = "nvme reset " + self.ctrl
+ return self.exec_cmd(ctrl_reset_cmd)
+
+ def test_ctrl_reset(self):
+ """ Testcase main """
+ self.assertEqual(self.ctrl_reset(), 0)
diff --git a/tests/nvme_dsm_test.py b/tests/nvme_dsm_test.py
new file mode 100644
index 0000000..d92bf58
--- /dev/null
+++ b/tests/nvme_dsm_test.py
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Author: Arunpandian J <apj.arun@samsung.com>
+
+"""
+NVMe DSM Testcase:-
+
+ 1. Issue DSM command on set of block; shall pass.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeDsm(TestNVMe):
+
+ """
+ Represents NVMe Verify testcase.
+ - Attributes:
+ - start_block : starting block of to verify operation.
+ - range : Range of blocks for DSM operation.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeDsm """
+ super().setUp()
+ self.start_block = 0
+ self.range = 0
+ self.namespace = 1
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeDsm """
+ super().tearDown()
+
+ def dsm(self):
+ """ Wrapper for nvme verify
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme dsm command.
+ """
+ dsm_cmd = "nvme dsm " + self.ctrl + \
+ " --namespace-id=" + str(self.namespace) + \
+ " --blocks=" + str(self.range) + \
+ " --slbs=" + str(self.start_block)
+ return self.exec_cmd(dsm_cmd)
+
+ def test_dsm(self):
+ """ Testcase main """
+ self.assertEqual(self.dsm(), 0)
diff --git a/tests/nvme_error_log_test.py b/tests/nvme_error_log_test.py
new file mode 100644
index 0000000..ba91c02
--- /dev/null
+++ b/tests/nvme_error_log_test.py
@@ -0,0 +1,64 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Smart Log Verification Testcase:-
+
+ 1. Execute error-log on controller.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeErrorLogCmd(TestNVMe):
+
+ """
+ Represents Smart Log testcae.
+
+ - Attributes:
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeErrorLogCmd """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeErrorLogCmd
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_error_log_ctrl(self):
+ """ Wrapper for executing error-log on controller.
+ - Args:
+ - None:
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ return self.get_error_log()
+
+ def test_get_error_log(self):
+ """ Testcase main """
+ self.assertEqual(self.get_error_log_ctrl(), 0)
diff --git a/tests/nvme_flush_test.py b/tests/nvme_flush_test.py
new file mode 100644
index 0000000..e4f127d
--- /dev/null
+++ b/tests/nvme_flush_test.py
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Flush Command Testcase:-
+
+ 1. Execute nvme flush on controller.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeFlushCmd(TestNVMe):
+
+ """
+ Represents Flush Testcase. Inherits TestNVMe class.
+
+ - Attributes:
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeFlushCmd """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeFlushCmd """
+ super().tearDown()
+
+ def nvme_flush(self):
+ """ Wrapper for nvme flush command.
+ - Args:
+ - None
+ - Returns:
+ - None
+ """
+ flush_cmd = "nvme flush " + self.ctrl + " -n " + str(self.default_nsid)
+ print(flush_cmd)
+ return self.exec_cmd(flush_cmd)
+
+ def test_nvme_flush(self):
+ """ Testcase main """
+ self.assertEqual(self.nvme_flush(), 0)
diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py
new file mode 100644
index 0000000..40635c1
--- /dev/null
+++ b/tests/nvme_format_test.py
@@ -0,0 +1,150 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+Namespace Format testcase :-
+
+ 1. Create, attach, detach, delete primary namespace and
+ extract the supported format information from default namespace:-
+ - List of the supported format.
+ - List of Metadata Size per format. Based on this we calculate
+ data protection parameter at the time of namespace.
+ - List of LBA Data Size per format.
+ 2. Use the collected information and iterate through each supported
+ format:-
+ - Create namespace.
+ - Attach namespace.
+ - Run IOs on the namespace under test.
+ - Detach namespace
+ - Delete Namespace.
+"""
+
+import subprocess
+import time
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeFormatCmd(TestNVMe):
+
+ """
+ Represents Format testcase.
+
+ - Attributes:
+ - dps : data protection information.
+ - flabs : LBA format information.
+ - nsze : namespace size.
+ - ncap : namespace capacity.
+ - ctrl_id : controller id.
+ - lba_format_list : lis of supported format.
+ - ms_list : list of metadat size per format.
+ - lbads_list : list of LBA data size per format.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeFormatCmd """
+ super().setUp()
+ self.dps = 0 # ns data protection settings
+ self.flbas = 0 # ns formattes logical block settings
+ self.nsze = 0x1400000 # ns size
+ self.ncap = 0x1400000 # ns capacity
+ self.ctrl_id = self.get_ctrl_id()
+ self.lba_format_list = []
+ self.ms_list = []
+ self.lbads_list = []
+ self.test_log_dir = self.log_dir + "/" + self.__class__.__name__
+ self.setup_log_dir(self.__class__.__name__)
+ self.delete_all_ns()
+ time.sleep(1)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeFormatCmd
+
+ - Create primary namespace.
+ - Attach it to controller.
+ - Call super class's destructor.
+ """
+ self.assertEqual(self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps), 0)
+ self.attach_ns(self.ctrl_id, self.default_nsid)
+ super().tearDown()
+
+ def attach_detach_primary_ns(self):
+ """ Extract supported format information using default namespace """
+ self.assertEqual(self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps), 0)
+ self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
+ # read lbaf information
+ id_ns = "nvme id-ns " + self.ctrl + \
+ " -n1 | grep ^lbaf | awk '{print $2}' | tr -s \"\\n\" \" \""
+ proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.lba_format_list = proc.stdout.read().strip().split(" ")
+ if proc.wait() == 0:
+ # read lbads information
+ id_ns = "nvme id-ns " + self.ctrl + \
+ " -n1 | grep ^lbaf | awk '{print $5}'" + \
+ " | cut -f 2 -d ':' | tr -s \"\\n\" \" \""
+ proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.lbads_list = proc.stdout.read().strip().split(" ")
+ # read metadata information
+ id_ns = "nvme id-ns " + self.ctrl + \
+ " -n1 | grep ^lbaf | awk '{print $4}'" + \
+ " | cut -f 2 -d ':' | tr -s \"\\n\" \" \""
+ proc = subprocess.Popen(id_ns, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.ms_list = proc.stdout.read().strip().split(" ")
+ self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
+ self.nvme_reset_ctrl()
+
+ def test_format_ns(self):
+ """ Testcase main """
+ # extract the supported format information.
+ self.attach_detach_primary_ns()
+
+ # iterate through all supported format
+ for i in range(0, len(self.lba_format_list)):
+ print("\nlba format " + str(self.lba_format_list[i]) +
+ " lbad " + str(self.lbads_list[i]) +
+ " ms " + str(self.ms_list[i]))
+ metadata_size = 1 if self.ms_list[i] == '8' else 0
+ err = self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.lba_format_list[i],
+ metadata_size)
+ self.assertEqual(err, 0)
+ self.assertEqual(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
+ self.run_ns_io(self.default_nsid, self.lbads_list[i])
+ time.sleep(5)
+ self.assertEqual(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ self.assertEqual(self.delete_and_validate_ns(self.default_nsid), 0)
+ self.nvme_reset_ctrl()
diff --git a/tests/nvme_fw_log_test.py b/tests/nvme_fw_log_test.py
new file mode 100644
index 0000000..b670671
--- /dev/null
+++ b/tests/nvme_fw_log_test.py
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Madhusudhana S.J <madhusudhana.sj@wdc.com>
+# Author: Dong Ho <dong.ho@wdc.com>
+#
+"""
+NVMe Firmware Log Testcase :-
+
+ 1. Execute fw-log on a device.
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeFwLogCmd(TestNVMe):
+
+ """
+ Represents NVMe Firmware Log test.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeFwLogCmd. """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeSimpleTestTemplate.
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_fw_log(self):
+ """ Wrapper for executing nvme fw-log.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ err = 0
+ fw_log_cmd = "nvme fw-log " + self.ctrl
+ proc = subprocess.Popen(fw_log_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ fw_log_output = proc.communicate()[0]
+ print("\n" + fw_log_output + "\n")
+ err = proc.wait()
+ return err
+
+ def test_fw_log(self):
+ """ Testcase main """
+ self.assertEqual(self.get_fw_log(), 0)
diff --git a/tests/nvme_get_features_test.py b/tests/nvme_get_features_test.py
new file mode 100644
index 0000000..974fc34
--- /dev/null
+++ b/tests/nvme_get_features_test.py
@@ -0,0 +1,108 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+Get Features Testcase:-
+
+Test the Mandatory features with get features command:-
+ 1. 01h M Arbitration.
+ 2. 02h M Power Management.
+ 3. 04h M Temperature Threshold.
+ 4. 05h M Error Recovery.
+ 5. 07h M Number of Queues.
+ 6. 08h M Interrupt Coalescing.
+ 7. 09h M Interrupt Vector Configuration.
+ 8. 0Ah M Write Atomicity Normal.
+ 9. 0Bh M Asynchronous Event Configuration.
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeGetMandatoryFeatures(TestNVMe):
+
+ """
+ Represents Get Features testcase.
+
+ - Attributes:
+ - feature_id_list : list of the mandatory features.
+ - get_vector_list_cmd : vector list collection for 09h.
+ - vector_list_len : number of the interrupt vectors.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeGetMandatoryFeatures """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+ self.feature_id_list = ["0x01", "0x02", "0x04", "0x05", "0x07",
+ "0x08", "0x09", "0x0A", "0x0B"]
+ 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,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.vector_list_len = len(proc.stdout.read().strip().split(" "))
+
+ def tearDown(self):
+ """ Post Section for TestNVMeGetMandatoryFeatures
+
+ Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_mandatory_features(self, feature_id):
+ """ Wrapper for NVMe get features command
+ - Args:
+ - feature_id : feature id to be used with get feature command.
+ - Returns:
+ - None
+ """
+ if str(feature_id) == "0x09":
+ for vector in range(self.vector_list_len):
+ get_feat_cmd = "nvme get-feature " + self.ctrl + \
+ " --feature-id=" + str(feature_id) + \
+ " --cdw11=" + str(vector) + " -H"
+ proc = subprocess.Popen(get_feat_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ feature_output = proc.communicate()[0]
+ print(feature_output)
+ self.assertEqual(proc.wait(), 0)
+ else:
+ get_feat_cmd = "nvme get-feature " + self.ctrl + \
+ " --feature-id=" + str(feature_id) + " -H"
+ proc = subprocess.Popen(get_feat_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ feature_output = proc.communicate()[0]
+ print(feature_output)
+ self.assertEqual(proc.wait(), 0)
+
+ def test_get_mandatory_features(self):
+ """ Testcase main """
+ for feature_id in self.feature_id_list:
+ self.get_mandatory_features(feature_id)
diff --git a/tests/nvme_get_lba_status_test.py b/tests/nvme_get_lba_status_test.py
new file mode 100644
index 0000000..539c493
--- /dev/null
+++ b/tests/nvme_get_lba_status_test.py
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Author: Arunpandian J <apj.arun@samsung.com>
+
+"""
+NVMe LBA Status Log Testcase :-
+
+ 1. Execute get-lba-status on a device.
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeGetLbaStatusCmd(TestNVMe):
+
+ """
+ Represents Get LBA Status test.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeGetLbaStatusCmd. """
+ super().setUp()
+ self.start_lba = 0
+ self.block_count = 0
+ self.namespace = 1
+ self.max_dw = 1
+ self.action = 11
+ self.range_len = 1
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeGetLbaStatusCmd.
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_lba_status(self):
+ """ Wrapper for executing nvme get-lba-status.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ err = 0
+ get_lba_status_cmd = "nvme get-lba-status " + self.ctrl + \
+ " --namespace-id=" + str(self.namespace) + \
+ " --start-lba=" + str(self.start_lba) + \
+ " --max-dw=" + str(self.max_dw) + \
+ " --action=" + str(self.action) + \
+ " --range-len=" + str(self.range_len)
+ proc = subprocess.Popen(get_lba_status_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ get_lba_status_output = proc.communicate()[0]
+ print("\n" + get_lba_status_output + "\n")
+ err = proc.wait()
+ return err
+
+ def test_get_lba_status(self):
+ """ Testcase main """
+ self.assertEqual(self.get_lba_status(), 0)
diff --git a/tests/nvme_id_ctrl_test.py b/tests/nvme_id_ctrl_test.py
new file mode 100644
index 0000000..2810d94
--- /dev/null
+++ b/tests/nvme_id_ctrl_test.py
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Madhusudhana S.J <madhusudhana.sj@wdc.com>
+# Author: Dong Ho <dong.ho@wdc.com>
+#
+"""
+NVMe Identify ctrl Testcase:-
+
+ 1. Execute id-ctrl on ctrl
+ 2. Execute id-ctrl vendor specific on ctrl
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeIdctrlCmd(TestNVMe):
+
+ """
+ Represents Id ctrl testcase
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeIdctrlCmd. """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeIdctrlCmd
+
+ Call super class's destructor.
+ """
+ super().tearDown()
+
+ def test_id_ctrl(self):
+ """ Testcase main """
+ vendor = True
+ self.assertEqual(self.get_id_ctrl(), 0)
+ self.assertEqual(self.get_id_ctrl(vendor), 0)
diff --git a/tests/nvme_id_ns_test.py b/tests/nvme_id_ns_test.py
new file mode 100644
index 0000000..66e2f93
--- /dev/null
+++ b/tests/nvme_id_ns_test.py
@@ -0,0 +1,90 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Madhusudhana S.J <madhusudhana.sj@wdc.com>
+# Author: Dong Ho <dong.ho@wdc.com>
+#
+"""
+NVme Identify Namespace Testcase:-
+
+ 1. Execute id-ns on a namespace
+ 2. Execute id-ns on all namespaces
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeIdentifyNamespace(TestNVMe):
+
+ """
+ Represents Identify Namesepace testcase
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeIdentifyNamespace. """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+ self.ns_list = self.get_ns_list()
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeIdentifyNamespace
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_id_ns(self, nsid):
+ """
+ Wrapper for executing nvme id-ns on a namespace.
+ - Args:
+ - nsid : namespace id to get info from.
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ err = 0
+ id_ns_cmd = "nvme id-ns " + self.ctrl + "n" + str(nsid)
+ proc = subprocess.Popen(id_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ id_ns_output = proc.communicate()[0]
+ print(id_ns_output + "\n")
+ err = proc.wait()
+ return err
+
+ def get_id_ns_all(self):
+ """
+ Wrapper for executing nvme id-ns on all namespaces.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ err = 0
+ for namespace in self.ns_list:
+ err = self.get_id_ns(str(namespace))
+ return err
+
+ def test_id_ns(self):
+ """ Testcase main """
+ self.assertEqual(self.get_id_ns(1), 0)
+ self.assertEqual(self.get_id_ns_all(), 0)
diff --git a/tests/nvme_lba_status_log_test.py b/tests/nvme_lba_status_log_test.py
new file mode 100644
index 0000000..c91d1e5
--- /dev/null
+++ b/tests/nvme_lba_status_log_test.py
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Author: Arunpandian J <apj.arun@samsung.com>
+
+"""
+NVMe LBA Status Log Testcase :-
+
+ 1. Execute lba-status-log on a device.
+"""
+
+import subprocess
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeLbaStatLogCmd(TestNVMe):
+
+ """
+ Represents LBA Status Log test.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeLbaStatLogCmd. """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeLbaStatLogCmd.
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_lba_stat_log(self):
+ """ Wrapper for executing nvme lba-status-log.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ err = 0
+ lba_stat_log_cmd = "nvme lba-status-log " + self.ctrl
+ proc = subprocess.Popen(lba_stat_log_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ lba_stat_log_output = proc.communicate()[0]
+ print("\n" + lba_stat_log_output + "\n")
+ err = proc.wait()
+ return err
+
+ def test_lba_stat_log(self):
+ """ Testcase main """
+ self.assertEqual(self.get_lba_stat_log(), 0)
diff --git a/tests/nvme_read_write_test.py b/tests/nvme_read_write_test.py
new file mode 100644
index 0000000..8cae140
--- /dev/null
+++ b/tests/nvme_read_write_test.py
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Read/Write Testcae:-
+
+ 1. Create data file with specific pattern outside of the device under test.
+ 2. Write data file on the namespace under test.
+ 3. Read the data from the namespace under test into different file.
+ 4. Compare file in #1 and #3.
+"""
+
+import filecmp
+
+from nvme_test_io import TestNVMeIO
+
+
+class TestNVMeReadWriteTest(TestNVMeIO):
+
+ """
+ Represents NVMe read, write testcase.
+
+ - Attributes:
+ - start_block : starting block of to perform IO.
+ - compare_file : data file to use in nvme compare command.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeReadWriteTest """
+ super().setUp()
+ self.start_block = 1023
+ self.test_log_dir = self.log_dir + "/" + self.__class__.__name__
+ self.setup_log_dir(self.__class__.__name__)
+ self.write_file = self.test_log_dir + "/" + self.write_file
+ self.read_file = self.test_log_dir + "/" + self.read_file
+ self.create_data_file(self.write_file, self.data_size, "15")
+ open(self.read_file, 'a').close()
+
+ def tearDown(self):
+ """ Post Section for TestNVMeReadWriteTest """
+ super().tearDown()
+
+ def read_validate(self):
+ """ Validate the data file read
+ - Args:
+ - None
+ - Returns:
+ - returns 0 on success, 1 on failure.
+ """
+ return 0 if filecmp.cmp(self.read_file, self.write_file) else 1
+
+ def test_nvme_write(self):
+ """ Testcaes main """
+ self.assertEqual(self.nvme_write(), 0)
+ self.assertEqual(self.nvme_read(), 0)
+ self.assertEqual(self.read_validate(), 0)
diff --git a/tests/nvme_simple_template_test.py b/tests/nvme_simple_template_test.py
new file mode 100644
index 0000000..2adaeb4
--- /dev/null
+++ b/tests/nvme_simple_template_test.py
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+""" Simple Template test example :-
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeSimpleTestTemplate(TestNVMe):
+
+ """ Represents Simple NVMe test """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeSimpleTestTemplate. """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+ # Add this test specific variables here
+
+ def tearDown(self):
+ """ Post Section for TestNVMeSimpleTestTemplate
+
+ Call super class's destructor.
+ """
+ # Add this test specific cleanup code here
+ super().tearDown()
+
+ def simple_template_test(self):
+ """ Wrapper for this test specific functions
+ - Args:
+ - None
+ - Returns:
+ - None
+ """
+ pass
+
+ def test_get_mandetory_features(self):
+ """ Testcase main """
+ self.simple_template_test()
diff --git a/tests/nvme_smart_log_test.py b/tests/nvme_smart_log_test.py
new file mode 100644
index 0000000..916ef49
--- /dev/null
+++ b/tests/nvme_smart_log_test.py
@@ -0,0 +1,89 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Smart Log Verification Testcase:-
+
+ 1. Execute smat-log on controller.
+ 2. Execute smart-log on each available namespace.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeSmartLogCmd(TestNVMe):
+
+ """
+ Represents Smart Log testcae.
+
+ - Attributes:
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeSmartLogCmd """
+ super().setUp()
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """
+ Post Section for TestNVMeSmartLogCmd
+
+ - Call super class's destructor.
+ """
+ super().tearDown()
+
+ def get_smart_log_ctrl(self):
+ """ Wrapper for executing smart-log on controller.
+ - Args:
+ - None:
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ return self.get_smart_log("0xFFFFFFFF")
+
+ def get_smart_log_ns(self, nsid):
+ """ Wrapper for executing smart-log on a namespace.
+ - Args:
+ - nsid: namespace id to be used in smart-log command.
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ return self.get_smart_log(nsid)
+
+ def get_smart_log_all_ns(self):
+ """ Wrapper for executing smart-log on all the namespaces.
+ - Args:
+ - None:
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ ns_list = self.get_ns_list()
+ for nsid in range(0, len(ns_list)):
+ self.get_smart_log_ns(ns_list[nsid])
+ return 0
+
+ def test_smart_log(self):
+ """ Testcase main """
+ self.assertEqual(self.get_smart_log_ctrl(), 0)
+ smlp = self.supp_check_id_ctrl("lpa")
+ if smlp & 0x1 == True:
+ self.assertEqual(self.get_smart_log_all_ns(), 0)
diff --git a/tests/nvme_test.py b/tests/nvme_test.py
new file mode 100644
index 0000000..0df3dac
--- /dev/null
+++ b/tests/nvme_test.py
@@ -0,0 +1,504 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+""" Base class for all the testcases
+"""
+
+import json
+import mmap
+import os
+import re
+import shutil
+import stat
+import subprocess
+import sys
+import time
+import unittest
+
+from nvme_test_logger import TestNVMeLogger
+
+
+class TestNVMe(unittest.TestCase):
+
+ """
+ Represents a testcase, each testcase should inherit this
+ class or appropriate subclass which is a child of this class.
+
+ Common utility functions used in various testcases.
+
+ - Attributes:
+ - ctrl : NVMe Controller.
+ - ns1 : default namespace.
+ - default_nsid : default namespace id.
+ - config_file : configuration file.
+ - clear_log_dir : default log directory.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMe. """
+ # common code used in various testcases.
+ self.ctrl = "XXX"
+ self.ns1 = "XXX"
+ self.test_log_dir = "XXX"
+ self.do_validate_pci_device = True
+ self.default_nsid = 0x1
+ self.config_file = 'tests/config.json'
+
+ self.load_config()
+ if self.do_validate_pci_device:
+ self.validate_pci_device()
+
+ def tearDown(self):
+ """ Post Section for TestNVMe. """
+ if self.clear_log_dir is True:
+ shutil.rmtree(self.log_dir, ignore_errors=True)
+
+ def validate_pci_device(self):
+ """ Validate underlying device belongs to pci subsystem.
+ - Args:
+ - None
+ - Returns:
+ - None
+ """
+ x1, x2, dev = self.ctrl.split('/')
+ cmd = cmd = "find /sys/devices -name \\*" + dev + " | grep -i pci"
+ err = subprocess.call(cmd, shell=True)
+ self.assertEqual(err, 0, "ERROR : Only NVMe PCI subsystem is supported")
+
+ def load_config(self):
+ """ Load Basic test configuration.
+ - Args:
+ - None
+ - Returns:
+ - None
+ """
+ with open(self.config_file) as data_file:
+ config = json.load(data_file)
+ self.ctrl = config['controller']
+ self.ns1 = config['ns1']
+ self.log_dir = config['log_dir']
+ self.do_validate_pci_device = config.get('do_validate_pci_device', self.do_validate_pci_device)
+ self.clear_log_dir = False
+
+ if self.clear_log_dir is True:
+ shutil.rmtree(self.log_dir, ignore_errors=True)
+
+ if not os.path.exists(self.log_dir):
+ os.makedirs(self.log_dir)
+
+ def setup_log_dir(self, test_name):
+ """ Set up the log directory for a testcase
+ Args:
+ - test_name : name of the testcase.
+ Returns:
+ - None
+ """
+ self.test_log_dir = self.log_dir + "/" + test_name
+ if not os.path.exists(self.test_log_dir):
+ os.makedirs(self.test_log_dir)
+ sys.stdout = TestNVMeLogger(self.test_log_dir + "/" + "stdout.log")
+ sys.stderr = TestNVMeLogger(self.test_log_dir + "/" + "stderr.log")
+
+ def exec_cmd(self, cmd):
+ """ Wrapper for executing a shell command and return the result. """
+ proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ return proc.wait()
+
+ def nvme_reset_ctrl(self):
+ """ Wrapper for nvme reset command.
+ - Args:
+ - None:
+ - Returns:
+ - None
+ """
+ nvme_reset_cmd = "nvme reset " + self.ctrl
+ err = subprocess.call(nvme_reset_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.assertEqual(err, 0, "ERROR : nvme reset failed")
+ time.sleep(5)
+ rescan_cmd = "echo 1 > /sys/bus/pci/rescan"
+ proc = subprocess.Popen(rescan_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ encoding='utf-8')
+ time.sleep(5)
+ self.assertEqual(proc.wait(), 0, "ERROR : pci rescan failed")
+
+ def get_ctrl_id(self):
+ """ Wrapper for extracting the controller id.
+ - Args:
+ - None
+ - Returns:
+ - controller id.
+ """
+ get_ctrl_id = "nvme list-ctrl " + self.ctrl
+ proc = subprocess.Popen(get_ctrl_id,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : nvme list-ctrl failed")
+ line = proc.stdout.readline()
+ ctrl_id = line.split(":")[1].strip()
+ return ctrl_id
+
+ def get_ns_list(self):
+ """ Wrapper for extracting the namespace list.
+ - Args:
+ - None
+ - Returns:
+ - List of the namespaces.
+ """
+ ns_list = []
+ ns_list_cmd = "nvme list-ns " + self.ctrl
+ proc = subprocess.Popen(ns_list_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.assertEqual(proc.wait(), 0, "ERROR : nvme list namespace failed")
+ for line in proc.stdout:
+ ns_list.append(line.split('x')[-1])
+
+ return ns_list
+
+ def get_max_ns(self):
+ """ Wrapper for extracting maximum number of namespaces supported.
+ - Args:
+ - None
+ - Returns:
+ - maximum number of namespaces supported.
+ """
+ pattern = re.compile("^nn[ ]+: [0-9]", re.IGNORECASE)
+ max_ns = -1
+ max_ns_cmd = "nvme id-ctrl " + self.ctrl
+ proc = subprocess.Popen(max_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : reading maximum namespace count failed")
+
+ for line in proc.stdout:
+ if pattern.match(line):
+ max_ns = line.split(":")[1].strip()
+ break
+ print(max_ns)
+ return int(max_ns)
+
+ def get_ncap(self):
+ """ Wrapper for extracting capacity.
+ - Args:
+ - None
+ - Returns:
+ - maximum number of namespaces supported.
+ """
+ pattern = re.compile("^tnvmcap[ ]+: [0-9]", re.IGNORECASE)
+ ncap = -1
+ ncap_cmd = "nvme id-ctrl " + self.ctrl
+ proc = subprocess.Popen(ncap_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : reading nvm capacity failed")
+
+ for line in proc.stdout:
+ if pattern.match(line):
+ ncap = line.split(":")[1].strip()
+ break
+ print(ncap)
+ return int(ncap)
+
+ def get_ocfs(self):
+ """ Wrapper for extracting optional copy formats supported
+ - Args:
+ - None
+ - Returns:
+ - Optional Copy Formats Supported
+ """
+ pattern = re.compile(r'^ocfs\s*: 0x[0-9a-fA-F]+$')
+ output = subprocess.check_output(["nvme", "id-ctrl", self.ctrl], encoding='utf-8')
+ ocfs_line = next(line for line in output.splitlines() if pattern.match(line))
+ ocfs = ocfs_line.split(":")[1].strip()
+ return int(ocfs, 16)
+
+ def get_format(self):
+ """ Wrapper for extracting format.
+ - Args:
+ - None
+ - Returns:
+ - maximum format of namespace.
+ """
+ # defaulting to 4K
+ nvm_format = 4096
+ nvm_format_cmd = "nvme id-ns " + self.ctrl + " -n1"
+ proc = subprocess.Popen(nvm_format_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : reading nvm capacity failed")
+
+ for line in proc.stdout:
+ if "in use" in line:
+ nvm_format = 2 ** int(line.split(":")[3].split()[0])
+ print(nvm_format)
+ return int(nvm_format)
+
+ def delete_all_ns(self):
+ """ Wrapper for deleting all the namespaces.
+ - Args:
+ - None
+ - Returns:
+ - None
+ """
+ delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n 0xFFFFFFFF"
+ self.assertEqual(self.exec_cmd(delete_ns_cmd), 0)
+ list_ns_cmd = "nvme list-ns " + self.ctrl + " --all | wc -l"
+ proc = subprocess.Popen(list_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ output = proc.stdout.read().strip()
+ self.assertEqual(output, '0', "ERROR : deleting all namespace failed")
+
+ def create_ns(self, nsze, ncap, flbas, dps):
+ """ Wrapper for creating a namespace.
+ - Args:
+ - nsze : new namespace size.
+ - ncap : new namespace capacity.
+ - flbas : new namespace format.
+ - dps : new namespace data protection information.
+ - Returns:
+ - return code of the nvme create namespace command.
+ """
+ create_ns_cmd = "nvme create-ns " + self.ctrl + " --nsze=" + \
+ str(nsze) + " --ncap=" + str(ncap) + \
+ " --flbas=" + str(flbas) + " --dps=" + str(dps)
+ return self.exec_cmd(create_ns_cmd)
+
+ def create_and_validate_ns(self, nsid, nsze, ncap, flbas, dps):
+ """ Wrapper for creating and validating a namespace.
+ - Args:
+ - nsid : new namespace id.
+ - nsze : new namespace size.
+ - ncap : new namespace capacity.
+ - flbas : new namespace format.
+ - dps : new namespace data protection information.
+ - Returns:
+ - return 0 on success, error code on failure.
+ """
+ err = self.create_ns(nsze, ncap, flbas, dps)
+ if err == 0:
+ time.sleep(2)
+ id_ns_cmd = "nvme id-ns " + self.ctrl + " -n " + str(nsid)
+ err = subprocess.call(id_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ return err
+
+ def attach_ns(self, ctrl_id, ns_id):
+ """ Wrapper for attaching the namespace.
+ - Args:
+ - ctrl_id : controller id to which namespace to be attached.
+ - nsid : new namespace id.
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ attach_ns_cmd = "nvme attach-ns " + self.ctrl + \
+ " --namespace-id=" + str(ns_id) + \
+ " --controllers=" + ctrl_id
+ err = subprocess.call(attach_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ time.sleep(5)
+ if err == 0:
+ # enumerate new namespace block device
+ self.nvme_reset_ctrl()
+ time.sleep(5)
+ # check if new namespace block device exists
+ err = 0 if stat.S_ISBLK(os.stat(self.ns1).st_mode) else 1
+ return err
+
+ def detach_ns(self, ctrl_id, nsid):
+ """ Wrapper for detaching the namespace.
+ - Args:
+ - ctrl_id : controller id to which namespace to be attached.
+ - nsid : new namespace id.
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ detach_ns_cmd = "nvme detach-ns " + self.ctrl + \
+ " --namespace-id=" + str(nsid) + \
+ " --controllers=" + ctrl_id
+ return subprocess.call(detach_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+
+ def delete_and_validate_ns(self, nsid):
+ """ Wrapper for deleting and validating that namespace is deleted.
+ - Args:
+ - nsid : new namespace id.
+ - Returns:
+ - 0 on success, 1 on failure.
+ """
+ # delete the namespace
+ delete_ns_cmd = "nvme delete-ns " + self.ctrl + " -n " + str(nsid)
+ err = subprocess.call(delete_ns_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ self.assertEqual(err, 0, "ERROR : delete namespace failed")
+ return err
+
+ def get_smart_log(self, nsid):
+ """ Wrapper for nvme smart-log command.
+ - Args:
+ - nsid : namespace id to get smart log from.
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ smart_log_cmd = "nvme smart-log " + self.ctrl + " -n " + str(nsid)
+ print(smart_log_cmd)
+ proc = subprocess.Popen(smart_log_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : nvme smart log failed")
+
+ for line in proc.stdout:
+ if "data_units_read" in line:
+ data_units_read = \
+ line.replace(",", "", 1)
+ if "data_units_written" in line:
+ data_units_written = \
+ line.replace(",", "", 1)
+ if "host_read_commands" in line:
+ host_read_commands = \
+ line.replace(",", "", 1)
+ if "host_write_commands" in line:
+ host_write_commands = \
+ line.replace(",", "", 1)
+
+ print("data_units_read " + data_units_read)
+ print("data_units_written " + data_units_written)
+ print("host_read_commands " + host_read_commands)
+ print("host_write_commands " + host_write_commands)
+ return err
+
+ def get_id_ctrl(self, vendor=False):
+ """ Wrapper for nvme id-ctrl command.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ if not vendor:
+ id_ctrl_cmd = "nvme id-ctrl " + self.ctrl
+ else:
+ id_ctrl_cmd = "nvme id-ctrl -v " + self.ctrl
+ print(id_ctrl_cmd)
+ proc = subprocess.Popen(id_ctrl_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : nvme id controller failed")
+ return err
+
+ def get_error_log(self):
+ """ Wrapper for nvme error-log command.
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, error code on failure.
+ """
+ pattern = re.compile("^ Entry\[[ ]*[0-9]+\]")
+ error_log_cmd = "nvme error-log " + self.ctrl
+ proc = subprocess.Popen(error_log_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : nvme error log failed")
+ line = proc.stdout.readline()
+ err_log_entry_count = int(line.split(" ")[5].strip().split(":")[1])
+ entry_count = 0
+ for line in proc.stdout:
+ if pattern.match(line):
+ entry_count += 1
+
+ return 0 if err_log_entry_count == entry_count else 1
+
+ def run_ns_io(self, nsid, lbads):
+ """ Wrapper to run ios on namespace under test.
+ - Args:
+ - lbads : LBA Data size supported in power of 2 format.
+ - Returns:
+ - None
+ """
+ block_size = mmap.PAGESIZE if int(lbads) < 9 else 2 ** int(lbads)
+ ns_path = self.ctrl + "n" + str(nsid)
+ io_cmd = "dd if=" + ns_path + " of=/dev/null" + " bs=" + \
+ str(block_size) + " count=10 > /dev/null 2>&1"
+ print(io_cmd)
+ run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ run_io_result = run_io.communicate()[1]
+ self.assertEqual(run_io_result, None)
+ io_cmd = "dd if=/dev/zero of=" + ns_path + " bs=" + \
+ str(block_size) + " count=10 > /dev/null 2>&1"
+ print(io_cmd)
+ run_io = subprocess.Popen(io_cmd, shell=True, stdout=subprocess.PIPE,
+ encoding='utf-8')
+ run_io_result = run_io.communicate()[1]
+ self.assertEqual(run_io_result, None)
+
+ def supp_check_id_ctrl(self, key):
+ """ Wrapper for support check.
+ - Args:
+ - key : search key.
+ - Returns:
+ - value for key requested.
+ """
+ id_ctrl = "nvme id-ctrl " + self.ctrl
+ print("\n" + id_ctrl)
+ proc = subprocess.Popen(id_ctrl,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ err = proc.wait()
+ self.assertEqual(err, 0, "ERROR : nvme Identify controller Data \
+ structure failed")
+ for line in proc.stdout:
+ if key in line:
+ key = line.replace(",", "", 1)
+ print(key)
+ val = (key.split(':'))[1].strip()
+ return int(val, 16)
diff --git a/tests/nvme_test_io.py b/tests/nvme_test_io.py
new file mode 100644
index 0000000..bf30e0a
--- /dev/null
+++ b/tests/nvme_test_io.py
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+""" Inherit TestNVMeIO for nvme read/write operations """
+
+import os
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeIO(TestNVMe):
+
+ """
+ Variable and Methods required to perform nvme read/write.
+
+ - Attributes:
+ - data_size : data size to perform IO.
+ - start_block : starting block of to perform IO.
+ - block_count : Number of blocks to use in IO.
+ - write_file : data file to use in nvme write command.
+ - read_file : data file to use in nvme read command.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeIO """
+ super().setUp()
+ # common code used in various testcases.
+ self.data_size = 512
+ self.start_block = 0
+ self.block_count = 0
+ self.write_file = "write_file.txt"
+ self.read_file = "read_file.txt"
+
+ def tearDown(self):
+ """ Post Section for TestNVMeIO """
+ super().tearDown()
+
+ def create_data_file(self, pathname, data_size, pattern):
+ """ Creates data file with specific pattern
+ - Args:
+ - pathname : data file path name.
+ - data_size : total size of the data.
+ - pattern : data pattern to create file.
+ - Returns:
+ None
+ """
+ pattern_len = len(pattern)
+ data_file = open(pathname, "w")
+ for i in range(0, data_size):
+ data_file.write(pattern[i % pattern_len])
+ data_file.flush()
+ os.fsync(data_file.fileno())
+ data_file.close()
+
+ def nvme_write(self):
+ """ Wrapper for nvme write operation
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme write command.
+ """
+ write_cmd = "nvme write " + self.ns1 + " --start-block=" + \
+ str(self.start_block) + " --block-count=" + \
+ str(self.block_count) + " --data-size=" + \
+ str(self.data_size) + " --data=" + self.write_file
+ return self.exec_cmd(write_cmd)
+
+ def nvme_read(self):
+ """ Wrapper for nvme read operation
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme read command.
+ """
+ read_cmd = "nvme read " + self.ns1 + " --start-block=" + \
+ str(self.start_block) + " --block-count=" + \
+ str(self.block_count) + " --data-size=" + \
+ str(self.data_size) + " --data=" + self.read_file
+ print(read_cmd)
+ return self.exec_cmd(read_cmd)
diff --git a/tests/nvme_test_logger.py b/tests/nvme_test_logger.py
new file mode 100644
index 0000000..d0182fd
--- /dev/null
+++ b/tests/nvme_test_logger.py
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+Logger for NVMe Test Framwwork:-
+
+"""
+import sys
+
+
+class TestNVMeLogger():
+ """ Represents Logger for NVMe Testframework. """
+
+ def __init__(self, log_file_path):
+ """ Logger setup
+ - Args:
+ log_file_path : path to store the log.
+ """
+ self.terminal = sys.stdout
+ self.log = open(log_file_path, "w")
+
+ def write(self, log_message):
+ """ Logger setup
+ - Args:
+ log_message: string to write in the log file.
+ - Returns:
+ None
+ """
+ self.terminal.write(log_message)
+ self.log.write(log_message)
+
+ def flush(self):
+ """ This flush method is needed for python 3 compatibility.
+ this handles the flush command by doing nothing.
+ you might want to specify some extra behavior here.
+ """
+ pass
diff --git a/tests/nvme_verify_test.py b/tests/nvme_verify_test.py
new file mode 100644
index 0000000..7c30828
--- /dev/null
+++ b/tests/nvme_verify_test.py
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# This file is part of nvme-cli
+#
+# Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved.
+#
+# Author: Arunpandian J <apj.arun@samsung.com>
+
+"""
+NVMe Verify Testcase:-
+
+ 1. Issue verify command on set of block; shall pass.
+
+"""
+
+from nvme_test import TestNVMe
+
+
+class TestNVMeVerify(TestNVMe):
+
+ """
+ Represents NVMe Verify testcase.
+ - Attributes:
+ - start_block : starting block of to verify operation.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeVerify """
+ super().setUp()
+ self.start_block = 0
+ self.block_count = 0
+ self.namespace = 1
+ self.setup_log_dir(self.__class__.__name__)
+
+ def tearDown(self):
+ """ Post Section for TestNVMeVerify """
+ super().tearDown()
+
+ def verify(self):
+ """ Wrapper for nvme verify
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme verify command.
+ """
+ verify_cmd = "nvme verify " + self.ctrl + \
+ " --namespace-id=" + str(self.namespace) + \
+ " --start-block=" + str(self.start_block) + \
+ " --block-count=" + str(self.block_count)
+ return self.exec_cmd(verify_cmd)
+
+ def test_verify(self):
+ """ Testcase main """
+ self.assertEqual(self.verify(), 0)
diff --git a/tests/nvme_writeuncor_test.py b/tests/nvme_writeuncor_test.py
new file mode 100644
index 0000000..1083d46
--- /dev/null
+++ b/tests/nvme_writeuncor_test.py
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Write Compare Testcae:-
+
+ 1. Read block of data successfully.
+ 2. Issue write uncorrectable to block of data.
+ 3. Attempt to read from same block; shall fail.
+ 4. Issue a write command to first block of data.
+ 5. Read from the same block; shall pass.
+
+"""
+
+from nvme_test_io import TestNVMeIO
+
+
+class TestNVMeUncor(TestNVMeIO):
+
+ """
+ Represents NVMe Write Uncorrecatble testcase.
+ - Attributes:
+ - start_block : starting block of to perform IO.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Constructor TestNVMeUncor """
+ super().setUp()
+ self.start_block = 1023
+ self.setup_log_dir(self.__class__.__name__)
+ self.write_file = self.test_log_dir + "/" + self.write_file
+ self.read_file = self.test_log_dir + "/" + self.read_file
+ self.create_data_file(self.write_file, self.data_size, "15")
+ open(self.read_file, 'a').close()
+
+ def tearDown(self):
+ """ Post Section for TestNVMeUncor """
+ super().tearDown()
+
+ def write_uncor(self):
+ """ Wrapper for nvme write uncorrectable
+ - Args:
+ - None
+ - Returns:
+ - return code of nvme write uncorrectable command.
+ """
+ write_uncor_cmd = "nvme write-uncor " + self.ns1 + \
+ " --start-block=" + str(self.start_block) + \
+ " --block-count=" + str(self.block_count)
+ return self.exec_cmd(write_uncor_cmd)
+
+ def test_write_uncor(self):
+ """ Testcase main """
+ self.assertEqual(self.nvme_read(), 0)
+ self.assertEqual(self.write_uncor(), 0)
+ self.assertNotEqual(self.nvme_read(), 0)
+ self.assertEqual(self.nvme_write(), 0)
+ self.assertEqual(self.nvme_read(), 0)
diff --git a/tests/nvme_writezeros_test.py b/tests/nvme_writezeros_test.py
new file mode 100644
index 0000000..3231e3d
--- /dev/null
+++ b/tests/nvme_writezeros_test.py
@@ -0,0 +1,105 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright (c) 2015-2016 Western Digital Corporation or its affiliates.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+# Author: Chaitanya Kulkarni <chaitanya.kulkarni@hgst.com>
+#
+"""
+NVMe Write Zeros:-
+
+ 1. Issue a write command to block of data.
+ 2. Read from same block to verify data pattern.
+ 3. Issue write zeros to the block of data.
+ 4. Read from same block, should be all zeroes.
+
+"""
+
+import filecmp
+
+from nvme_test_io import TestNVMeIO
+
+
+class TestNVMeWriteZeros(TestNVMeIO):
+
+ """
+ Represents NVMe Write Zero Testcase.
+
+ - Attributes:
+ - zero_file : file with all '\0' to compare the zero data.
+ - data_size : data size to perform IO.
+ - start_block : starting block of to perform IO.
+ - block_count: Number of blocks to use in IO.
+ - test_log_dir : directory for logs, temp files.
+ """
+
+ def setUp(self):
+ """ Pre Section for TestNVMeWriteZeros """
+ super().setUp()
+ self.start_block = 1023
+ self.block_count = 0
+ self.setup_log_dir(self.__class__.__name__)
+ self.write_file = self.test_log_dir + "/" + self.write_file
+ self.read_file = self.test_log_dir + "/" + self.read_file
+ self.zero_file = self.test_log_dir + "/" + "zero_file.txt"
+ self.create_data_file(self.write_file, self.data_size, "15")
+ self.create_data_file(self.zero_file, self.data_size, '\0')
+ open(self.read_file, 'a').close()
+
+ def tearDown(self):
+ """ Post Section for TestNVMeWriteZeros """
+ super().tearDown()
+
+ def write_zeroes(self):
+ """ Wrapper for nvme write-zeroe
+ - Args:
+ - None
+ - Returns:
+ - return code for nvme write command.
+ """
+ write_zeroes_cmd = "nvme write-zeroes " + self.ns1 + \
+ " --start-block=" + str(self.start_block) + \
+ " --block-count=" + str(self.block_count)
+ return self.exec_cmd(write_zeroes_cmd)
+
+ def validate_write_read(self):
+ """ Validate the file which had been read from the device
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, 1 on failure
+ """
+ return 0 if filecmp.cmp(self.write_file, self.read_file) is True else 1
+
+ def validate_zeroes(self):
+ """
+ Validate the data which is zeroed out via write-zeroes
+ - Args:
+ - None
+ - Returns:
+ - 0 on success, 1 on failure
+ """
+ return 0 if filecmp.cmp(self.zero_file, self.read_file) is True else 1
+
+ def test_write_zeros(self):
+ """ Testcae main """
+ self.assertEqual(self.nvme_write(), 0)
+ self.assertEqual(self.nvme_read(), 0)
+ self.assertEqual(self.validate_write_read(), 0)
+ self.assertEqual(self.write_zeroes(), 0)
+ self.assertEqual(self.nvme_read(), 0)
+ self.assertEqual(self.validate_zeroes(), 0)
diff --git a/tests/run_py_linters.py b/tests/run_py_linters.py
new file mode 100644
index 0000000..869b3e4
--- /dev/null
+++ b/tests/run_py_linters.py
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# Copied from https://github.com/python-sdbus/python-sdbus
+# Copyright (C) 2020, 2021 igo95862
+
+# This file is part of nvme-cli
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+from __future__ import annotations
+
+from argparse import ArgumentParser
+from os import environ
+from pathlib import Path
+from subprocess import run
+from typing import List
+
+source_root = Path(environ['MESON_SOURCE_ROOT'])
+build_dir = Path(environ['MESON_BUILD_ROOT'])
+
+tests_dir = source_root / 'tests'
+
+all_python_modules = [
+ tests_dir,
+]
+
+mypy_cache_dir = build_dir / '.mypy_cache'
+
+
+def run_mypy(path: Path) -> None:
+ print(f"Running mypy on {path}")
+ run(
+ args=(
+ 'mypy', '--strict',
+ '--cache-dir', mypy_cache_dir,
+ '--python-version', '3.8',
+ '--namespace-packages',
+ '--ignore-missing-imports',
+ path,
+ ),
+ check=False,
+ env={'MYPYPATH': str(tests_dir.absolute()), **environ},
+ )
+
+
+def linter_main() -> None:
+ run(
+ args=(
+ 'flake8',
+ *all_python_modules,
+ ),
+ check=False,
+ )
+
+ for x in all_python_modules:
+ run_mypy(x)
+
+
+def get_all_python_files() -> List[Path]:
+ python_files: List[Path] = []
+
+ for python_module in all_python_modules:
+ if python_module.is_dir():
+ for a_file in python_module.iterdir():
+ if a_file.suffix == '.py':
+ python_files.append(a_file)
+ else:
+ python_files.append(python_module)
+
+ return python_files
+
+
+def formater_main() -> None:
+ all_python_files = get_all_python_files()
+
+ run(
+ args=('autopep8', '--in-place', *all_python_files),
+ check=False,
+ )
+
+ run(
+ args=(
+ 'isort',
+ '-m', 'VERTICAL_HANGING_INDENT',
+ '--trailing-comma',
+ *all_python_files,
+ ),
+ check=False,
+ )
+
+
+def main() -> None:
+ parser = ArgumentParser()
+ parser.add_argument(
+ 'mode',
+ choices=('lint', 'format'),
+ )
+
+ args = parser.parse_args()
+
+ mode = args.mode
+
+ if mode == 'lint':
+ linter_main()
+ elif mode == 'format':
+ formater_main()
+ else:
+ raise ValueError('Unknown mode', mode)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/unit/meson.build b/unit/meson.build
new file mode 100644
index 0000000..7e0e878
--- /dev/null
+++ b/unit/meson.build
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+test_uint128 = executable(
+ 'test-uint128',
+ ['test-uint128.c', '../util/types.c', '../util/suffix.c'],
+ include_directories: [incdir, '..'],
+ dependencies: [libnvme_dep],
+)
+
+test('uint128', test_uint128)
+
+test_suffix_si_parse = executable(
+ 'test-suffix-si-parse',
+ ['test-suffix-si-parse.c', '../util/suffix.c'],
+ include_directories: [incdir, '..'],
+ dependencies: [libnvme_dep],
+)
+
+test('suffix_si_parse', test_suffix_si_parse)
+
+test_suffix_binary_parse = executable(
+ 'test-suffix-binary-parse',
+ ['test-suffix-binary-parse.c', '../util/suffix.c'],
+ include_directories: [incdir, '..'],
+ dependencies: [libnvme_dep],
+)
+
+test('suffix_binary_parse', test_suffix_binary_parse)
+
+test_uint128_si = executable(
+ 'test-uint128-si',
+ ['test-uint128-si.c', '../util/types.c', '../util/suffix.c'],
+ include_directories: [incdir, '..'],
+ dependencies: [libnvme_dep],
+)
+
+test('uint128-si', test_uint128_si)
+
+test_argconfig_parse = executable(
+ 'test-argconfig-parse',
+ ['test-argconfig-parse.c', '../util/argconfig.c', '../util/suffix.c'],
+ include_directories: [incdir, '..'],
+ dependencies: [libnvme_dep],
+)
+
+test('argconfig_parse', test_argconfig_parse)
diff --git a/unit/test-argconfig-parse.c b/unit/test-argconfig-parse.c
new file mode 100644
index 0000000..23c8d4f
--- /dev/null
+++ b/unit/test-argconfig-parse.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <locale.h>
+
+#include "../util/argconfig.h"
+#include "nvme/types.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static int test_rc;
+
+union val {
+ bool flag;
+ __u64 suffix;
+ __u32 uint;
+ int int_val;
+ __u64 long_val;
+ double double_val;
+ __u8 byte;
+ __u16 shrt;
+ int incr;
+ char *string;
+ char *fmt;
+ char *file;
+ char *list;
+ char *str;
+};
+
+struct toval_test {
+ char *arg;
+ void *val;
+ union val exp;
+ int size;
+ int ret;
+};
+
+static void check_val(const char *arg, void *exp, void *val, int size)
+{
+ if ((size && !memcmp(exp, val, size)) ||
+ (!size && !strcmp(*(char **)exp, *(char **)val)))
+ return;
+
+ switch (size) {
+ case 0:
+ printf("ERROR: printing {%s}, got '%s', expected '%s'\n",
+ arg, *(char **)val, *(char **)exp);
+ break;
+ default:
+ printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n",
+ arg, *(unsigned long long *)val, *(unsigned long long *)exp);
+ break;
+ }
+
+ test_rc = 1;
+}
+
+struct cfg {
+ bool flag;
+ __u64 suffix;
+ __u32 uint;
+ int int_val;
+ __u64 long_val;
+ double double_val;
+ __u8 byte;
+ __u16 shrt;
+ int incr;
+ char *string;
+ char *fmt;
+ char *file;
+ char *list;
+ char *str;
+};
+
+static struct cfg cfg;
+
+#define VAL_TEST(a, c, v, l, r) \
+ { a, &cfg.c, { .c = v }, l ? sizeof(cfg.c) : 0, r }
+
+static struct toval_test toval_tests[] = {
+ VAL_TEST("--flag", flag, true, true, 0),
+ VAL_TEST("--flag=1", flag, false, true, -EINVAL),
+ VAL_TEST("--suffix=0", suffix, 0, true, 0),
+ VAL_TEST("--suffix=1", suffix, 1, true, 0),
+ VAL_TEST("--suffix=1234", suffix, 1234, true, 0),
+ VAL_TEST("--suffix=4096", suffix, 4096, true, 0),
+ VAL_TEST("--suffix=1Ki", suffix, 1024, true, 0),
+ VAL_TEST("--suffix=34Gi", suffix, 36507222016, true, 0),
+ VAL_TEST("--suffix=34.9Ki", suffix, 0, true, -EINVAL),
+ VAL_TEST("--suffix=32Gii", suffix, 0, true, -EINVAL),
+ VAL_TEST("--uint=1", uint, 1, true, 0),
+ VAL_TEST("--int=1", int_val, 1, true, 0),
+ VAL_TEST("--long=1", long_val, 1, true, 0),
+ VAL_TEST("--double=1", double_val, 1, true, 0),
+ VAL_TEST("--byte=1", byte, 1, true, 0),
+ VAL_TEST("--byte=256", byte, 0, true, -EINVAL),
+ VAL_TEST("--shrt=1", shrt, 1, true, 0),
+ VAL_TEST("--incr", incr, 1, true, 0),
+ VAL_TEST("--incr=1", incr, 0, true, -EINVAL),
+ VAL_TEST("--string=string", string, "string", false, 0),
+ VAL_TEST("--fmt=fmt", fmt, "fmt", false, 0),
+ VAL_TEST("--file=file", file, "file", false, 0),
+ VAL_TEST("--list=list", list, "list", false, 0),
+ VAL_TEST("--str=str", str, "str", false, 0),
+};
+
+void toval_test(struct toval_test *test)
+{
+ const char *desc = "Test argconfig parse";
+ int ret;
+ char *argv[] = { "test-argconfig", test->arg };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("flag",'f', &cfg.flag, "flag"),
+ OPT_SUFFIX("suffix", 's', &cfg.suffix, "suffix"),
+ OPT_UINT("uint", 'u', &cfg.uint, "uint"),
+ OPT_INT("int", 'i', &cfg.int_val, "int"),
+ OPT_LONG("long", 'l', &cfg.long_val, "long"),
+ OPT_DOUBLE("double", 'd', &cfg.double_val, "double"),
+ OPT_BYTE("byte", 'b', &cfg.byte, "byte"),
+ OPT_SHRT("shrt", 'S', &cfg.shrt, "shrt"),
+ OPT_INCR("incr", 'I', &cfg.incr, "incr"),
+ OPT_STRING("string", 't', "STRING", &cfg.string, "string"),
+ OPT_FMT("fmt", 'F', &cfg.fmt, "fmt"),
+ OPT_FILE("file", 'L', &cfg.file, "file"),
+ OPT_LIST("list", 'T', &cfg.list, "list"),
+ OPT_STR("str", 'r', &cfg.str, "str"),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(2, argv, desc, opts);
+ if (ret != test->ret) {
+ printf("ERROR: converting {%s} failed\n", test->arg);
+ test_rc = 1;
+ return;
+ }
+ if (ret)
+ return;
+
+ check_val(test->arg, &test->exp, test->val, test->size);
+}
+
+int main(void)
+{
+ unsigned int i;
+ FILE *f;
+
+ test_rc = 0;
+ setlocale(LC_NUMERIC, "C");
+ f = freopen("/dev/null", "w", stderr);
+ if (!f)
+ printf("ERROR: reopening stderr failed: %s\n", strerror(errno));
+
+ for (i = 0; i < ARRAY_SIZE(toval_tests); i++)
+ toval_test(&toval_tests[i]);
+
+ if (f)
+ fclose(f);
+
+ return test_rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/unit/test-suffix-binary-parse.c b/unit/test-suffix-binary-parse.c
new file mode 100644
index 0000000..5f6ac4a
--- /dev/null
+++ b/unit/test-suffix-binary-parse.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "../util/suffix.h"
+#include "../util/types.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static int test_rc;
+
+static void check_num(const char *val, __u64 exp, __u64 num)
+{
+ if (exp == num)
+ return;
+
+ printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n",
+ val, (unsigned long long)num, (unsigned long long)exp);
+
+ test_rc = 1;
+}
+
+struct tonum_test {
+ const char *val;
+ const uint64_t exp;
+ int ret;
+};
+
+static struct tonum_test tonum_tests[] = {
+ { "1234", 1234, 0 },
+ { "1Ki", 1024, 0},
+ { "34Gi", 36507222016, 0 },
+ { "34.9Ki", 0, -EINVAL},
+ { "32Gii", 0, -EINVAL },
+};
+
+void tonum_test(struct tonum_test *test)
+{
+ char *endptr;
+ uint64_t num;
+ int ret;
+
+ ret = suffix_binary_parse(test->val, &endptr, &num);
+ if (ret != test->ret) {
+ printf("ERROR: converting {%s} failed\n", test->val);
+ test_rc = 1;
+ return;
+ }
+ if (ret)
+ return;
+
+ check_num(test->val, test->exp, num);
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ test_rc = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tonum_tests); i++)
+ tonum_test(&tonum_tests[i]);
+
+ return test_rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/unit/test-suffix-si-parse.c b/unit/test-suffix-si-parse.c
new file mode 100644
index 0000000..54cff0e
--- /dev/null
+++ b/unit/test-suffix-si-parse.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <locale.h>
+
+#include "../util/suffix.h"
+#include "../util/types.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static int test_rc;
+
+static void check_num(const char *val, __u64 exp, __u64 num)
+{
+ if (exp == num)
+ return;
+
+ printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n",
+ val, (unsigned long long)num, (unsigned long long)exp);
+
+ test_rc = 1;
+}
+
+struct tonum_test {
+ const char *val;
+ const uint64_t exp;
+ int ret;
+};
+
+static struct tonum_test tonum_tests[] = {
+ { "11995709440", 11995709440, 0 },
+ { "1199570940", 1199570940, 0},
+ { "234.567M", 234567000, 0 },
+ { "1.2k", 1200, 0 },
+ { "6.14T", 6140000000000, 0 },
+ { "123.4567k", 123456, 0 },
+ { "12345.6789101112M", 12345678910, 0},
+ { "6.14", 6, 0 },
+ { "6.14#", 0, -EINVAL },
+ { "2,33", 0, -EINVAL },
+ { "3..3", 0, -EINVAL },
+ { "123.12MM", 0, -EINVAL },
+ { "800G", 800000000000, 0 },
+ { "800GG", 0, -EINVAL },
+ { "800G800", 0, -EINVAL },
+ { "800.0G", 800000000000, 0 },
+ { "800.G", 0, -EINVAL },
+ { "800.", 0, -EINVAL },
+};
+
+void tonum_test(struct tonum_test *test)
+{
+ char *endptr;
+ uint64_t num;
+ int ret;
+
+ ret = suffix_si_parse(test->val, &endptr, &num);
+ if (ret != test->ret) {
+ printf("ERROR: converting {%s} failed\n", test->val);
+ test_rc = 1;
+ return;
+ }
+ if (ret)
+ return;
+
+ check_num(test->val, test->exp, num);
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ test_rc = 0;
+ setlocale(LC_NUMERIC, "C");
+
+ for (i = 0; i < ARRAY_SIZE(tonum_tests); i++)
+ tonum_test(&tonum_tests[i]);
+
+ return test_rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/unit/test-uint128-si.c b/unit/test-uint128-si.c
new file mode 100644
index 0000000..cc13450
--- /dev/null
+++ b/unit/test-uint128-si.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../util/types.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+/* create a uint128_t from four uint32_ts. w0 is the most significant value,
+ * w2 the least */
+#define U128(w0, w1, w2, w3) { .words = { w0, w1, w2, w3 } }
+
+static int test_rc;
+
+static void check_str(nvme_uint128_t val, __u32 bytes_per_unit, const char *exp,
+ const char *res)
+{
+ if (!strcmp(res, exp))
+ return;
+
+ printf("ERROR: printing {%08x.%08x.%08x.%08x} (bytes per unit %u), got '%s', expected '%s'\n",
+ val.words[3], val.words[2], val.words[1], val.words[0],
+ bytes_per_unit, res, exp);
+
+ test_rc = 1;
+}
+
+struct tostr_test {
+ nvme_uint128_t val;
+ __u32 bytes_per_unit;
+ const char *exp;
+};
+
+static struct tostr_test tostr_tests[] = {
+ { U128(0, 0, 0, 0), 1, "0.00 B" },
+ { U128(0, 0, 0, 1), 1, "1.00 B" },
+ { U128(0, 0, 0, 10), 1, "10.00 B" },
+ { U128(4, 3, 2, 1), 1, "316.91 RB" },
+ { U128(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff), 1,
+ "340282366.92 QB" },
+ { U128(0, 0, 0, 0xae0dc2), 1000 * 512, "5.84 TB" },
+ { U128(0, 0, 0, 0xf9c546), 1000 * 512, "8.38 TB" },
+ { U128(0, 0, 0, 0x4c2aa594), 1000 * 512, "654.27 TB" },
+ { U128(0, 0, 0, 0x5b013de8), 1000 * 512, "781.73 TB" },
+};
+
+void tostr_test(struct tostr_test *test)
+{
+ char *str;
+ str = uint128_t_to_si_string(test->val, test->bytes_per_unit);
+ check_str(test->val, test->bytes_per_unit, test->exp, str);
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ test_rc = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tostr_tests); i++)
+ tostr_test(&tostr_tests[i]);
+
+ return test_rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/unit/test-uint128.c b/unit/test-uint128.c
new file mode 100644
index 0000000..f8478ef
--- /dev/null
+++ b/unit/test-uint128.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+#include "../util/types.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+/* create a uint128_t from four uint32_ts. w0 is the most significant value,
+ * w2 the least */
+#define U128(w0, w1, w2, w3) { .words = { w0, w1, w2, w3 } }
+
+static int test_rc;
+
+static void check_str(nvme_uint128_t val, const char *exp, const char *res)
+{
+ if (!strcmp(res, exp))
+ return;
+
+ printf("ERROR: printing {%08x.%08x.%08x.%08x}, got '%s', expected '%s'\n",
+ val.words[3], val.words[2], val.words[1], val.words[0],
+ res, exp);
+
+ test_rc = 1;
+}
+
+struct tostr_test {
+ const char *locale;
+ nvme_uint128_t val;
+ const char *exp;
+};
+
+static struct tostr_test tostr_tests[] = {
+ { NULL, U128(0, 0, 0, 0),"0" },
+ { NULL, U128(0, 0, 0, 1), "1" },
+ { NULL, U128(0, 0, 0, 10), "10" },
+ { NULL, U128(4, 3, 2, 1), "316912650112397582603894390785" },
+ {
+ NULL,
+ U128(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff),
+ "340282366920938463463374607431768211455"
+ },
+ { "fr_FR.utf-8", U128(0, 0, 0, 1000), "1\u202f000" },
+};
+
+void tostr_test(struct tostr_test *test)
+{
+ char *str;
+
+ if (!setlocale(LC_NUMERIC, test->locale))
+ return;
+
+ if (test->locale)
+ str = uint128_t_to_l10n_string(test->val);
+ else
+ str = uint128_t_to_string(test->val);
+
+ check_str(test->val, test->exp, str);
+}
+
+int main(void)
+{
+ unsigned int i;
+
+ test_rc = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tostr_tests); i++)
+ tostr_test(&tostr_tests[i]);
+
+ return test_rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/util/argconfig.c b/util/argconfig.c
new file mode 100644
index 0000000..5ec3d6f
--- /dev/null
+++ b/util/argconfig.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * Author: Logan Gunthorpe
+ *
+ * Date: Oct 23 2014
+ *
+ * Description:
+ * Functions for parsing command line options.
+ *
+ */
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+#include <locale.h>
+
+static const char *append_usage_str = "";
+
+static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option,
+ int index);
+
+void argconfig_append_usage(const char *str)
+{
+ append_usage_str = str;
+}
+
+void print_word_wrapped(const char *s, int indent, int start, FILE *stream)
+{
+ const int width = 76;
+ const char *c, *t;
+ int next_space = -1;
+ int last_line = indent;
+
+ while (start < indent) {
+ putc(' ', stream);
+ start++;
+ }
+
+ for (c = s; *c != 0; c++) {
+ if (*c == '\n')
+ goto new_line;
+
+ if (*c == ' ' || next_space < 0) {
+ next_space = 0;
+ for (t = c + 1; *t != 0 && *t != ' '; t++)
+ next_space++;
+
+ if (((int)(c - s) + start + next_space) > (last_line - indent + width)) {
+ int i;
+new_line:
+ last_line = (int) (c-s) + start;
+ putc('\n', stream);
+ for (i = 0; i < indent; i++)
+ putc(' ', stream);
+ start = indent;
+ continue;
+ }
+ }
+ putc(*c, stream);
+ }
+}
+
+static void show_option(const struct argconfig_commandline_options *option)
+{
+ char buffer[0x1000];
+ char *b = buffer;
+
+ b += sprintf(b, " [ ");
+ if (option->option) {
+ b += sprintf(b, " --%s", option->option);
+ if (option->argument_type == optional_argument)
+ b += sprintf(b, "[=<%s>]", option->meta ? option->meta : "arg");
+ if (option->argument_type == required_argument)
+ b += sprintf(b, "=<%s>", option->meta ? option->meta : "arg");
+ if (option->short_option)
+ b += sprintf(b, ",");
+ }
+ if (option->short_option) {
+ b += sprintf(b, " -%c", option->short_option);
+ if (option->argument_type == optional_argument)
+ b += sprintf(b, " [<%s>]", option->meta ? option->meta : "arg");
+ if (option->argument_type == required_argument)
+ b += sprintf(b, " <%s>", option->meta ? option->meta : "arg");
+ }
+ b += sprintf(b, " ] ");
+
+ fprintf(stderr, "%s", buffer);
+ if (option->help) {
+ print_word_wrapped("--- ", 40, b - buffer, stderr);
+ print_word_wrapped(option->help, 44, 44, stderr);
+ }
+ fprintf(stderr, "\n");
+}
+
+void argconfig_print_help(const char *program_desc,
+ struct argconfig_commandline_options *s)
+{
+ fprintf(stderr, "\033[1mUsage: %s\033[0m\n\n",
+ append_usage_str);
+
+ print_word_wrapped(program_desc, 0, 0, stderr);
+ fprintf(stderr, "\n");
+
+ if (!s || !s->option)
+ return;
+
+ fprintf(stderr, "\n\033[1mOptions:\033[0m\n");
+ for (; s && s->option; s++)
+ show_option(s);
+}
+
+static int argconfig_error(char *type, const char *opt, const char *arg)
+{
+ fprintf(stderr, "Expected %s argument for '%s' but got '%s'!\n", type, opt, arg);
+ return -EINVAL;
+}
+
+int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val)
+{
+ char *endptr;
+ unsigned long tmp = strtoul(str, &endptr, 0);
+
+ if (errno || tmp >= 1 << 8 || str == endptr)
+ return argconfig_error("byte", opt, str);
+
+ *val = tmp;
+
+ return 0;
+}
+
+static int argconfig_parse_type(struct argconfig_commandline_options *s, struct option *option,
+ int index)
+{
+ void *value = (void *)(char *)s->default_value;
+ char *endptr;
+ int ret = 0;
+
+ errno = 0; /* To distinguish success/failure after strtol/stroul call */
+
+ switch (s->config_type) {
+ case CFG_STRING:
+ *((char **)value) = optarg;
+ break;
+ case CFG_SIZE:
+ *((size_t *)value) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr)
+ ret = argconfig_error("integer", option[index].name, optarg);
+ break;
+ case CFG_INT:
+ *((int *)value) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr)
+ ret = argconfig_error("integer", option[index].name, optarg);
+ break;
+ case CFG_BYTE:
+ ret = argconfig_parse_byte(option[index].name, optarg, (uint8_t *)value);
+ break;
+ case CFG_SHORT: {
+ unsigned long tmp = strtoul(optarg, &endptr, 0);
+
+ if (errno || tmp >= 1 << 16 || optarg == endptr)
+ ret = argconfig_error("short", option[index].name, optarg);
+ else
+ *((uint16_t *)value) = tmp;
+ break;
+ }
+ case CFG_POSITIVE: {
+ uint32_t tmp = strtoul(optarg, &endptr, 0);
+
+ if (errno || optarg == endptr)
+ ret = argconfig_error("word", option[index].name, optarg);
+ else
+ *((uint32_t *)value) = tmp;
+ break;
+ }
+ case CFG_INCREMENT:
+ *((int *)value) += 1;
+ break;
+ case CFG_LONG:
+ *((unsigned long *)value) = strtoul(optarg, &endptr, 0);
+ if (errno || optarg == endptr)
+ ret = argconfig_error("long integer", option[index].name, optarg);
+ break;
+ case CFG_LONG_SUFFIX:
+ ret = suffix_binary_parse(optarg, &endptr, (uint64_t *)value);
+ if (ret)
+ argconfig_error("long suffixed integer", option[index].name, optarg);
+ break;
+ case CFG_DOUBLE:
+ *((double *)value) = strtod(optarg, &endptr);
+ if (errno || optarg == endptr)
+ ret = argconfig_error("float", option[index].name, optarg);
+ break;
+ case CFG_FLAG:
+ *((bool *)value) = true;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static int argconfig_get_val_len(struct argconfig_opt_val *opt_val, const char *str)
+{
+ struct argconfig_opt_val *v;
+ int len;
+ int match;
+
+ for (len = 1; len <= strlen(str); len++) {
+ match = 0;
+ for (v = opt_val; v && v->str; v++) {
+ if (!strncasecmp(str, v->str, len))
+ match++;
+ }
+ if (match == 1)
+ break;
+ }
+
+ return len;
+}
+
+static int argconfig_set_opt_val(enum argconfig_types type, union argconfig_val *opt_val, void *val)
+{
+ switch (type) {
+ case CFG_FLAG:
+ *(bool *)val = opt_val->bool_val;
+ break;
+ case CFG_LONG_SUFFIX:
+ *(uint64_t *)val = opt_val->long_suffix;
+ break;
+ case CFG_POSITIVE:
+ *(uint32_t *)val = opt_val->positive;
+ break;
+ case CFG_INT:
+ *(int *)val = opt_val->int_val;
+ break;
+ case CFG_LONG:
+ *(unsigned long *)val = opt_val->long_val;
+ break;
+ case CFG_DOUBLE:
+ *(double *)val = opt_val->double_val;
+ break;
+ case CFG_BYTE:
+ *(uint8_t *)val = opt_val->byte;
+ break;
+ case CFG_SHORT:
+ *(uint16_t *)val = opt_val->short_val;
+ break;
+ case CFG_INCREMENT:
+ *(int *)val = opt_val->increment;
+ break;
+ case CFG_STRING:
+ *(char **)val = opt_val->string;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option,
+ int index)
+{
+ const char *str = optarg;
+ void *val = s->default_value;
+ int len = strlen(optarg);
+ struct argconfig_opt_val *v;
+ int val_len;
+
+ for (v = s->opt_val; v && v->str; v++) {
+ val_len = argconfig_get_val_len(s->opt_val, v->str);
+ if (strncasecmp(str, v->str, len > val_len ? len : val_len))
+ continue;
+ return argconfig_set_opt_val(v->type, &v->val, val);
+ }
+
+ return argconfig_parse_type(s, option, index);
+}
+
+static bool argconfig_check_human_readable(struct argconfig_commandline_options *s)
+{
+ for (; s && s->option; s++) {
+ if (!strcmp(s->option, "human-readable") && s->config_type == CFG_FLAG)
+ return s->seen;
+ }
+
+ return false;
+}
+
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+ struct argconfig_commandline_options *options)
+{
+ char *short_opts;
+ struct option *long_opts;
+ struct argconfig_commandline_options *s;
+ int c, option_index = 0, short_index = 0, options_count = 0;
+ int ret = 0;
+
+ errno = 0;
+ for (s = options; s->option; s++)
+ options_count++;
+
+ long_opts = calloc(1, sizeof(struct option) * (options_count + 3));
+ short_opts = calloc(1, sizeof(*short_opts) * (options_count * 3 + 5));
+
+ if (!long_opts || !short_opts) {
+ fprintf(stderr, "failed to allocate memory for opts: %s\n", strerror(errno));
+ ret = -errno;
+ goto out;
+ }
+
+ for (s = options; s->option && option_index < options_count; s++) {
+ if (s->short_option) {
+ short_opts[short_index++] = s->short_option;
+ if (s->argument_type == required_argument ||
+ s->argument_type == optional_argument)
+ short_opts[short_index++] = ':';
+ if (s->argument_type == optional_argument)
+ short_opts[short_index++] = ':';
+ }
+ if (s->option && strlen(s->option)) {
+ long_opts[option_index].name = s->option;
+ long_opts[option_index].has_arg = s->argument_type;
+ }
+ s->seen = false;
+ option_index++;
+ }
+
+ long_opts[option_index].name = "help";
+ long_opts[option_index].val = 'h';
+
+ short_opts[short_index++] = '?';
+ short_opts[short_index] = 'h';
+
+ optind = 0;
+ while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &option_index)) != -1) {
+ if (c) {
+ if (c == '?' || c == 'h') {
+ argconfig_print_help(program_desc, options);
+ ret = -EINVAL;
+ break;
+ }
+ for (option_index = 0; option_index < options_count; option_index++) {
+ if (c == options[option_index].short_option)
+ break;
+ }
+ if (option_index == options_count)
+ continue;
+ }
+
+ s = &options[option_index];
+ s->seen = true;
+
+ if (!s->default_value)
+ continue;
+
+ if (s->opt_val)
+ ret = argconfig_parse_val(s, long_opts, option_index);
+ else
+ ret = argconfig_parse_type(s, long_opts, option_index);
+ if (ret)
+ break;
+ }
+
+ if (!argconfig_check_human_readable(options))
+ setlocale(LC_ALL, "C");
+
+out:
+ free(short_opts);
+ free(long_opts);
+ return ret;
+}
+
+int argconfig_parse_comma_sep_array(char *string, int *val, unsigned int max_length)
+{
+ int ret = 0;
+ unsigned long v;
+ char *tmp;
+ char *p;
+
+ if (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (!tmp)
+ return 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) {
+ tmp = strtok(NULL, ",");
+
+ if (tmp == NULL)
+ return ret;
+
+ if (ret >= max_length)
+ return -1;
+
+ 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++;
+ }
+}
+
+int argconfig_parse_comma_sep_array_short(char *string, unsigned short *val,
+ unsigned int max_length)
+{
+ int ret = 0;
+ unsigned long v;
+ char *tmp;
+ char *p;
+
+ if (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (!tmp)
+ return 0;
+
+ v = strtoul(tmp, &p, 0);
+ if (*p != 0)
+ return -1;
+ if (v > UINT16_MAX) {
+ fprintf(stderr, "%s out of range\n", tmp);
+ return -1;
+ }
+ val[ret] = v;
+ ret++;
+
+ while (1) {
+ tmp = strtok(NULL, ",");
+ if (tmp == NULL)
+ return ret;
+
+ if (ret >= max_length)
+ return -1;
+
+ v = strtoul(tmp, &p, 0);
+ if (*p != 0)
+ return -1;
+ if (v > UINT16_MAX) {
+ fprintf(stderr, "%s out of range\n", tmp);
+ return -1;
+ }
+ val[ret] = v;
+ ret++;
+ }
+}
+
+int argconfig_parse_comma_sep_array_long(char *string, unsigned long long *val,
+ unsigned int max_length)
+{
+ int ret = 0;
+ char *tmp;
+ char *p;
+
+ if (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (tmp == NULL)
+ return 0;
+
+ val[ret] = strtoll(tmp, &p, 0);
+ if (*p != 0)
+ return -1;
+ ret++;
+ while (1) {
+ tmp = strtok(NULL, ",");
+
+ if (tmp == NULL)
+ return ret;
+
+ if (ret >= max_length)
+ return -1;
+
+ val[ret] = strtoll(tmp, &p, 0);
+ if (*p != 0)
+ return -1;
+ ret++;
+ }
+}
+
+#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(size) \
+int argconfig_parse_comma_sep_array_u##size(char *string, \
+ __u##size *val, \
+ unsigned int max_length) \
+{ \
+ int ret = 0; \
+ uintmax_t v; \
+ char *tmp; \
+ char *p; \
+ \
+ if (!string || !strlen(string)) \
+ return 0; \
+ \
+ tmp = strtok(string, ","); \
+ if (!tmp) \
+ return 0; \
+ \
+ v = strtoumax(tmp, &p, 0); \
+ if (*p != 0) \
+ return -1; \
+ if (v > UINT##size##_MAX) { \
+ fprintf(stderr, "%s out of range\n", tmp); \
+ return -1; \
+ } \
+ val[ret] = v; \
+ \
+ ret++; \
+ while (1) { \
+ tmp = strtok(NULL, ","); \
+ \
+ if (tmp == NULL) \
+ return ret; \
+ \
+ if (ret >= max_length) \
+ return -1; \
+ \
+ v = strtoumax(tmp, &p, 0); \
+ if (*p != 0) \
+ return -1; \
+ if (v > UINT##size##_MAX) { \
+ fprintf(stderr, "%s out of range\n", tmp); \
+ return -1; \
+ } \
+ val[ret] = v; \
+ ret++; \
+ } \
+}
+
+DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(16);
+DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(32);
+DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(64);
+
+bool argconfig_parse_seen(struct argconfig_commandline_options *s,
+ const char *option)
+{
+ for (; s && s->option; s++) {
+ if (!strcmp(s->option, option))
+ return s->seen;
+ }
+
+ return false;
+}
diff --git a/util/argconfig.h b/util/argconfig.h
new file mode 100644
index 0000000..2a04a32
--- /dev/null
+++ b/util/argconfig.h
@@ -0,0 +1,189 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * Author: Logan Gunthorpe <logang@deltatee.com>
+ * Logan Gunthorpe
+ *
+ * Date: Oct 23 2014
+ *
+ * Description:
+ * Header file for argconfig.c
+ *
+ */
+
+#ifndef argconfig_H
+#define argconfig_H
+
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <linux/types.h>
+
+enum argconfig_types {
+ CFG_FLAG,
+ CFG_STRING,
+ CFG_INT,
+ CFG_SIZE,
+ CFG_LONG,
+ CFG_LONG_SUFFIX,
+ CFG_DOUBLE,
+ CFG_BYTE,
+ CFG_SHORT,
+ CFG_POSITIVE,
+ CFG_INCREMENT,
+};
+
+#define OPT_ARGS(n) \
+ struct argconfig_commandline_options n[]
+
+#define OPT_END() { NULL }
+
+#define OPT_FLAG(l, s, v, d, ...) \
+ {l, s, NULL, CFG_FLAG, v, no_argument, d, false, __VA_ARGS__}
+
+#define OPT_SUFFIX(l, s, v, d, ...) \
+ {l, s, "IONUM", CFG_LONG_SUFFIX, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_UINT(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_POSITIVE, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_INT(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_INT, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_LONG(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_LONG, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_DOUBLE(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_DOUBLE, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_BYTE(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_BYTE, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_SHRT(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_SHORT, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_INCR(l, s, v, d, ...) \
+ {l, s, "NUM", CFG_INCREMENT, v, no_argument, d, false, __VA_ARGS__}
+
+#define OPT_STRING(l, s, m, v, d, ...) \
+ {l, s, m, CFG_STRING, v, required_argument, d, false, __VA_ARGS__}
+
+#define OPT_FMT(l, s, v, d, ...) OPT_STRING(l, s, "FMT", v, d, __VA_ARGS__)
+#define OPT_FILE(l, s, v, d, ...) OPT_STRING(l, s, "FILE", v, d, __VA_ARGS__)
+#define OPT_LIST(l, s, v, d, ...) OPT_STRING(l, s, "LIST", v, d, __VA_ARGS__)
+#define OPT_STR(l, s, v, d, ...) OPT_STRING(l, s, "STRING", v, d, __VA_ARGS__)
+
+#define OPT_VALS(n) \
+ struct argconfig_opt_val n[]
+
+#define VAL_END() { NULL }
+
+#define VAL_FLAG(s, l, v) \
+ {s, CFG_FLAG, .val.flag = v}
+
+#define VAL_LONG_SUFFIX(s, v) \
+ {s, CFG_LONG_SUFFIX, .val.long_suffix = v}
+
+#define VAL_UINT(s, v) \
+ {s, CFG_POSITIVE, v}
+
+#define VAL_INT(s, v) \
+ {s, CFG_INT, .val.int_val = v}
+
+#define VAL_LONG(s, v) \
+ {s, CFG_LONG, .val.long_val = v}
+
+#define VAL_DOUBLE(s, v) \
+ {s, CFG_DOUBLE, .val.double_val = v}
+
+#define VAL_BYTE(s, v) \
+ {s, CFG_BYTE, .val.byte = v}
+
+#define VAL_SHRT(s, v) \
+ {s, CFG_SHORT, .val.short_val = v}
+
+#define VAL_INCR(s, v) \
+ {s, CFG_INCREMENT, .val.increment = v}
+
+#define VAL_STRING(s, m, v) \
+ {s, CFG_STRING, .val.string = v}
+
+union argconfig_val {
+ char *string;
+ size_t size;
+ int int_val;
+ int bool_val;
+ uint8_t byte;
+ uint16_t short_val;
+ uint32_t positive;
+ int increment;
+ unsigned long long_val;
+ uint64_t long_suffix;
+ double double_val;
+ bool flag;
+};
+
+struct argconfig_opt_val {
+ const char *str;
+ enum argconfig_types type;
+ union argconfig_val val;
+};
+
+struct argconfig_commandline_options {
+ const char *option;
+ const char short_option;
+ const char *meta;
+ enum argconfig_types config_type;
+ void *default_value;
+ int argument_type;
+ const char *help;
+ bool seen;
+ struct argconfig_opt_val *opt_val;
+};
+
+void argconfig_append_usage(const char *str);
+void argconfig_print_help(const char *program_desc,
+ struct argconfig_commandline_options *options);
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+ struct argconfig_commandline_options *options);
+int argconfig_parse_comma_sep_array(char *string, int *ret, unsigned int max_length);
+int argconfig_parse_comma_sep_array_short(char *string, unsigned short *ret,
+ unsigned int max_length);
+int argconfig_parse_comma_sep_array_long(char *string, unsigned long long *ret,
+ unsigned int max_length);
+int argconfig_parse_comma_sep_array_u16(char *string, __u16 *val,
+ unsigned int max_length);
+int argconfig_parse_comma_sep_array_u32(char *string, __u32 *val,
+ unsigned int max_length);
+int argconfig_parse_comma_sep_array_u64(char *string, __u64 *val,
+ unsigned int max_length);
+int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val);
+
+void print_word_wrapped(const char *s, int indent, int start, FILE *stream);
+bool argconfig_parse_seen(struct argconfig_commandline_options *options,
+ const char *option);
+#endif
diff --git a/util/base64.c b/util/base64.c
new file mode 100644
index 0000000..7f47cda
--- /dev/null
+++ b/util/base64.c
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * base64.c - RFC4648-compliant base64 encoding
+ *
+ * Copyright (c) 2020 Hannes Reinecke, SUSE
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+static const char base64_table[65] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode() - base64-encode some bytes
+ * @src: the bytes to encode
+ * @srclen: number of bytes to encode
+ * @dst: (output) the base64-encoded string. Not NUL-terminated.
+ *
+ * Encodes the input string using characters from the set [A-Za-z0-9+,].
+ * The encoded string is roughly 4/3 times the size of the input string.
+ *
+ * Return: length of the encoded string
+ */
+int base64_encode(const unsigned char *src, int srclen, char *dst)
+{
+ int i, bits = 0;
+ u_int32_t ac = 0;
+ char *cp = dst;
+
+ for (i = 0; i < srclen; i++) {
+ ac = (ac << 8) | src[i];
+ bits += 8;
+ do {
+ bits -= 6;
+ *cp++ = base64_table[(ac >> bits) & 0x3f];
+ } while (bits >= 6);
+ }
+ if (bits) {
+ *cp++ = base64_table[(ac << (6 - bits)) & 0x3f];
+ bits -= 6;
+ }
+ while (bits < 0) {
+ *cp++ = '=';
+ bits += 2;
+ }
+
+ return cp - dst;
+}
+
+/**
+ * base64_decode() - base64-decode some bytes
+ * @src: the base64-encoded string to decode
+ * @len: number of bytes to decode
+ * @dst: (output) the decoded bytes.
+ *
+ * Decodes the base64-encoded bytes @src according to RFC 4648.
+ *
+ * Return: number of decoded bytes
+ */
+int base64_decode(const char *src, int srclen, unsigned char *dst)
+{
+ u_int32_t ac = 0;
+ int i, bits = 0;
+ unsigned char *bp = dst;
+
+ for (i = 0; i < srclen; i++) {
+ const char *p = strchr(base64_table, src[i]);
+
+ if (src[i] == '=') {
+ ac = (ac << 6);
+ bits += 6;
+ if (bits >= 8)
+ bits -= 8;
+ continue;
+ }
+ if (!p || !src[i])
+ return -EINVAL;
+ ac = (ac << 6) | (p - base64_table);
+ bits += 6;
+ if (bits >= 8) {
+ bits -= 8;
+ *bp++ = (unsigned char)(ac >> bits);
+ }
+ }
+ if (ac && ((1 << bits) - 1))
+ return -EAGAIN;
+
+ return bp - dst;
+}
diff --git a/util/base64.h b/util/base64.h
new file mode 100644
index 0000000..c0f62e2
--- /dev/null
+++ b/util/base64.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _BASE64_H
+#define _BASE64_H
+
+int base64_encode(const unsigned char *src, int len, char *dst);
+int base64_decode(const char *src, int len, unsigned char *dst);
+
+#endif /* _BASE64_H */
diff --git a/util/cleanup.h b/util/cleanup.h
new file mode 100644
index 0000000..ee9b120
--- /dev/null
+++ b/util/cleanup.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __CLEANUP_H
+#define __CLEANUP_H
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "util/mem.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); \
+}
+
+static inline void freep(void *p)
+{
+ free(*(void**) p);
+}
+#define _cleanup_free_ __cleanup__(freep)
+
+#define _cleanup_huge_ __cleanup__(nvme_free_huge)
+
+static inline void close_file(int *f)
+{
+ if (*f > STDERR_FILENO)
+ close(*f);
+}
+#define _cleanup_file_ __cleanup__(close_file)
+
+#endif
diff --git a/util/crc32.c b/util/crc32.c
new file mode 100644
index 0000000..bb5f129
--- /dev/null
+++ b/util/crc32.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ * This file is part of elfutils.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * * the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version
+ *
+ * or
+ *
+ * * the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version
+ *
+ * or both in parallel, as here.
+ *
+ * elfutils 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.
+ *
+ * You should have received copies of the GNU General Public License and
+ * the GNU Lesser General Public License along with this program. If
+ * not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/crc32.c;hb=575198c29a427392823cc8f2400579a23d06a875 */
+
+#include "crc32.h"
+
+/* Table computed with Mark Adler's makecrc.c utility. */
+static const uint32_t crc32_table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len)
+{
+ unsigned char *end;
+
+ crc = ~crc;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc;
+}
diff --git a/util/crc32.h b/util/crc32.h
new file mode 100644
index 0000000..e48c97d
--- /dev/null
+++ b/util/crc32.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef crc32_H
+#define crc32_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len);
+
+#endif
diff --git a/util/json.c b/util/json.c
new file mode 100644
index 0000000..2de5848
--- /dev/null
+++ b/util/json.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <stdio.h>
+#include <errno.h>
+
+#include "json.h"
+#include "types.h"
+
+struct json_object *util_json_object_new_double(long double d)
+{
+ struct json_object *obj;
+ char *str;
+
+ if (asprintf(&str, "%Lf", d) < 0)
+ return NULL;
+
+ obj = json_object_new_string(str);
+
+ free(str);
+ return obj;
+
+}
+
+struct json_object *util_json_object_new_uint64(uint64_t i)
+{
+ struct json_object *obj;
+ char *str;
+
+ if (asprintf(&str, "%" PRIu64, i) < 0)
+ return NULL;
+
+ obj = json_object_new_string(str);
+
+ free(str);
+ return obj;
+
+}
+
+static int util_json_object_string_to_number(struct json_object *jso,
+ struct printbuf *pb, int level,
+ int flags)
+{
+ ssize_t len = json_object_get_string_len(jso);
+
+ printbuf_memappend(pb, json_object_get_string(jso), len);
+
+ return 0;
+}
+
+struct json_object *util_json_object_new_uint128(nvme_uint128_t val)
+{
+ struct json_object *obj;
+
+ obj = json_object_new_string(uint128_t_to_string(val));
+ json_object_set_serializer(obj, util_json_object_string_to_number, NULL, NULL);
+
+ return obj;
+}
+
+uint64_t util_json_object_get_uint64(struct json_object *obj)
+{
+ uint64_t val = 0;
+
+ if (json_object_is_type(obj, json_type_string)) {
+ char *end = NULL;
+ const char *buf;
+
+ buf = json_object_get_string(obj);
+ val = strtoull(buf, &end, 10);
+ if ((val == 0 && errno != 0) || (end == buf))
+ return 0;
+ }
+
+ return val;
+}
diff --git a/util/json.h b/util/json.h
new file mode 100644
index 0000000..54e33e3
--- /dev/null
+++ b/util/json.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef __JSON__H
+#define __JSON__H
+
+#ifdef CONFIG_JSONC
+#include <json.h>
+#include "util/types.h"
+
+/* Wrappers around json-c's API */
+
+#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_uint64(v))
+#define json_object_add_value_int(o, k, v) \
+ json_object_object_add(o, k, json_object_new_int(v))
+#ifndef CONFIG_JSONC_14
+#define json_object_new_uint64(v) util_json_object_new_uint64(v)
+#define json_object_get_uint64(v) util_json_object_get_uint64(v)
+#endif
+#define json_object_add_value_uint64(o, k, v) \
+ json_object_object_add(o, k, json_object_new_uint64(v))
+#define json_object_add_value_uint128(o, k, v) \
+ json_object_object_add(o, k, util_json_object_new_uint128(v))
+#define json_object_add_value_double(o, k, v) \
+ json_object_object_add(o, k, util_json_object_new_double(v))
+#define json_object_add_value_float(o, k, v) \
+ json_object_object_add(o, k, json_object_new_double(v))
+static inline int json_object_add_value_string(struct json_object *o, const char *k, const char *v) {
+ return json_object_object_add(o, k, v ? json_object_new_string(v) : NULL);
+}
+#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)
+static inline int json_array_add_value_string(struct json_object *o, const char *v) {
+ return json_object_array_add(o, v ? json_object_new_string(v) : NULL);
+}
+#define json_print_object(o, u) \
+ printf("%s", json_object_to_json_string_ext(o, \
+ JSON_C_TO_STRING_PRETTY | \
+ JSON_C_TO_STRING_NOSLASHESCAPE))
+
+struct json_object *util_json_object_new_double(long double d);
+struct json_object *util_json_object_new_uint64(uint64_t i);
+struct json_object *util_json_object_new_uint128(nvme_uint128_t val);
+struct json_object *util_json_object_new_uint128(nvme_uint128_t val);
+
+uint64_t util_json_object_get_uint64(struct json_object *obj);
+
+#else /* !CONFIG_JSONC */
+
+struct json_object;
+
+#endif
+
+#endif
diff --git a/util/mem.c b/util/mem.c
new file mode 100644
index 0000000..d2be46e
--- /dev/null
+++ b/util/mem.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "mem.h"
+
+#include "common.h"
+
+#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
+#define HUGE_MIN 0x80000
+
+void *nvme_alloc(size_t len)
+{
+ void *p;
+
+ len = ROUND_UP(len, 0x1000);
+ if (posix_memalign((void *)&p, getpagesize(), len))
+ return NULL;
+
+ memset(p, 0, len);
+ return p;
+}
+
+void *nvme_realloc(void *p, size_t len)
+{
+ size_t old_len = malloc_usable_size(p);
+
+ void *result = nvme_alloc(len);
+
+ if (p) {
+ memcpy(result, p, min(old_len, len));
+ free(p);
+ }
+
+ return result;
+}
+
+void *nvme_alloc_huge(size_t len, struct nvme_mem_huge *mh)
+{
+ memset(mh, 0, sizeof(*mh));
+
+ len = ROUND_UP(len, 0x1000);
+
+ /*
+ * For smaller allocation we just use posix_memalign and hope the kernel
+ * is able to convert to a contiguous memory region.
+ */
+ if (len < HUGE_MIN) {
+ mh->p = nvme_alloc(len);
+ if (!mh->p)
+ return NULL;
+ mh->posix_memalign = true;
+ mh->len = len;
+ return mh->p;
+ }
+
+ /*
+ * Larger allocation will almost certainly fail with the small
+ * allocation approach. Instead try pre-allocating memory from the
+ * HugeTLB pool.
+ *
+ * https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt
+ */
+ mh->p = mmap(NULL, len, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_HUGETLB, -1, 0);
+ if (mh->p != MAP_FAILED) {
+ mh->len = len;
+ return mh->p;
+ }
+
+ /*
+ * And if mmap fails because the pool is empty, try to use
+ * posix_memalign/madvise as fallback with a 2MB aligmnent in order to
+ * fullfil the request. This gives the kernel a chance to try to claim
+ * some huge pages. This might still fail though.
+ */
+ len = ROUND_UP(len, 0x200000);
+ if (posix_memalign(&mh->p, 0x200000, len))
+ return NULL;
+ mh->posix_memalign = true;
+ mh->len = len;
+
+ memset(mh->p, 0, mh->len);
+
+ if (madvise(mh->p, mh->len, MADV_HUGEPAGE) < 0) {
+ nvme_free_huge(mh);
+ return NULL;
+ }
+
+ return mh->p;
+}
+
+void nvme_free_huge(struct nvme_mem_huge *mh)
+
+{
+ if (!mh || mh->len == 0)
+ return;
+
+ if (mh->posix_memalign)
+ free(mh->p);
+ else
+ munmap(mh->p, mh->len);
+
+ mh->len = 0;
+ mh->p = NULL;
+}
diff --git a/util/mem.h b/util/mem.h
new file mode 100644
index 0000000..d13eb3a
--- /dev/null
+++ b/util/mem.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef MEM_H_
+#define MEM_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+
+void *nvme_alloc(size_t len);
+void *nvme_realloc(void *p, size_t len);
+
+struct nvme_mem_huge {
+ size_t len;
+ bool posix_memalign; /* p has been allocated using posix_memalign */
+ void *p;
+};
+
+void *nvme_alloc_huge(size_t len, struct nvme_mem_huge *mh);
+void nvme_free_huge(struct nvme_mem_huge *mh);
+
+#endif /* MEM_H_ */
diff --git a/util/meson.build b/util/meson.build
new file mode 100644
index 0000000..dfc683b
--- /dev/null
+++ b/util/meson.build
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+sources += [
+ 'util/argconfig.c',
+ 'util/base64.c',
+ 'util/crc32.c',
+ 'util/mem.c',
+ 'util/suffix.c',
+ 'util/types.c',
+]
+
+if json_c_dep.found()
+ sources += [
+ 'util/json.c',
+ ]
+endif
diff --git a/util/suffix.c b/util/suffix.c
new file mode 100644
index 0000000..f010f3b
--- /dev/null
+++ b/util/suffix.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * Author: Logan Gunthorpe
+ *
+ * Date: Oct 23 2014
+ *
+ * Description:
+ * Functions for dealing with number suffixes
+ *
+ */
+
+#include "suffix.h"
+#include "common.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <float.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+
+static struct si_suffix {
+ long double magnitude;
+ unsigned int exponent;
+ const char *suffix;
+} si_suffixes[] = {
+ {1e30, 30, "Q"},
+ {1e27, 27, "R"},
+ {1e24, 24, "Y"},
+ {1e21, 21, "Z"},
+ {1e18, 18, "E"},
+ {1e15, 15, "P"},
+ {1e12, 12, "T"},
+ {1e9, 9, "G"},
+ {1e6, 6, "M"},
+ {1e3, 3, "k"},
+};
+
+const char *suffix_si_get(double *value)
+{
+ long double value_ld = *value;
+ const char *suffix = suffix_si_get_ld(&value_ld);
+
+ *value = value_ld;
+
+ return suffix;
+}
+
+static bool suffix_si_check(const char val)
+{
+ int i;
+ struct si_suffix *s;
+
+ for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) {
+ s = &si_suffixes[i];
+
+ if (val == *s->suffix)
+ return true;
+ }
+
+ return false;
+}
+
+int suffix_si_parse(const char *str, char **endptr, uint64_t *val)
+{
+ unsigned long long num, frac = 0;
+ char *sep, *tmp;
+ int frac_len = 0, len, i;
+
+ num = strtoull(str, endptr, 0);
+ if (str == *endptr ||
+ ((num == ULLONG_MAX) && errno == ERANGE))
+ return -EINVAL;
+
+ /* simple number, no decimal point not suffix */
+ if ((*endptr)[0] == '\0') {
+ *val = num;
+ return 0;
+ }
+
+ /* get rid of the decimal point */
+ sep = localeconv()->decimal_point;
+ if (sep)
+ len = strlen(sep);
+ else
+ len = 0;
+
+ for (i = 0; i < len; i++) {
+ if (suffix_si_check((*endptr)[i]))
+ break;
+ if (((*endptr)[i] == '\0') || (*endptr)[i] != sep[i])
+ return -EINVAL;
+ }
+
+ if (suffix_si_check((*endptr)[i])) {
+ if ((*endptr)[i + 1] != '\0')
+ return -EINVAL;
+ } else {
+ *endptr += len;
+ tmp = *endptr;
+
+ /* extract the digits after decimal point */
+ frac = strtoull(tmp, endptr, 0);
+ if (tmp == *endptr ||
+ ((frac == ULLONG_MAX) && errno == ERANGE))
+ return -EINVAL;
+
+ /* test that we have max one character as suffix */
+ if ((*endptr)[0] != '\0' && (*endptr)[1] != '\0')
+ return -EINVAL;
+
+ frac_len = *endptr - tmp;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) {
+ struct si_suffix *s = &si_suffixes[i];
+
+ if ((*endptr)[0] != s->suffix[0])
+ continue;
+
+ /* we should check for overflow */
+ for (int j = 0; j < s->exponent; j++)
+ num *= 10;
+
+ if (s->exponent > frac_len) {
+ for (int j = 0; j < s->exponent - frac_len; j++)
+ frac *= 10;
+ } else if (s->exponent < frac_len) {
+ for (int j = 0; j < frac_len - s->exponent; j++)
+ frac /= 10;
+ } else {
+ frac = 0;
+ }
+
+ *val = num + frac;
+ return 0;
+ }
+
+ if ((*endptr)[0] != '\0')
+ return -EINVAL;
+
+ *val = num;
+ return 0;
+}
+
+const char *suffix_si_get_ld(long double *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) {
+ struct si_suffix *s = &si_suffixes[i];
+
+ if (*value >= s->magnitude) {
+ *value /= s->magnitude;
+ return s->suffix;
+ }
+ }
+
+ return "";
+}
+
+static struct binary_suffix {
+ int shift;
+ const char *suffix;
+} binary_suffixes[] = {
+ {50, "Pi"},
+ {40, "Ti"},
+ {30, "Gi"},
+ {20, "Mi"},
+ {10, "Ki"},
+};
+
+const char *suffix_binary_get(long long *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) {
+ struct binary_suffix *s = &binary_suffixes[i];
+
+ if (llabs(*value) >= (1LL << s->shift)) {
+ *value =
+ (*value + (1LL << (s->shift - 1))) / (1LL << s->shift);
+ return s->suffix;
+ }
+ }
+
+ return "";
+}
+
+const char *suffix_dbinary_get(double *value)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) {
+ struct binary_suffix *s = &binary_suffixes[i];
+
+ if (fabs(*value) >= (1LL << s->shift)) {
+ *value = *value / (1LL << s->shift);
+ return s->suffix;
+ }
+ }
+
+ return "";
+}
+
+int suffix_binary_parse(const char *str, char **endptr, uint64_t *val)
+{
+ uint64_t ret;
+ int i;
+
+ ret = strtoull(str, endptr, 0);
+ if (str == *endptr ||
+ ((ret == ULLONG_MAX) && errno == ERANGE))
+ return -EINVAL;
+
+ if (str == *endptr) {
+ *val = ret;
+ return 0;
+ }
+
+ /* simple number, no decimal point, no suffix */
+ if ((*endptr)[0] == '\0') {
+ *val = ret;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) {
+ struct binary_suffix *s = &binary_suffixes[i];
+
+ if (tolower((*endptr)[0]) == tolower(s->suffix[0]) &&
+ (s->suffix[0] != '\0' &&
+ (((*endptr)[0] != '\0' &&
+ (*endptr)[1] != '\0' &&
+ (*endptr)[2] == '\0') &&
+ (tolower((*endptr)[1]) == tolower(s->suffix[1]))))) {
+ ret <<= s->shift;
+ *val = ret;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
diff --git a/util/suffix.h b/util/suffix.h
new file mode 100644
index 0000000..5ea58f4
--- /dev/null
+++ b/util/suffix.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * Author: Logan Gunthorpe
+ *
+ * Date: Oct 23 2014
+ *
+ * Description:
+ * Functions for dealing with number suffixes
+ *
+ */
+
+#ifndef __ARGCONFIG_SUFFIX_H__
+
+#include <inttypes.h>
+#include <stdbool.h>
+
+const char *suffix_si_get(double *value);
+int suffix_si_parse(const char *str, char **endptr, uint64_t *val);
+const char *suffix_si_get_ld(long double *value);
+const char *suffix_binary_get(long long *value);
+const char *suffix_dbinary_get(double *value);
+int suffix_binary_parse(const char *str, char **endptr, uint64_t *val);
+
+#endif
diff --git a/util/types.c b/util/types.c
new file mode 100644
index 0000000..376c734
--- /dev/null
+++ b/util/types.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <time.h>
+
+#include <ccan/endian/endian.h>
+
+#include "types.h"
+#include "util/suffix.h"
+
+nvme_uint128_t le128_to_cpu(__u8 *data)
+{
+ nvme_uint128_t u;
+ nvme_uint128_t tmp;
+
+ memcpy(tmp.bytes, data, 16);
+ u.words[0] = le32_to_cpu(tmp.words[3]);
+ u.words[1] = le32_to_cpu(tmp.words[2]);
+ u.words[2] = le32_to_cpu(tmp.words[1]);
+ u.words[3] = le32_to_cpu(tmp.words[0]);
+ return u;
+}
+
+long double int128_to_double(__u8 *data)
+{
+ long double result = 0;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+ return result;
+}
+
+uint64_t int48_to_long(__u8 *data)
+{
+ int i;
+ uint64_t result = 0;
+
+ for (i = 0; i < 6; i++) {
+ result *= 256;
+ result += data[5 - i];
+ }
+ return result;
+}
+
+static long double uint128_t_to_double(nvme_uint128_t data)
+{
+ long double result = 0;
+ int i;
+
+ for (i = 0; i < sizeof(data.words) / sizeof(*data.words); i++) {
+ result *= 4294967296;
+ result += data.words[i];
+ }
+
+ return result;
+}
+
+static char *__uint128_t_to_string(nvme_uint128_t val, bool l10n)
+{
+ static char str[60];
+ int idx = 60;
+ __u64 div, rem;
+ char *sep = NULL;
+ int i, len = 0, cl = 0;
+
+ if (l10n) {
+ sep = localeconv()->thousands_sep;
+ len = strlen(sep);
+ cl = 1;
+ }
+
+ /* terminate at the end, and build up from the ones */
+ str[--idx] = '\0';
+
+ do {
+ if (len && !((sizeof(str) - idx) % (3 + cl))) {
+ for (i = 0; i < len; i++)
+ str[--idx] = sep[len - i - 1];
+ }
+
+ rem = val.words[0];
+
+ div = rem / 10;
+ rem = ((rem - div * 10) << 32) + val.words[1];
+ val.words[0] = div;
+
+ div = rem / 10;
+ rem = ((rem - div * 10) << 32) + val.words[2];
+ val.words[1] = div;
+
+ div = rem / 10;
+ rem = ((rem - div * 10) << 32) + val.words[3];
+ val.words[2] = div;
+
+ div = rem / 10;
+ rem = rem - div * 10;
+ val.words[3] = div;
+
+ str[--idx] = '0' + rem;
+ } while (val.words[0] || val.words[1] || val.words[2] || val.words[3]);
+
+ return str + idx;
+}
+
+char *uint128_t_to_string(nvme_uint128_t val)
+{
+ return __uint128_t_to_string(val, false);
+}
+
+char *uint128_t_to_l10n_string(nvme_uint128_t val)
+{
+ return __uint128_t_to_string(val, true);
+}
+
+char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit)
+{
+ long double bytes = uint128_t_to_double(val) * bytes_per_unit;
+ static char str[40];
+ const char *suffix = suffix_si_get_ld(&bytes);
+ int n = snprintf(str, sizeof(str), "%.2Lf %sB", bytes, suffix);
+
+ if (n <= 0)
+ return "";
+
+ if (n >= sizeof(str))
+ str[sizeof(str) - 1] = '\0';
+
+ return str;
+}
+
+const char *util_uuid_to_string(unsigned char uuid[NVME_UUID_LEN])
+{
+ static char uuid_str[NVME_UUID_LEN_STRING];
+
+ nvme_uuid_to_string(uuid, uuid_str);
+
+ return uuid_str;
+}
+
+const char *util_fw_to_string(char *c)
+{
+ static char ret[9];
+ int i;
+
+ for (i = 0; i < 8; i++)
+ ret[i] = c[i] >= '!' && c[i] <= '~' ? c[i] : '.';
+ ret[i] = '\0';
+ return ret;
+}
+
+int convert_ts(time_t time, char *ts_buf)
+{
+ struct tm time_info;
+ time_t time_human, time_ms;
+ char buf[80];
+
+ time_human = time / 1000;
+ time_ms = time % 1000;
+
+ gmtime_r((const time_t *)&time_human, &time_info);
+
+ strftime(buf, sizeof(buf), "%Y-%m-%dD|%H:%M:%S", &time_info);
+ sprintf(ts_buf, "%s:%03ld", buf, time_ms);
+
+ return 0;
+}
+
+void util_spinner(const char *disp_name, float percent)
+{
+ static const char dash[51] = {[0 ... 49] = '=', '\0'};
+ static const char space[51] = {[0 ... 49] = ' ', '\0'};
+ static const char spin[] = {'-', '\\', '|', '/' };
+ static int progress;
+ static int i;
+ const char *dn = disp_name ? disp_name : "";
+
+ if (percent < 0)
+ percent = 0;
+ else if (percent > 1)
+ percent = 1;
+
+ progress = (int)(percent * 100.0);
+ if (progress < 2)
+ printf("\r%s [%c%.*s] %3d%%", dn,
+ spin[i % 4], 49,
+ space, progress);
+ else if (progress < 100)
+ printf("\r%s [%.*s%c%.*s] %3d%%", dn,
+ progress / 2 - 1, dash,
+ spin[i % 4], 50 - progress / 2,
+ space, progress);
+ else
+ printf("\r%s [%.*s] %3d%%\n", dn,
+ 50, dash, 100);
+ i++;
+
+ fflush(stdout);
+}
diff --git a/util/types.h b/util/types.h
new file mode 100644
index 0000000..595958b
--- /dev/null
+++ b/util/types.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _MISC_H
+#define _MISC_H
+
+/* type conversion helpers */
+
+#include <stdint.h>
+#include <linux/types.h>
+
+#include <libnvme.h>
+
+#define ABSOLUTE_ZERO_CELSIUS -273
+
+static inline long kelvin_to_celsius(long t)
+{
+ return t + ABSOLUTE_ZERO_CELSIUS;
+}
+
+/* uint128_t is not always available, define our own. */
+union nvme_uint128 {
+ __u8 bytes[16];
+ __u32 words[4]; /* [0] is most significant word */
+};
+
+typedef union nvme_uint128 nvme_uint128_t;
+
+nvme_uint128_t le128_to_cpu(__u8 *data);
+long double int128_to_double(__u8 *data);
+uint64_t int48_to_long(__u8 *data);
+
+char *uint128_t_to_string(nvme_uint128_t val);
+char *uint128_t_to_l10n_string(nvme_uint128_t val);
+char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit);
+const char *util_uuid_to_string(unsigned char uuid[NVME_UUID_LEN]);
+const char *util_fw_to_string(char *c);
+
+/**
+ * @brief convert time_t format time to a human readable string
+ *
+ * @param time, input time_t time
+ * @param ts_buf, output time string
+ * @Note, time string format is "Y-M-D|H:M:S:MS"
+ *
+ * @return 0 success
+ */
+int convert_ts(time_t time, char *ts_buf);
+
+/**
+ * @brief print once a progress of spinner to stdout
+ * the output will be looks like if disp_name is "LogDump" and percent is 0.5
+ * LogDump [========================- ] 50%
+
+ *
+ * @param disp_name, const string displayed before spiner
+ * @param percent [0, 1.0] about the progress
+ *
+ */
+void util_spinner(const char *disp_name, float percent);
+
+#endif /* _MISC_H */