summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:40:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:40:30 +0000
commitdc597ce8df5ae6efd2728a2d7ba7d92486028f79 (patch)
tree55b9e9257eba4579667f9522368aa29f5be6754a
parentInitial commit. (diff)
downloadnvme-cli-dc597ce8df5ae6efd2728a2d7ba7d92486028f79.tar.xz
nvme-cli-dc597ce8df5ae6efd2728a2d7ba7d92486028f79.zip
Adding upstream version 1.12.upstream/1.12
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--.gitignore18
-rw-r--r--CONTRIBUTING.md20
-rw-r--r--Documentation/Makefile265
-rw-r--r--Documentation/asciidoc.conf91
-rw-r--r--Documentation/asciidoctor-extensions.rb29
-rw-r--r--Documentation/cmds-main.txt137
-rwxr-xr-xDocumentation/install-webdoc.sh39
-rw-r--r--Documentation/manpage-base.xsl35
-rw-r--r--Documentation/manpage-normal.xsl13
-rw-r--r--Documentation/nvme-admin-passthru.1171
-rw-r--r--Documentation/nvme-admin-passthru.html989
-rw-r--r--Documentation/nvme-admin-passthru.txt128
-rw-r--r--Documentation/nvme-ana-log.177
-rw-r--r--Documentation/nvme-ana-log.html819
-rw-r--r--Documentation/nvme-ana-log.txt41
-rw-r--r--Documentation/nvme-attach-ns.175
-rw-r--r--Documentation/nvme-attach-ns.html813
-rw-r--r--Documentation/nvme-attach-ns.txt39
-rw-r--r--Documentation/nvme-changed-ns-list-log.1106
-rw-r--r--Documentation/nvme-changed-ns-list-log.html842
-rw-r--r--Documentation/nvme-changed-ns-list-log.txt58
-rw-r--r--Documentation/nvme-compare.1210
-rw-r--r--Documentation/nvme-compare.html1063
-rw-r--r--Documentation/nvme-compare.txt148
-rw-r--r--Documentation/nvme-connect-all.1253
-rw-r--r--Documentation/nvme-connect-all.html1118
-rw-r--r--Documentation/nvme-connect-all.txt194
-rw-r--r--Documentation/nvme-connect.1220
-rw-r--r--Documentation/nvme-connect.html1077
-rw-r--r--Documentation/nvme-connect.txt157
-rw-r--r--Documentation/nvme-create-ns.1102
-rw-r--r--Documentation/nvme-create-ns.html888
-rw-r--r--Documentation/nvme-create-ns.txt74
-rw-r--r--Documentation/nvme-delete-ns.153
-rw-r--r--Documentation/nvme-delete-ns.html802
-rw-r--r--Documentation/nvme-delete-ns.txt34
-rw-r--r--Documentation/nvme-dera-stat.171
-rw-r--r--Documentation/nvme-dera-stat.html798
-rw-r--r--Documentation/nvme-dera-stat.txt38
-rw-r--r--Documentation/nvme-detach-ns.157
-rw-r--r--Documentation/nvme-detach-ns.html813
-rw-r--r--Documentation/nvme-detach-ns.txt37
-rw-r--r--Documentation/nvme-device-self-test.1101
-rw-r--r--Documentation/nvme-device-self-test.html840
-rw-r--r--Documentation/nvme-device-self-test.txt55
-rw-r--r--Documentation/nvme-dir-receive.1235
-rw-r--r--Documentation/nvme-dir-receive.html975
-rw-r--r--Documentation/nvme-dir-receive.txt118
-rw-r--r--Documentation/nvme-dir-send.1241
-rw-r--r--Documentation/nvme-dir-send.html988
-rw-r--r--Documentation/nvme-dir-send.txt124
-rw-r--r--Documentation/nvme-disconnect-all.169
-rw-r--r--Documentation/nvme-disconnect-all.html798
-rw-r--r--Documentation/nvme-disconnect-all.txt34
-rw-r--r--Documentation/nvme-disconnect.1101
-rw-r--r--Documentation/nvme-disconnect.html846
-rw-r--r--Documentation/nvme-disconnect.txt56
-rw-r--r--Documentation/nvme-discover.1261
-rw-r--r--Documentation/nvme-discover.html1129
-rw-r--r--Documentation/nvme-discover.txt208
-rw-r--r--Documentation/nvme-dsm.197
-rw-r--r--Documentation/nvme-dsm.html896
-rw-r--r--Documentation/nvme-dsm.txt82
-rw-r--r--Documentation/nvme-effects-log.1108
-rw-r--r--Documentation/nvme-effects-log.html854
-rw-r--r--Documentation/nvme-effects-log.txt62
-rw-r--r--Documentation/nvme-endurance-log.1106
-rw-r--r--Documentation/nvme-endurance-log.html841
-rw-r--r--Documentation/nvme-endurance-log.txt56
-rw-r--r--Documentation/nvme-error-log.1112
-rw-r--r--Documentation/nvme-error-log.html856
-rw-r--r--Documentation/nvme-error-log.txt65
-rw-r--r--Documentation/nvme-flush.151
-rw-r--r--Documentation/nvme-flush.html803
-rw-r--r--Documentation/nvme-flush.txt34
-rw-r--r--Documentation/nvme-format.1225
-rw-r--r--Documentation/nvme-format.html1045
-rw-r--r--Documentation/nvme-format.txt157
-rw-r--r--Documentation/nvme-fw-commit.1147
-rw-r--r--Documentation/nvme-fw-commit.html908
-rw-r--r--Documentation/nvme-fw-commit.txt93
-rw-r--r--Documentation/nvme-fw-download.188
-rw-r--r--Documentation/nvme-fw-download.html859
-rw-r--r--Documentation/nvme-fw-download.txt68
-rw-r--r--Documentation/nvme-fw-log.1106
-rw-r--r--Documentation/nvme-fw-log.html838
-rw-r--r--Documentation/nvme-fw-log.txt58
-rw-r--r--Documentation/nvme-gen-hostnqn.148
-rw-r--r--Documentation/nvme-gen-hostnqn.html788
-rw-r--r--Documentation/nvme-gen-hostnqn.txt29
-rw-r--r--Documentation/nvme-get-feature.1214
-rw-r--r--Documentation/nvme-get-feature.html961
-rw-r--r--Documentation/nvme-get-feature.txt118
-rw-r--r--Documentation/nvme-get-log.1142
-rw-r--r--Documentation/nvme-get-log.html925
-rw-r--r--Documentation/nvme-get-log.txt98
-rw-r--r--Documentation/nvme-get-ns-id.167
-rw-r--r--Documentation/nvme-get-ns-id.html797
-rw-r--r--Documentation/nvme-get-ns-id.txt32
-rw-r--r--Documentation/nvme-get-property.1123
-rw-r--r--Documentation/nvme-get-property.html846
-rw-r--r--Documentation/nvme-get-property.txt62
-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.html800
-rw-r--r--Documentation/nvme-huawei-list.txt31
-rw-r--r--Documentation/nvme-id-ctrl.1196
-rw-r--r--Documentation/nvme-id-ctrl.html913
-rw-r--r--Documentation/nvme-id-ctrl.txt113
-rw-r--r--Documentation/nvme-id-ns.1229
-rw-r--r--Documentation/nvme-id-ns.html962
-rw-r--r--Documentation/nvme-id-ns.txt144
-rw-r--r--Documentation/nvme-id-nvmset.1142
-rw-r--r--Documentation/nvme-id-nvmset.html858
-rw-r--r--Documentation/nvme-id-nvmset.txt73
-rw-r--r--Documentation/nvme-intel-id-ctrl.195
-rw-r--r--Documentation/nvme-intel-id-ctrl.html856
-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.html850
-rw-r--r--Documentation/nvme-intel-internal-log.txt74
-rw-r--r--Documentation/nvme-intel-lat-stats.1100
-rw-r--r--Documentation/nvme-intel-lat-stats.html835
-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.html816
-rw-r--r--Documentation/nvme-intel-market-name.txt43
-rw-r--r--Documentation/nvme-intel-smart-log-add.1109
-rw-r--r--Documentation/nvme-intel-smart-log-add.html857
-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.html825
-rw-r--r--Documentation/nvme-intel-temp-stats.txt51
-rw-r--r--Documentation/nvme-io-passthru.1133
-rw-r--r--Documentation/nvme-io-passthru.html971
-rw-r--r--Documentation/nvme-io-passthru.txt116
-rw-r--r--Documentation/nvme-list-ctrl.170
-rw-r--r--Documentation/nvme-list-ctrl.html819
-rw-r--r--Documentation/nvme-list-ctrl.txt46
-rw-r--r--Documentation/nvme-list-ns.161
-rw-r--r--Documentation/nvme-list-ns.html821
-rw-r--r--Documentation/nvme-list-ns.txt44
-rw-r--r--Documentation/nvme-list-subsys.1126
-rw-r--r--Documentation/nvme-list-subsys.html857
-rw-r--r--Documentation/nvme-list-subsys.txt85
-rw-r--r--Documentation/nvme-list.162
-rw-r--r--Documentation/nvme-list.html819
-rw-r--r--Documentation/nvme-list.txt42
-rw-r--r--Documentation/nvme-lnvm-create.1100
-rw-r--r--Documentation/nvme-lnvm-create.html865
-rw-r--r--Documentation/nvme-lnvm-create.txt60
-rw-r--r--Documentation/nvme-lnvm-diag-bbtbl.1117
-rw-r--r--Documentation/nvme-lnvm-diag-bbtbl.html864
-rw-r--r--Documentation/nvme-lnvm-diag-bbtbl.txt65
-rw-r--r--Documentation/nvme-lnvm-diag-set-bbtbl.199
-rw-r--r--Documentation/nvme-lnvm-diag-set-bbtbl.html869
-rw-r--r--Documentation/nvme-lnvm-diag-set-bbtbl.txt63
-rw-r--r--Documentation/nvme-lnvm-factory.1109
-rw-r--r--Documentation/nvme-lnvm-factory.html857
-rw-r--r--Documentation/nvme-lnvm-factory.txt54
-rw-r--r--Documentation/nvme-lnvm-id-ns.188
-rw-r--r--Documentation/nvme-lnvm-id-ns.html850
-rw-r--r--Documentation/nvme-lnvm-id-ns.txt49
-rw-r--r--Documentation/nvme-lnvm-info.148
-rw-r--r--Documentation/nvme-lnvm-info.html786
-rw-r--r--Documentation/nvme-lnvm-info.txt27
-rw-r--r--Documentation/nvme-lnvm-init.197
-rw-r--r--Documentation/nvme-lnvm-init.html833
-rw-r--r--Documentation/nvme-lnvm-init.txt44
-rw-r--r--Documentation/nvme-lnvm-list.148
-rw-r--r--Documentation/nvme-lnvm-list.html786
-rw-r--r--Documentation/nvme-lnvm-list.txt27
-rw-r--r--Documentation/nvme-lnvm-remove.153
-rw-r--r--Documentation/nvme-lnvm-remove.html800
-rw-r--r--Documentation/nvme-lnvm-remove.txt32
-rw-r--r--Documentation/nvme-netapp-ontapdevices.174
-rw-r--r--Documentation/nvme-netapp-ontapdevices.html810
-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.1115
-rw-r--r--Documentation/nvme-ns-descs.html863
-rw-r--r--Documentation/nvme-ns-descs.txt74
-rw-r--r--Documentation/nvme-ns-rescan.167
-rw-r--r--Documentation/nvme-ns-rescan.html455
-rw-r--r--Documentation/nvme-ns-rescan.txt32
-rw-r--r--Documentation/nvme-read.1186
-rw-r--r--Documentation/nvme-read.html1040
-rw-r--r--Documentation/nvme-read.txt137
-rw-r--r--Documentation/nvme-reset.167
-rw-r--r--Documentation/nvme-reset.html801
-rw-r--r--Documentation/nvme-reset.txt32
-rw-r--r--Documentation/nvme-resv-acquire.1177
-rw-r--r--Documentation/nvme-resv-acquire.html954
-rw-r--r--Documentation/nvme-resv-acquire.txt92
-rw-r--r--Documentation/nvme-resv-register.1153
-rw-r--r--Documentation/nvme-resv-register.html944
-rw-r--r--Documentation/nvme-resv-register.txt93
-rw-r--r--Documentation/nvme-resv-release.1165
-rw-r--r--Documentation/nvme-resv-release.html937
-rw-r--r--Documentation/nvme-resv-release.txt84
-rw-r--r--Documentation/nvme-resv-report.180
-rw-r--r--Documentation/nvme-resv-report.html861
-rw-r--r--Documentation/nvme-resv-report.txt63
-rw-r--r--Documentation/nvme-sanitize-log.1144
-rw-r--r--Documentation/nvme-sanitize-log.html888
-rw-r--r--Documentation/nvme-sanitize-log.txt82
-rw-r--r--Documentation/nvme-sanitize.1105
-rw-r--r--Documentation/nvme-sanitize.html903
-rw-r--r--Documentation/nvme-sanitize.txt93
-rw-r--r--Documentation/nvme-security-recv.191
-rw-r--r--Documentation/nvme-security-recv.html893
-rw-r--r--Documentation/nvme-security-recv.txt80
-rw-r--r--Documentation/nvme-security-send.183
-rw-r--r--Documentation/nvme-security-send.html879
-rw-r--r--Documentation/nvme-security-send.txt72
-rw-r--r--Documentation/nvme-self-test-log.1121
-rw-r--r--Documentation/nvme-self-test-log.html836
-rw-r--r--Documentation/nvme-self-test-log.txt61
-rw-r--r--Documentation/nvme-set-feature.1124
-rw-r--r--Documentation/nvme-set-feature.html889
-rw-r--r--Documentation/nvme-set-feature.txt79
-rw-r--r--Documentation/nvme-set-property.157
-rw-r--r--Documentation/nvme-set-property.html812
-rw-r--r--Documentation/nvme-set-property.txt36
-rw-r--r--Documentation/nvme-show-hostnqn.148
-rw-r--r--Documentation/nvme-show-hostnqn.html792
-rw-r--r--Documentation/nvme-show-hostnqn.txt29
-rw-r--r--Documentation/nvme-show-regs.1123
-rw-r--r--Documentation/nvme-show-regs.html855
-rw-r--r--Documentation/nvme-show-regs.txt63
-rw-r--r--Documentation/nvme-smart-log.1112
-rw-r--r--Documentation/nvme-smart-log.html853
-rw-r--r--Documentation/nvme-smart-log.txt65
-rw-r--r--Documentation/nvme-subsystem-reset.167
-rw-r--r--Documentation/nvme-subsystem-reset.html797
-rw-r--r--Documentation/nvme-subsystem-reset.txt32
-rw-r--r--Documentation/nvme-telemetry-log.187
-rw-r--r--Documentation/nvme-telemetry-log.html845
-rw-r--r--Documentation/nvme-telemetry-log.txt54
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.166
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.html797
-rw-r--r--Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt34
-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.txt64
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.1106
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.html846
-rw-r--r--Documentation/nvme-toshiba-vs-smart-add-log.txt64
-rw-r--r--Documentation/nvme-transcend-badblock.171
-rw-r--r--Documentation/nvme-transcend-badblock.html803
-rw-r--r--Documentation/nvme-transcend-badblock.txt37
-rw-r--r--Documentation/nvme-transcend-healthvalue.171
-rw-r--r--Documentation/nvme-transcend-healthvalue.html803
-rw-r--r--Documentation/nvme-transcend-healthvalue.txt37
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.1138
-rw-r--r--Documentation/nvme-virtium-save-smart-to-vtview-log.html883
-rwxr-xr-xDocumentation/nvme-virtium-save-smart-to-vtview-log.txt84
-rw-r--r--Documentation/nvme-virtium-show-identify.171
-rw-r--r--Documentation/nvme-virtium-show-identify.html801
-rwxr-xr-xDocumentation/nvme-virtium-show-identify.txt39
-rw-r--r--Documentation/nvme-wdc-cap-diag.1163
-rw-r--r--Documentation/nvme-wdc-cap-diag.html859
-rw-r--r--Documentation/nvme-wdc-cap-diag.txt64
-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.txt39
-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.txt38
-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.html802
-rw-r--r--Documentation/nvme-wdc-clear-pcie-correctable-errors.txt40
-rw-r--r--Documentation/nvme-wdc-drive-essentials.195
-rw-r--r--Documentation/nvme-wdc-drive-essentials.html828
-rw-r--r--Documentation/nvme-wdc-drive-essentials.txt48
-rw-r--r--Documentation/nvme-wdc-drive-log.1116
-rw-r--r--Documentation/nvme-wdc-drive-log.html832
-rw-r--r--Documentation/nvme-wdc-drive-log.txt52
-rw-r--r--Documentation/nvme-wdc-drive-resize.176
-rw-r--r--Documentation/nvme-wdc-drive-resize.html813
-rw-r--r--Documentation/nvme-wdc-drive-resize.txt42
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.1116
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.html833
-rw-r--r--Documentation/nvme-wdc-get-crash-dump.txt52
-rw-r--r--Documentation/nvme-wdc-get-drive-status.1122
-rw-r--r--Documentation/nvme-wdc-get-drive-status.html839
-rw-r--r--Documentation/nvme-wdc-get-drive-status.txt60
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.1116
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.html835
-rw-r--r--Documentation/nvme-wdc-get-pfail-dump.txt54
-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.1115
-rw-r--r--Documentation/nvme-wdc-namespace-resize.html841
-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.txt63
-rw-r--r--Documentation/nvme-wdc-purge.173
-rw-r--r--Documentation/nvme-wdc-purge.html802
-rw-r--r--Documentation/nvme-wdc-purge.txt40
-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-drive-info.158
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.html794
-rw-r--r--Documentation/nvme-wdc-vs-drive-info.txt42
-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.txt76
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.1255
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.html957
-rw-r--r--Documentation/nvme-wdc-vs-internal-log.txt111
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.178
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.html817
-rw-r--r--Documentation/nvme-wdc-vs-nand-stats.txt45
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.1496
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.html1136
-rw-r--r--Documentation/nvme-wdc-vs-smart-add-log.txt268
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.1130
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.html860
-rw-r--r--Documentation/nvme-wdc-vs-telemetry-controller-option.txt63
-rw-r--r--Documentation/nvme-write-uncor.163
-rw-r--r--Documentation/nvme-write-uncor.html823
-rw-r--r--Documentation/nvme-write-uncor.txt40
-rw-r--r--Documentation/nvme-write-zeroes.1155
-rw-r--r--Documentation/nvme-write-zeroes.html944
-rw-r--r--Documentation/nvme-write-zeroes.txt87
-rw-r--r--Documentation/nvme-write.1196
-rw-r--r--Documentation/nvme-write.html1062
-rw-r--r--Documentation/nvme-write.txt145
-rw-r--r--Documentation/nvme.1312
-rw-r--r--Documentation/nvme.html1197
-rw-r--r--Documentation/nvme.txt60
-rw-r--r--LICENSE340
-rw-r--r--Makefile235
-rwxr-xr-xNVME-VERSION-GEN42
-rw-r--r--README.md215
-rw-r--r--cmd.h10
-rw-r--r--cmd_handler.h108
-rw-r--r--common.h12
-rw-r--r--completions/README120
-rw-r--r--completions/_nvme659
-rw-r--r--completions/bash-nvme-completion.sh238
-rw-r--r--define_cmd.h19
-rw-r--r--etc/discovery.conf.in4
-rw-r--r--fabrics.c1626
-rw-r--r--fabrics.h13
-rw-r--r--linux/lightnvm.h174
-rw-r--r--linux/nvme.h1418
-rw-r--r--linux/nvme_ioctl.h91
-rw-r--r--nvme-builtin.h81
-rw-r--r--nvme-filters.c88
-rw-r--r--nvme-ioctl.c879
-rw-r--r--nvme-ioctl.h155
-rw-r--r--nvme-lightnvm.c700
-rw-r--r--nvme-lightnvm.h329
-rw-r--r--nvme-models.c338
-rw-r--r--nvme-models.h6
-rw-r--r--nvme-print.c4706
-rw-r--r--nvme-print.h67
-rw-r--r--nvme-status.c167
-rw-r--r--nvme-status.h14
-rw-r--r--nvme-topology.c608
-rw-r--r--nvme.c4841
-rw-r--r--nvme.control.in9
-rw-r--r--nvme.h110
-rw-r--r--nvme.spec.in71
-rw-r--r--nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in1
-rw-r--r--nvmf-autoconnect/systemd/nvmefc-boot-connections.service10
-rw-r--r--nvmf-autoconnect/systemd/nvmf-autoconnect.service12
-rw-r--r--nvmf-autoconnect/systemd/nvmf-connect.target2
-rw-r--r--nvmf-autoconnect/systemd/nvmf-connect@.service14
-rw-r--r--nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules19
-rw-r--r--nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules3
-rw-r--r--plugin.c188
-rw-r--r--plugin.h36
-rw-r--r--plugins/dera/dera-nvme.c211
-rw-r--r--plugins/dera/dera-nvme.h17
-rw-r--r--plugins/huawei/huawei-nvme.c374
-rw-r--r--plugins/huawei/huawei-nvme.h18
-rw-r--r--plugins/intel/intel-nvme.c1316
-rw-r--r--plugins/intel/intel-nvme.h23
-rw-r--r--plugins/lnvm/lnvm-nvme.c436
-rw-r--r--plugins/lnvm/lnvm-nvme.h27
-rw-r--r--plugins/memblaze/memblaze-nvme.c759
-rw-r--r--plugins/memblaze/memblaze-nvme.h27
-rw-r--r--plugins/memblaze/memblaze-utils.h164
-rw-r--r--plugins/micron/micron-nvme.c1180
-rw-r--r--plugins/micron/micron-nvme.h21
-rw-r--r--plugins/netapp/netapp-nvme.c639
-rw-r--r--plugins/netapp/netapp-nvme.h18
-rw-r--r--plugins/scaleflux/sfx-nvme.c873
-rw-r--r--plugins/scaleflux/sfx-nvme.h25
-rw-r--r--plugins/seagate/seagate-diag.h269
-rw-r--r--plugins/seagate/seagate-nvme.c1397
-rw-r--r--plugins/seagate/seagate-nvme.h45
-rw-r--r--plugins/shannon/shannon-nvme.c374
-rw-r--r--plugins/shannon/shannon-nvme.h20
-rw-r--r--plugins/toshiba/toshiba-nvme.c563
-rw-r--r--plugins/toshiba/toshiba-nvme.h20
-rw-r--r--plugins/transcend/transcend-nvme.c92
-rw-r--r--plugins/transcend/transcend-nvme.h20
-rw-r--r--plugins/virtium/virtium-nvme.c1044
-rw-r--r--plugins/virtium/virtium-nvme.h21
-rw-r--r--plugins/wdc/wdc-nvme.c5663
-rw-r--r--plugins/wdc/wdc-nvme.h38
-rw-r--r--plugins/wdc/wdc-utils.c146
-rw-r--r--plugins/wdc/wdc-utils.h77
-rwxr-xr-xregress112
-rw-r--r--scripts/gen-hostnqn.sh42
-rwxr-xr-xscripts/latency114
-rw-r--r--tests/Makefile48
-rw-r--r--tests/README93
-rw-r--r--tests/TODO14
-rw-r--r--tests/config.json5
-rw-r--r--tests/nvme_attach_detach_ns_test.py90
-rw-r--r--tests/nvme_compare_test.py79
-rw-r--r--tests/nvme_create_max_ns_test.py97
-rw-r--r--tests/nvme_error_log_test.py63
-rw-r--r--tests/nvme_flush_test.py61
-rw-r--r--tests/nvme_format_test.py148
-rw-r--r--tests/nvme_fw_log_test.py71
-rw-r--r--tests/nvme_get_features_test.py105
-rw-r--r--tests/nvme_id_ctrl_test.py56
-rw-r--r--tests/nvme_id_ns_test.py88
-rw-r--r--tests/nvme_read_write_test.py72
-rw-r--r--tests/nvme_simple_template_test.py55
-rw-r--r--tests/nvme_smart_log_test.py86
-rw-r--r--tests/nvme_test.py479
-rw-r--r--tests/nvme_test_io.py99
-rw-r--r--tests/nvme_test_logger.py52
-rw-r--r--tests/nvme_writeuncor_test.py76
-rw-r--r--tests/nvme_writezeros_test.py102
-rw-r--r--util/argconfig.c534
-rw-r--r--util/argconfig.h130
-rw-r--r--util/json.c407
-rw-r--r--util/json.h88
-rw-r--r--util/parser.c284
-rw-r--r--util/parser.h34
-rw-r--r--util/suffix.c132
-rw-r--r--util/suffix.h41
457 files changed, 159628 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b0efd0b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+nvme
+*.xml
+a.out
+*.o
+*~
+*.swp
+NVME-VERSION-FILE
+
+cscope.*
+
+/debian/files
+/debian/nvme-cli.debhelper.log
+/debian/nvme-cli.substvars
+/debian/nvme-cli
+
+tests/__pycache__
+tests/nvmetests
+tests/*.pyc
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3b7f55f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,20 @@
+# 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).**
+
+### 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/Makefile b/Documentation/Makefile
new file mode 100644
index 0000000..9edae99
--- /dev/null
+++ b/Documentation/Makefile
@@ -0,0 +1,265 @@
+# Guard against environment variables
+MAN1_TXT =
+TECH_DOCS =
+ARTICLES =
+SP_ARTICLES =
+
+MAN1_TXT += $(filter-out \
+ $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
+ $(wildcard nvme-*.txt))
+MAN1_TXT += nvme.txt
+MAN_TXT = $(MAN1_TXT)
+MAN_XML = $(patsubst %.txt,%.xml,$(MAN_TXT))
+MAN_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
+
+DOC_HTML = $(MAN_HTML) $(OBSOLETE_HTML)
+
+API_DOCS =
+SP_ARTICLES += $(API_DOCS)
+SP_ARTICLES += $(TECH_DOCS)
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET_ASCIIDOC = @echo ' ' ASCIIDOC $@;
+ QUIET_XMLTO = @echo ' ' XMLTO $@;
+ QUIET_DB2TEXI = @echo ' ' DB2TEXI $@;
+ QUIET_MAKEINFO = @echo ' ' MAKEINFO $@;
+ QUIET_DBLATEX = @echo ' ' DBLATEX $@;
+ QUIET_XSLTPROC = @echo ' ' XSLTPROC $@;
+ QUIET_GEN = @echo ' ' GEN $@;
+ QUIET_LINT = @echo ' ' LINT $@;
+ QUIET_STDERR = 2> /dev/null
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ export V
+endif
+endif
+
+DOC_MAN1 = $(patsubst %.txt,%.1,$(MAN1_TXT))
+
+ASCIIDOC = asciidoc
+ASCIIDOC_EXTRA =
+ASCIIDOC_DOCBOOK = docbook
+ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA)
+TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
+MANPAGE_XSL = manpage-normal.xsl
+XMLTO = xmlto
+XMLTO_EXTRA = --skip-validation
+INSTALL ?= install
+RM ?= rm -f
+MAN_REPO = ../../nvme-manpages
+
+ASCIIDOC_HTML = xhtml11
+ASCIIDOC_CONF = -f asciidoc.conf
+
+ifdef USE_ASCIIDOCTOR
+ASCIIDOC = asciidoctor
+ASCIIDOC_CONF =
+ASCIIDOC_HTML = xhtml5
+ASCIIDOC_DOCBOOK = docbook5
+ASCIIDOC_EXTRA += -acompat-mode
+ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
+ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;'
+ASCIIDOC_EXTRA += -amansource='NVMe'
+ASCIIDOC_EXTRA += -amanmanual='NVMe Manual'
+endif
+
+ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF)
+TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
+
+MAKEINFO = makeinfo
+INSTALL_INFO = install-info
+DOCBOOK2X_TEXI = docbook2x-texi
+DBLATEX = dblatex
+ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex
+ifndef PERL_PATH
+ PERL_PATH = /usr/bin/perl
+endif
+
+ifdef DOCBOOK_XSL_172
+MANPAGE_XSL = manpage-1.72.xsl
+else
+ ifndef ASCIIDOC_ROFF
+ endif
+endif
+ifdef MAN_BOLD_LITERAL
+XMLTO_EXTRA += -m manpage-bold-literal.xsl
+endif
+ifdef DOCBOOK_SUPPRESS_SP
+XMLTO_EXTRA += -m manpage-suppress-sp.xsl
+endif
+
+ifndef MAN_BASE_URL
+MAN_BASE_URL = file://$(htmldir)/
+endif
+XMLTO_EXTRA +=
+
+ifdef GNU_ROFF
+XMLTO_EXTRA +=
+endif
+
+SHELL_PATH ?= $(SHELL)
+# Shell quote;
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+
+ifdef DEFAULT_PAGER
+DEFAULT_PAGER_SQ = $(subst ','\'',$(DEFAULT_PAGER))
+endif
+
+ifdef DEFAULT_EDITOR
+DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR))
+endif
+
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+DESTDIR =
+PREFIX ?= /usr/local
+
+all: man html
+
+html: $(DOC_HTML)
+
+man: man1
+man1: $(DOC_MAN1)
+
+install-no-build:
+ $(INSTALL) -d -m 755 $(DESTDIR)$(PREFIX)/share/man/man1
+ $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(PREFIX)/share/man/man1
+
+install: install-man
+
+install-man: man
+ $(INSTALL) -d -m 755 $(DESTDIR)$(PREFIX)/share/man/man1
+ $(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(PREFIX)/share/man/man1
+
+docdep_prereqs = \
+ cmd-list.made $(cmds_txt)
+
+doc.dep : $(docdep_prereqs) $(wildcard *.txt) build-docdep.perl
+ $(QUIET_GEN)$(RM) $@+ $@ && \
+ $(PERL_PATH) ./build-docdep.perl >$@+ $(QUIET_STDERR) && \
+ mv $@+ $@
+
+-include doc.dep
+
+cmds_txt = cmds-ancillaryinterrogators.txt \
+ cmds-ancillarymanipulators.txt \
+ cmds-mainporcelain.txt \
+ cmds-plumbinginterrogators.txt \
+ cmds-plumbingmanipulators.txt \
+ cmds-synchingrepositories.txt \
+ cmds-synchelpers.txt \
+ cmds-purehelpers.txt \
+ cmds-foreignscminterface.txt
+
+$(cmds_txt): cmd-list.made
+
+cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
+ $(QUIET_GEN)$(RM) $@ && \
+ $(PERL_PATH) ./cmd-list.perl ../command-list.txt $(QUIET_STDERR) && \
+ date >$@
+
+clean:
+ $(RM) *.xml *.xml+ *.html+
+ $(RM) *.texi *.texi+ *.texi++ nvme.info nvmeman.info
+ $(RM) *.pdf
+ $(RM) howto-index.txt howto/*.html doc.dep
+ $(RM) technical/*.html technical/api-index.txt
+ $(RM) $(cmds_txt) *.made
+ $(RM) manpage-base-url.xsl
+ $(RM) *~
+
+clobber: clean
+ $(RM) *.html *.1
+
+%.1 : %.xml
+ $(QUIET_XMLTO)$(RM) $@ && \
+ $(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+
+%.xml : %.txt
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(TXT_TO_XML) -d manpage -o $@+ $< && \
+ mv $@+ $@
+
+user-manual.xml: user-manual.txt user-manual.conf
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(TXT_TO_XML) -d article -o $@+ $< && \
+ mv $@+ $@
+
+technical/api-index.txt: technical/api-index-skel.txt \
+ technical/api-index.sh $(patsubst %,%.txt,$(API_DOCS))
+ $(QUIET_GEN)cd technical && '$(SHELL_PATH_SQ)' ./api-index.sh
+
+XSLT = docbook.xsl
+XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css
+
+nvme.info: user-manual.texi
+ $(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
+
+user-manual.texi: user-manual.xml
+ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
+ $(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@++ && \
+ $(PERL_PATH) fix-texi.perl <$@++ >$@+ && \
+ rm $@++ && \
+ mv $@+ $@
+
+user-manual.pdf: user-manual.xml
+ $(QUIET_DBLATEX)$(RM) $@+ $@ && \
+ $(DBLATEX) -o $@+ -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty $< && \
+ mv $@+ $@
+
+nvmeman.texi: $(MAN_XML) cat-texi.perl
+ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
+ ($(foreach xml,$(MAN_XML),$(DOCBOOK2X_TEXI) --encoding=UTF-8 \
+ --to-stdout $(xml) &&) true) > $@++ && \
+ $(PERL_PATH) cat-texi.perl $@ <$@++ >$@+ && \
+ rm $@++ && \
+ mv $@+ $@
+
+nvmeman.info: nvmeman.texi
+ $(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $*.texi
+
+$(patsubst %.txt,%.texi,$(MAN_TXT)): %.texi : %.xml
+ $(QUIET_DB2TEXI)$(RM) $@+ $@ && \
+ $(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@+ && \
+ mv $@+ $@
+
+howto-index.txt: howto-index.sh $(wildcard howto/*.txt)
+ $(QUIET_GEN)$(RM) $@+ $@ && \
+ '$(SHELL_PATH_SQ)' ./howto-index.sh $(sort $(wildcard howto/*.txt)) >$@+ && \
+ mv $@+ $@
+
+WEBDOC_DEST = /pub/software/scm/nvme/docs
+
+$(MAN_HTML): %.html : %.txt
+ $(QUIET_ASCIIDOC)$(RM) $@+ $@ && \
+ $(TXT_TO_HTML) -d manpage -o $@+ $< && \
+ mv $@+ $@
+
+quick-install: quick-install-man
+
+$(patsubst %,%.html,$(ARTICLES)) : %.html : %.txt
+ $(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.txt
+
+install-webdoc : html
+ '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
+
+require-manrepo::
+ @if test ! -d $(MAN_REPO); \
+ then echo "nvme-manpages repository must exist at $(MAN_REPO)"; exit 1; fi
+
+quick-install-man: require-manrepo
+ '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(MAN_REPO) $(DESTDIR)$(mandir)
+
+print-man1:
+ @for i in $(MAN1_TXT); do echo $$i; done
+
+.PHONY: FORCE
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/cmds-main.txt b/Documentation/cmds-main.txt
new file mode 100644
index 0000000..824ca69
--- /dev/null
+++ b/Documentation/cmds-main.txt
@@ -0,0 +1,137 @@
+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-dms[1]::
+ Submit Data Set Management
+
+linknvme:nvme-format[1]::
+ Format namespace(s)
+
+linknvme:nvme-fw-activate[1]::
+ F/W Activate
+
+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-smart-log[1]::
+ Retrieve Smart Log
+
+linknvme:nvme-endurance-log[1]::
+ Retrieve endurance Log
+
+linknvme:nvme-effects-log[1]::
+ Retrieve effects 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-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-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-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-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
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/nvme-admin-passthru.1 b/Documentation/nvme-admin-passthru.1
new file mode 100644
index 0000000..f6d247f
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.1
@@ -0,0 +1,171 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ADMIN\-PASSTHR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>] [\-\-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>]
+ [\-\-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>]
+.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
+\-\-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
+.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..4a113ba
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.html
@@ -0,0 +1,989 @@
+<!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-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;
+}
+
+
+#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-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;] [--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;]
+ [--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;]</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">
+--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>
+</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 2019-09-06 10:35:44 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-admin-passthru.txt b/Documentation/nvme-admin-passthru.txt
new file mode 100644
index 0000000..f2bff2e
--- /dev/null
+++ b/Documentation/nvme-admin-passthru.txt
@@ -0,0 +1,128 @@
+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>] [--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>]
+ [--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>]
+
+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.
+
+--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.
+
+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..862f42d
--- /dev/null
+++ b/Documentation/nvme-ana-log.1
@@ -0,0 +1,77 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ANA\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-ana-log \- Send NVMe ANA log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ana\-log\fR <device> [\-o <fmt> | \-\-output\-format=<fmt>]
+.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
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the 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..131205a
--- /dev/null
+++ b/Documentation/nvme-ana-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 8.6.10" />
+<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 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-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; [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the 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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ana-log.txt b/Documentation/nvme-ana-log.txt
new file mode 100644
index 0000000..fdd412e
--- /dev/null
+++ b/Documentation/nvme-ana-log.txt
@@ -0,0 +1,41 @@
+nvme-ana-log(1)
+===============
+
+NAME
+----
+nvme-ana-log - Send NVMe ANA log page request, returns result and log
+
+SYNOPSIS
+--------
+[verse]
+'nvme ana-log' <device> [-o <fmt> | --output-format=<fmt>]
+
+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
+-------
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the 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..0af22ae
--- /dev/null
+++ b/Documentation/nvme-attach-ns.1
@@ -0,0 +1,75 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ATTACH\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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,>]
+.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 namesapce too\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+Attach namspace 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..9415c01
--- /dev/null
+++ b/Documentation/nvme-attach-ns.html
@@ -0,0 +1,813 @@
+<!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-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;
+}
+
+
+#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-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;]</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 namesapce too.
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-attach-ns.txt b/Documentation/nvme-attach-ns.txt
new file mode 100644
index 0000000..a5d3471
--- /dev/null
+++ b/Documentation/nvme-attach-ns.txt
@@ -0,0 +1,39 @@
+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,>]
+
+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 namesapce too.
+
+EXAMPLES
+--------
+ Attach namspace to the controller:
+
+ # nvme attach-ns /dev/nvme1 -n 0x2 -c 0x21
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-changed-ns-list-log.1 b/Documentation/nvme-changed-ns-list-log.1
new file mode 100644
index 0000000..13dda55
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-log.1
@@ -0,0 +1,106 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CHANGED\-NS\-L" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the 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..a331e49
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-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 8.6.10" />
+<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 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-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;]</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;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the 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
+ 2018-11-29 13:32:28 GMT
+</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..4cfd065
--- /dev/null
+++ b/Documentation/nvme-changed-ns-list-log.txt
@@ -0,0 +1,58 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the 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-compare.1 b/Documentation/nvme-compare.1
new file mode 100644
index 0000000..0f1c6ff
--- /dev/null
+++ b/Documentation/nvme-compare.1
@@ -0,0 +1,210 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-COMPARE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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 trasnferred in bytes\&.
+.RE
+.PP
+\-r <reftag>, \-\-ref\-tag=<regtag>
+.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\&.
+.RE
+.sp
++
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+Bit
+T}:T{
+.sp
+Description
+T}
+T{
+.sp
+3
+T}:T{
+.sp
+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{
+.sp
+2:0
+T}:T{
+.sp
+PRCHK: Protection Information Check:
+T}
+T{
+.sp
+2
+T}:T{
+.sp
+Set to 1 enables checking the guard tag
+T}
+T{
+.sp
+1
+T}:T{
+.sp
+Set to 1 enables checking the application tag
+T}
+T{
+.sp
+0
+T}:T{
+.sp
+Set to 1 enables checking the reference tag
+T}
+.TE
+.sp 1
+.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 specifcation (1\&.3a) defines only one directive, 01h, for write stream idenfiers\&.
+.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 lower 16 bits of the DSM field in a write command; the upper 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
+.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..e3b6857
--- /dev/null
+++ b/Documentation/nvme-compare.html
@@ -0,0 +1,1063 @@
+<!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-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;
+}
+
+
+#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-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]</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 trasnferred in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+--ref-tag=&lt;regtag&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>
+</dd>
+</dl></div>
+<div class="paragraph"><p>+</p></div>
+<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>
+<div class="dlist"><dl>
+<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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+</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 lower 16 bits of the DSM field in a write
+ command; the upper 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>
+</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 2018-12-17 13:07:47 MST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-compare.txt b/Documentation/nvme-compare.txt
new file mode 100644
index 0000000..9185c5f
--- /dev/null
+++ b/Documentation/nvme-compare.txt
@@ -0,0 +1,148 @@
+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]
+
+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 trasnferred in bytes.
+
+-r <reftag>::
+--ref-tag=<regtag>::
+ 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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+
+-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 lower 16 bits of the DSM field in a write
+ command; the upper 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).
+
+EXAMPLES
+--------
+No examples yet.
+
+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..f829935
--- /dev/null
+++ b/Documentation/nvme-connect-all.1
@@ -0,0 +1,253 @@
+'\" 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: 04/29/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CONNECT\-ALL" "1" "04/29/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-connect-all \- Discover and Connect to Fabrics controllers\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme connect\-all\fR
+ [\-\-transport=<trtype> | \-t <trtype>]
+ [\-\-traddr=<traddr> | \-a <traddr>]
+ [\-\-trsvcid=<trsvcid> | \-s <trsvcid>]
+ [\-\-host\-traddr=<traddr> | \-w <traddr>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-raw=<filename> | \-r <filename>]
+ [\-\-keep\-alive\-tmo=<#> | \-k <#>]
+ [\-\-reconnect\-delay=<#> | \-c <#>]
+ [\-\-ctrl\-loss\-tmo=<#> | \-l <#>]
+ [\-\-hdr\-digest | \-g]
+ [\-\-data\-digest | \-G]
+ [\-\-nr\-io\-queues=<#> | \-i <#>]
+ [\-\-nr\-write\-queues=<#> | \-W <#>]
+ [\-\-nr\-poll\-queues=<#> | \-P <#>]
+ [\-\-queue\-size=<#> | \-Q <#>]
+ [\-\-matching | \-m]
+ [\-\-persistent | \-p]
+ [\-\-quiet | \-q]
+.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 /etc/nvme/discovery\&.conf file to use to supply a list of connect\-all commands to run\&. If no /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 Diѕcovery 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.
+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{
+loop
+T}:T{
+Connect to a NVMe over Fabrics target on the local host
+T}
+.TE
+.sp 1
+.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 Discovery Controller\&.
+.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 /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
+\-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
+\-g, \-\-hdr\-digest
+.RS 4
+Generates/verifies header digest (TCP)\&.
+.RE
+.PP
+\-G, \-\-data\-digest
+.RS 4
+Generates/verifies data digest (TCP)\&.
+.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
+\-m, \-\-matching
+.RS 4
+If a traddr was specified on the command line or in the configuration file, only create controllers for discovery records that match the given traddr, rather than for all entries in the discovery log page\&.
+.RE
+.PP
+\-p, \-\-persistent
+.RS 4
+Don\(cqt remove the discovery controller after retrieving the discovery log page\&.
+.RE
+.PP
+\-q, \-\-quiet
+.RS 4
+Suppress error messages\&.
+.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 a /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..b5f22f7
--- /dev/null
+++ b/Documentation/nvme-connect-all.html
@@ -0,0 +1,1118 @@
+<?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-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;]
+ [--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;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&gt;]
+ [--raw=&lt;filename&gt; | -r &lt;filename&gt;]
+ [--keep-alive-tmo=&lt;#&gt; | -k &lt;#&gt;]
+ [--reconnect-delay=&lt;#&gt; | -c &lt;#&gt;]
+ [--ctrl-loss-tmo=&lt;#&gt; | -l &lt;#&gt;]
+ [--hdr-digest | -g]
+ [--data-digest | -G]
+ [--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;]
+ [--matching | -m]
+ [--persistent | -p]
+ [--quiet | -q]</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 /etc/nvme/discovery.conf file to use to supply a list of
+connect-all commands to run. If no /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 Diѕcovery
+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">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">
+-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 Discovery Controller.
+</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
+ /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">
+-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">
+-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">
+-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">
+-m
+</dt>
+<dt class="hdlist1">
+--matching
+</dt>
+<dd>
+<p>
+ If a traddr was specified on the command line or in the configuration
+ file, only create controllers for discovery records that match the
+ given traddr, rather than for all entries in the discovery log page.
+</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">
+-q
+</dt>
+<dt class="hdlist1">
+--quiet
+</dt>
+<dd>
+<p>
+ Suppress error messages.
+</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 a /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
+ 2020-04-29 22:28:00 CEST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-connect-all.txt b/Documentation/nvme-connect-all.txt
new file mode 100644
index 0000000..63d3c8f
--- /dev/null
+++ b/Documentation/nvme-connect-all.txt
@@ -0,0 +1,194 @@
+nvme-connect-all(1)
+===================
+
+NAME
+----
+nvme-connect-all - Discover and Connect to Fabrics controllers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme connect-all'
+ [--transport=<trtype> | -t <trtype>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--raw=<filename> | -r <filename>]
+ [--keep-alive-tmo=<#> | -k <#>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>]
+ [--hdr-digest | -g]
+ [--data-digest | -G]
+ [--nr-io-queues=<#> | -i <#>]
+ [--nr-write-queues=<#> | -W <#>]
+ [--nr-poll-queues=<#> | -P <#>]
+ [--queue-size=<#> | -Q <#>]
+ [--matching | -m]
+ [--persistent | -p]
+ [--quiet | -q]
+
+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 /etc/nvme/discovery.conf file to use to supply a list of
+connect-all commands to run. If no /etc/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 Diѕcovery
+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.
+|loop|Connect to a NVMe over Fabrics target on the local host
+|=================
+
+-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 Discovery Controller.
+
+-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
+ /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.
+
+-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.
+
+-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).
+
+-g::
+--hdr-digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data-digest::
+ Generates/verifies data digest (TCP).
+
+-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.
+
+-m::
+--matching::
+ If a traddr was specified on the command line or in the configuration
+ file, only create controllers for discovery records that match the
+ given traddr, rather than for all entries in the discovery log page.
+
+-p::
+--persistent::
+ Don't remove the discovery controller after retrieving the discovery
+ log page.
+
+-q::
+--quiet::
+ Suppress error messages.
+
+
+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 a /etc/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..9170d01
--- /dev/null
+++ b/Documentation/nvme-connect.1
@@ -0,0 +1,220 @@
+'\" t
+.\" Title: nvme-connect
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CONNECT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-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]
+.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.
+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{
+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\&.
+.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 /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
+\-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
+\-D, \-\-duplicate\-connect
+.RS 4
+Allows duplicated connections between same trnsport 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
+.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..3387333
--- /dev/null
+++ b/Documentation/nvme-connect.html
@@ -0,0 +1,1077 @@
+<?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-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 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-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;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&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;]
+ [--duplicate-connect | -D]
+ [--disable-sqflow | -d]
+ [--hdr-digest | -g]
+ [--data-digest | -G]</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">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.
+</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
+ /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">
+-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">
+-D
+</dt>
+<dt class="hdlist1">
+--duplicate-connect
+</dt>
+<dd>
+<p>
+ Allows duplicated connections between same trnsport 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>
+</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
+ 2020-02-15 08:33:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-connect.txt b/Documentation/nvme-connect.txt
new file mode 100644
index 0000000..3f12ec0
--- /dev/null
+++ b/Documentation/nvme-connect.txt
@@ -0,0 +1,157 @@
+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>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--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]
+
+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.
+|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.
+
+-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
+ /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.
+
+-I <hostid>::
+--hostid=<hostid>::
+ UUID(Universally Unique Identifier) to be discovered which should be
+ formatted.
+
+-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 trnsport 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).
+
+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-create-ns.1 b/Documentation/nvme-create-ns.1
new file mode 100644
index 0000000..7f358c1
--- /dev/null
+++ b/Documentation/nvme-create-ns.1
@@ -0,0 +1,102 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-CREATE\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-block\-size=<block\-size> | \-b <block\-size>]
+ [\-\-timeout=<timeout> | \-t <timeout>]
+DESCRIPTION
+.fi
+.sp
+.nf
+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
+.fi
+.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 Gorup 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
+\-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
+.SH "EXAMPLES"
+.sp
+No examples provided yet\&.
+.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..1ecc66e
--- /dev/null
+++ b/Documentation/nvme-create-ns.html
@@ -0,0 +1,888 @@
+<!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-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;
+}
+
+
+#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-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;]
+ [--block-size=&lt;block-size&gt; | -b &lt;block-size&gt;]
+ [--timeout=&lt;timeout&gt; | -t &lt;timeout&gt;]
+DESCRIPTION</pre>
+<div class="attribution">
+</div></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>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 &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).
+
+OPTIONS</code></pre>
+</div></div>
+<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 Gorup 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">
+-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>
+</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 2019-11-16 14:07:32 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-create-ns.txt b/Documentation/nvme-create-ns.txt
new file mode 100644
index 0000000..661b01b
--- /dev/null
+++ b/Documentation/nvme-create-ns.txt
@@ -0,0 +1,74 @@
+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>]
+ [--block-size=<block-size> | -b <block-size>]
+ [--timeout=<timeout> | -t <timeout>]
+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 Gorup 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.
+
+-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.
+
+
+EXAMPLES
+--------
+No examples provided yet.
+
+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..c186a86
--- /dev/null
+++ b/Documentation/nvme-delete-ns.1
@@ -0,0 +1,53 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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
+.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..481d85b
--- /dev/null
+++ b/Documentation/nvme-delete-ns.html
@@ -0,0 +1,802 @@
+<!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(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(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;]</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>
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-delete-ns.txt b/Documentation/nvme-delete-ns.txt
new file mode 100644
index 0000000..62301b4
--- /dev/null
+++ b/Documentation/nvme-delete-ns.txt
@@ -0,0 +1,34 @@
+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>]
+
+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.
+
+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..bf2ec27
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DERA\-STAT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..49f8d39
--- /dev/null
+++ b/Documentation/nvme-dera-stat.html
@@ -0,0 +1,798 @@
+<!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-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;
+}
+
+
+#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="article">
+<div id="header">
+<h1>nvme-dera-stat(1)</h1>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_name">NAME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>nvme-dera-stat - Send NVMe Dera Device status and Additional SMART log page request, returns result and log</p></div>
+</div>
+</div>
+<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 2019-11-26 13:57:30 CST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dera-stat.txt b/Documentation/nvme-dera-stat.txt
new file mode 100644
index 0000000..512e584
--- /dev/null
+++ b/Documentation/nvme-dera-stat.txt
@@ -0,0 +1,38 @@
+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..5765c85
--- /dev/null
+++ b/Documentation/nvme-detach-ns.1
@@ -0,0 +1,57 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DETACH\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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,>
+.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
+.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..6cb9ab9
--- /dev/null
+++ b/Documentation/nvme-detach-ns.html
@@ -0,0 +1,813 @@
+<!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-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;
+}
+
+
+#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-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;</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>
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-detach-ns.txt b/Documentation/nvme-detach-ns.txt
new file mode 100644
index 0000000..ed23c15
--- /dev/null
+++ b/Documentation/nvme-detach-ns.txt
@@ -0,0 +1,37 @@
+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,>
+
+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.
+
+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..699c178
--- /dev/null
+++ b/Documentation/nvme-device-self-test.1
@@ -0,0 +1,101 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DEVICE\-SELF\-" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 becarried out
+.RE
+.PP
+\-s <NUM>, \-\-self\-test\-code=<NUM>
+.RS 4
+This field specifies the action taken by the device self\-test command : 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
+.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..3e91e02
--- /dev/null
+++ b/Documentation/nvme-device-self-test.html
@@ -0,0 +1,840 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 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-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;]</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 becarried 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 :
+ 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
+</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
+ 2019-11-08 02:18:28 JST
+</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..b7273a0
--- /dev/null
+++ b/Documentation/nvme-device-self-test.txt
@@ -0,0 +1,55 @@
+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>]
+
+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 becarried out
+
+-s <NUM>::
+--self-test-code=<NUM>::
+ This field specifies the action taken by the device self-test command :
+ 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
+
+
+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-dir-receive.1 b/Documentation/nvme-dir-receive.1
new file mode 100644
index 0000000..44e8a2a
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DIR\-RECEIVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+.RE
+.sp
++
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+Select
+T}:T{
+.sp
+Description
+T}
+T{
+.sp
+0
+T}:T{
+.sp
+Current
+T}
+T{
+.sp
+1
+T}:T{
+.sp
+Default
+T}
+T{
+.sp
+2
+T}:T{
+.sp
+Saved
+T}
+T{
+.sp
+3
+T}:T{
+.sp
+Supported capabilities
+T}
+T{
+.sp
+4\(en7
+T}:T{
+.sp
+Reserved
+T}
+.TE
+.sp 1
+.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
+.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..3e0e01e
--- /dev/null
+++ b/Documentation/nvme-dir-receive.html
@@ -0,0 +1,975 @@
+<!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-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]</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>
+</dd>
+</dl></div>
+<div class="paragraph"><p>+</p></div>
+<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>
+<div class="dlist"><dl>
+<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>
+</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
+ 2017-08-10 18:23:42 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dir-receive.txt b/Documentation/nvme-dir-receive.txt
new file mode 100644
index 0000000..b412c0b
--- /dev/null
+++ b/Documentation/nvme-dir-receive.txt
@@ -0,0 +1,118 @@
+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]
+
+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.
+
+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..77f9120
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DIR\-SEND" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+.RE
+.sp
++
+.TS
+allbox tab(:);
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt
+lt lt.
+T{
+.sp
+Select
+T}:T{
+.sp
+Description
+T}
+T{
+.sp
+0
+T}:T{
+.sp
+Current
+T}
+T{
+.sp
+1
+T}:T{
+.sp
+Default
+T}
+T{
+.sp
+2
+T}:T{
+.sp
+Saved
+T}
+T{
+.sp
+3
+T}:T{
+.sp
+Supported capabilities
+T}
+T{
+.sp
+4\(en7
+T}:T{
+.sp
+Reserved
+T}
+.TE
+.sp 1
+.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
+.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..8132e5e
--- /dev/null
+++ b/Documentation/nvme-dir-send.html
@@ -0,0 +1,988 @@
+<!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-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]</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>
+</dd>
+</dl></div>
+<div class="paragraph"><p>+</p></div>
+<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>
+<div class="dlist"><dl>
+<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>
+</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
+ 2017-08-10 19:09:21 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dir-send.txt b/Documentation/nvme-dir-send.txt
new file mode 100644
index 0000000..eb5dad0
--- /dev/null
+++ b/Documentation/nvme-dir-send.txt
@@ -0,0 +1,124 @@
+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]
+
+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.
+
+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..04aec10
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.1
@@ -0,0 +1,69 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCONNECT\-AL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-disconnect-all \- Disconnect from all connected Fabrics controllers\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme disconnect\-all\fR
+.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 "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..8e1d365
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.html
@@ -0,0 +1,798 @@
+<!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-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;
+}
+
+
+#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-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></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="_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 2018-09-05 18:17:33 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-disconnect-all.txt b/Documentation/nvme-disconnect-all.txt
new file mode 100644
index 0000000..6be7e41
--- /dev/null
+++ b/Documentation/nvme-disconnect-all.txt
@@ -0,0 +1,34 @@
+nvme-disconnect-all(1)
+======================
+
+NAME
+----
+nvme-disconnect-all - Disconnect from all connected Fabrics controllers.
+
+SYNOPSIS
+--------
+[verse]
+'nvme disconnect-all'
+
+DESCRIPTION
+-----------
+Disconnects and removes all existing NVMe over Fabrics controllers.
+
+See the documentation for the nvme-disconnect(1) command for further
+background.
+
+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..23e1af7
--- /dev/null
+++ b/Documentation/nvme-disconnect.1
@@ -0,0 +1,101 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCONNECT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-disconnect \- Disconnect one or more Fabrics controller(s)\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme disconnect\fR
+ [\-\-nqn=<subnqn> | \-n <subnqn>]
+ [\-\-device=<device> | \-d <device>]
+.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
+.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..8d8c55d
--- /dev/null
+++ b/Documentation/nvme-disconnect.html
@@ -0,0 +1,846 @@
+<?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-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 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-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;]</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>
+</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
+ 2019-04-04 01:17:26 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-disconnect.txt b/Documentation/nvme-disconnect.txt
new file mode 100644
index 0000000..badb86f
--- /dev/null
+++ b/Documentation/nvme-disconnect.txt
@@ -0,0 +1,56 @@
+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>]
+
+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.
+
+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..f354560
--- /dev/null
+++ b/Documentation/nvme-discover.1
@@ -0,0 +1,261 @@
+'\" t
+.\" Title: nvme-discover
+.\" Author: [see the "AUTHORS" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DISCOVER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-discover \- Send Get Log Page request to Discovery Controller\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme discover\fR
+ [\-\-transport=<trtype> | \-t <trtype>]
+ [\-\-traddr=<traddr> | \-a <traddr>]
+ [\-\-trsvcid=<trsvcid> | \-s <trsvcid>]
+ [\-\-host\-traddr=<traddr> | \-w <traddr>]
+ [\-\-hostnqn=<hostnqn> | \-q <hostnqn>]
+ [\-\-hostid=<hostid> | \-I <hostid>]
+ [\-\-raw=<filename> | \-r <filename>]
+ [\-\-keep\-alive\-tmo=<sec> | \-k <sec>]
+ [\-\-reconnect\-delay=<#> | \-c <#>]
+ [\-\-ctrl\-loss\-tmo=<#> | \-l <#>]
+ [\-\-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]
+.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 /etc/nvme/discovery\&.conf file to use to supply a list of Discovery commands to run\&. If no /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 Diѕcovery 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 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.
+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{
+loop
+T}:T{
+Connect to a NVMe over Fabrics target on the local host
+T}
+.TE
+.sp 1
+.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 (ex\&. IPv4) address\&.
+.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 Discovery Controller\&.
+.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 /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
+\-k <#>, \-\-keep\-alive\-tmo=<#>
+.RS 4
+Overrides the default dealy (in seconds) for keep alive\&. This option will be ignored for the 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
+\-g, \-\-hdr_digest
+.RS 4
+Generates/verifies header digest (TCP)\&.
+.RE
+.PP
+\-G, \-\-data_digest
+.RS 4
+Generates/verifies data digest (TCP)\&.
+.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
+\-p, \-\-persistent
+.RS 4
+Persistent discovery connection\&.
+.RE
+.PP
+\-S, \-\-quiet
+.RS 4
+Suppress already connected errors\&.
+.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 a /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..dc6c7a1
--- /dev/null
+++ b/Documentation/nvme-discover.html
@@ -0,0 +1,1129 @@
+<?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-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 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-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;]
+ [--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;]
+ [--hostnqn=&lt;hostnqn&gt; | -q &lt;hostnqn&gt;]
+ [--hostid=&lt;hostid&gt; | -I &lt;hostid&gt;]
+ [--raw=&lt;filename&gt; | -r &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;]
+ [--hdr_digest | -g]
+ [--data_digest | -G]
+ [--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;]
+ [--persistent | -p]
+ [--quiet | -S]</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 /etc/nvme/discovery.conf file to use to supply a list of
+Discovery commands to run. If no /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 Diѕcovery
+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 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">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">
+-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 (ex. IPv4) address.
+</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 Discovery Controller.
+</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
+ /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">
+-k &lt;#&gt;
+</dt>
+<dt class="hdlist1">
+--keep-alive-tmo=&lt;#&gt;
+</dt>
+<dd>
+<p>
+ Overrides the default dealy (in seconds) for keep alive.
+ This option will be ignored for the 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">
+-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">
+-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">
+-p
+</dt>
+<dt class="hdlist1">
+--persistent
+</dt>
+<dd>
+<p>
+ Persistent discovery connection.
+</p>
+</dd>
+<dt class="hdlist1">
+-S
+</dt>
+<dt class="hdlist1">
+--quiet
+</dt>
+<dd>
+<p>
+ Suppress already connected errors.
+</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 a /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
+ 2019-11-08 08:22:36 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-discover.txt b/Documentation/nvme-discover.txt
new file mode 100644
index 0000000..f006639
--- /dev/null
+++ b/Documentation/nvme-discover.txt
@@ -0,0 +1,208 @@
+nvme-discover(1)
+================
+
+NAME
+----
+nvme-discover - Send Get Log Page request to Discovery Controller.
+
+SYNOPSIS
+--------
+[verse]
+'nvme discover'
+ [--transport=<trtype> | -t <trtype>]
+ [--traddr=<traddr> | -a <traddr>]
+ [--trsvcid=<trsvcid> | -s <trsvcid>]
+ [--host-traddr=<traddr> | -w <traddr>]
+ [--hostnqn=<hostnqn> | -q <hostnqn>]
+ [--hostid=<hostid> | -I <hostid>]
+ [--raw=<filename> | -r <filename>]
+ [--keep-alive-tmo=<sec> | -k <sec>]
+ [--reconnect-delay=<#> | -c <#>]
+ [--ctrl-loss-tmo=<#> | -l <#>]
+ [--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]
+
+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 /etc/nvme/discovery.conf file to use to supply a list of
+Discovery commands to run. If no /etc/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 Diѕcovery
+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 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.
+|loop|Connect to a NVMe over Fabrics target on the local host
+|=================
+
+-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 (ex. IPv4) address.
+
+-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 Discovery Controller.
+
+-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
+ /etc/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.
+
+-k <#>::
+--keep-alive-tmo=<#>::
+ Overrides the default dealy (in seconds) for keep alive.
+ This option will be ignored for the 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).
+
+-g::
+--hdr_digest::
+ Generates/verifies header digest (TCP).
+
+-G::
+--data_digest::
+ Generates/verifies data digest (TCP).
+
+-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.
+
+-p::
+--persistent::
+ Persistent discovery connection.
+
+-S::
+--quiet::
+ Suppress already connected errors.
+
+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 a /etc/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..899a6a6
--- /dev/null
+++ b/Documentation/nvme-dsm.1
@@ -0,0 +1,97 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-DSM" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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 | \-d ] [ \-\-idw | \-w ] [ \-\-idr | \-r ]
+ [ \-\-cdw11=<cdw11> | \-c <cdw11> ]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, sends an 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
+.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..37948df
--- /dev/null
+++ b/Documentation/nvme-dsm.html
@@ -0,0 +1,896 @@
+<!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-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;
+}
+
+
+#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-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 | -d ] [ --idw | -w ] [ --idr | -r ]
+ [ --cdw11=&lt;cdw11&gt; | -c &lt;cdw11&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 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>
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-dsm.txt b/Documentation/nvme-dsm.txt
new file mode 100644
index 0000000..e81de14
--- /dev/null
+++ b/Documentation/nvme-dsm.txt
@@ -0,0 +1,82 @@
+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 | -d ] [ --idw | -w ] [ --idr | -r ]
+ [ --cdw11=<cdw11> | -c <cdw11> ]
+
+
+DESCRIPTION
+-----------
+For the NVMe device given, sends an 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
+
+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..72b22fb
--- /dev/null
+++ b/Documentation/nvme-effects-log.1
@@ -0,0 +1,108 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-EFFECTS\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-effects-log \- Send NVMe Command Effects log page request, returns result and log
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme effects\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+ [\-\-human\-readable | \-H]
+ [\-\-raw\-binary | \-b]
+.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
+\-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
+\-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
+.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..5928b8b
--- /dev/null
+++ b/Documentation/nvme-effects-log.html
@@ -0,0 +1,854 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 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-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; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
+ [--human-readable | -H]
+ [--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 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">
+-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">
+-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>
+</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
+ 2018-11-29 13:32:28 GMT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-effects-log.txt b/Documentation/nvme-effects-log.txt
new file mode 100644
index 0000000..f7d0092
--- /dev/null
+++ b/Documentation/nvme-effects-log.txt
@@ -0,0 +1,62 @@
+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> [--output-format=<fmt> | -o <fmt>]
+ [--human-readable | -H]
+ [--raw-binary | -b]
+
+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
+-------
+
+-o <format>::
+--output-format=<format>::
+ This option will set the reporting format to normal, json, or binary.
+ Only one output format can be used at a time.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields into 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.
+
+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-log.1 b/Documentation/nvme-endurance-log.1
new file mode 100644
index 0000000..067a7a3
--- /dev/null
+++ b/Documentation/nvme-endurance-log.1
@@ -0,0 +1,106 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ENDURANCE\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the Endurance log page in a human readable format:
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme endurance\-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..42fe267
--- /dev/null
+++ b/Documentation/nvme-endurance-log.html
@@ -0,0 +1,841 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-endurance-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;]</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;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the Endurance log page in a human readable format:
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme endurance-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
+ 2019-11-08 02:18:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-endurance-log.txt b/Documentation/nvme-endurance-log.txt
new file mode 100644
index 0000000..5e18b57
--- /dev/null
+++ b/Documentation/nvme-endurance-log.txt
@@ -0,0 +1,56 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the Endurance log page in a human readable format:
++
+------------
+# nvme endurance-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..e116ad4
--- /dev/null
+++ b/Documentation/nvme-error-log.1
@@ -0,0 +1,112 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ERROR\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the 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..f1b68bf
--- /dev/null
+++ b/Documentation/nvme-error-log.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 8.6.10" />
+<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 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-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;]</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;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get the 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
+ 2018-11-29 13:35:56 GMT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-error-log.txt b/Documentation/nvme-error-log.txt
new file mode 100644
index 0000000..eebaca7
--- /dev/null
+++ b/Documentation/nvme-error-log.txt
@@ -0,0 +1,65 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+
+EXAMPLES
+--------
+* Get the 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-flush.1 b/Documentation/nvme-flush.1
new file mode 100644
index 0000000..3c4ddeb
--- /dev/null
+++ b/Documentation/nvme-flush.1
@@ -0,0 +1,51 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FLUSH" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-flush \- Flush command\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme flush\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.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
+.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..3a21e65
--- /dev/null
+++ b/Documentation/nvme-flush.html
@@ -0,0 +1,803 @@
+<!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-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;
+}
+
+
+#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-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;]</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>
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-flush.txt b/Documentation/nvme-flush.txt
new file mode 100644
index 0000000..28cfa63
--- /dev/null
+++ b/Documentation/nvme-flush.txt
@@ -0,0 +1,34 @@
+nvme-flush(1)
+=============
+
+NAME
+----
+nvme-flush - Flush command.
+
+SYNOPSIS
+--------
+[verse]
+'nvme flush' <device> [--namespace-id=<nsid> | -n <nsid>]
+
+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.
+
+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..b47c53e
--- /dev/null
+++ b/Documentation/nvme-format.1
@@ -0,0 +1,225 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FORMAT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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 | \-f ]
+ [\-\-timeout=<timeout> | \-t <timeout> ]
+.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
+\-f, \-\-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
+.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..032a870
--- /dev/null
+++ b/Documentation/nvme-format.html
@@ -0,0 +1,1045 @@
+<?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-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 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-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 | -f ]
+ [--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, 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">
+-f
+</dt>
+<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>
+</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
+ 2019-09-18 00:00:58 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-format.txt b/Documentation/nvme-format.txt
new file mode 100644
index 0000000..9ef788a
--- /dev/null
+++ b/Documentation/nvme-format.txt
@@ -0,0 +1,157 @@
+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 | -f ]
+ [--timeout=<timeout> | -t <timeout> ]
+
+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.
+
+-f::
+--force::
+ Just send the command immediately without warning of the implications.
+
+-t <timeout>::
+--timeout=<timeout>::
+ Override default timeout value. In milliseconds.
+
+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..2a965a7
--- /dev/null
+++ b/Documentation/nvme-fw-commit.1
@@ -0,0 +1,147 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-COMMIT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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> ]
+.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
+Specifiies the Boot partition that shall be used for the Commit Action, if applicable (default: 0)
+.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..39f749f
--- /dev/null
+++ b/Documentation/nvme-fw-commit.html
@@ -0,0 +1,908 @@
+<!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-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;
+}
+
+
+#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-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; ]</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>
+ Specifiies the Boot partition that shall be used for the Commit Action,
+ if applicable (default: 0)
+</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 2017-12-19 13:33:25 MST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-commit.txt b/Documentation/nvme-fw-commit.txt
new file mode 100644
index 0000000..c164c5a
--- /dev/null
+++ b/Documentation/nvme-fw-commit.txt
@@ -0,0 +1,93 @@
+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> ]
+
+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>::
+ Specifiies the Boot partition that shall be used for the Commit Action,
+ if applicable (default: 0)
+
+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..0fd360b
--- /dev/null
+++ b/Documentation/nvme-fw-download.1
@@ -0,0 +1,88 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-DOWNLOAD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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=<firmeware\-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
+.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..e37ca2f
--- /dev/null
+++ b/Documentation/nvme-fw-download.html
@@ -0,0 +1,859 @@
+<?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-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 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-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;]</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;firmeware-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>
+</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
+ 2019-11-08 07:24:12 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-download.txt b/Documentation/nvme-fw-download.txt
new file mode 100644
index 0000000..6b11d05
--- /dev/null
+++ b/Documentation/nvme-fw-download.txt
@@ -0,0 +1,68 @@
+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>]
+
+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=<firmeware-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.
+
+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..f96bcdc
--- /dev/null
+++ b/Documentation/nvme-fw-log.1
@@ -0,0 +1,106 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-FW\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the 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..15f937a
--- /dev/null
+++ b/Documentation/nvme-fw-log.html
@@ -0,0 +1,838 @@
+<!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-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;
+}
+
+
+#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-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;]</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;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the 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 2017-02-27 10:11:57 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-fw-log.txt b/Documentation/nvme-fw-log.txt
new file mode 100644
index 0000000..4b73577
--- /dev/null
+++ b/Documentation/nvme-fw-log.txt
@@ -0,0 +1,58 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+
+EXAMPLES
+--------
+* Print the 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-hostnqn.1 b/Documentation/nvme-gen-hostnqn.1
new file mode 100644
index 0000000..255dcca
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.1
@@ -0,0 +1,48 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GEN\-HOSTNQN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-gen-hostnqn \- Generate a host NVMe Qualified Name
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme gen\-hostnqn\fR
+.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"
+.sp
+No options needed
+.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..7e3a178
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.html
@@ -0,0 +1,788 @@
+<!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-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;
+}
+
+
+#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-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></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="paragraph"><p>No options needed</p></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 2017-08-31 11:05:22 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-gen-hostnqn.txt b/Documentation/nvme-gen-hostnqn.txt
new file mode 100644
index 0000000..9efefb5
--- /dev/null
+++ b/Documentation/nvme-gen-hostnqn.txt
@@ -0,0 +1,29 @@
+nvme-gen-hostnqn(1)
+===================
+
+NAME
+----
+nvme-gen-hostnqn - Generate a host NVMe Qualified Name
+
+SYNOPSIS
+--------
+[verse]
+'nvme gen-hostnqn'
+
+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
+-------
+No options needed
+
+EXAMPLES
+--------
+nvme gen-hostnqn
+
+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..1bc451f
--- /dev/null
+++ b/Documentation/nvme-get-feature.1
@@ -0,0 +1,214 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-FEATURE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-sel=<select> | \-s <select>]
+ [\-\-raw\-binary | \-b]
+ [\-\-human\-readable | \-H]
+.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\(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
+\-\-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
+.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
+.\}
+.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..19c2444
--- /dev/null
+++ b/Documentation/nvme-get-feature.html
@@ -0,0 +1,961 @@
+<!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-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;
+}
+
+
+#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-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;]
+ [--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]</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">
+-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>
+</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>
+</li>
+<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 2018-02-07 09:54:27 MST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-feature.txt b/Documentation/nvme-get-feature.txt
new file mode 100644
index 0000000..56542dc
--- /dev/null
+++ b/Documentation/nvme-get-feature.txt
@@ -0,0 +1,118 @@
+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>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--sel=<select> | -s <select>]
+ [--raw-binary | -b]
+ [--human-readable | -H]
+
+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
+|==================
+
+-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.
+
+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
+------------
++
+
+* 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-log.1 b/Documentation/nvme-get-log.1
new file mode 100644
index 0000000..742a791
--- /dev/null
+++ b/Documentation/nvme-get-log.1
@@ -0,0 +1,142 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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> | \-o <offset>]
+ [\-\-lsp=<field> | \-s <field>]
+ [\-\-rae | \-r]
+.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
+\-o <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
+\-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 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..9aa20e0
--- /dev/null
+++ b/Documentation/nvme-get-log.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 8.6.10" />
+<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 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-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; | -o &lt;offset&gt;]
+ [--lsp=&lt;field&gt; | -s &lt;field&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>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">
+-o &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">
+-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 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
+ 2019-09-18 00:00:58 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-log.txt b/Documentation/nvme-get-log.txt
new file mode 100644
index 0000000..1d49e28
--- /dev/null
+++ b/Documentation/nvme-get-log.txt
@@ -0,0 +1,98 @@
+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> | -o <offset>]
+ [--lsp=<field> | -s <field>]
+ [--rae | -r]
+
+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.
+
+-o <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.
+
+-r::
+--rae::
+ Retain an Asynchronous Event.
+
+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..f7e69e4
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.1
@@ -0,0 +1,67 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-NS\-ID" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-get-ns-id \- Retrieves the namespace ID for an NVMe block device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme get\-ns\-id\fR <device>
+.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"
+.sp
+None
+.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..bd02929
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.html
@@ -0,0 +1,797 @@
+<!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-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;
+}
+
+
+#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-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;</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="paragraph"><p>None</p></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 2016-05-16 12:47:42 EDT
+</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..5dcdc6d
--- /dev/null
+++ b/Documentation/nvme-get-ns-id.txt
@@ -0,0 +1,32 @@
+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>
+
+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
+-------
+None
+
+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..116c338
--- /dev/null
+++ b/Documentation/nvme-get-property.1
@@ -0,0 +1,123 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-GET\-PROPERTY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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 ]
+.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
+.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..0a3fa8a
--- /dev/null
+++ b/Documentation/nvme-get-property.html
@@ -0,0 +1,846 @@
+<!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-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;
+}
+
+
+#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-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 ]</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>
+</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 2018-08-05 00:59:45 IDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-get-property.txt b/Documentation/nvme-get-property.txt
new file mode 100644
index 0000000..b2b7d29
--- /dev/null
+++ b/Documentation/nvme-get-property.txt
@@ -0,0 +1,62 @@
+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 ]
+
+
+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
+
+
+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..fc49411
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-HELP" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..50a49a0
--- /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 8.6.10" />
+<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 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-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
+ 2019-11-08 08:41:30 JST
+</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..b4dbb69
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-HUAWEI\-ID\-CT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-huawei-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme huawei id\-ctrl\fR <device> [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary]
+ [\-o <fmt> | \-\-output\-format=<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 <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 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..542db9c
--- /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 8.6.10" />
+<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 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-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; [-v | --vendor-specific] [-b | --raw-binary]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends 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;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 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
+ 2019-09-18 00:00:58 JST
+</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..f4d2f80
--- /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> [-v | --vendor-specific] [-b | --raw-binary]
+ [-o <fmt> | --output-format=<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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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..3cbe6f4
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-huawei-list \- List all recognized Huawei NVMe devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme huawei list\fR [\-o <fmt> | \-\-output\-format=<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 <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\&.
+.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..57c1ff9
--- /dev/null
+++ b/Documentation/nvme-huawei-list.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-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;
+}
+
+
+#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-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> [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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;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.
+</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 2017-05-01 17:34:17 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-huawei-list.txt b/Documentation/nvme-huawei-list.txt
new file mode 100644
index 0000000..65a6c21
--- /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' [-o <fmt> | --output-format=<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 <format>::
+--output-format=<format>::
+ 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..258188a
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.1
@@ -0,0 +1,196 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-CTRL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-ctrl\fR <device> [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary]
+ [\-o <fmt> | \-\-output\-format=<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\&.
+.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 <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\-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..294c5b0
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.html
@@ -0,0 +1,913 @@
+<!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-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;
+}
+
+
+#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-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; [-v | --vendor-specific] [-b | --raw-binary]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends 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;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-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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-ctrl.txt b/Documentation/nvme-id-ctrl.txt
new file mode 100644
index 0000000..b9fcffc
--- /dev/null
+++ b/Documentation/nvme-id-ctrl.txt
@@ -0,0 +1,113 @@
+nvme-id-ctrl(1)
+===============
+
+NAME
+----
+nvme-id-ctrl - Send NVMe Identify Controller, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ctrl' <device> [-v | --vendor-specific] [-b | --raw-binary]
+ [-o <fmt> | --output-format=<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.
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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-ns.1 b/Documentation/nvme-id-ns.1
new file mode 100644
index 0000000..55094c9
--- /dev/null
+++ b/Documentation/nvme-id-ns.1
@@ -0,0 +1,229 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-id-ns \- Send NVMe Identify Namespace, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-ns\fR <device> [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>] [\-f | \-\-force]
+ [\-\-human\-readable | \-H]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.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\&.
+.RE
+.PP
+\-f, \-\-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 <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 /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..283fc33
--- /dev/null
+++ b/Documentation/nvme-id-ns.html
@@ -0,0 +1,962 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-id-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-id-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; [-v | --vendor-specific] [-b | --raw-binary]
+ [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;] [-f | --force]
+ [--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 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">
+-f
+</dt>
+<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;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 /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
+ 2018-11-29 13:36:39 GMT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-ns.txt b/Documentation/nvme-id-ns.txt
new file mode 100644
index 0000000..4b3c258
--- /dev/null
+++ b/Documentation/nvme-id-ns.txt
@@ -0,0 +1,144 @@
+nvme-id-ns(1)
+=============
+
+NAME
+----
+nvme-id-ns - Send NVMe Identify Namespace, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-ns' <device> [-v | --vendor-specific] [-b | --raw-binary]
+ [--namespace-id=<nsid> | -n <nsid>] [-f | --force]
+ [--human-readable | -H]
+ [--output-format=<fmt> | -o <fmt>]
+
+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.
+
+-f::
+--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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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..bcec988
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.1
@@ -0,0 +1,142 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NVMSET" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-id-nvmset \- Send NVMe Identify NVM Set List, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme id\-nvmset\fR <device> [\-i <id> | \-\-nvmset_id=<id> ]
+ [\-o <fmt> | \-\-output\-format=<fmt>]
+.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 <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\-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..f04e1cd
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.html
@@ -0,0 +1,858 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-id-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; [-i &lt;id&gt; | --nvmset_id=&lt;id&gt; ]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends 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;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-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
+ 2019-11-08 02:18:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-id-nvmset.txt b/Documentation/nvme-id-nvmset.txt
new file mode 100644
index 0000000..c331410
--- /dev/null
+++ b/Documentation/nvme-id-nvmset.txt
@@ -0,0 +1,73 @@
+nvme-id-nvmset(1)
+=================
+
+NAME
+----
+nvme-id-nvmset - Send NVMe Identify NVM Set List, return result and structure
+
+SYNOPSIS
+--------
+[verse]
+'nvme id-nvmset' <device> [-i <id> | --nvmset_id=<id> ]
+ [-o <fmt> | --output-format=<fmt>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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-intel-id-ctrl.1 b/Documentation/nvme-intel-id-ctrl.1
new file mode 100644
index 0000000..9e90231
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-ID\-CTR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-intel-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme intel id\-ctrl\fR <device> [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary]
+ [\-o <fmt> | \-\-output\-format=<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 <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 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..8e79675
--- /dev/null
+++ b/Documentation/nvme-intel-id-ctrl.html
@@ -0,0 +1,856 @@
+<!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-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;
+}
+
+
+#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-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; [-v | --vendor-specific] [-b | --raw-binary]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends 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;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 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 2017-02-27 10:11:58 EST
+</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..1a6369c
--- /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> [-v | --vendor-specific] [-b | --raw-binary]
+ [-o <fmt> | --output-format=<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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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..fdefc66
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-INTERNA" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..94397c1
--- /dev/null
+++ b/Documentation/nvme-intel-internal-log.html
@@ -0,0 +1,850 @@
+<!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-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;
+}
+
+
+#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-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;]
+ [--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>
+</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 2017-02-27 10:11:58 EST
+</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..2f00313
--- /dev/null
+++ b/Documentation/nvme-intel-internal-log.txt
@@ -0,0 +1,74 @@
+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..a936e9a
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-LAT\-ST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..85597a0
--- /dev/null
+++ b/Documentation/nvme-intel-lat-stats.html
@@ -0,0 +1,835 @@
+<!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-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;
+}
+
+
+#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-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 2017-02-27 10:11:58 EST
+</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..a19a844
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-MARKET\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..79d9796
--- /dev/null
+++ b/Documentation/nvme-intel-market-name.html
@@ -0,0 +1,816 @@
+<!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-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;
+}
+
+
+#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-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 2017-02-27 10:11:58 EST
+</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..94eac80
--- /dev/null
+++ b/Documentation/nvme-intel-smart-log-add.1
@@ -0,0 +1,109 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-SMART\-" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..a7b7585
--- /dev/null
+++ b/Documentation/nvme-intel-smart-log-add.html
@@ -0,0 +1,857 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 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-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
+ 2018-11-29 13:32:28 GMT
+</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..7cfe794
--- /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..aaab8fa
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-INTEL\-TEMP\-S" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..2005af0
--- /dev/null
+++ b/Documentation/nvme-intel-temp-stats.html
@@ -0,0 +1,825 @@
+<!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-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;
+}
+
+
+#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-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 2017-02-27 10:11:58 EST
+</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-passthru.1 b/Documentation/nvme-io-passthru.1
new file mode 100644
index 0000000..0f6c9be
--- /dev/null
+++ b/Documentation/nvme-io-passthru.1
@@ -0,0 +1,133 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-IO\-PASSTHRU" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-timeout=<to> | \-t <to>]
+ [\-\-show\-command | \-s]
+ [\-\-dry\-run | \-d]
+ [\-\-raw\-binary | \-b]
+ [\-\-prefill=<prefill> | \-p <prefill>]
+.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\&.
+.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
+.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..96b9e1e
--- /dev/null
+++ b/Documentation/nvme-io-passthru.html
@@ -0,0 +1,971 @@
+<!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-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;]
+ [--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;]</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.
+</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>
+</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
+ 2018-01-30 19:28:39 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-io-passthru.txt b/Documentation/nvme-io-passthru.txt
new file mode 100644
index 0000000..318e801
--- /dev/null
+++ b/Documentation/nvme-io-passthru.txt
@@ -0,0 +1,116 @@
+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>]
+ [--timeout=<to> | -t <to>]
+ [--show-command | -s]
+ [--dry-run | -d]
+ [--raw-binary | -b]
+ [--prefill=<prefill> | -p <prefill>]
+
+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.
+
+-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.
+
+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-list-ctrl.1 b/Documentation/nvme-list-ctrl.1
new file mode 100644
index 0000000..516f1e8
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.1
@@ -0,0 +1,70 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+DESCRIPTION
+.fi
+.sp
+.nf
+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
+`\*(Aq\-\-cntid\*(Aq` option is given to override\&.
+
+On success, the controller array is printed for each index and controller
+identifier\&.
+
+OPTIONS
+.fi
+.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
+.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..c3aa941
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.html
@@ -0,0 +1,819 @@
+<!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(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(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;]
+DESCRIPTION</pre>
+<div class="attribution">
+</div></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>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 &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
+`'--cntid'` option is given to override.
+
+On success, the controller array is printed for each index and controller
+identifier.
+
+OPTIONS</code></pre>
+</div></div>
+<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>
+</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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-ctrl.txt b/Documentation/nvme-list-ctrl.txt
new file mode 100644
index 0000000..b60afb7
--- /dev/null
+++ b/Documentation/nvme-list-ctrl.txt
@@ -0,0 +1,46 @@
+nvme-id-ns(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>]
+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).
+
+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..3297d39
--- /dev/null
+++ b/Documentation/nvme-list-ns.1
@@ -0,0 +1,61 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-all | \-a]
+.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
+\-a, \-\-all
+.RS 4
+Retrieve the identify list structure for all namespaces in the subsystem, whether attached or inactive\&.
+.RE
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.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..45737bb
--- /dev/null
+++ b/Documentation/nvme-list-ns.html
@@ -0,0 +1,821 @@
+<!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-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;]
+ [--all | -a]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, 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">
+-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>
+</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
+ 2018-01-30 19:28:39 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-ns.txt b/Documentation/nvme-list-ns.txt
new file mode 100644
index 0000000..7cc90d8
--- /dev/null
+++ b/Documentation/nvme-list-ns.txt
@@ -0,0 +1,44 @@
+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>]
+ [--all | -a]
+
+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.
+
+-a::
+--all::
+ Retrieve the identify list structure for all namespaces in the
+ subsystem, whether attached or inactive.
+
+EXAMPLES
+--------
+No examples yet.
+
+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..a120021
--- /dev/null
+++ b/Documentation/nvme-list-subsys.1
@@ -0,0 +1,126 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST\-SUBSYS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-list-subsys \- List all NVMe subsystems
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\-subsys\fR [\-o <fmt> | \-\-output\-format=<fmt>] <device>
+.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 <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\&.
+.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..34e7525
--- /dev/null
+++ b/Documentation/nvme-list-subsys.html
@@ -0,0 +1,857 @@
+<!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-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;
+}
+
+
+#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-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> [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;] &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>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;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.
+</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 2018-11-16 09:53:53 MST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list-subsys.txt b/Documentation/nvme-list-subsys.txt
new file mode 100644
index 0000000..56045b8
--- /dev/null
+++ b/Documentation/nvme-list-subsys.txt
@@ -0,0 +1,85 @@
+nvme-list-subsys(1)
+===================
+
+NAME
+----
+nvme-list-subsys - List all NVMe subsystems
+
+SYNOPSIS
+--------
+[verse]
+'nvme list-subsys' [-o <fmt> | --output-format=<fmt>] <device>
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal' or 'json'. Only one output
+ format can be used at a time.
+
+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..da23dad
--- /dev/null
+++ b/Documentation/nvme-list.1
@@ -0,0 +1,62 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-list \- List all recognized NVMe devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme list\fR [\-o <fmt> | \-\-output\-format=<fmt>]
+.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 <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\&.
+.RE
+.PP
+\-v, \-\-verbose
+.RS 4
+Increase the information in the output, showing nvme subsystems, controllers and namespaces separately and how they\(cqre realted 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..2cc45bc
--- /dev/null
+++ b/Documentation/nvme-list.html
@@ -0,0 +1,819 @@
+<!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-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;
+}
+
+
+#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-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> [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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;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.
+</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 realted 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 2019-08-26 14:55:40 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-list.txt b/Documentation/nvme-list.txt
new file mode 100644
index 0000000..22e0081
--- /dev/null
+++ b/Documentation/nvme-list.txt
@@ -0,0 +1,42 @@
+nvme-list(1)
+============
+
+NAME
+----
+nvme-list - List all recognized NVMe devices
+
+SYNOPSIS
+--------
+[verse]
+'nvme list' [-o <fmt> | --output-format=<fmt>]
+
+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 <format>::
+--output-format=<format>::
+ 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 realted 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-lnvm-create.1 b/Documentation/nvme-lnvm-create.1
new file mode 100644
index 0000000..68a3a6f
--- /dev/null
+++ b/Documentation/nvme-lnvm-create.1
@@ -0,0 +1,100 @@
+'\" t
+.\" Title: nvme-lnvm-create
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-CREATE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-create \- Instantiate a target on top of a LightNVM enabled device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-create\fR [\-\-device\-name=<DEVICE> | \-d <DEVICE>]
+ [\-\-target\-name=<TARGET> | \-n <TARGET>]
+ [\-\-target\-type=<TARGETTYPE> | \-t <TARGETTYPE>]
+ [\-\-lun\-begin <NUM> | \-b <NUM>]
+ [\-\-lun\-end <NUM> | \-e <NUM>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Instantiate a target on top of a LightNVM enabled device\&. This exposes the physical for the user to use\&.
+.sp
+The target name is the name of which the media is exposed as in /dev/<targetname>
+.sp
+The target type is the target to be instantiated\&. Typically pblk or rrpc\&.
+.sp
+LUN begin and end defines the range of LUNs to use for a target instantiation\&.
+.SH "OPTIONS"
+.PP
+\-\-device\-name=<DEVICE>, \-d <DEVICE>
+.RS 4
+Device name to initialize\&.
+.RE
+.PP
+\-\-target\-name=<TARGET>, \-n <TARGET>
+.RS 4
+Target name of the device to initialize\&. For example: target0\&.
+.RE
+.PP
+\-\-target\-type=<TARGETTYPE>, \-t <TARGETTYPE>
+.RS 4
+Target type of the device to use\&. For example: pblk
+.RE
+.PP
+\-\-lun\-begin <NUM>, \-b <NUM>
+.RS 4
+Begin LUN id offset to use for target
+.RE
+.PP
+\-\-lun\-end <NUM>, \-e <NUM>
+.RS 4
+End LUN id offset to use for target
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Initialize nvme0n1 with pblk target with 64 LUNs\&.
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-create \-d nvme0n1 \-t pblk \-n target0 \-b 0 \-e 63
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-create.html b/Documentation/nvme-lnvm-create.html
new file mode 100644
index 0000000..cde3761
--- /dev/null
+++ b/Documentation/nvme-lnvm-create.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 8.6.10" />
+<title>nvme-lnvm-create(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-lnvm-create(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-create -
+ Instantiate a target on top of a LightNVM enabled 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 lnvm-create</em> [--device-name=&lt;DEVICE&gt; | -d &lt;DEVICE&gt;]
+ [--target-name=&lt;TARGET&gt; | -n &lt;TARGET&gt;]
+ [--target-type=&lt;TARGETTYPE&gt; | -t &lt;TARGETTYPE&gt;]
+ [--lun-begin &lt;NUM&gt; | -b &lt;NUM&gt;]
+ [--lun-end &lt;NUM&gt; | -e &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>Instantiate a target on top of a LightNVM enabled device. This exposes the
+physical for the user to use.</p></div>
+<div class="paragraph"><p>The target name is the name of which the media is exposed as in
+/dev/&lt;targetname&gt;</p></div>
+<div class="paragraph"><p>The target type is the target to be instantiated. Typically pblk or rrpc.</p></div>
+<div class="paragraph"><p>LUN begin and end defines the range of LUNs to use for a target instantiation.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--device-name=&lt;DEVICE&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;DEVICE&gt;
+</dt>
+<dd>
+<p>
+ Device name to initialize.
+</p>
+</dd>
+<dt class="hdlist1">
+--target-name=&lt;TARGET&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;TARGET&gt;
+</dt>
+<dd>
+<p>
+ Target name of the device to initialize. For example: target0.
+</p>
+</dd>
+<dt class="hdlist1">
+--target-type=&lt;TARGETTYPE&gt;
+</dt>
+<dt class="hdlist1">
+-t &lt;TARGETTYPE&gt;
+</dt>
+<dd>
+<p>
+ Target type of the device to use. For example: pblk
+</p>
+</dd>
+<dt class="hdlist1">
+--lun-begin &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-b &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Begin LUN id offset to use for target
+</p>
+</dd>
+<dt class="hdlist1">
+--lun-end &lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-e &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ End LUN id offset to use for target
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Initialize nvme0n1 with pblk target with 64 LUNs.
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-create -d nvme0n1 -t pblk -n target0 -b 0 -e 63</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
+ 2019-11-08 08:41:30 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-create.txt b/Documentation/nvme-lnvm-create.txt
new file mode 100644
index 0000000..3c9109d
--- /dev/null
+++ b/Documentation/nvme-lnvm-create.txt
@@ -0,0 +1,60 @@
+nvme-lnvm-create(1)
+===================
+
+NAME
+----
+nvme-lnvm-create - Instantiate a target on top of a LightNVM enabled device
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-create' [--device-name=<DEVICE> | -d <DEVICE>]
+ [--target-name=<TARGET> | -n <TARGET>]
+ [--target-type=<TARGETTYPE> | -t <TARGETTYPE>]
+ [--lun-begin <NUM> | -b <NUM>]
+ [--lun-end <NUM> | -e <NUM>]
+
+DESCRIPTION
+-----------
+Instantiate a target on top of a LightNVM enabled device. This exposes the
+physical for the user to use.
+
+The target name is the name of which the media is exposed as in
+/dev/<targetname>
+
+The target type is the target to be instantiated. Typically pblk or rrpc.
+
+LUN begin and end defines the range of LUNs to use for a target instantiation.
+
+OPTIONS
+-------
+--device-name=<DEVICE>::
+-d <DEVICE>::
+ Device name to initialize.
+
+--target-name=<TARGET>::
+-n <TARGET>::
+ Target name of the device to initialize. For example: target0.
+
+--target-type=<TARGETTYPE>::
+-t <TARGETTYPE>::
+ Target type of the device to use. For example: pblk
+
+--lun-begin <NUM>::
+-b <NUM>::
+ Begin LUN id offset to use for target
+
+--lun-end <NUM>::
+-e <NUM>::
+ End LUN id offset to use for target
+
+EXAMPLES
+--------
+* Initialize nvme0n1 with pblk target with 64 LUNs.
+------------
+# nvme lnvm-create -d nvme0n1 -t pblk -n target0 -b 0 -e 63
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-diag-bbtbl.1 b/Documentation/nvme-lnvm-diag-bbtbl.1
new file mode 100644
index 0000000..3d80de0
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-bbtbl.1
@@ -0,0 +1,117 @@
+'\" t
+.\" Title: nvme-lnvm-diag-bbtbl
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-DIAG\-BB" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-diag-bbtbl \- Diagnose the bad block table
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-diag\-bbtbl\fR [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-channel\-id=<CHID> | \-c <CHID>]
+ [\-\-lun\-id=<LUNID> | \-l <LUNID>]
+ [\-\-raw\-binary | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+Retrieve the bad block table for a given channel and lun\&.
+.sp
+The statistics will be shown in the default case, and the actual output bad block information can be retrieved when \-\-raw\-binary is passed\&.
+.sp
+The raw binary output follows this format:
+.sp
+Channel 0, LUN0 (Dual plane flash)
+.sp
+Byte 0 \(-> Plane 0, Block 0 Byte 1 \(-> Plane 1, Block 0 Byte 2 \(-> Plane 0, Block 1 \&...
+.SH "OPTIONS"
+.PP
+\-\-namespace\-id=<NUM>, \-n <NUM>
+.RS 4
+Namespace id to use
+.RE
+.PP
+\-\-channel\-id=<NUM>, \-c
+.RS 4
+Channel id
+.RE
+.PP
+\-\-lun\-id=<NUM>, \-l
+.RS 4
+LUN id
+.RE
+.PP
+\-\-raw\-binary, \-b
+.RS 4
+Returns the bad block table in binary form without statistics\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve bad block table statistics for physical device nvme0, channel 0, and lun 0:
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-diag\-bbtbl /dev/nvme0 \-c 0 \-n 0
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Display the bad block table in raw form without statistics for same query:
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-diag\-bbtbl /dev/nvme0 \-c 0 \-n 0 \-b | hexdump
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-diag-bbtbl.html b/Documentation/nvme-lnvm-diag-bbtbl.html
new file mode 100644
index 0000000..4b177c7
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-bbtbl.html
@@ -0,0 +1,864 @@
+<!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-lnvm-diag-bbtbl(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-lnvm-diag-bbtbl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-diag-bbtbl -
+ Diagnose the bad block 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 lnvm-diag-bbtbl</em> [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--channel-id=&lt;CHID&gt; | -c &lt;CHID&gt;]
+ [--lun-id=&lt;LUNID&gt; | -l &lt;LUNID&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>Retrieve the bad block table for a given channel and lun.</p></div>
+<div class="paragraph"><p>The statistics will be shown in the default case, and the actual output bad
+block information can be retrieved when --raw-binary is passed.</p></div>
+<div class="paragraph"><p>The raw binary output follows this format:</p></div>
+<div class="paragraph"><p>Channel 0, LUN0 (Dual plane flash)</p></div>
+<div class="paragraph"><p>Byte 0 &#8594; Plane 0, Block 0
+Byte 1 &#8594; Plane 1, Block 0
+Byte 2 &#8594; Plane 0, Block 1
+&#8230;</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Namespace id to use
+</p>
+</dd>
+<dt class="hdlist1">
+--channel-id=&lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-c
+</dt>
+<dd>
+<p>
+ Channel id
+</p>
+</dd>
+<dt class="hdlist1">
+--lun-id=&lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-l
+</dt>
+<dd>
+<p>
+ LUN id
+</p>
+</dd>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dt class="hdlist1">
+-b
+</dt>
+<dd>
+<p>
+ Returns the bad block table in binary form without statistics.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve bad block table statistics for physical device nvme0, channel 0, and
+lun 0:
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-diag-bbtbl /dev/nvme0 -c 0 -n 0</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Display the bad block table in raw form without statistics for same query:
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-diag-bbtbl /dev/nvme0 -c 0 -n 0 -b | hexdump</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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-diag-bbtbl.txt b/Documentation/nvme-lnvm-diag-bbtbl.txt
new file mode 100644
index 0000000..7324807
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-bbtbl.txt
@@ -0,0 +1,65 @@
+nvme-lnvm-diag-bbtbl(1)
+=======================
+
+NAME
+----
+nvme-lnvm-diag-bbtbl - Diagnose the bad block table
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-diag-bbtbl' [--namespace-id=<NUM> | -n <NUM>]
+ [--channel-id=<CHID> | -c <CHID>]
+ [--lun-id=<LUNID> | -l <LUNID>]
+ [--raw-binary | -b]
+
+DESCRIPTION
+-----------
+Retrieve the bad block table for a given channel and lun.
+
+The statistics will be shown in the default case, and the actual output bad
+block information can be retrieved when --raw-binary is passed.
+
+The raw binary output follows this format:
+
+Channel 0, LUN0 (Dual plane flash)
+
+Byte 0 -> Plane 0, Block 0
+Byte 1 -> Plane 1, Block 0
+Byte 2 -> Plane 0, Block 1
+...
+
+OPTIONS
+-------
+--namespace-id=<NUM>::
+-n <NUM>::
+ Namespace id to use
+
+--channel-id=<NUM>::
+-c::
+ Channel id
+
+--lun-id=<NUM>::
+-l::
+ LUN id
+
+--raw-binary::
+-b::
+ Returns the bad block table in binary form without statistics.
+
+EXAMPLES
+--------
+* Retrieve bad block table statistics for physical device nvme0, channel 0, and
+lun 0:
+------------
+# nvme lnvm-diag-bbtbl /dev/nvme0 -c 0 -n 0
+------------
+
+* Display the bad block table in raw form without statistics for same query:
+------------
+# nvme lnvm-diag-bbtbl /dev/nvme0 -c 0 -n 0 -b | hexdump
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-diag-set-bbtbl.1 b/Documentation/nvme-lnvm-diag-set-bbtbl.1
new file mode 100644
index 0000000..1d67328
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-set-bbtbl.1
@@ -0,0 +1,99 @@
+'\" t
+.\" Title: nvme-lnvm-diag-set-bbtbl
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-DIAG\-SE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-diag-set-bbtbl \- Set a block state in the bad block table
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-diag\-set\-bbtbl\fR [\-\-namespace\-id=<NUM> | \-n <NUM>]
+ [\-\-channel\-id=<CHID> | \-c <CHID>]
+ [\-\-lun\-id=<LUNID> | \-l <LUNID>]
+ [\-\-plane\-id=<PLANEID> | \-p <PLANEID>]
+ [\-\-block\-id=<BLKID> | \-b <BLKID>]
+ [\-\-value=<NUM> | \-v <NUM>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Set the bad block table for a given channel, lun, plane and block with value v\&.
+.sp
+For each block available, the status byte is read as follows:
+.sp
+0: Good block 1: Bad block 2: Grown bad block 4: Device reserved block 8: Host\-side reserved block 16: Media managed reserved block
+.SH "OPTIONS"
+.PP
+\-\-namespace\-id=<NUM>, \-n <NUM>
+.RS 4
+Namespace id to use
+.RE
+.PP
+\-\-channel\-id, \-c
+.RS 4
+Channel id
+.RE
+.PP
+\-\-lun\-id, \-l
+.RS 4
+LUN id
+.RE
+.PP
+\-\-plane\-id, \-p
+.RS 4
+Plane id
+.RE
+.PP
+\-\-block\-id, \-b
+.RS 4
+Block id
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Set channel 0, lun 0, plane 0, block 10 to bad block value 2 (grown bad) on physical device /dev/nvme0
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-diag\-set\-bbtbl /dev/nvme0 \-c 0 \-l 0 \-p 0 \-b 10 \-v 2
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-diag-set-bbtbl.html b/Documentation/nvme-lnvm-diag-set-bbtbl.html
new file mode 100644
index 0000000..be9d173
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-set-bbtbl.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 8.6.10" />
+<title>nvme-lnvm-diag-set-bbtbl(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-lnvm-diag-set-bbtbl(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-diag-set-bbtbl -
+ Set a block state in the bad block 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 lnvm-diag-set-bbtbl</em> [--namespace-id=&lt;NUM&gt; | -n &lt;NUM&gt;]
+ [--channel-id=&lt;CHID&gt; | -c &lt;CHID&gt;]
+ [--lun-id=&lt;LUNID&gt; | -l &lt;LUNID&gt;]
+ [--plane-id=&lt;PLANEID&gt; | -p &lt;PLANEID&gt;]
+ [--block-id=&lt;BLKID&gt; | -b &lt;BLKID&gt;]
+ [--value=&lt;NUM&gt; | -v &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>Set the bad block table for a given channel, lun, plane and block with value v.</p></div>
+<div class="paragraph"><p>For each block available, the status byte is read as follows:</p></div>
+<div class="paragraph"><p>0: Good block
+1: Bad block
+2: Grown bad block
+4: Device reserved block
+8: Host-side reserved block
+16: Media managed reserved block</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--namespace-id=&lt;NUM&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;NUM&gt;
+</dt>
+<dd>
+<p>
+ Namespace id to use
+</p>
+</dd>
+<dt class="hdlist1">
+--channel-id
+</dt>
+<dt class="hdlist1">
+-c
+</dt>
+<dd>
+<p>
+ Channel id
+</p>
+</dd>
+<dt class="hdlist1">
+--lun-id
+</dt>
+<dt class="hdlist1">
+-l
+</dt>
+<dd>
+<p>
+ LUN id
+</p>
+</dd>
+<dt class="hdlist1">
+--plane-id
+</dt>
+<dt class="hdlist1">
+-p
+</dt>
+<dd>
+<p>
+ Plane id
+</p>
+</dd>
+<dt class="hdlist1">
+--block-id
+</dt>
+<dt class="hdlist1">
+-b
+</dt>
+<dd>
+<p>
+ Block id
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Set channel 0, lun 0, plane 0, block 10 to bad block value 2 (grown bad)
+ on physical device /dev/nvme0
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-diag-set-bbtbl /dev/nvme0 -c 0 -l 0 -p 0 -b 10 -v 2</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
+ 2019-11-08 02:18:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-diag-set-bbtbl.txt b/Documentation/nvme-lnvm-diag-set-bbtbl.txt
new file mode 100644
index 0000000..f5dd004
--- /dev/null
+++ b/Documentation/nvme-lnvm-diag-set-bbtbl.txt
@@ -0,0 +1,63 @@
+nvme-lnvm-diag-set-bbtbl(1)
+===========================
+
+NAME
+----
+nvme-lnvm-diag-set-bbtbl - Set a block state in the bad block table
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-diag-set-bbtbl' [--namespace-id=<NUM> | -n <NUM>]
+ [--channel-id=<CHID> | -c <CHID>]
+ [--lun-id=<LUNID> | -l <LUNID>]
+ [--plane-id=<PLANEID> | -p <PLANEID>]
+ [--block-id=<BLKID> | -b <BLKID>]
+ [--value=<NUM> | -v <NUM>]
+
+DESCRIPTION
+-----------
+Set the bad block table for a given channel, lun, plane and block with value v.
+
+For each block available, the status byte is read as follows:
+
+0: Good block
+1: Bad block
+2: Grown bad block
+4: Device reserved block
+8: Host-side reserved block
+16: Media managed reserved block
+
+OPTIONS
+-------
+--namespace-id=<NUM>::
+-n <NUM>::
+ Namespace id to use
+
+--channel-id::
+-c::
+ Channel id
+
+--lun-id::
+-l::
+ LUN id
+
+--plane-id::
+-p::
+ Plane id
+
+--block-id::
+-b::
+ Block id
+
+EXAMPLES
+--------
+* Set channel 0, lun 0, plane 0, block 10 to bad block value 2 (grown bad)
+ on physical device /dev/nvme0
+------------
+# nvme lnvm-diag-set-bbtbl /dev/nvme0 -c 0 -l 0 -p 0 -b 10 -v 2
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-factory.1 b/Documentation/nvme-lnvm-factory.1
new file mode 100644
index 0000000..fb0a70b
--- /dev/null
+++ b/Documentation/nvme-lnvm-factory.1
@@ -0,0 +1,109 @@
+'\" t
+.\" Title: nvme-lnvm-factory
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-FACTORY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-factory \- Factory reset a LightNVM device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-factory\fR [\-\-device\-name=<DEVICE> | \-d <DEVICE>]
+ [\-\-erase\-only\-marked | \-e]
+ [\-\-clear\-host\-side\-blks | \-s]
+ [\-\-clear\-bb\-blks | \-b]
+.fi
+.SH "DESCRIPTION"
+.sp
+Instantiate a target on top of a LightNVM enabled device\&. This exposes the physical for the user to use\&.
+.SH "OPTIONS"
+.PP
+\-\-device\-name=<DEVICE>, \-d <DEVICE>
+.RS 4
+Device name to factory initialize
+.RE
+.PP
+\-\-erase\-only\-marked, \-e
+.RS 4
+Erases only blocks that are marked in the bad block list
+.RE
+.PP
+\-\-clear\-host\-side\-blks, \-s
+.RS 4
+Remove host\-side bad block marks\&. This clear the media manager registration
+.RE
+.PP
+\-\-clear\-bb\-blks, \-b
+.RS 4
+Removes the grown bad block marks\&. Allowing them to be rediscovered\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Factory reset of device nvme0n1
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-factory \-d nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Complete factory reset of device nvme0n1
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-factory \-d nvme0n1 \-s \-b
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-factory.html b/Documentation/nvme-lnvm-factory.html
new file mode 100644
index 0000000..a93e398
--- /dev/null
+++ b/Documentation/nvme-lnvm-factory.html
@@ -0,0 +1,857 @@
+<!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-lnvm-factory(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-lnvm-factory(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-factory -
+ Factory reset a LightNVM 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 lnvm-factory</em> [--device-name=&lt;DEVICE&gt; | -d &lt;DEVICE&gt;]
+ [--erase-only-marked | -e]
+ [--clear-host-side-blks | -s]
+ [--clear-bb-blks | -b]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Instantiate a target on top of a LightNVM enabled device. This exposes the
+physical for the user to use.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--device-name=&lt;DEVICE&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;DEVICE&gt;
+</dt>
+<dd>
+<p>
+ Device name to factory initialize
+</p>
+</dd>
+<dt class="hdlist1">
+--erase-only-marked
+</dt>
+<dt class="hdlist1">
+-e
+</dt>
+<dd>
+<p>
+ Erases only blocks that are marked in the bad block list
+</p>
+</dd>
+<dt class="hdlist1">
+--clear-host-side-blks
+</dt>
+<dt class="hdlist1">
+-s
+</dt>
+<dd>
+<p>
+ Remove host-side bad block marks. This clear the media manager
+ registration
+</p>
+</dd>
+<dt class="hdlist1">
+--clear-bb-blks
+</dt>
+<dt class="hdlist1">
+-b
+</dt>
+<dd>
+<p>
+ Removes the grown bad block marks. Allowing them to be rediscovered.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Factory reset of device nvme0n1
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-factory -d nvme0n1</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Complete factory reset of device nvme0n1
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-factory -d nvme0n1 -s -b</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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-factory.txt b/Documentation/nvme-lnvm-factory.txt
new file mode 100644
index 0000000..baa7a69
--- /dev/null
+++ b/Documentation/nvme-lnvm-factory.txt
@@ -0,0 +1,54 @@
+nvme-lnvm-factory(1)
+====================
+
+NAME
+----
+nvme-lnvm-factory - Factory reset a LightNVM device
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-factory' [--device-name=<DEVICE> | -d <DEVICE>]
+ [--erase-only-marked | -e]
+ [--clear-host-side-blks | -s]
+ [--clear-bb-blks | -b]
+
+DESCRIPTION
+-----------
+Instantiate a target on top of a LightNVM enabled device. This exposes the
+physical for the user to use.
+
+OPTIONS
+-------
+--device-name=<DEVICE>::
+-d <DEVICE>::
+ Device name to factory initialize
+
+--erase-only-marked::
+-e::
+ Erases only blocks that are marked in the bad block list
+
+--clear-host-side-blks::
+-s::
+ Remove host-side bad block marks. This clear the media manager
+ registration
+
+--clear-bb-blks::
+-b::
+ Removes the grown bad block marks. Allowing them to be rediscovered.
+
+EXAMPLES
+--------
+* Factory reset of device nvme0n1
+------------
+# nvme lnvm-factory -d nvme0n1
+------------
+
+* Complete factory reset of device nvme0n1
+------------
+# nvme lnvm-factory -d nvme0n1 -s -b
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-id-ns.1 b/Documentation/nvme-lnvm-id-ns.1
new file mode 100644
index 0000000..22efa51
--- /dev/null
+++ b/Documentation/nvme-lnvm-id-ns.1
@@ -0,0 +1,88 @@
+'\" t
+.\" Title: nvme-lnvm-id-ns
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-id-ns \- Identify Geometry for LightNVM NVMe device
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-id\-ns\fR <device> [\-\-namespace\-id=<nsid> | \-n <nsid>]
+ [\-\-force | \-f]
+ [\-\-raw\-binary | \-b]
+ [\-\-human\-readable | \-H]
+.fi
+.SH "DESCRIPTION"
+.sp
+Send an Identify Geometry command to the given LightNVM device, returns properties of the specified namespace in either human\-readable or binary format\&.
+.SH "OPTIONS"
+.PP
+\-\-namespace\-id=<nsid>, \-n <nsid>
+.RS 4
+Retrieve the geometry from the selected namespace\&.
+.RE
+.PP
+\-\-force, \-f
+.RS 4
+Try to read the data and assume it is a LightNVM device
+.RE
+.PP
+\-\-raw\-binary, \-b
+.RS 4
+Output the raw output
+.RE
+.PP
+\-\-human\-readable, \-H
+.RS 4
+Output the status in human readable format
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Retrieve the geometry from nvme0
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-id\-ns /dev/nvme0 \-n 1
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-id-ns.html b/Documentation/nvme-lnvm-id-ns.html
new file mode 100644
index 0000000..a3bc888
--- /dev/null
+++ b/Documentation/nvme-lnvm-id-ns.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 8.6.10" />
+<title>nvme-lnvm-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 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-lnvm-id-ns(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-id-ns -
+ Identify Geometry for LightNVM 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 lnvm-id-ns</em> &lt;device&gt; [--namespace-id=&lt;nsid&gt; | -n &lt;nsid&gt;]
+ [--force | -f]
+ [--raw-binary | -b]
+ [--human-readable | -H]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Send an Identify Geometry command to the given LightNVM device, returns
+properties of the specified namespace in either human-readable or binary
+format.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Retrieve the geometry from the selected namespace.
+</p>
+</dd>
+<dt class="hdlist1">
+--force
+</dt>
+<dt class="hdlist1">
+-f
+</dt>
+<dd>
+<p>
+ Try to read the data and assume it is a LightNVM device
+</p>
+</dd>
+<dt class="hdlist1">
+--raw-binary
+</dt>
+<dt class="hdlist1">
+-b
+</dt>
+<dd>
+<p>
+ Output the raw output
+</p>
+</dd>
+<dt class="hdlist1">
+--human-readable
+</dt>
+<dt class="hdlist1">
+-H
+</dt>
+<dd>
+<p>
+ Output the status in human readable format
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Retrieve the geometry from nvme0
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-id-ns /dev/nvme0 -n 1</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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-id-ns.txt b/Documentation/nvme-lnvm-id-ns.txt
new file mode 100644
index 0000000..1a3565f
--- /dev/null
+++ b/Documentation/nvme-lnvm-id-ns.txt
@@ -0,0 +1,49 @@
+nvme-lnvm-id-ns(1)
+==================
+
+NAME
+----
+nvme-lnvm-id-ns - Identify Geometry for LightNVM NVMe device
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-id-ns' <device> [--namespace-id=<nsid> | -n <nsid>]
+ [--force | -f]
+ [--raw-binary | -b]
+ [--human-readable | -H]
+
+DESCRIPTION
+-----------
+Send an Identify Geometry command to the given LightNVM device, returns
+properties of the specified namespace in either human-readable or binary
+format.
+
+OPTIONS
+-------
+--namespace-id=<nsid>::
+-n <nsid>::
+ Retrieve the geometry from the selected namespace.
+
+--force::
+-f::
+ Try to read the data and assume it is a LightNVM device
+
+--raw-binary::
+-b::
+ Output the raw output
+
+--human-readable::
+-H::
+ Output the status in human readable format
+
+EXAMPLES
+--------
+* Retrieve the geometry from nvme0
+------------
+# nvme lnvm-id-ns /dev/nvme0 -n 1
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-info.1 b/Documentation/nvme-lnvm-info.1
new file mode 100644
index 0000000..e1f9c97
--- /dev/null
+++ b/Documentation/nvme-lnvm-info.1
@@ -0,0 +1,48 @@
+'\" t
+.\" Title: nvme-lnvm-info
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-INFO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-info \- Show general information and registered target types with LightNVM
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-info\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Show general information and registered target types with LightNVM\&.
+.SH "OPTIONS"
+.sp
+No options yet\&.
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-info.html b/Documentation/nvme-lnvm-info.html
new file mode 100644
index 0000000..13b714f
--- /dev/null
+++ b/Documentation/nvme-lnvm-info.html
@@ -0,0 +1,786 @@
+<!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-lnvm-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;
+}
+
+
+#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-lnvm-info(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-info -
+ Show general information and registered target types with LightNVM
+</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 lnvm-info</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Show general information and registered target types with LightNVM.</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="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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-info.txt b/Documentation/nvme-lnvm-info.txt
new file mode 100644
index 0000000..e755c9c
--- /dev/null
+++ b/Documentation/nvme-lnvm-info.txt
@@ -0,0 +1,27 @@
+nvme-lnvm-info(1)
+=================
+
+NAME
+----
+nvme-lnvm-info - Show general information and registered target types with LightNVM
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-info'
+
+DESCRIPTION
+-----------
+Show general information and registered target types with LightNVM.
+
+OPTIONS
+-------
+No options yet.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-init.1 b/Documentation/nvme-lnvm-init.1
new file mode 100644
index 0000000..b21a5c7
--- /dev/null
+++ b/Documentation/nvme-lnvm-init.1
@@ -0,0 +1,97 @@
+'\" t
+.\" Title: nvme-lnvm-init
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-INIT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-init \- Initialize LightNVM device with media manager
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-init\fR [\-\-device\-name=<DEVICE> | \-d <DEVICE>]
+ [\-\-mediamgr\-name | \-m]
+.fi
+.SH "DESCRIPTION"
+.sp
+Initialize LightNVM device\&. A LightNVM/Open\-Channel SSD must have a media manager associated before it can be exposed to the user\&. The default is to initialize the general media manager on top of the device\&.
+.SH "OPTIONS"
+.PP
+\-\-device\-name=<DEVICE>, \-d <DEVICE>
+.RS 4
+Device name to initialize\&.
+.RE
+.PP
+\-\-mediamgr\-name=<MediaMgr>, \-m <MediaMgr>
+.RS 4
+Media Manager name to use for initialization\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Initialize nvme0n1
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-init \-d nvme0n1
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Initialize nvme0n1 with gennvm media manager (default media manager)
+.RE
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+# nvme lnvm\-init \-d nvme0n1 \-m gennvm
+.fi
+.if n \{\
+.RE
+.\}
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-init.html b/Documentation/nvme-lnvm-init.html
new file mode 100644
index 0000000..d1fc894
--- /dev/null
+++ b/Documentation/nvme-lnvm-init.html
@@ -0,0 +1,833 @@
+<!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-lnvm-init(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-lnvm-init(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-init -
+ Initialize LightNVM device with media manager
+</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 lnvm-init</em> [--device-name=&lt;DEVICE&gt; | -d &lt;DEVICE&gt;]
+ [--mediamgr-name | -m]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Initialize LightNVM device. A LightNVM/Open-Channel SSD must have a media
+manager associated before it can be exposed to the user. The default is to
+initialize the general media manager on top of the device.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--device-name=&lt;DEVICE&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;DEVICE&gt;
+</dt>
+<dd>
+<p>
+ Device name to initialize.
+</p>
+</dd>
+<dt class="hdlist1">
+--mediamgr-name=&lt;MediaMgr&gt;
+</dt>
+<dt class="hdlist1">
+-m &lt;MediaMgr&gt;
+</dt>
+<dd>
+<p>
+ Media Manager name to use for initialization.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Initialize nvme0n1
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-init -d nvme0n1</code></pre>
+</div></div>
+<div class="ulist"><ul>
+<li>
+<p>
+Initialize nvme0n1 with gennvm media manager (default media manager)
+</p>
+</li>
+</ul></div>
+<div class="listingblock">
+<div class="content">
+<pre><code># nvme lnvm-init -d nvme0n1 -m gennvm</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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-init.txt b/Documentation/nvme-lnvm-init.txt
new file mode 100644
index 0000000..0d922a9
--- /dev/null
+++ b/Documentation/nvme-lnvm-init.txt
@@ -0,0 +1,44 @@
+nvme-lnvm-init(1)
+=================
+
+NAME
+----
+nvme-lnvm-init - Initialize LightNVM device with media manager
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-init' [--device-name=<DEVICE> | -d <DEVICE>]
+ [--mediamgr-name | -m]
+
+DESCRIPTION
+-----------
+Initialize LightNVM device. A LightNVM/Open-Channel SSD must have a media
+manager associated before it can be exposed to the user. The default is to
+initialize the general media manager on top of the device.
+
+OPTIONS
+-------
+--device-name=<DEVICE>::
+-d <DEVICE>::
+ Device name to initialize.
+
+--mediamgr-name=<MediaMgr>::
+-m <MediaMgr>::
+ Media Manager name to use for initialization.
+
+EXAMPLES
+--------
+* Initialize nvme0n1
+------------
+# nvme lnvm-init -d nvme0n1
+------------
+
+* Initialize nvme0n1 with gennvm media manager (default media manager)
+------------
+# nvme lnvm-init -d nvme0n1 -m gennvm
+------------
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-list.1 b/Documentation/nvme-lnvm-list.1
new file mode 100644
index 0000000..65eb085
--- /dev/null
+++ b/Documentation/nvme-lnvm-list.1
@@ -0,0 +1,48 @@
+'\" t
+.\" Title: nvme-lnvm-list
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-LIST" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-list \- List all recognized LightNVM NVMe devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-list\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+List all registered LightNVM devices\&.
+.SH "OPTIONS"
+.sp
+No options yet\&.
+.SH "EXAMPLES"
+.sp
+No examples yet\&.
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-list.html b/Documentation/nvme-lnvm-list.html
new file mode 100644
index 0000000..0f42d8f
--- /dev/null
+++ b/Documentation/nvme-lnvm-list.html
@@ -0,0 +1,786 @@
+<!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-lnvm-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;
+}
+
+
+#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-lnvm-list(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-list -
+ List all recognized LightNVM 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 lnvm-list</em></pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>List all registered LightNVM devices.</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="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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-list.txt b/Documentation/nvme-lnvm-list.txt
new file mode 100644
index 0000000..959f6b9
--- /dev/null
+++ b/Documentation/nvme-lnvm-list.txt
@@ -0,0 +1,27 @@
+nvme-lnvm-list(1)
+=================
+
+NAME
+----
+nvme-lnvm-list - List all recognized LightNVM NVMe devices
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-list'
+
+DESCRIPTION
+-----------
+List all registered LightNVM devices.
+
+OPTIONS
+-------
+No options yet.
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-lnvm-remove.1 b/Documentation/nvme-lnvm-remove.1
new file mode 100644
index 0000000..3dc3140
--- /dev/null
+++ b/Documentation/nvme-lnvm-remove.1
@@ -0,0 +1,53 @@
+'\" t
+.\" Title: nvme-lnvm-remove
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-LNVM\-REMOVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-lnvm-remove \- Remove an initialized LightNVM target\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme lnvm\-remove\fR [\-\-target\-name=<TARGET> | \-n <TARGET>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Remove an initialized target\&.
+.sp
+The target name is the name of which the media is exposed as in /dev/<TARGET>
+.SH "OPTIONS"
+.PP
+\-\-target\-name=<TARGET>, \-n <TARGET>
+.RS 4
+Target name of the device to initialize\&. For example: target0\&.
+.RE
+.SH "EXAMPLES"
+.sp
+None yet
+.SH "NVME"
+.sp
+Part of the nvme\-user suite
diff --git a/Documentation/nvme-lnvm-remove.html b/Documentation/nvme-lnvm-remove.html
new file mode 100644
index 0000000..ac2e69a
--- /dev/null
+++ b/Documentation/nvme-lnvm-remove.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-lnvm-remove(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-lnvm-remove(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-lnvm-remove -
+ Remove an initialized LightNVM target.
+</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 lnvm-remove</em> [--target-name=&lt;TARGET&gt; | -n &lt;TARGET&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Remove an initialized target.</p></div>
+<div class="paragraph"><p>The target name is the name of which the media is exposed as in
+/dev/&lt;TARGET&gt;</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="dlist"><dl>
+<dt class="hdlist1">
+--target-name=&lt;TARGET&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;TARGET&gt;
+</dt>
+<dd>
+<p>
+ Target name of the device to initialize. For example: target0.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None 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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-lnvm-remove.txt b/Documentation/nvme-lnvm-remove.txt
new file mode 100644
index 0000000..f5cdd6e
--- /dev/null
+++ b/Documentation/nvme-lnvm-remove.txt
@@ -0,0 +1,32 @@
+nvme-lnvm-remove(1)
+===================
+
+NAME
+----
+nvme-lnvm-remove - Remove an initialized LightNVM target.
+
+SYNOPSIS
+--------
+[verse]
+'nvme lnvm-remove' [--target-name=<TARGET> | -n <TARGET>]
+
+DESCRIPTION
+-----------
+Remove an initialized target.
+
+The target name is the name of which the media is exposed as in
+/dev/<TARGET>
+
+OPTIONS
+-------
+--target-name=<TARGET>::
+-n <TARGET>::
+ Target name of the device to initialize. For example: target0.
+
+EXAMPLES
+--------
+None yet
+
+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..83bc5cb
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NETAPP\-ONTAPD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-netapp-ontapdevices \- Display information about ONTAP devices
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme netapp ontapdevices\fR [\-o <fmt> | \-\-output\-format=<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..29f4bda
--- /dev/null
+++ b/Documentation/nvme-netapp-ontapdevices.html
@@ -0,0 +1,810 @@
+<!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-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;
+}
+
+
+#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-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> [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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 2019-04-15 08:37:59 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-netapp-ontapdevices.txt b/Documentation/nvme-netapp-ontapdevices.txt
new file mode 100644
index 0000000..c292758
--- /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' [-o <fmt> | --output-format=<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..78622ea
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NETAPP\-SMDEVI" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-netapp-smdevices \- Display information for each NVMe path to an E\-Series volume
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme netapp smdevices\fR [\-o <fmt> | \-\-output\-format=<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..71e5014
--- /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 8.6.10" />
+<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 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-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> [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>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
+ 2019-09-18 00:00:58 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-netapp-smdevices.txt b/Documentation/nvme-netapp-smdevices.txt
new file mode 100644
index 0000000..b66b98d
--- /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' [-o <fmt> | --output-format=<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..cddc126
--- /dev/null
+++ b/Documentation/nvme-ns-descs.1
@@ -0,0 +1,115 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NS\-DESCS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <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
+.\}
+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..9751724
--- /dev/null
+++ b/Documentation/nvme-ns-descs.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.9" />
+<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;]</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;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>
+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
+ 2018-01-30 19:28:39 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ns-descs.txt b/Documentation/nvme-ns-descs.txt
new file mode 100644
index 0000000..8afeba5
--- /dev/null
+++ b/Documentation/nvme-ns-descs.txt
@@ -0,0 +1,74 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or 'binary'.
+ Only one output format can be used at a time.
+
+
+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..5fcf6e8
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.1
@@ -0,0 +1,67 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-NS\-RESCAN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-ns-rescan \- Rescans the nvme namespaces\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme ns\-rescan\fR <device>
+.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"
+.sp
+None
+.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..f4b0346
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.html
@@ -0,0 +1,455 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.4.5" />
+<title>nvme-ns-rescan(1)</title>
+<style type="text/css">
+/* Debug borders */
+p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
+/*
+ border: 1px solid red;
+*/
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+tt {
+ color: navy;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ font-family: sans-serif;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+
+div.sectionbody {
+ font-family: serif;
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+
+pre {
+ padding: 0;
+ margin: 0;
+}
+
+span#author {
+ color: #527bbd;
+ font-family: sans-serif;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+span#email {
+}
+span#revnumber, span#revdate, span#revremark {
+ font-family: sans-serif;
+}
+
+div#footer {
+ font-family: sans-serif;
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+div#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+div#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+div#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.5em;
+ margin-bottom: 2.5em;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-family: sans-serif;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid silver;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid silver;
+ background: #f4f4f4;
+ padding: 0.5em;
+}
+
+div.quoteblock {
+ padding-left: 2.0em;
+ margin-right: 10%;
+}
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock {
+ padding-left: 2.0em;
+ margin-right: 10%;
+}
+div.verseblock > div.content {
+ white-space: pre;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 2px solid silver;
+}
+
+div.exampleblock > div.content {
+ border-left: 2px solid silver;
+ padding: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead {
+ font-family: sans-serif;
+ font-weight: bold;
+}
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overridden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+@media print {
+ div#footer-badges { display: none; }
+}
+
+div#toctitle {
+ color: #527bbd;
+ font-family: sans-serif;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+/* Overrides for manpage documents */
+h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+h2 {
+ border-style: none;
+}
+div.sectionbody {
+ margin-left: 5%;
+}
+
+@media print {
+ div#toc { display: none; }
+}
+
+/* Workarounds for IE6's broken and incomplete CSS2. */
+
+div.sidebar-content {
+ background: #ffffee;
+ border: 1px solid silver;
+ padding: 0.5em;
+}
+div.sidebar-title, div.image-title {
+ color: #527bbd;
+ font-family: sans-serif;
+ font-weight: bold;
+ margin-top: 0.0em;
+ margin-bottom: 0.5em;
+}
+
+div.listingblock div.content {
+ border: 1px solid silver;
+ background: #f4f4f4;
+ padding: 0.5em;
+}
+
+div.quoteblock-attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock-content {
+ white-space: pre;
+}
+div.verseblock-attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+
+div.exampleblock-content {
+ border-left: 2px solid silver;
+ padding-left: 0.5em;
+}
+
+/* IE6 sets dynamically generated links as visited. */
+div#toc a:visited { color: blue; }
+</style>
+</head>
+<body>
+<div id="header">
+<h1>
+nvme-ns-rescan(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-ns-rescan -
+ Rescans the nvme namespaces.
+</p>
+</div>
+</div>
+<h2 id="_synopsis">SYNOPSIS</h2>
+<div class="sectionbody">
+<div class="verseblock">
+<div class="verseblock-content"><em>nvme ns-rescan</em> &lt;device&gt;</div>
+<div class="verseblock-attribution">
+</div></div>
+</div>
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Requests NVMe controller rescans the namespaces. The &lt;device&gt; param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).</p></div>
+</div>
+<h2 id="_options">OPTIONS</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>None</p></div>
+</div>
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Rescans the nvme namespaces.
+</p>
+<div class="listingblock">
+<div class="content">
+<pre><tt># nvme ns-rescan /dev/nvme0</tt></pre>
+</div></div>
+</li>
+</ul></div>
+</div>
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite</p></div>
+</div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2017-09-22 16:31:43 CDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-ns-rescan.txt b/Documentation/nvme-ns-rescan.txt
new file mode 100644
index 0000000..cd41870
--- /dev/null
+++ b/Documentation/nvme-ns-rescan.txt
@@ -0,0 +1,32 @@
+nvme-ns-rescan(1)
+=================
+
+NAME
+----
+nvme-ns-rescan - Rescans the nvme namespaces.
+
+SYNOPSIS
+--------
+[verse]
+'nvme ns-rescan' <device>
+
+DESCRIPTION
+-----------
+Requests NVMe controller rescans the namespaces. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Rescans the nvme namespaces.
++
+------------
+# nvme ns-rescan /dev/nvme0
+------------
+
+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..ae7faf6
--- /dev/null
+++ b/Documentation/nvme-read.1
@@ -0,0 +1,186 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-READ" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+\-\-start\-block=<slba>, \-s <slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-\-block\-count, \-c
+.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
+\-\-data\-size=<size>, \-z <size>
+.RS 4
+Size of data, in bytes\&.
+.RE
+.PP
+\-\-metadata\-size=<size>, \-y <size>
+.RS 4
+Size of metadata in bytes\&.
+.RE
+.PP
+\-\-data=<data\-file>, \-d <data\-file>
+.RS 4
+Data file\&. If none provided, contents are sent to STDOUT\&.
+.RE
+.PP
+\-\-metadata=<metadata\-file>, \-M <metadata\-file>
+.RS 4
+Metadata file, if necessary\&.
+.RE
+.PP
+\-\-prinfo=<prinfo>, \-p <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
+\-\-ref\-tag=<reftag>, \-r <reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-\-app\-tag\-mask=<appmask>, \-m <appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-\-force\-unit\-access, \-f
+.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 specifcation (1\&.3a) defines only one directive, 01h, for write stream idenfiers\&.
+.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 lower 16 bits of the DSM field in a write command; the upper 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
+.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..fdc1606
--- /dev/null
+++ b/Documentation/nvme-read.html
@@ -0,0 +1,1040 @@
+<?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-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 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-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]</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">
+--start-block=&lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+--block-count
+</dt>
+<dt class="hdlist1">
+-c
+</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">
+--data-size=&lt;size&gt;
+</dt>
+<dt class="hdlist1">
+-z &lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of data, in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+--metadata-size=&lt;size&gt;
+</dt>
+<dt class="hdlist1">
+-y &lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Data file. If none provided, contents are sent to STDOUT.
+</p>
+</dd>
+<dt class="hdlist1">
+--metadata=&lt;metadata-file&gt;
+</dt>
+<dt class="hdlist1">
+-M &lt;metadata-file&gt;
+</dt>
+<dd>
+<p>
+ Metadata file, if necessary.
+</p>
+</dd>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+-p &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">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dt class="hdlist1">
+-f
+</dt>
+<dd>
+<p>
+ Set the force-unit access flag.
+</p>
+</dd>
+<dt class="hdlist1">
+-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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+</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 lower 16 bits of the DSM field in a write
+ command; the upper 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>
+</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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-read.txt b/Documentation/nvme-read.txt
new file mode 100644
index 0000000..55a701c
--- /dev/null
+++ b/Documentation/nvme-read.txt
@@ -0,0 +1,137 @@
+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]
+
+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
+-------
+--start-block=<slba>::
+-s <slba>::
+ Start block.
+
+--block-count::
+-c::
+ 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).
+
+--data-size=<size>::
+-z <size>::
+ Size of data, in bytes.
+
+--metadata-size=<size>::
+-y <size>::
+ Size of metadata in bytes.
+
+--data=<data-file>::
+-d <data-file>::
+ Data file. If none provided, contents are sent to STDOUT.
+
+--metadata=<metadata-file>::
+-M <metadata-file>::
+ Metadata file, if necessary.
+
+--prinfo=<prinfo>::
+-p <prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+--ref-tag=<reftag>::
+-r <reftag>::
+ Optional reftag when used with protection information.
+
+--app-tag-mask=<appmask>::
+-m <appmask>::
+ Optional application tag mask when used with protection information.
+
+--force-unit-access::
+-f::
+ 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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+
+-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 lower 16 bits of the DSM field in a write
+ command; the upper 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).
+
+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..7b8f3de
--- /dev/null
+++ b/Documentation/nvme-reset.1
@@ -0,0 +1,67 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESET" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-reset \- Reset the nvme controller\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme reset\fR <device>
+.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"
+.sp
+None
+.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..40ac603
--- /dev/null
+++ b/Documentation/nvme-reset.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 8.6.10" />
+<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 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-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;</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="paragraph"><p>None</p></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
+ 2019-11-08 08:41:30 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-reset.txt b/Documentation/nvme-reset.txt
new file mode 100644
index 0000000..d1a282b
--- /dev/null
+++ b/Documentation/nvme-reset.txt
@@ -0,0 +1,32 @@
+nvme-reset(1)
+=============
+
+NAME
+----
+nvme-reset - Reset the nvme controller.
+
+SYNOPSIS
+--------
+[verse]
+'nvme reset' <device>
+
+DESCRIPTION
+-----------
+Requests NVMe controller reset. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+None
+
+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..f96d127
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.1
@@ -0,0 +1,177 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-ACQUIRE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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>, \-\-rtyep=<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
+.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..17b3d94
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.html
@@ -0,0 +1,954 @@
+<!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-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]</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">
+--rtyep=&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>
+</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
+ 2018-01-30 19:28:39 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-acquire.txt b/Documentation/nvme-resv-acquire.txt
new file mode 100644
index 0000000..41cbf8f
--- /dev/null
+++ b/Documentation/nvme-resv-acquire.txt
@@ -0,0 +1,92 @@
+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]
+
+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>::
+--rtyep=<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'.
+
+EXAMPLES
+--------
+No examples yet
+
+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..4a50513
--- /dev/null
+++ b/Documentation/nvme-resv-register.1
@@ -0,0 +1,153 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-REGISTER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+\-a <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
+.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..a17f869
--- /dev/null
+++ b/Documentation/nvme-resv-register.html
@@ -0,0 +1,944 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-resv-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-resv-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]</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">
+-a &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>
+</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
+ 2019-11-08 02:18:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-register.txt b/Documentation/nvme-resv-register.txt
new file mode 100644
index 0000000..076e979
--- /dev/null
+++ b/Documentation/nvme-resv-register.txt
@@ -0,0 +1,93 @@
+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]
+
+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.
+|=================
+
+-a <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'.
+
+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..1817e51
--- /dev/null
+++ b/Documentation/nvme-resv-release.1
@@ -0,0 +1,165 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-RELEASE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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>, \-\-rtyep=<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
+.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..884dc78
--- /dev/null
+++ b/Documentation/nvme-resv-release.html
@@ -0,0 +1,937 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-resv-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-resv-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]</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">
+--rtyep=&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>
+</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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-release.txt b/Documentation/nvme-resv-release.txt
new file mode 100644
index 0000000..a6a895e
--- /dev/null
+++ b/Documentation/nvme-resv-release.txt
@@ -0,0 +1,84 @@
+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]
+
+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>::
+--rtyep=<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'.
+
+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..7242f3a
--- /dev/null
+++ b/Documentation/nvme-resv-report.1
@@ -0,0 +1,80 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-RESV\-REPORT" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-cdw11=<cdw11> | \-c <cdw11>]
+ [\-\-raw\-binary | \-b]
+ [\-\-output\-format=<fmt> | \-o <fmt>]
+.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
+\-c <cdw11>, \-\-cdw11=<cdw11>
+.RS 4
+The value for command dword 11\&. Setting bit 0 specifies that 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 <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
+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..d34e6da
--- /dev/null
+++ b/Documentation/nvme-resv-report.html
@@ -0,0 +1,861 @@
+<!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-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;]
+ [--cdw11=&lt;cdw11&gt; | -c &lt;cdw11&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>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">
+-c &lt;cdw11&gt;
+</dt>
+<dt class="hdlist1">
+--cdw11=&lt;cdw11&gt;
+</dt>
+<dd>
+<p>
+ The value for command dword 11. Setting bit 0 specifies that 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;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="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
+ 2018-01-30 19:28:39 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-resv-report.txt b/Documentation/nvme-resv-report.txt
new file mode 100644
index 0000000..b53c141
--- /dev/null
+++ b/Documentation/nvme-resv-report.txt
@@ -0,0 +1,63 @@
+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>]
+ [--cdw11=<cdw11> | -c <cdw11>]
+ [--raw-binary | -b]
+ [--output-format=<fmt> | -o <fmt>]
+
+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.
+
+-c <cdw11>::
+--cdw11=<cdw11>::
+ The value for command dword 11. Setting bit 0 specifies that the
+ controller returns the Extended Data Structure.
+
+-b::
+--raw-binary::
+ Print the raw buffer to stdout. Structure is not parsed by
+ program.
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme-sanitize-log.1 b/Documentation/nvme-sanitize-log.1
new file mode 100644
index 0000000..72787c7
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.1
@@ -0,0 +1,144 @@
+'\" t
+.\" Title: nvme-sanitize-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SANITIZE\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-sanitize-log \- Send NVMe sanitize\-log Command, return result
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme sanitize\-log\fR <device> [\-\-output\-format=<fmt> | \-o <fmt>]
+ [\-\-human\-readable | \-H]
+ [\-\-raw\-binary | \-b]
+.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
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.PP
+\-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
+.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..d369a10
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.html
@@ -0,0 +1,888 @@
+<?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-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 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-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; [--output-format=&lt;fmt&gt; | -o &lt;fmt&gt;]
+ [--human-readable | -H]
+ [--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 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">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+<dt class="hdlist1">
+-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>
+</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
+ 2019-11-08 02:18:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-sanitize-log.txt b/Documentation/nvme-sanitize-log.txt
new file mode 100644
index 0000000..3c3b73e
--- /dev/null
+++ b/Documentation/nvme-sanitize-log.txt
@@ -0,0 +1,82 @@
+nvme-sanitize-log(1)
+====================
+
+NAME
+----
+nvme-sanitize-log - Send NVMe sanitize-log Command, return result
+
+SYNOPSIS
+--------
+[verse]
+'nvme sanitize-log' <device> [--output-format=<fmt> | -o <fmt>]
+ [--human-readable | -H]
+ [--raw-binary | -b]
+
+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
+-------
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+-H::
+--human-readable::
+ This option will parse and format many of the bit fields
+ into human-readable formats.
+
+-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
+--------
+* 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..85d2bd4
--- /dev/null
+++ b/Documentation/nvme-sanitize.1
@@ -0,0 +1,105 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SANITIZE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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\-delloc
+.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: 000b \- Reserved 001b \- Exit Failure Mode 010b \- Start a Block Erase sanitize operation 011b \- Start an Overwrite sanitize operation 100b \- Start a Crypto Erase sanitize operation
+.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
+.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/nvme0n1 \-a 0x02
+# nvme sanitize /dev/nvme0n1 \-\-sanact=0x01
+.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..9870cbc
--- /dev/null
+++ b/Documentation/nvme-sanitize.html
@@ -0,0 +1,903 @@
+<!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-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;]</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-delloc
+</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:
+ 000b - Reserved
+ 001b - Exit Failure Mode
+ 010b - Start a Block Erase sanitize operation
+ 011b - Start an Overwrite sanitize operation
+ 100b - Start a Crypto Erase sanitize operation
+</p>
+</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>
+</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/nvme0n1 -a 0x02
+# nvme sanitize /dev/nvme0n1 --sanact=0x01</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
+ 2017-06-28 18:52:37 PDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-sanitize.txt b/Documentation/nvme-sanitize.txt
new file mode 100644
index 0000000..b1d9a0e
--- /dev/null
+++ b/Documentation/nvme-sanitize.txt
@@ -0,0 +1,93 @@
+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>]
+
+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-delloc::
+ 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:
+ 000b - Reserved
+ 001b - Exit Failure Mode
+ 010b - Start a Block Erase sanitize operation
+ 011b - Start an Overwrite sanitize operation
+ 100b - 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.
+
+EXAMPLES
+--------
+* Has the program issue Sanitize Command :
++
+------------
+# nvme sanitize /dev/nvme0n1 -a 0x02
+# nvme sanitize /dev/nvme0n1 --sanact=0x01
+
+------------
+
+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..df47abb
--- /dev/null
+++ b/Documentation/nvme-security-recv.1
@@ -0,0 +1,91 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SECURITY\-RECV" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+.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..39e7ee2
--- /dev/null
+++ b/Documentation/nvme-security-recv.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 8.6.10" />
+<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 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-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]</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>
+</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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-security-recv.txt b/Documentation/nvme-security-recv.txt
new file mode 100644
index 0000000..0b9fe99
--- /dev/null
+++ b/Documentation/nvme-security-recv.txt
@@ -0,0 +1,80 @@
+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]
+
+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.
+
+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..919464c
--- /dev/null
+++ b/Documentation/nvme-security-send.1
@@ -0,0 +1,83 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SECURITY\-SEND" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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
+.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..4ffa0d6
--- /dev/null
+++ b/Documentation/nvme-security-send.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 8.6.10" />
+<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 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-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;]</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>
+</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
+ 2019-11-08 08:41:30 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-security-send.txt b/Documentation/nvme-security-send.txt
new file mode 100644
index 0000000..ae22628
--- /dev/null
+++ b/Documentation/nvme-security-send.txt
@@ -0,0 +1,72 @@
+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>]
+
+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.
+
+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..caff6ff
--- /dev/null
+++ b/Documentation/nvme-self-test-log.1
@@ -0,0 +1,121 @@
+'\" t
+.\" Title: nvme-self-test-log
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SELF\-TEST\-LO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-self-test-log \- Retrieve the log information initited by device\-self\-test and display it
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme self\-test\fR\-log <device> [\-\-output\-format=<FMT> | \-o <FMT>]
+.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
+\-o <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Get the 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..7f02a76
--- /dev/null
+++ b/Documentation/nvme-self-test-log.html
@@ -0,0 +1,836 @@
+<!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-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;
+}
+
+
+#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-self-test-log(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-self-test-log -
+ Retrieve the log information initited 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; [--output-format=&lt;FMT&gt; | -o &lt;FMT&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Retrieves the 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">
+-o &lt;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Get the 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 2018-06-15 13:12:28 MDT
+</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..78798d9
--- /dev/null
+++ b/Documentation/nvme-self-test-log.txt
@@ -0,0 +1,61 @@
+nvme-self-test-log(1)
+=====================
+
+NAME
+----
+nvme-self-test-log - Retrieve the log information initited by device-self-test and display it
+
+SYNOPSIS
+--------
+[verse]
+'nvme self-test'-log <device> [--output-format=<FMT> | -o <FMT>]
+
+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
+-------
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+
+EXAMPLES
+--------
+* Get the 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..a39755e
--- /dev/null
+++ b/Documentation/nvme-set-feature.1
@@ -0,0 +1,124 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SET\-FEATURE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+ [\-\-data\-len=<data\-len> | \-l <data\-len>]
+ [\-\-data=<data\-file> | \-d <data\-file>]
+ [\-\-save| \-s]
+.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
+.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
+.\}
+.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..b813b91
--- /dev/null
+++ b/Documentation/nvme-set-feature.html
@@ -0,0 +1,889 @@
+<!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-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;
+}
+
+
+#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-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;]
+ [--data-len=&lt;data-len&gt; | -l &lt;data-len&gt;]
+ [--data=&lt;data-file&gt; | -d &lt;data-file&gt;]
+ [--save| -s]</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>
+</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>
+</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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-set-feature.txt b/Documentation/nvme-set-feature.txt
new file mode 100644
index 0000000..ca1874d
--- /dev/null
+++ b/Documentation/nvme-set-feature.txt
@@ -0,0 +1,79 @@
+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>]
+ [--data-len=<data-len> | -l <data-len>]
+ [--data=<data-file> | -d <data-file>]
+ [--save| -s]
+
+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.
+
+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
+----
+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..d87efd4
--- /dev/null
+++ b/Documentation/nvme-set-property.1
@@ -0,0 +1,57 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SET\-PROPERTY" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-set-property \- Writes and shows the defined NVMe controller property for NVMe ove Fabric
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme set\-property\fR <device> [\-\-offset=<offset> | \-o <offset>]
+ [\-\-value=<val> | \-v <val>]
+.fi
+.SH "DESCRIPTION"
+.sp
+Writes and shows the defined NVMe controller property for NVMe ove 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
+.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..41b06e2
--- /dev/null
+++ b/Documentation/nvme-set-property.html
@@ -0,0 +1,812 @@
+<?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-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 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-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 ove 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;]</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 ove 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>
+</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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-set-property.txt b/Documentation/nvme-set-property.txt
new file mode 100644
index 0000000..0d04f52
--- /dev/null
+++ b/Documentation/nvme-set-property.txt
@@ -0,0 +1,36 @@
+nvme-set-property(1)
+====================
+
+NAME
+----
+nvme-set-property - Writes and shows the defined NVMe controller property
+for NVMe ove Fabric
+
+SYNOPSIS
+--------
+[verse]
+'nvme set-property' <device> [--offset=<offset> | -o <offset>]
+ [--value=<val> | -v <val>]
+
+
+DESCRIPTION
+-----------
+Writes and shows the defined NVMe controller property for NVMe ove Fabric.
+
+OPTIONS
+-------
+-o::
+--offset::
+ The offset of the property.
+
+-v::
+--value:
+ The value of the property to be set.
+
+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..8f901aa
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.1
@@ -0,0 +1,48 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SHOW\-HOSTNQN" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-show-hostnqn \- Generate a host NVMe Qualified Name
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme show\-hostnqn\fR
+.fi
+.SH "DESCRIPTION"
+.sp
+Show the host NQN configured for the system\&. If /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"
+.sp
+No options needed
+.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..b459d0a
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.html
@@ -0,0 +1,792 @@
+<?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-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 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-show-hostnqn(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-show-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 show-hostnqn</em></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 /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="paragraph"><p>No options needed</p></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
+ 2019-10-12 00:12:24 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-show-hostnqn.txt b/Documentation/nvme-show-hostnqn.txt
new file mode 100644
index 0000000..044346c
--- /dev/null
+++ b/Documentation/nvme-show-hostnqn.txt
@@ -0,0 +1,29 @@
+nvme-show-hostnqn(1)
+===================
+
+NAME
+----
+nvme-show-hostnqn - Generate a host NVMe Qualified Name
+
+SYNOPSIS
+--------
+[verse]
+'nvme show-hostnqn'
+
+DESCRIPTION
+-----------
+Show the host NQN configured for the system. If /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.
+
+OPTIONS
+-------
+No options needed
+
+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..b29271d
--- /dev/null
+++ b/Documentation/nvme-show-regs.1
@@ -0,0 +1,123 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ID\-NS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <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
+.\}
+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..1b56c47
--- /dev/null
+++ b/Documentation/nvme-show-regs.html
@@ -0,0 +1,855 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-id-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-id-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;]</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;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>
+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
+ 2019-04-07 06:12:04 KST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-show-regs.txt b/Documentation/nvme-show-regs.txt
new file mode 100644
index 0000000..892b394
--- /dev/null
+++ b/Documentation/nvme-show-regs.txt
@@ -0,0 +1,63 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+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-smart-log.1 b/Documentation/nvme-smart-log.1
new file mode 100644
index 0000000..95fbb70
--- /dev/null
+++ b/Documentation/nvme-smart-log.1
@@ -0,0 +1,112 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SMART\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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 <format>, \-\-output\-format=<format>
+.RS 4
+Set the reporting format to
+\fInormal\fR,
+\fIjson\fR, or
+\fIbinary\fR\&. Only one output format can be used at a time\&.
+.RE
+.SH "EXAMPLES"
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+.sp -1
+.IP \(bu 2.3
+.\}
+Print the 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..465cb91
--- /dev/null
+++ b/Documentation/nvme-smart-log.html
@@ -0,0 +1,853 @@
+<!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-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;
+}
+
+
+#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-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;]</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;format&gt;
+</dt>
+<dt class="hdlist1">
+--output-format=&lt;format&gt;
+</dt>
+<dd>
+<p>
+ Set the reporting format to <em>normal</em>, <em>json</em>, or
+ <em>binary</em>. Only one output format can be used at a time.
+</p>
+</dd>
+</dl></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_examples">EXAMPLES</h2>
+<div class="sectionbody">
+<div class="ulist"><ul>
+<li>
+<p>
+Print the 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 2017-06-26 15:57:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-smart-log.txt b/Documentation/nvme-smart-log.txt
new file mode 100644
index 0000000..77d0015
--- /dev/null
+++ b/Documentation/nvme-smart-log.txt
@@ -0,0 +1,65 @@
+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>]
+
+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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Print the 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..abf7d0d
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.1
@@ -0,0 +1,67 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-SUBSYSTEM\-RES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-subsystem-reset \- Reset the nvme subsystem\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme subsystem\-reset\fR <device>
+.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"
+.sp
+None
+.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..cd0dcc3
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.html
@@ -0,0 +1,797 @@
+<!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-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;
+}
+
+
+#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-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;</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="paragraph"><p>None</p></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 2016-05-16 12:47:42 EDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-subsystem-reset.txt b/Documentation/nvme-subsystem-reset.txt
new file mode 100644
index 0000000..2267acd
--- /dev/null
+++ b/Documentation/nvme-subsystem-reset.txt
@@ -0,0 +1,32 @@
+nvme-subsystem-reset(1)
+=======================
+
+NAME
+----
+nvme-subsystem-reset - Reset the nvme subsystem.
+
+SYNOPSIS
+--------
+[verse]
+'nvme subsystem-reset' <device>
+
+DESCRIPTION
+-----------
+Requests NVMe subsystem reset. The <device> param is mandatory and must
+be an NVMe character device (ex: /dev/nvme0).
+
+OPTIONS
+-------
+None
+
+EXAMPLES
+--------
+* Resets the subsystem.
++
+------------
+# nvme subsystem-reset /dev/nvme0
+------------
+
+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..e978e83
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.1
@@ -0,0 +1,87 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TELEMETRY\-LOG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.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\&. If this option is not specified, the default value is 3, since that will always give the user all three data areas\&.
+.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..aa32c7c
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.html
@@ -0,0 +1,845 @@
+<?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-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 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-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;]</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. If
+ this option is not specified, the default value is 3, since that will
+ always give the user all three data areas.
+</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
+ 2020-03-18 00:47:34 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-telemetry-log.txt b/Documentation/nvme-telemetry-log.txt
new file mode 100644
index 0000000..9b1c9e4
--- /dev/null
+++ b/Documentation/nvme-telemetry-log.txt
@@ -0,0 +1,54 @@
+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>]
+
+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. If
+ this option is not specified, the default value is 3, since that will
+ always give the user all three data areas.
+
+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..fd92c33
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-CLEAR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..a09c5b5
--- /dev/null
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.html
@@ -0,0 +1,797 @@
+<!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-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
+ 2018-01-08 13:19:04 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..5871900
--- /dev/null
+++ b/Documentation/nvme-toshiba-clear-pcie-correctable-errors.txt
@@ -0,0 +1,34 @@
+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..325ebbd
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-VS\-I" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..7b30cc2
--- /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 8.6.10" />
+<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 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-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
+ 2019-09-18 00:00:58 JST
+</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..d3c0104
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-internal-log.txt
@@ -0,0 +1,64 @@
+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..7463a72
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TOSHIBA\-VS\-S" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..d0df5d8
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.html
@@ -0,0 +1,846 @@
+<!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-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
+ 2018-03-07 13:58:54 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..8ea4d3e
--- /dev/null
+++ b/Documentation/nvme-toshiba-vs-smart-add-log.txt
@@ -0,0 +1,64 @@
+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..4986df0
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TRANSCEND\-BAD" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..77967a2
--- /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 8.6.10" />
+<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 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-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
+ 2020-04-24 05:24:31 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-transcend-badblock.txt b/Documentation/nvme-transcend-badblock.txt
new file mode 100644
index 0000000..888076c
--- /dev/null
+++ b/Documentation/nvme-transcend-badblock.txt
@@ -0,0 +1,37 @@
+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..47e16a9
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-TRANSCEND\-HEA" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-transcend-healthvalue \- Use NVMe SMART table to analyse the health value of Transcend device\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme transcned 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 transcned 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..a9bb89b
--- /dev/null
+++ b/Documentation/nvme-transcend-healthvalue.html
@@ -0,0 +1,803 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 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-transcend-healthvalue(1) Manual Page
+</h1>
+<h2>NAME</h2>
+<div class="sectionbody">
+<p>nvme-transcend-healthvalue -
+ Use NVMe SMART table to analyse 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 transcned 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 transcned 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
+ 2020-04-24 05:24:52 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-transcend-healthvalue.txt b/Documentation/nvme-transcend-healthvalue.txt
new file mode 100644
index 0000000..eecf68b
--- /dev/null
+++ b/Documentation/nvme-transcend-healthvalue.txt
@@ -0,0 +1,37 @@
+nvme-transcend-healthvalue(1)
+=============================
+
+NAME
+----
+nvme-transcend-healthvalue - Use NVMe SMART table to analyse the health value of Transcend device.
+
+SYNOPSIS
+--------
+[verse]
+'nvme transcned 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 transcned healthvalue /dev/nvme0
+------------
+
+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..7f70ccf
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-VIRTIUM\-SAVE\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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, collecting 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\-tim=<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..f420f62
--- /dev/null
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.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 8.6.10" />
+<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 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-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,
+collecting 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-tim=&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
+ 2019-11-08 02:18:28 JST
+</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 100755
index 0000000..3e27b7e
--- /dev/null
+++ b/Documentation/nvme-virtium-save-smart-to-vtview-log.txt
@@ -0,0 +1,84 @@
+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,
+collecting 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-tim=<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..0d778f6
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-VIRTIUM\-SHOW\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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..9238dd3
--- /dev/null
+++ b/Documentation/nvme-virtium-show-identify.html
@@ -0,0 +1,801 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<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;
+}
+
+
+#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-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 2019-05-22 16:39:25 MDT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-virtium-show-identify.txt b/Documentation/nvme-virtium-show-identify.txt
new file mode 100755
index 0000000..5ce1933
--- /dev/null
+++ b/Documentation/nvme-virtium-show-identify.txt
@@ -0,0 +1,39 @@
+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..3d47e7c
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CAP\-DIAG" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..166d0ca
--- /dev/null
+++ b/Documentation/nvme-wdc-cap-diag.html
@@ -0,0 +1,859 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 2019-04-08 14:47:25 MDT
+</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..9439eaa
--- /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-clear-assert-dump.1 b/Documentation/nvme-wdc-clear-assert-dump.1
new file mode 100644
index 0000000..1f1569e
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-AS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..b416976
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+ 2019-09-18 00:00:58 JST
+</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..a575089
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-assert-dump.txt
@@ -0,0 +1,39 @@
+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..0a0a999
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-FW" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..b3f6488
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+ 2020-01-07 11:33:59 MST
+</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..50be1e9
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-fw-activate-history.txt
@@ -0,0 +1,38 @@
+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..1f45364
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-CLEAR\-PC" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..37929c6
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.html
@@ -0,0 +1,802 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 2019-01-11 13:56:35 MST
+</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..4788f1f
--- /dev/null
+++ b/Documentation/nvme-wdc-clear-pcie-correctable-errors.txt
@@ -0,0 +1,40 @@
+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-drive-essentials.1 b/Documentation/nvme-wdc-drive-essentials.1
new file mode 100644
index 0000000..e0a2902
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-ES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..782c788
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-essentials.html
@@ -0,0 +1,828 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.10" />
+<title>nvme-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+ 2019-11-08 08:41:30 JST
+</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..59b2787
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-essentials.txt
@@ -0,0 +1,48 @@
+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..4ce6955
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-LO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..f0cdf4f
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-log.html
@@ -0,0 +1,832 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#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-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 2017-03-01 10:14:21 EST
+</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..3c6a589
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-log.txt
@@ -0,0 +1,52 @@
+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..0949d70
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-DRIVE\-RE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..5fc393f
--- /dev/null
+++ b/Documentation/nvme-wdc-drive-resize.html
@@ -0,0 +1,813 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 2019-01-29 08:50:21 MST
+</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-get-crash-dump.1 b/Documentation/nvme-wdc-get-crash-dump.1
new file mode 100644
index 0000000..152643f
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-CRAS" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..3c8ce5e
--- /dev/null
+++ b/Documentation/nvme-wdc-get-crash-dump.html
@@ -0,0 +1,833 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#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-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 2017-03-01 10:14:21 EST
+</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-drive-status.1 b/Documentation/nvme-wdc-get-drive-status.1
new file mode 100644
index 0000000..b19520d
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-DRIV" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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 Unavaiable\&.
+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..53d65e1
--- /dev/null
+++ b/Documentation/nvme-wdc-get-drive-status.html
@@ -0,0 +1,839 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 Unavaiable.</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 2019-01-29 08:50:16 MST
+</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..f8a37d6
--- /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 Unavaiable.
+
+|*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-pfail-dump.1 b/Documentation/nvme-wdc-get-pfail-dump.1
new file mode 100644
index 0000000..230ce79
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-GET\-PFAI" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..717f883
--- /dev/null
+++ b/Documentation/nvme-wdc-get-pfail-dump.html
@@ -0,0 +1,835 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#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-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 2018-10-19 11:14:26 MDT
+</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-id-ctrl.1 b/Documentation/nvme-wdc-id-ctrl.1
new file mode 100644
index 0000000..220d953
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-ID\-CTRL" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-id-ctrl \- Send NVMe Identify Controller, return result and structure
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc id\-ctrl\fR <device> [\-v | \-\-vendor\-specific] [\-b | \-\-raw\-binary]
+ [\-H | \-\-human\-readable]
+ [\-o <fmt> | \-\-output\-format=<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 <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 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..4aba45e
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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; [-v | --vendor-specific] [-b | --raw-binary]
+ [-H | --human-readable]
+ [-o &lt;fmt&gt; | --output-format=&lt;fmt&gt;]</pre>
+<div class="attribution">
+</div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_description">DESCRIPTION</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>For the NVMe device given, sends 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;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 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
+ 2019-10-12 00:12:24 JST
+</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..a9c6afe
--- /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> [-v | --vendor-specific] [-b | --raw-binary]
+ [-H | --human-readable]
+ [-o <fmt> | --output-format=<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 <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', 'json', or
+ 'binary'. Only one output format can be used at a time.
+
+EXAMPLES
+--------
+* Has the program interpret the returned buffer and display the known
+fields in a human readable format:
++
+------------
+# nvme 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..0d407ba
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-LOG\-PAGE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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 <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\&. 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..2bca3ee
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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;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. 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
+ 2020-01-23 12:59:40 CST
+</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..4d6192f
--- /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 <format>::
+--output-format=<format>::
+ 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..ea0235a
--- /dev/null
+++ b/Documentation/nvme-wdc-namespace-resize.1
@@ -0,0 +1,115 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-NAMESPACE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-namespace-resize \- Resizes the device\*(Aqs namespace\&.
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme wdc namespace\-resize\fR <device> [\-\-nsid=<NAMSPACE 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 by 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 <NAMSPACE ID>, \-\-namespace\-id=<NAMSPACE_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
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+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
+.fi
+.if n \{\
+.RE
+.\}
+.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 orginal 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 orginal 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..efebe9e
--- /dev/null
+++ b/Documentation/nvme-wdc-namespace-resize.html
@@ -0,0 +1,841 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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;NAMSPACE 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
+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>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;NAMSPACE ID&gt;
+</dt>
+<dt class="hdlist1">
+--namespace-id=&lt;NAMSPACE_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
+</p>
+<div class="literalblock">
+<div class="content">
+<pre><code>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</code></pre>
+</div></div>
+</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 orginal 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 orginal 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 2020-02-04 15:47:14 CST
+</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..288430f
--- /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=<NAMSPACE 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
+by 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 <NAMSPACE ID>::
+--namespace-id=<NAMSPACE_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 orginal TNVMCAP reported value:
++
+------------
+# nvme wdc namespace-resize /dev/nvme0 -n 1 -o 3
+------------
+* Resizes namespace 2 to 7% of the orginal 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..3df192a
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-PURGE\-MO" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..698904d
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+ 2019-11-08 08:41:30 JST
+</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..313c8db
--- /dev/null
+++ b/Documentation/nvme-wdc-purge-monitor.txt
@@ -0,0 +1,63 @@
+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..748f78d
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-PURGE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-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..35a29e8
--- /dev/null
+++ b/Documentation/nvme-wdc-purge.html
@@ -0,0 +1,802 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#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-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 2018-06-05 09:00:22 MDT
+</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-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-drive-info.1 b/Documentation/nvme-wdc-vs-drive-info.1
new file mode 100644
index 0000000..4f5dd1c
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.1
@@ -0,0 +1,58 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-DRIVE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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 2 fields returned from this command:
+.sp
+Drive HW Revision
+.sp
+FTL Unit Size
+.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..0013ea6
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.html
@@ -0,0 +1,794 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 2 fields returned from this command:</p></div>
+<div class="paragraph"><p>Drive HW Revision</p></div>
+<div class="paragraph"><p>FTL Unit Size</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 2020-02-19 16:28:35 CST
+</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..15e7c6b
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-drive-info.txt
@@ -0,0 +1,42 @@
+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 2 fields returned from this command:
+
+Drive HW Revision
+
+FTL Unit Size
+
+
+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..2770ce3
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-ERROR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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..2bcc5b8
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+ 2020-01-07 11:33:59 MST
+</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..054d675
--- /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..25ce40a
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-FW\-A" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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 actiation 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 <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
+.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 tht 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 ouput 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..6e203f5
--- /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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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 actiation
+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;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>
+</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 tht 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 ouput 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
+ 2020-01-07 11:33:59 MST
+</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..1ef20a6
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-fw-activate-history.txt
@@ -0,0 +1,76 @@
+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 actiation
+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 <format>::
+--output-format=<format>::
+ 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 tht 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 ouput 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-internal-log.1 b/Documentation/nvme-wdc-vs-internal-log.1
new file mode 100644
index 0000000..abb6e94
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.1
@@ -0,0 +1,255 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-INTER" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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, 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..d07be0e
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.html
@@ -0,0 +1,957 @@
+<?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-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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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, 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
+ 2019-12-19 04:03:07 JST
+</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..eaeb21e
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-internal-log.txt
@@ -0,0 +1,111 @@
+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, 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..ec93cf0
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-NAND\" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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 <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
+.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..97c436d
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-nand-stats.html
@@ -0,0 +1,817 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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;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>
+</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 2019-02-27 08:37:46 MST
+</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..cc1f422
--- /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 <format>::
+--output-format=<format>::
+ 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..5b3f8ec
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.1
@@ -0,0 +1,496 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-SMART" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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>]
+.fi
+.SH "DESCRIPTION"
+.sp
+For the NVMe device given, send a Vendor Unique WDC vs\-smart\-add\-log command and provide the additional smart log\&. The \-\-interval option will return performance statistics from the specified reporting interval\&.
+.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 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
+.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..182b9c2
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.html
@@ -0,0 +1,1136 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
+<meta name="generator" content="AsciiDoc 8.6.8" />
+<title>nvme-wdc-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;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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;]</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. 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 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>
+</ul></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_nvme">NVME</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Part of the nvme-user suite.</p></div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr /></div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2019-01-11 13:56:35 MST
+</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..a9c4ead
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-smart-add-log.txt
@@ -0,0 +1,268 @@
+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>]
+
+DESCRIPTION
+-----------
+For the NVMe device given, send a Vendor Unique WDC vs-smart-add-log command and
+provide the additional smart log. The --interval option will return performance
+statistics from the specified reporting interval.
+
+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.
+
+OPTIONS
+-------
+-i <NUM>::
+--interval=<NUM>::
+ Return the statistics from specific interval, defaults to 14
+
+-o <format>::
+--output-format=<format>::
+ Set the reporting format to 'normal', or
+ 'json'. Only one output format can be used at a time.
+ Default is normal.
+
+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.
+|===
+
+CA Log Page Data Output Explanation
+-----------------------------------
+[cols="2*", frame="topbot", align="center", options="header"]
+|===
+|Field |Description
+
+|*Physical NAND bytes written.*
+|The number of bytes written to NAND. 16 bytes - hi/lo
+
+|*Physical NAND bytes read*
+|The number of bytes read from NAND. 16 bytes - hi/lo
+
+|*Bad NAND Block Count*
+|Raw and normalized count of the number of NAND blocks that have been
+retired after the drives manufacturing tests (i.e. grown back blocks).
+2 bytes normalized, 6 bytes raw count
+
+|*Uncorrectable Read Error Count*
+|Total count of NAND reads that were not correctable by read retries, all
+levels of ECC, or XOR (as applicable). 8 bytes
+
+|*Soft ECC Error Count*
+|Total count of NAND reads that were not correctable by read retries, or
+first-level ECC. 8 bytes
+
+|*SSD End to End Detection Count*
+|A count of the detected errors by the SSD end to end error correction which
+includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
+NAND ECC). 4 bytes
+
+|*SSD End to End Correction Count*
+|A count of the corrected errors by the SSD end to end error correction which
+includes DRAM, SRAM, or other storage element ECC/CRC protection mechanism (not
+NAND ECC). 4 bytes
+
+|*System Data % Used*
+|A normalized cumulative count of the number of erase cycles per block since
+leaving the factory for the system (FW and metadata) area. Starts at 0 and
+increments. 100 indicates that the estimated endurance has been consumed.
+
+|*User Data Max Erase Count*
+|The maximum erase count across all NAND blocks in the drive. 4 bytes
+
+|*User Data Min Erase Count*
+|The minimum erase count across all NAND blocks in the drive. 4 bytes
+
+|*Refresh Count*
+|A count of the number of blocks that have been re-allocated due to
+background operations only. 8 bytes
+
+|*Program Fail Count*
+|Raw and normalized count of total program failures. Normalized count
+starts at 100 and shows the percent of remaining allowable failures.
+2 bytes normalized, 6 bytes raw count
+
+|*User Data Erase Fail Count*
+|Raw and normalized count of total erase failures in the user area.
+Normalized count starts at 100 and shows the percent of remaining
+allowable failures. 2 bytes normalized, 6 bytes raw count
+
+|*System Area Erase Fail Count*
+|Raw and normalized count of total erase failures in the system area.
+Normalized count starts at 100 and shows the percent of remaining
+allowable failures. 2 bytes normalized, 6 bytes raw count
+
+|*Thermal Throttling Status*
+|The current status of thermal throttling (enabled or disabled).
+2 bytes
+
+|*Thermal Throttling Count*
+|A count of the number of thermal throttling events. 2 bytes
+
+|*PCIe Correctable Error Count*
+|Summation counter of all PCIe correctable errors (Bad TLP, Bad
+DLLP, Receiver error, Replay timeouts, Replay rollovers). 8 bytes
+|===
+
+
+C1 Log Page Data Output Explanation
+-----------------------------------
+[cols="2*", frame="topbot", align="center", options="header"]
+|===
+|Field |Description
+
+|*Host Read Commands*
+|Number of host read commands received during the reporting period.
+
+|*Host Read Blocks*
+|Number of 512-byte blocks requested during the reporting period.
+
+|*Average Read Size*
+|Average Read size is calculated using (Host Read Blocks/Host Read Commands).
+
+|*Host Read Cache Hit Commands*
+|Number of host read commands that serviced entirely from the on-board read
+cache during the reporting period. No access to the NAND flash memory was required.
+This count is only updated if the entire command was serviced from the cache memory.
+
+|*Host Read Cache Hit Percentage*
+|Percentage of host read commands satisfied from the cache.
+
+|*Host Read Cache Hit Blocks*
+|Number of 512-byte blocks of data that have been returned for Host Read Cache Hit
+Commands during the reporting period. This count is only updated with the blocks
+returned for host read commands that were serviced entirely from cache memory.
+
+|*Average Read Cache Hit Size*
+|Average size of read commands satisfied from the cache.
+
+|*Host Read Commands Stalled*
+|Number of host read commands that were stalled due to a lack of resources within
+the SSD during the reporting period (NAND flash command queue full, low cache page count,
+cache page contention, etc.). Commands are not considered stalled if the only reason for
+the delay was waiting for the data to be physically read from the NAND flash. It is normal
+to expect this count to equal zero on heavily utilized systems.
+
+|*Host Read Commands Stalled Percentage*
+|Percentage of read commands that were stalled. If the figure is consistently high,
+then consideration should be given to spreading the data across multiple SSDs.
+
+|*Host Write Commands*
+|Number of host write commands received during the reporting period.
+
+|*Host Write Blocks*
+|Number of 512-byte blocks written during the reporting period.
+
+|*Average Write Size*
+|Average Write size calculated using (Host Write Blocks/Host Write Commands).
+
+|*Host Write Odd Start Commands*
+|Number of host write commands that started on a non-aligned boundary during
+the reporting period. The size of the boundary alignment is normally 4K; therefore
+this returns the number of commands that started on a non-4K aligned boundary.
+The SSD requires slightly more time to process non-aligned write commands than it
+does to process aligned write commands.
+
+|*Host Write Odd Start Commands Percentage*
+|Percentage of host write commands that started on a non-aligned boundary. If this
+figure is equal to or near 100%, and the NAND Read Before Write value is also high,
+then the user should investigate the possibility of offsetting the file system. For
+Microsoft Windows systems, the user can use Diskpart. For Unix-based operating systems,
+there is normally a method whereby file system partitions can be placed where required.
+
+|*Host Write Odd End Commands*
+|Number of host write commands that ended on a non-aligned boundary during the
+reporting period. The size of the boundary alignment is normally 4K; therefore this
+returns the number of commands that ended on a non-4K aligned boundary.
+
+|*Host Write Odd End Commands Percentage*
+|Percentage of host write commands that ended on a non-aligned boundary.
+
+|*Host Write Commands Stalled*
+|Number of host write commands that were stalled due to a lack of resources within the
+SSD during the reporting period. The most likely cause is that the write data was being
+received faster than it could be saved to the NAND flash memory. If there was a large
+volume of read commands being processed simultaneously, then other causes might include
+the NAND flash command queue being full, low cache page count, or cache page contention, etc.
+It is normal to expect this count to be non-zero on heavily utilized systems.
+
+|*Host Write Commands Stalled Percentage*
+|Percentage of write commands that were stalled. If the figure is consistently high, then
+consideration should be given to spreading the data across multiple SSDs.
+
+|*NAND Read Commands*
+|Number of read commands issued to the NAND devices during the reporting period.
+This figure will normally be much higher than the host read commands figure, as the data
+needed to satisfy a single host read command may be spread across several NAND flash devices.
+
+|*NAND Read Blocks*
+|Number of 512-byte blocks requested from NAND flash devices during the reporting period.
+This figure would normally be about the same as the host read blocks figure
+
+|*Average NAND Read Size*
+|Average size of NAND read commands.
+
+|*NAND Write Commands*
+|Number of write commands issued to the NAND devices during the reporting period.
+There is no real correlation between the number of host write commands issued and the
+number of NAND Write Commands.
+
+|*NAND Write Blocks*
+|Number of 512-byte blocks written to the NAND flash devices during the reporting period.
+This figure would normally be about the same as the host write blocks figure.
+
+|*Average NAND Write Size*
+|Average size of NAND write commands. This figure should never be greater than 128K, as
+this is the maximum size write that is ever issued to a NAND device.
+
+|*NAND Read Before Write*
+|This is the number of read before write operations that were required to process
+non-aligned host write commands during the reporting period. See Host Write Odd Start
+Commands and Host Write Odd End Commands. NAND Read Before Write operations have
+a detrimental effect on the overall performance of the device.
+|===
+
+
+EXAMPLES
+--------
+* Has the program issue WDC vs-smart-add-log Vendor Unique Command with default interval (14) :
++
+------------
+# nvme wdc vs-smart-add-log /dev/nvme0
+------------
+
+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..0359a0b
--- /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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WDC\-VS\-TELEM" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-wdc-vs-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 of 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..ca22758
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.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 8.6.10" />
+<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 overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install();
+/*]]>*/
+</script>
+</head>
+<body class="manpage">
+<div id="header">
+<h1>
+nvme-wdc-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
+of 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
+ 2020-03-18 00:47:34 JST
+</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..8c1a7e7
--- /dev/null
+++ b/Documentation/nvme-wdc-vs-telemetry-controller-option.txt
@@ -0,0 +1,63 @@
+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
+of 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-write-uncor.1 b/Documentation/nvme-write-uncor.1
new file mode 100644
index 0000000..2cc5c88
--- /dev/null
+++ b/Documentation/nvme-write-uncor.1
@@ -0,0 +1,63 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-UNCOR" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-write-uncor \- Send an NVMe write uncorrectable command, return results
+.SH "SYNOPSIS"
+.sp
+.nf
+\fInvme\-write\-uncorr\fR <device> [\-\-start\-block=<slba> | \-s <slba>]
+ [\-\-block\-count=<nlb> | \-c <nlb>]
+ [\-\-namespace\-id=<nsid> | \-n <nsid>]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Write Uncorrectable command is used to invalidate a range of logical blocks\&.
+.SH "OPTIONS"
+.PP
+\-\-start\-block=<slba>, \-s <slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-\-block\-count=<nlb>, \-c
+.RS 4
+Number of logical blocks to write uncorrectable\&.
+.RE
+.PP
+\-\-namespace\-id=<nsid>, \-n <nsid>
+.RS 4
+Namespace ID use in the command\&.
+.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..7df26b2
--- /dev/null
+++ b/Documentation/nvme-write-uncor.html
@@ -0,0 +1,823 @@
+<!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-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;
+}
+
+
+#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-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-uncorr</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;]</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">
+--start-block=&lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dt class="hdlist1">
+-c
+</dt>
+<dd>
+<p>
+ Number of logical blocks to write uncorrectable.
+</p>
+</dd>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID use in the command.
+</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 2017-02-27 10:11:58 EST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write-uncor.txt b/Documentation/nvme-write-uncor.txt
new file mode 100644
index 0000000..0d824d7
--- /dev/null
+++ b/Documentation/nvme-write-uncor.txt
@@ -0,0 +1,40 @@
+nvme-uncor(1)
+=============
+
+NAME
+----
+nvme-write-uncor - Send an NVMe write uncorrectable command, return results
+
+SYNOPSIS
+--------
+[verse]
+'nvme-write-uncorr' <device> [--start-block=<slba> | -s <slba>]
+ [--block-count=<nlb> | -c <nlb>]
+ [--namespace-id=<nsid> | -n <nsid>]
+
+DESCRIPTION
+-----------
+The Write Uncorrectable command is used to invalidate a range of logical
+blocks.
+
+OPTIONS
+-------
+--start-block=<slba>::
+-s <slba>::
+ Start block.
+
+--block-count=<nlb>::
+-c::
+ Number of logical blocks to write uncorrectable.
+
+--namespace-id=<nsid>::
+-n <nsid>::
+ Namespace ID use in the command.
+
+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..c1a5b52
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.1
@@ -0,0 +1,155 @@
+'\" t
+.\" Title: nvme-zeroes
+.\" Author: [FIXME: author] [see http://www.docbook.org/tdg5/en/html/author]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-ZEROES" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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>]
+.fi
+.SH "DESCRIPTION"
+.sp
+The Write Zeroes command is used to set a range of logical blocks to 0\&.
+.SH "OPTIONS"
+.PP
+\-\-start\-block=<slba>, \-s <slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-\-block\-count=<nlb>, \-c <nlb>
+.RS 4
+Number of logical blocks to write zeroes\&.
+.RE
+.PP
+\-\-prinfo=<prinfo>, \-p <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
+\-\-ref\-tag=<reftag>, \-r <reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-\-app\-tag\-mask=<appmask>, \-m <appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-\-app\-tag=<apptag>, \-a <apptag>
+.RS 4
+Optional application tag when used with protection information\&.
+.RE
+.PP
+\-\-limited\-retry, \-l
+.RS 4
+Sets the limited retry flag\&.
+.RE
+.PP
+\-\-deac, \-d
+.RS 4
+Sets the DEAC bit, requesting controller deallocate the logical blocks\&.
+.RE
+.PP
+\-\-force\-unit\-access, \-f
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-\-namespace\-id=<nsid>, \-n <nsid>
+.RS 4
+Namespace ID use in the command\&.
+.RE
+.sp
+EXAMPLES EXAMPLES
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+No examples yet\&.
+
+NVME
+.fi
+.if n \{\
+.RE
+.\}
+.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..f3a3838
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.html
@@ -0,0 +1,944 @@
+<?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-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 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-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;]</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">
+--start-block=&lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+--block-count=&lt;nlb&gt;
+</dt>
+<dt class="hdlist1">
+-c &lt;nlb&gt;
+</dt>
+<dd>
+<p>
+ Number of logical blocks to write zeroes.
+</p>
+</dd>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+-p &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">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--limited-retry
+</dt>
+<dt class="hdlist1">
+-l
+</dt>
+<dd>
+<p>
+ Sets the limited retry flag.
+</p>
+</dd>
+<dt class="hdlist1">
+--deac
+</dt>
+<dt class="hdlist1">
+-d
+</dt>
+<dd>
+<p>
+ Sets the DEAC bit, requesting controller deallocate the logical blocks.
+</p>
+</dd>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dt class="hdlist1">
+-f
+</dt>
+<dd>
+<p>
+ Set the force-unit access flag.
+</p>
+</dd>
+<dt class="hdlist1">
+--namespace-id=&lt;nsid&gt;
+</dt>
+<dt class="hdlist1">
+-n &lt;nsid&gt;
+</dt>
+<dd>
+<p>
+ Namespace ID use in the command.
+</p>
+</dd>
+</dl></div>
+<div class="paragraph"><p>EXAMPLES
+EXAMPLES</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>No examples yet.
+
+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
+ 2019-09-18 00:00:58 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write-zeroes.txt b/Documentation/nvme-write-zeroes.txt
new file mode 100644
index 0000000..02adee1
--- /dev/null
+++ b/Documentation/nvme-write-zeroes.txt
@@ -0,0 +1,87 @@
+nvme-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>]
+
+DESCRIPTION
+-----------
+The Write Zeroes command is used to set a range of logical blocks to 0.
+
+OPTIONS
+-------
+--start-block=<slba>::
+-s <slba>::
+ Start block.
+
+--block-count=<nlb>::
+-c <nlb>::
+ Number of logical blocks to write zeroes.
+
+--prinfo=<prinfo>::
+-p <prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+--ref-tag=<reftag>::
+-r <reftag>::
+ Optional reftag when used with protection information.
+
+--app-tag-mask=<appmask>::
+-m <appmask>::
+ Optional application tag mask when used with protection information.
+
+--app-tag=<apptag>::
+-a <apptag>::
+ Optional application tag when used with protection information.
+
+--limited-retry::
+-l::
+ Sets the limited retry flag.
+
+--deac::
+-d::
+ Sets the DEAC bit, requesting controller deallocate the logical blocks.
+
+--force-unit-access::
+-f::
+ Set the force-unit access flag.
+
+--namespace-id=<nsid>::
+-n <nsid>::
+ Namespace ID use in the command.
+
+EXAMPLES
+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..5e9101a
--- /dev/null
+++ b/Documentation/nvme-write.1
@@ -0,0 +1,196 @@
+'\" 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: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME\-WRITE" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme-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]
+.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
+\-\-start\-block=<slba>, \-s <slba>
+.RS 4
+Start block\&.
+.RE
+.PP
+\-\-block\-count, \-c
+.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
+\-\-data\-size=<size>, \-z <size>
+.RS 4
+Size of data, in bytes\&.
+.RE
+.PP
+\-\-metadata\-size=<size>, \-y <size>
+.RS 4
+Size of metadata in bytes\&.
+.RE
+.PP
+\-\-data=<data\-file>, \-d <data\-file>
+.RS 4
+Data file\&. If none provided, contents are sent from STDIN\&.
+.RE
+.PP
+\-\-metadata=<metadata\-file>, \-M <metadata\-file>
+.RS 4
+Metadata file, if necessary\&.
+.RE
+.PP
+\-\-prinfo=<prinfo>, \-p <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
+\-\-ref\-tag=<reftag>, \-r <reftag>
+.RS 4
+Optional reftag when used with protection information\&.
+.RE
+.PP
+\-\-app\-tag\-mask=<appmask>, \-m <appmask>
+.RS 4
+Optional application tag mask when used with protection information\&.
+.RE
+.PP
+\-\-app\-tag=<apptag>, \-a <apptag>
+.RS 4
+Optional application tag when used with protection information\&.
+.RE
+.PP
+\-\-limited\-retry, \-l
+.RS 4
+Sets the limited retry flag\&.
+.RE
+.PP
+\-\-force\-unit\-access, \-f
+.RS 4
+Set the force\-unit access flag\&.
+.RE
+.PP
+\-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 specifcation (1\&.3a) defines only one directive, 01h, for write stream idenfiers\&.
+.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 lower 16 bits of the DSM field in a write command; the upper 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
+.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..b59de9d
--- /dev/null
+++ b/Documentation/nvme-write.html
@@ -0,0 +1,1062 @@
+<?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-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 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-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]</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">
+--start-block=&lt;slba&gt;
+</dt>
+<dt class="hdlist1">
+-s &lt;slba&gt;
+</dt>
+<dd>
+<p>
+ Start block.
+</p>
+</dd>
+<dt class="hdlist1">
+--block-count
+</dt>
+<dt class="hdlist1">
+-c
+</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">
+--data-size=&lt;size&gt;
+</dt>
+<dt class="hdlist1">
+-z &lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of data, in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+--metadata-size=&lt;size&gt;
+</dt>
+<dt class="hdlist1">
+-y &lt;size&gt;
+</dt>
+<dd>
+<p>
+ Size of metadata in bytes.
+</p>
+</dd>
+<dt class="hdlist1">
+--data=&lt;data-file&gt;
+</dt>
+<dt class="hdlist1">
+-d &lt;data-file&gt;
+</dt>
+<dd>
+<p>
+ Data file. If none provided, contents are sent from STDIN.
+</p>
+</dd>
+<dt class="hdlist1">
+--metadata=&lt;metadata-file&gt;
+</dt>
+<dt class="hdlist1">
+-M &lt;metadata-file&gt;
+</dt>
+<dd>
+<p>
+ Metadata file, if necessary.
+</p>
+</dd>
+<dt class="hdlist1">
+--prinfo=&lt;prinfo&gt;
+</dt>
+<dt class="hdlist1">
+-p &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">
+--ref-tag=&lt;reftag&gt;
+</dt>
+<dt class="hdlist1">
+-r &lt;reftag&gt;
+</dt>
+<dd>
+<p>
+ Optional reftag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag-mask=&lt;appmask&gt;
+</dt>
+<dt class="hdlist1">
+-m &lt;appmask&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag mask when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--app-tag=&lt;apptag&gt;
+</dt>
+<dt class="hdlist1">
+-a &lt;apptag&gt;
+</dt>
+<dd>
+<p>
+ Optional application tag when used with protection information.
+</p>
+</dd>
+<dt class="hdlist1">
+--limited-retry
+</dt>
+<dt class="hdlist1">
+-l
+</dt>
+<dd>
+<p>
+ Sets the limited retry flag.
+</p>
+</dd>
+<dt class="hdlist1">
+--force-unit-access
+</dt>
+<dt class="hdlist1">
+-f
+</dt>
+<dd>
+<p>
+ Set the force-unit access flag.
+</p>
+</dd>
+<dt class="hdlist1">
+-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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+</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 lower 16 bits of the DSM field in a write
+ command; the upper 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>
+</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
+ 2018-11-29 13:31:13 GMT
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme-write.txt b/Documentation/nvme-write.txt
new file mode 100644
index 0000000..2074f52
--- /dev/null
+++ b/Documentation/nvme-write.txt
@@ -0,0 +1,145 @@
+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]
+
+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
+-------
+--start-block=<slba>::
+-s <slba>::
+ Start block.
+
+--block-count::
+-c::
+ 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).
+
+--data-size=<size>::
+-z <size>::
+ Size of data, in bytes.
+
+--metadata-size=<size>::
+-y <size>::
+ Size of metadata in bytes.
+
+--data=<data-file>::
+-d <data-file>::
+ Data file. If none provided, contents are sent from STDIN.
+
+--metadata=<metadata-file>::
+-M <metadata-file>::
+ Metadata file, if necessary.
+
+--prinfo=<prinfo>::
+-p <prinfo>::
+ Protection Information field definition.
++
+[]
+|=================
+|Bit|Description
+|3|PRACT: Protection Information Action. When set to 1, PI is stripped/inserted
+on read/write when the block format's metadata size is 8. When set to 0,
+metadata is passes.
+|2:0|PRCHK: Protection Information Check:
+|2|Set to 1 enables checking the guard tag
+|1|Set to 1 enables checking the application tag
+|0|Set to 1 enables checking the reference tag
+|=================
+
+--ref-tag=<reftag>::
+-r <reftag>::
+ Optional reftag when used with protection information.
+
+--app-tag-mask=<appmask>::
+-m <appmask>::
+ Optional application tag mask when used with protection information.
+
+--app-tag=<apptag>::
+-a <apptag>::
+ Optional application tag when used with protection information.
+
+--limited-retry::
+-l::
+ Sets the limited retry flag.
+
+--force-unit-access::
+-f::
+ 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
+ specifcation (1.3a) defines only one directive, 01h, for write
+ stream idenfiers.
+
+-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 lower 16 bits of the DSM field in a write
+ command; the upper 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).
+
+EXAMPLES
+--------
+No examples yet.
+
+NVME
+----
+Part of the nvme-user suite
diff --git a/Documentation/nvme.1 b/Documentation/nvme.1
new file mode 100644
index 0000000..55dbfc8
--- /dev/null
+++ b/Documentation/nvme.1
@@ -0,0 +1,312 @@
+'\" t
+.\" Title: nvme
+.\" Author: [see the "Authors" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\" Date: 04/24/2020
+.\" Manual: NVMe Manual
+.\" Source: NVMe
+.\" Language: English
+.\"
+.TH "NVME" "1" "04/24/2020" "NVMe" "NVMe Manual"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+nvme \- 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-dms\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
+.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-smart-log\fR(1)
+.RS 4
+Retrieve Smart 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-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-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-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-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-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
+.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..5f9856c
--- /dev/null
+++ b/Documentation/nvme.html
@@ -0,0 +1,1197 @@
+<?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(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(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-dms.html">nvme-dms(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
+</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-smart-log.html">nvme-smart-log(1)</a>
+</dt>
+<dd>
+<p>
+ Retrieve Smart 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-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-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-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-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-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>
+</dl></div>
+</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
+ 2020-02-15 08:33:28 JST
+</div>
+</div>
+</body>
+</html>
diff --git a/Documentation/nvme.txt b/Documentation/nvme.txt
new file mode 100644
index 0000000..b9a1f59
--- /dev/null
+++ b/Documentation/nvme.txt
@@ -0,0 +1,60 @@
+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[]
+
+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..9db121c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,235 @@
+CFLAGS ?= -O2 -g -Wall -Werror
+override CFLAGS += -std=gnu99 -I.
+override CPPFLAGS += -D_GNU_SOURCE -D__CHECK_ENDIAN__
+LIBUUID = $(shell $(LD) -o /dev/null -luuid >/dev/null 2>&1; echo $$?)
+LIBHUGETLBFS = $(shell $(LD) -o /dev/null -lhugetlbfs >/dev/null 2>&1; echo $$?)
+HAVE_SYSTEMD = $(shell pkg-config --exists libsystemd --atleast-version=242; echo $$?)
+NVME = nvme
+INSTALL ?= install
+DESTDIR =
+DESTDIROLD = /usr/local/sbin
+PREFIX ?= /usr
+SYSCONFDIR = /etc
+SBINDIR = $(PREFIX)/sbin
+LIBDIR ?= $(PREFIX)/lib
+SYSTEMDDIR ?= $(LIBDIR)/systemd
+UDEVDIR ?= $(SYSCONFDIR)/udev
+UDEVRULESDIR ?= $(UDEVDIR)/rules.d
+DRACUTDIR ?= $(LIBDIR)/dracut
+LIB_DEPENDS =
+
+ifeq ($(LIBUUID),0)
+ override LDFLAGS += -luuid
+ override CFLAGS += -DLIBUUID
+ override LIB_DEPENDS += uuid
+endif
+
+ifeq ($(LIBHUGETLBFS),0)
+ override LDFLAGS += -lhugetlbfs
+ override CFLAGS += -DLIBHUGETLBFS
+ override LIB_DEPENDS += hugetlbfs
+endif
+
+INC=-Iutil
+
+ifeq ($(HAVE_SYSTEMD),0)
+ override LDFLAGS += -lsystemd
+ override CFLAGS += -DHAVE_SYSTEMD
+endif
+
+RPMBUILD = rpmbuild
+TAR = tar
+RM = rm -f
+
+AUTHOR=Keith Busch <kbusch@kernel.org>
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET_CC = @echo ' ' CC $@;
+endif
+endif
+
+default: $(NVME)
+
+NVME-VERSION-FILE: FORCE
+ @$(SHELL_PATH) ./NVME-VERSION-GEN
+-include NVME-VERSION-FILE
+override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"'
+
+NVME_DPKG_VERSION=1~`lsb_release -sc`
+
+OBJS := nvme-print.o nvme-ioctl.o \
+ nvme-lightnvm.o fabrics.o nvme-models.o plugin.o \
+ nvme-status.o nvme-filters.o nvme-topology.o
+
+UTIL_OBJS := util/argconfig.o util/suffix.o util/json.o util/parser.o
+
+PLUGIN_OBJS := \
+ plugins/intel/intel-nvme.o \
+ plugins/lnvm/lnvm-nvme.o \
+ plugins/memblaze/memblaze-nvme.o \
+ plugins/wdc/wdc-nvme.o \
+ plugins/wdc/wdc-utils.o \
+ plugins/huawei/huawei-nvme.o \
+ plugins/netapp/netapp-nvme.o \
+ plugins/toshiba/toshiba-nvme.o \
+ plugins/micron/micron-nvme.o \
+ plugins/seagate/seagate-nvme.o \
+ plugins/virtium/virtium-nvme.o \
+ plugins/shannon/shannon-nvme.o \
+ plugins/dera/dera-nvme.o \
+ plugins/scaleflux/sfx-nvme.o \
+ plugins/transcend/transcend-nvme.o
+
+nvme: nvme.c nvme.h $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) NVME-VERSION-FILE
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) $< -o $(NVME) $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) $(LDFLAGS)
+
+verify-no-dep: nvme.c nvme.h $(OBJS) NVME-VERSION-FILE
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $< -o $@ $(OBJS) $(LDFLAGS)
+
+nvme.o: nvme.c nvme.h nvme-print.h nvme-ioctl.h util/argconfig.h util/suffix.h nvme-lightnvm.h fabrics.h
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -c $<
+
+%.o: %.c %.h nvme.h linux/nvme.h linux/nvme_ioctl.h nvme-ioctl.h nvme-print.h util/argconfig.h
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -o $@ -c $<
+
+%.o: %.c nvme.h linux/nvme.h linux/nvme_ioctl.h nvme-ioctl.h nvme-print.h util/argconfig.h
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(INC) -o $@ -c $<
+
+doc: $(NVME)
+ $(MAKE) -C Documentation
+
+test:
+ $(MAKE) -C tests/ run
+
+all: doc
+
+clean:
+ $(RM) $(NVME) $(OBJS) $(PLUGIN_OBJS) $(UTIL_OBJS) *~ a.out NVME-VERSION-FILE *.tar* nvme.spec version control nvme-*.deb 70-nvmf-autoconnect.conf
+ $(MAKE) -C Documentation clean
+ $(RM) tests/*.pyc
+ $(RM) verify-no-dep
+
+clobber: clean
+ $(MAKE) -C Documentation clobber
+
+install-man:
+ $(MAKE) -C Documentation install-no-build
+
+install-bin: default
+ $(RM) $(DESTDIROLD)/nvme
+ $(INSTALL) -d $(DESTDIR)$(SBINDIR)
+ $(INSTALL) -m 755 nvme $(DESTDIR)$(SBINDIR)
+
+install-bash-completion:
+ $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/bash-completion/completions
+ $(INSTALL) -m 644 -T ./completions/bash-nvme-completion.sh $(DESTDIR)$(PREFIX)/share/bash-completion/completions/nvme
+
+install-systemd:
+ $(INSTALL) -d $(DESTDIR)$(SYSTEMDDIR)/system
+ $(INSTALL) -m 644 ./nvmf-autoconnect/systemd/* $(DESTDIR)$(SYSTEMDDIR)/system
+
+install-udev:
+ $(INSTALL) -d $(DESTDIR)$(UDEVRULESDIR)
+ $(INSTALL) -m 644 ./nvmf-autoconnect/udev-rules/* $(DESTDIR)$(UDEVRULESDIR)
+
+install-dracut: 70-nvmf-autoconnect.conf
+ $(INSTALL) -d $(DESTDIR)$(DRACUTDIR)/dracut.conf.d
+ $(INSTALL) -m 644 $< $(DESTDIR)$(DRACUTDIR)/dracut.conf.d
+
+install-zsh-completion:
+ $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/zsh/site-functions
+ $(INSTALL) -m 644 -T ./completions/_nvme $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_nvme
+
+install-hostparams: install-etc
+ if [ ! -s $(DESTDIR)$(SYSCONFDIR)/nvme/hostnqn ]; then \
+ echo `$(DESTDIR)$(SBINDIR)/nvme gen-hostnqn` > $(DESTDIR)$(SYSCONFDIR)/nvme/hostnqn; \
+ fi
+ if [ ! -s $(DESTDIR)$(SYSCONFDIR)/nvme/hostid ]; then \
+ uuidgen > $(DESTDIR)$(SYSCONFDIR)/nvme/hostid; \
+ fi
+
+install-etc:
+ $(INSTALL) -d $(DESTDIR)$(SYSCONFDIR)/nvme
+ touch $(DESTDIR)$(SYSCONFDIR)/nvme/hostnqn
+ touch $(DESTDIR)$(SYSCONFDIR)/nvme/hostid
+ if [ ! -f $(DESTDIR)$(SYSCONFDIR)/nvme/discovery.conf ]; then \
+ $(INSTALL) -m 644 -T ./etc/discovery.conf.in $(DESTDIR)$(SYSCONFDIR)/nvme/discovery.conf; \
+ fi
+
+install-spec: install-bin install-man install-bash-completion install-zsh-completion install-etc install-systemd install-udev install-dracut
+install: install-spec install-hostparams
+
+nvme.spec: nvme.spec.in NVME-VERSION-FILE
+ sed -e 's/@@VERSION@@/$(NVME_VERSION)/g' < $< > $@+
+ mv $@+ $@
+
+70-nvmf-autoconnect.conf: nvmf-autoconnect/dracut-conf/70-nvmf-autoconnect.conf.in
+ sed -e 's#@@UDEVRULESDIR@@#$(UDEVRULESDIR)#g' < $< > $@+
+ mv $@+ $@
+
+dist: nvme.spec
+ git archive --format=tar --prefix=nvme-$(NVME_VERSION)/ HEAD > nvme-$(NVME_VERSION).tar
+ @echo $(NVME_VERSION) > version
+ $(TAR) rf nvme-$(NVME_VERSION).tar nvme.spec version
+ gzip -f -9 nvme-$(NVME_VERSION).tar
+
+control: nvme.control.in NVME-VERSION-FILE
+ sed -e 's/@@VERSION@@/$(NVME_VERSION)/g' < $< > $@+
+ mv $@+ $@
+ sed -e 's/@@DEPENDS@@/$(LIB_DEPENDS)/g' < $@ > $@+
+ mv $@+ $@
+
+pkg: control nvme.control.in
+ mkdir -p nvme-$(NVME_VERSION)$(SBINDIR)
+ mkdir -p nvme-$(NVME_VERSION)$(PREFIX)/share/man/man1
+ mkdir -p nvme-$(NVME_VERSION)/DEBIAN/
+ cp Documentation/*.1 nvme-$(NVME_VERSION)$(PREFIX)/share/man/man1
+ cp nvme nvme-$(NVME_VERSION)$(SBINDIR)
+ cp control nvme-$(NVME_VERSION)/DEBIAN/
+
+# Make a reproducible tar.gz in the super-directory. Uses
+# git-restore-mtime if available to adjust timestamps.
+../nvme-cli_$(NVME_VERSION).orig.tar.gz:
+ find . -type f -perm -u+rwx -exec chmod 0755 '{}' +
+ find . -type f -perm -u+rw '!' -perm -u+x -exec chmod 0644 '{}' +
+ if which git-restore-mtime >/dev/null; then git-restore-mtime; fi
+ git ls-files | tar cf ../nvme-cli_$(NVME_VERSION).orig.tar \
+ --owner=root --group=root \
+ --transform='s#^#nvme-cli-$(NVME_VERSION)/#' --files-from -
+ touch -d "`git log --format=%ci -1`" ../nvme-cli_$(NVME_VERSION).orig.tar
+ gzip -f -9 ../nvme-cli_$(NVME_VERSION).orig.tar
+
+dist-orig: ../nvme-cli_$(NVME_VERSION).orig.tar.gz
+
+# Create a throw-away changelog, which dpkg-buildpackage uses to
+# determine the package version.
+deb-changelog:
+ printf '%s\n\n * Auto-release.\n\n %s\n' \
+ "nvme-cli ($(NVME_VERSION)-$(NVME_DPKG_VERSION)) `lsb_release -sc`; urgency=low" \
+ "-- $(AUTHOR) `git log -1 --format=%cD`" \
+ > debian/changelog
+
+deb: deb-changelog dist-orig
+ dpkg-buildpackage -uc -us -sa
+
+# After this target is build you need to do a debsign and dput on the
+# ../<name>.changes file to upload onto the relevant PPA. For example:
+#
+# > make AUTHOR='First Last <first.last@company.com>' \
+# NVME_DPKG_VERSION='0ubuntu1' deb-ppa
+# > debsign <name>.changes
+# > dput ppa:<lid>/ppa <name>.changes
+#
+# where lid is your launchpad.net ID.
+deb-ppa: deb-changelog dist-orig
+ debuild -uc -us -S
+
+deb-light: $(NVME) pkg nvme.control.in
+ dpkg-deb --build nvme-$(NVME_VERSION)
+
+rpm: dist
+ $(RPMBUILD) --define '_libdir ${LIBDIR}' -ta nvme-$(NVME_VERSION).tar.gz
+
+.PHONY: default doc all clean clobber install-man install-bin install
+.PHONY: dist pkg dist-orig deb deb-light rpm FORCE test
diff --git a/NVME-VERSION-GEN b/NVME-VERSION-GEN
new file mode 100755
index 0000000..75b13d1
--- /dev/null
+++ b/NVME-VERSION-GEN
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+GVF=NVME-VERSION-FILE
+DEF_VER=v1.12
+
+LF='
+'
+
+# First see if there is a version file (included in release tarballs),
+# then try git-describe, then default.
+if test -f version
+then
+ VN=$(cat version) || VN="$DEF_VER"
+elif test -d .git -o -f .git &&
+ VN=$(git describe --tags --match "v[0-9]*" --abbrev=4 HEAD 2>/dev/null) &&
+ case "$VN" in
+ *$LF*) (exit 1) ;;
+ v[0-9]*)
+ git update-index -q --refresh
+ test -z "$(git diff-index --name-only HEAD --)" ||
+ VN="$VN-dirty" ;;
+ esac
+then
+ VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+ VN="$DEF_VER"
+fi
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+if test -r $GVF
+then
+ VC=$(sed -e 's/^NVME_VERSION = //' <$GVF)
+else
+ VC=unset
+fi
+test "$VN" = "$VC" || {
+ echo >&2 "NVME_VERSION = $VN"
+ echo "NVME_VERSION = $VN" >$GVF
+}
+
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b4d2574
--- /dev/null
+++ b/README.md
@@ -0,0 +1,215 @@
+# nvme-cli
+NVM-Express user space tooling for Linux.
+
+To install, run:
+
+ $ make
+ # make install
+
+If not sure how to use, find the top-level documentation with:
+
+ $ man nvme
+
+Or find a short summary with:
+
+ $ nvme help
+
+## Distro Support
+
+### Alpine Linux
+
+nvme-cli is tested on Alpine Linux 3.3. Install it using:
+
+ # apk update && apk add nvme-cli nvme-cli-doc
+
+if you just use the device you're after, it will work flawless.
+```
+# nvme smart-log /dev/nvme0
+Smart Log for NVME device:/dev/nvme0 namespace-id:ffffffff
+critical_warning : 0
+temperature : 49 C
+available_spare : 100%
+```
+
+### Arch Linux
+
+nvme-cli is available in the `[community]` repository. It can be installed with:
+
+ # pacman -S nvme-cli
+
+The development version can be installed from AUR, e.g.:
+
+ $ yay -S nvme-cli-git
+
+### Fedora
+
+nvme-cli is available in Fedora 23 and up. Install it with your favorite
+package manager. For example:
+
+ $ sudo dnf install nvme-cli
+
+### FreeBSD
+
+`nvme-cli` is available in the FreeBSD Ports Collection. A prebuilt binary
+package can be installed with:
+
+```console
+# pkg install nvme-cli
+```
+
+### Gentoo
+
+nvme-cli is available and tested in portage:
+```
+$ emerge -av nvme-cli
+```
+
+### Nix(OS)
+
+The attribute is named `nvme-cli` and can e.g. be installed with:
+```
+$ nix-env -f '<nixpkgs>' -iA nvme-cli
+```
+
+### openSUSE
+
+nvme-cli is available in openSUSE Leap 42.2 or later and Tumbleweed. You can install it using zypper.
+For example:
+
+ $ sudo zypper install nvme-cli
+
+### Ubuntu
+
+nvme-cli is supported in the Universe package sources for Xenial for
+many architectures. For a complete list try running:
+ ```
+ rmadison nvme-cli
+ nvme-cli | 0.3-1 | xenial/universe | source, amd64, arm64, armhf, i386, powerpc, ppc64el, s390x
+ ```
+A Debian based package for nvme-cli is currently maintained as a
+Ubuntu PPA. Right now there is support for Trusty, Vivid and Wiley. To
+install nvme-cli using this approach please perform the following
+steps:
+ 1. Add the sbates PPA to your sources. One way to do this is to run
+ ```
+ sudo add-apt-repository ppa:sbates
+ ```
+ 2. Perform an update of your repository list:
+ ```
+ sudo apt-get update
+ ```
+ 3. Get nvme-cli!
+ ```
+ sudo apt-get install nvme-cli
+ ```
+ 4. Test the code.
+ ```
+ sudo nvme list
+ ```
+ In the case of no NVMe devices you will see
+ ```
+ No NVMe devices detected.
+ ```
+ otherwise you will see information about each NVMe device installed
+ in the system.
+
+### 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`.
+
+### Other Distros
+
+TBD
+
+## 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 Makefile's "OBJS".
diff --git a/cmd.h b/cmd.h
new file mode 100644
index 0000000..cd1183a
--- /dev/null
+++ b/cmd.h
@@ -0,0 +1,10 @@
+#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..d40740d
--- /dev/null
+++ b/cmd_handler.h
@@ -0,0 +1,108 @@
+/*
+ * Stage 1
+ *
+ * Define function prototypes.
+ */
+
+#undef NAME
+#define NAME(n, d)
+
+#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)
+
+#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)
+
+#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) .name = n, .desc = d,
+
+#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/common.h b/common.h
new file mode 100644
index 0000000..aed2a99
--- /dev/null
+++ b/common.h
@@ -0,0 +1,12 @@
+#ifndef _COMMON_H
+#define _COMMON_H
+
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+
+#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))
+
+#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..e076232
--- /dev/null
+++ b/completions/_nvme
@@ -0,0 +1,659 @@
+#compdef _nvme nvme
+
+# 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=(
+ 'id-ctrl:display information about the controller'
+ 'id-ns:display information about the namespace'
+ 'list-ns:identify all namespace(s) attached'
+ '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'
+ 'get-ns-id:get namespace id of opened block device'
+ 'get-log:retrieve any log in raw format'
+ 'fw-log:retrieve fw log'
+ 'smart-log:retrieve SMART log'
+ 'smart-log-add:retrieve additional SMART log'
+ 'error-log:retrieve error log'
+ 'get-feature:display a controller feature'
+ 'set-feature:set a controller feature and show results'
+ '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 IOCTL'
+ 'io-passthru:submit a passthrough IOCTL'
+ 'security-send:send security/secure data to controller'
+ 'security-recv:ask for security/secure data from controller'
+ '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'
+ 'flush:submit a flush'
+ 'compare:compare data on device to data elsewhere'
+ 'read:submit a read command'
+ 'write:submit a write command'
+ 'show-regs:shows the controller registers; requires admin character device'
+ 'help:print brief descriptions of all nvme commands'
+ )
+
+ local expl
+
+ _arguments '*:: :->subcmds' && return 0
+
+ if (( CURRENT == 1 )); then
+ _describe -t commands "nvme subcommands" _cmds
+ return
+ else
+ case ${words[CURRENT-1]} in
+ (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
+ ;;
+ (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'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme list-ns options" _listns
+ ;;
+ (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'
+ -n':alias of --nmic'
+ )
+ _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'
+ )
+ _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'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme get-log options" _getlog
+ ;;
+ (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
+ ;;
+ (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
+ ;;
+ (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
+ ;;
+ (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'
+ --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
+ ;;
+ (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'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme set-feature options" _setf
+ ;;
+ (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'
+ --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
+ ;;
+ (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
+ ;;
+ (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 acquiry 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'
+ --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'
+ -a':alias for --rrega'
+ --iekey':ignore existing reservation key'
+ -i':alias for --iekey'
+ )
+ _arguments '*:: :->subcmds'
+ _describe -t commands "nvme resv-register options" _reg
+ ;;
+ (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
+ ;;
+ (help)
+ local _h
+ _h=( id-ctrl id-ns list-ns create-ns delete-ns attach-ns detach-ns
+ list-ctrl get-ns-id get-log fw-log smart-log error-log get-feature
+ set-feature format fw-activate fw-download admin-passthru io-passthru
+ security-send security-recv resv-acquire resv-register resv-release
+ resv-report flush compare read write show-regs
+ )
+ _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..b7c2aa1
--- /dev/null
+++ b/completions/bash-nvme-completion.sh
@@ -0,0 +1,238 @@
+# 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
+
+_cmds="list id-ctrl id-ns list-ns create-ns delete-ns \
+ attach-ns detach-ns list-ctrl get-ns-id get-log \
+ fw-log smart-log smart-log-add error-log \
+ get-feature set-feature format fw-activate \
+ fw-download admin-passthru io-passthru security-send \
+ security-recv resv-acquire resv-register resv-release \
+ resv-report dsm flush compare read write write-zeroes \
+ write-uncor reset subsystem-reset show-regs discover \
+ connect-all connect disconnect version help \
+ intel lnvm memblaze list-subsys"
+
+nvme_list_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 2 ]; then
+ opts="/dev/nvme* "
+ fi
+
+ opts+=" "
+
+ case "$1" in
+ "list")
+ opts=""
+ ;;
+ "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"
+ ;;
+ "list-ns")
+ opts+=" --namespace-id= -n --al -a"
+ ;;
+ "create-ns")
+ opts+=" --nsze= -s --ncap= -c --flbas= -f \
+ --dps= -d --nmic= -n"
+ ;;
+ "delete-ns")
+ opts+=" -namespace-id= -n"
+ ;;
+ "attach-ns")
+ opts+=" --namespace-id= -n --controllers= -c"
+ ;;
+ "detach-ns")
+ opts+=" --namespace-id= -n --controllers= -c"
+ ;;
+ "list-ctrl")
+ opts+=" --namespace-id= -n --cntid= -c"
+ ;;
+ "get-ns-id")
+ ;;
+ "get-log")
+ opts+=" --log-id= -i --log-len= -l --namespace-id= -n \
+ --raw-binary= -b"
+ ;;
+ "fw-log")
+ opts+=" --raw-binary -b --output-format= -o"
+ ;;
+ "smart-log")
+ opts+=" --namespace-id= -n --raw-binary -b \
+ --output-format= -o"
+ ;;
+ "smart-log-add")
+ opts+=" --namespace-id= -n --raw-binary -b"
+ ;;
+ "error-log")
+ opts+=" --namespace-id= -n --raw-binary -b --log-entries= -e \
+ --output-format= -o"
+ ;;
+ "get-feature")
+ opts+=" --namespace-id= -n --feature-id= -f --sel= -s \
+ --data-len= -l --cdw11= --raw-binary -b \
+ --human-readable -H"
+ ;;
+ "set-feature")
+ opts+=" --namespace-id= -n --feature-id= -f --value= -v \
+ --data-len= -l -data= -d --value= --save -s"
+ ;;
+ "format")
+ opts+=" --namespace-id= -n --timeout= -t --lbaf= -l \
+ --ses= -s --pil= -p -pi= -i --ms= -m --reset -r"
+ ;;
+ "fw-activate")
+ opts+=" --action= -a --slot= -s"
+ ;;
+ "fw-download")
+ opts+=" --fw= -f --xfer= -x --offset= -o"
+ ;;
+ "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"
+ ;;
+ "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"
+ ;;
+ "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"
+ ;;
+ "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 --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"
+ ;;
+ "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 --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 --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 --show-command -v \
+ --dry-run -w --latency -t"
+ ;;
+ "write-zeros")
+ opts+=" --namespace-id= -n --start-block= -s \
+ --block-count= -c --limited-retry -l \
+ --force-unit-access -f --prinfo= -p --ref-tag= -r \
+ --app-tag-mask= -m --app-tag= -a"
+ ;;
+ "write-uncor")
+ opts+=" --namespace-id= -n --start-block= -s \
+ --block-count= -c"
+ ;;
+ "reset")
+ opts+=""
+ ;;
+ "subsystem-reset")
+ opts+=""
+ ;;
+ "show-regs")
+ opts+=" --human-readable -H"
+ ;;
+ "discover")
+ opts+=" --transport= -t -traddr= -a -trsvcid= -s \
+ --hostnqn= -q --raw= -r"
+ ;;
+ "connect-all")
+ opts+=" --transport= -t --traddr= -a --trsvcid= -s
+ --hostnqn= -q --raw= -r"
+ ;;
+ "connect")
+ opts+=" --transport= -t --nqn= -n --traddr= -a --trsvcid -s \
+ --hostnqn= -q --nr-io-queues= -i --keep-alive-tmo -k \
+ --reconnect-delay -r"
+ ;;
+ "disconnect")
+ opts+=" --nqn -n --device -d"
+ ;;
+ "version")
+ opts+=""
+ ;;
+ "help")
+ opts=$_cmds
+ ;;
+ esac
+
+ opts+=" -h --help"
+
+ COMPREPLY+=( $( compgen $compargs -W "$opts" -- $cur ) )
+
+ return 0
+}
+
+_nvme_subcmds () {
+ local cur prev words cword
+ _init_completion || return
+
+ if [[ ${#words[*]} -lt 3 ]]; then
+ COMPREPLY+=( $(compgen -W "$_cmds" -- $cur ) )
+ else
+ 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..7379f5e
--- /dev/null
+++ b/define_cmd.h
@@ -0,0 +1,19 @@
+#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..14e0d9c
--- /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>
diff --git a/fabrics.c b/fabrics.c
new file mode 100644
index 0000000..2fec802
--- /dev/null
+++ b/fabrics.c
@@ -0,0 +1,1626 @@
+/*
+ * 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 <sys/ioctl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "util/parser.h"
+#include "nvme-ioctl.h"
+#include "nvme-status.h"
+#include "fabrics.h"
+
+#include "nvme.h"
+#include "util/argconfig.h"
+
+#include "common.h"
+
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-id128.h>
+#define NVME_HOSTNQN_ID SD_ID128_MAKE(c7,f4,61,81,12,be,49,32,8c,83,10,6f,9d,dd,d8,6b)
+#endif
+
+#define NVMF_HOSTID_SIZE 36
+
+const char *conarg_nqn = "nqn";
+const char *conarg_transport = "transport";
+const char *conarg_traddr = "traddr";
+const char *conarg_trsvcid = "trsvcid";
+const char *conarg_host_traddr = "host_traddr";
+
+static struct config {
+ char *nqn;
+ char *transport;
+ char *traddr;
+ char *trsvcid;
+ char *host_traddr;
+ char *hostnqn;
+ char *hostid;
+ int nr_io_queues;
+ int nr_write_queues;
+ int nr_poll_queues;
+ int queue_size;
+ int keep_alive_tmo;
+ int reconnect_delay;
+ int ctrl_loss_tmo;
+ int tos;
+ char *raw;
+ char *device;
+ int duplicate_connect;
+ int disable_sqflow;
+ int hdr_digest;
+ int data_digest;
+ bool persistent;
+ bool quiet;
+ bool matching_only;
+} cfg = { NULL };
+
+struct connect_args {
+ char *subsysnqn;
+ char *transport;
+ char *traddr;
+ char *trsvcid;
+ char *host_traddr;
+};
+
+#define BUF_SIZE 4096
+#define PATH_NVME_FABRICS "/dev/nvme-fabrics"
+#define PATH_NVMF_DISC "/etc/nvme/discovery.conf"
+#define PATH_NVMF_HOSTNQN "/etc/nvme/hostnqn"
+#define PATH_NVMF_HOSTID "/etc/nvme/hostid"
+#define MAX_DISC_ARGS 10
+#define MAX_DISC_RETRIES 10
+
+enum {
+ OPT_INSTANCE,
+ OPT_CNTLID,
+ OPT_ERR
+};
+
+static const match_table_t opt_tokens = {
+ { OPT_INSTANCE, "instance=%d" },
+ { OPT_CNTLID, "cntlid=%d" },
+ { OPT_ERR, NULL },
+};
+
+static const char *arg_str(const char * const *strings,
+ size_t array_size, size_t idx)
+{
+ if (idx < array_size && strings[idx])
+ return strings[idx];
+ return "unrecognized";
+}
+
+static const char * const trtypes[] = {
+ [NVMF_TRTYPE_RDMA] = "rdma",
+ [NVMF_TRTYPE_FC] = "fc",
+ [NVMF_TRTYPE_TCP] = "tcp",
+ [NVMF_TRTYPE_LOOP] = "loop",
+};
+
+static const char *trtype_str(__u8 trtype)
+{
+ return arg_str(trtypes, ARRAY_SIZE(trtypes), trtype);
+}
+
+static const char * const adrfams[] = {
+ [NVMF_ADDR_FAMILY_PCI] = "pci",
+ [NVMF_ADDR_FAMILY_IP4] = "ipv4",
+ [NVMF_ADDR_FAMILY_IP6] = "ipv6",
+ [NVMF_ADDR_FAMILY_IB] = "infiniband",
+ [NVMF_ADDR_FAMILY_FC] = "fibre-channel",
+ [NVMF_ADDR_FAMILY_LOOP] = "loop",
+};
+
+static inline const char *adrfam_str(__u8 adrfam)
+{
+ return arg_str(adrfams, ARRAY_SIZE(adrfams), adrfam);
+}
+
+static const char * const subtypes[] = {
+ [NVME_NQN_DISC] = "discovery subsystem",
+ [NVME_NQN_NVME] = "nvme subsystem",
+};
+
+static inline const char *subtype_str(__u8 subtype)
+{
+ return arg_str(subtypes, ARRAY_SIZE(subtypes), subtype);
+}
+
+static const char * const treqs[] = {
+ [NVMF_TREQ_NOT_SPECIFIED] = "not specified",
+ [NVMF_TREQ_REQUIRED] = "required",
+ [NVMF_TREQ_NOT_REQUIRED] = "not required",
+ [NVMF_TREQ_DISABLE_SQFLOW] = "not specified, "
+ "sq flow control disable supported",
+};
+
+static inline const char *treq_str(__u8 treq)
+{
+ return arg_str(treqs, ARRAY_SIZE(treqs), treq);
+}
+
+static const char * const sectypes[] = {
+ [NVMF_TCP_SECTYPE_NONE] = "none",
+ [NVMF_TCP_SECTYPE_TLS] = "tls",
+};
+
+static inline const char *sectype_str(__u8 sectype)
+{
+ return arg_str(sectypes, ARRAY_SIZE(sectypes), sectype);
+}
+
+static const char * const prtypes[] = {
+ [NVMF_RDMA_PRTYPE_NOT_SPECIFIED] = "not specified",
+ [NVMF_RDMA_PRTYPE_IB] = "infiniband",
+ [NVMF_RDMA_PRTYPE_ROCE] = "roce",
+ [NVMF_RDMA_PRTYPE_ROCEV2] = "roce-v2",
+ [NVMF_RDMA_PRTYPE_IWARP] = "iwarp",
+};
+
+static inline const char *prtype_str(__u8 prtype)
+{
+ return arg_str(prtypes, ARRAY_SIZE(prtypes), prtype);
+}
+
+static const char * const qptypes[] = {
+ [NVMF_RDMA_QPTYPE_CONNECTED] = "connected",
+ [NVMF_RDMA_QPTYPE_DATAGRAM] = "datagram",
+};
+
+static inline const char *qptype_str(__u8 qptype)
+{
+ return arg_str(qptypes, ARRAY_SIZE(qptypes), qptype);
+}
+
+static const char * const cms[] = {
+ [NVMF_RDMA_CMS_RDMA_CM] = "rdma-cm",
+};
+
+static const char *cms_str(__u8 cm)
+{
+ return arg_str(cms, ARRAY_SIZE(cms), cm);
+}
+
+static int do_discover(char *argstr, bool connect);
+
+/*
+ * parse strings with connect arguments to find a particular field.
+ * If field found, return string containing field value. If field
+ * not found, return an empty string.
+ */
+static char *parse_conn_arg(char *conargs, const char delim, const char *field)
+{
+ char *s, *e;
+ size_t cnt;
+
+ /*
+ * There are field name overlaps: traddr and host_traddr.
+ * By chance, both connect arg strings are set up to
+ * have traddr field followed by host_traddr field. Thus field
+ * name matching doesn't overlap in the searches. Technically,
+ * as is, the loop and delimiter checking isn't necessary.
+ * However, better to be prepared.
+ */
+ do {
+ s = strstr(conargs, field);
+ if (!s)
+ goto empty_field;
+ /* validate prior character is delimiter */
+ if (s == conargs || *(s - 1) == delim) {
+ /* match requires next character to be assignment */
+ s += strlen(field);
+ if (*s == '=')
+ /* match */
+ break;
+ }
+ /* field overlap: seek to delimiter and keep looking */
+ conargs = strchr(s, delim);
+ if (!conargs)
+ goto empty_field;
+ conargs++; /* skip delimiter */
+ } while (1);
+ s++; /* skip assignment character */
+ e = strchr(s, delim);
+ if (e)
+ cnt = e - s;
+ else
+ cnt = strlen(s);
+
+ return strndup(s, cnt);
+
+empty_field:
+ return strdup("\0");
+}
+
+static int ctrl_instance(char *device)
+{
+ char d[64];
+ int ret, instance;
+
+ device = basename(device);
+ ret = sscanf(device, "nvme%d", &instance);
+ if (ret <= 0)
+ return -EINVAL;
+ if (snprintf(d, sizeof(d), "nvme%d", instance) <= 0 ||
+ strcmp(device, d))
+ return -EINVAL;
+ return instance;
+}
+
+/*
+ * Given a controller name, create a connect_args with its
+ * attributes and compare the attributes against the connect args
+ * given.
+ * Return true/false based on whether it matches
+ */
+static bool ctrl_matches_connectargs(char *name, struct connect_args *args)
+{
+ struct connect_args cargs;
+ bool found = false;
+ char *path, *addr;
+ int ret;
+
+ ret = asprintf(&path, "%s/%s", SYS_NVME, name);
+ if (ret < 0)
+ return found;
+
+ addr = nvme_get_ctrl_attr(path, "address");
+ cargs.subsysnqn = nvme_get_ctrl_attr(path, "subsysnqn");
+ cargs.transport = nvme_get_ctrl_attr(path, "transport");
+ cargs.traddr = parse_conn_arg(addr, ' ', conarg_traddr);
+ cargs.trsvcid = parse_conn_arg(addr, ' ', conarg_trsvcid);
+ cargs.host_traddr = parse_conn_arg(addr, ' ', conarg_host_traddr);
+
+ if (!strcmp(cargs.subsysnqn, args->subsysnqn) &&
+ !strcmp(cargs.transport, args->transport) &&
+ (!strcmp(cargs.traddr, args->traddr) ||
+ !strcmp(args->traddr, "none")) &&
+ (!strcmp(cargs.trsvcid, args->trsvcid) ||
+ !strcmp(args->trsvcid, "none")) &&
+ (!strcmp(cargs.host_traddr, args->host_traddr) ||
+ !strcmp(args->host_traddr, "none")))
+ found = true;
+
+ free(cargs.subsysnqn);
+ free(cargs.transport);
+ free(cargs.traddr);
+ free(cargs.trsvcid);
+ free(cargs.host_traddr);
+
+ return found;
+}
+
+/*
+ * Look through the system to find an existing controller whose
+ * attributes match the connect arguments specified
+ * If found, a string containing the controller name (ex: "nvme?")
+ * is returned.
+ * If not found, a NULL is returned.
+ */
+static char *find_ctrl_with_connectargs(struct connect_args *args)
+{
+ struct dirent **devices;
+ char *devname = NULL;
+ int i, n;
+
+ n = scandir(SYS_NVME, &devices, scan_ctrls_filter, alphasort);
+ if (n < 0) {
+ fprintf(stderr, "no NVMe controller(s) detected.\n");
+ return NULL;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ctrl_matches_connectargs(devices[i]->d_name, args)) {
+ devname = strdup(devices[i]->d_name);
+ if (devname == NULL)
+ fprintf(stderr, "no memory for ctrl name %s\n",
+ devices[i]->d_name);
+ goto cleanup_devices;
+ }
+ }
+
+cleanup_devices:
+ for (i = 0; i < n; i++)
+ free(devices[i]);
+ free(devices);
+
+ return devname;
+}
+
+static int add_ctrl(const char *argstr)
+{
+ substring_t args[MAX_OPT_ARGS];
+ char buf[BUF_SIZE], *options, *p;
+ int token, ret, fd, len = strlen(argstr);
+
+ fd = open(PATH_NVME_FABRICS, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n",
+ PATH_NVME_FABRICS, strerror(errno));
+ ret = -errno;
+ goto out;
+ }
+
+ ret = write(fd, argstr, len);
+ if (ret != len) {
+ if (errno != EALREADY || !cfg.quiet)
+ fprintf(stderr, "Failed to write to %s: %s\n",
+ PATH_NVME_FABRICS, strerror(errno));
+ ret = -errno;
+ goto out_close;
+ }
+
+ len = read(fd, buf, BUF_SIZE);
+ if (len < 0) {
+ fprintf(stderr, "Failed to read from %s: %s\n",
+ PATH_NVME_FABRICS, strerror(errno));
+ ret = -errno;
+ goto out_close;
+ }
+
+ buf[len] = '\0';
+ options = buf;
+ while ((p = strsep(&options, ",\n")) != NULL) {
+ if (!*p)
+ continue;
+
+ token = match_token(p, opt_tokens, args);
+ switch (token) {
+ case OPT_INSTANCE:
+ if (match_int(args, &token))
+ goto out_fail;
+ ret = token;
+ goto out_close;
+ default:
+ /* ignore */
+ break;
+ }
+ }
+
+out_fail:
+ fprintf(stderr, "Failed to parse ctrl info for \"%s\"\n", argstr);
+ ret = -EINVAL;
+out_close:
+ close(fd);
+out:
+ return ret;
+}
+
+static int remove_ctrl_by_path(char *sysfs_path)
+{
+ int ret, fd;
+
+ fd = open(sysfs_path, O_WRONLY);
+ if (fd < 0) {
+ ret = -errno;
+ fprintf(stderr, "Failed to open %s: %s\n", sysfs_path,
+ strerror(errno));
+ goto out;
+ }
+
+ if (write(fd, "1", 1) != 1) {
+ ret = -errno;
+ goto out_close;
+ }
+
+ ret = 0;
+out_close:
+ close(fd);
+out:
+ return ret;
+}
+
+static int remove_ctrl(int instance)
+{
+ char *sysfs_path;
+ int ret;
+
+ if (asprintf(&sysfs_path, "/sys/class/nvme/nvme%d/delete_controller",
+ instance) < 0) {
+ ret = -errno;
+ goto out;
+ }
+
+ ret = remove_ctrl_by_path(sysfs_path);
+ free(sysfs_path);
+out:
+ return ret;
+}
+
+enum {
+ DISC_OK,
+ DISC_NO_LOG,
+ DISC_GET_NUMRECS,
+ DISC_GET_LOG,
+ DISC_RETRY_EXHAUSTED,
+ DISC_NOT_EQUAL,
+};
+
+static int nvmf_get_log_page_discovery(const char *dev_path,
+ struct nvmf_disc_rsp_page_hdr **logp, int *numrec, int *status)
+{
+ struct nvmf_disc_rsp_page_hdr *log;
+ unsigned int hdr_size;
+ unsigned long genctr;
+ int error, fd, max_retries = MAX_DISC_RETRIES, retries = 0;
+
+ fd = open(dev_path, O_RDWR);
+ if (fd < 0) {
+ error = -errno;
+ fprintf(stderr, "Failed to open %s: %s\n",
+ dev_path, strerror(errno));
+ goto out;
+ }
+
+ /* first get_log_page we just need numrec entry from discovery hdr.
+ * host supplies its desired bytes via dwords, per NVMe spec.
+ */
+ hdr_size = round_up((offsetof(struct nvmf_disc_rsp_page_hdr, numrec) +
+ sizeof(log->numrec)), sizeof(__u32));
+
+ /*
+ * Issue first get log page w/numdl small enough to retrieve numrec.
+ * We just want to know how many records to retrieve.
+ */
+ log = calloc(1, hdr_size);
+ if (!log) {
+ error = -ENOMEM;
+ goto out_close;
+ }
+
+ error = nvme_discovery_log(fd, log, hdr_size);
+ if (error) {
+ error = DISC_GET_NUMRECS;
+ goto out_free_log;
+ }
+
+ do {
+ unsigned int log_size;
+
+ /* check numrec limits */
+ *numrec = le64_to_cpu(log->numrec);
+ genctr = le64_to_cpu(log->genctr);
+ free(log);
+
+ if (*numrec == 0) {
+ error = DISC_NO_LOG;
+ goto out_close;
+ }
+
+ /* we are actually retrieving the entire discovery tables
+ * for the second get_log_page(), per
+ * NVMe spec so no need to round_up(), or there is something
+ * seriously wrong with the standard
+ */
+ log_size = sizeof(struct nvmf_disc_rsp_page_hdr) +
+ sizeof(struct nvmf_disc_rsp_page_entry) * *numrec;
+
+ /* allocate discovery log pages based on page_hdr->numrec */
+ log = calloc(1, log_size);
+ if (!log) {
+ error = -ENOMEM;
+ goto out_close;
+ }
+
+ /*
+ * issue new get_log_page w/numdl+numdh set to get all records,
+ * up to MAX_DISC_LOGS.
+ */
+ error = nvme_discovery_log(fd, log, log_size);
+ if (error) {
+ error = DISC_GET_LOG;
+ goto out_free_log;
+ }
+
+ /*
+ * The above call to nvme_discovery_log() might result
+ * in several calls (with different offsets), so we need
+ * to fetch the header again to have the most up-to-date
+ * value for the generation counter
+ */
+ genctr = le64_to_cpu(log->genctr);
+ error = nvme_discovery_log(fd, log, hdr_size);
+ if (error) {
+ error = DISC_GET_LOG;
+ goto out_free_log;
+ }
+ } while (genctr != le64_to_cpu(log->genctr) &&
+ ++retries < max_retries);
+
+ /*
+ * If genctr is still different with the one in the log entry, it
+ * means the retires have been exhausted to max_retries. Then it
+ * should be retried by the caller or the user.
+ */
+ if (genctr != le64_to_cpu(log->genctr)) {
+ error = DISC_RETRY_EXHAUSTED;
+ goto out_free_log;
+ }
+
+ if (*numrec != le64_to_cpu(log->numrec)) {
+ error = DISC_NOT_EQUAL;
+ goto out_free_log;
+ }
+
+ /* needs to be freed by the caller */
+ *logp = log;
+ error = DISC_OK;
+ goto out_close;
+
+out_free_log:
+ free(log);
+out_close:
+ close(fd);
+out:
+ *status = nvme_status_to_errno(error, true);
+ return error;
+}
+
+static int space_strip_len(int max, const char *str)
+{
+ int i;
+
+ for (i = max - 1; i >= 0; i--)
+ if (str[i] != '\0' && str[i] != ' ')
+ break;
+
+ return i + 1;
+}
+
+static void print_discovery_log(struct nvmf_disc_rsp_page_hdr *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_rsp_page_entry *e = &log->entries[i];
+
+ printf("=====Discovery Log Entry %d======\n", i);
+ printf("trtype: %s\n", trtype_str(e->trtype));
+ printf("adrfam: %s\n", adrfam_str(e->adrfam));
+ printf("subtype: %s\n", subtype_str(e->subtype));
+ printf("treq: %s\n", treq_str(e->treq));
+ printf("portid: %d\n", e->portid);
+ printf("trsvcid: %.*s\n",
+ space_strip_len(NVMF_TRSVCID_SIZE, e->trsvcid),
+ e->trsvcid);
+ printf("subnqn: %s\n", e->subnqn);
+ printf("traddr: %.*s\n",
+ space_strip_len(NVMF_TRADDR_SIZE, e->traddr),
+ e->traddr);
+
+ switch (e->trtype) {
+ case NVMF_TRTYPE_RDMA:
+ printf("rdma_prtype: %s\n",
+ prtype_str(e->tsas.rdma.prtype));
+ printf("rdma_qptype: %s\n",
+ qptype_str(e->tsas.rdma.qptype));
+ printf("rdma_cms: %s\n",
+ cms_str(e->tsas.rdma.cms));
+ printf("rdma_pkey: 0x%04x\n",
+ e->tsas.rdma.pkey);
+ break;
+ case NVMF_TRTYPE_TCP:
+ printf("sectype: %s\n",
+ sectype_str(e->tsas.tcp.sectype));
+ break;
+ }
+ }
+}
+
+static void save_discovery_log(struct nvmf_disc_rsp_page_hdr *log, int numrec)
+{
+ int fd;
+ int len, ret;
+
+ fd = open(cfg.raw, O_CREAT|O_RDWR|O_TRUNC, S_IRUSR|S_IWUSR);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open %s: %s\n",
+ cfg.raw, strerror(errno));
+ return;
+ }
+
+ len = sizeof(struct nvmf_disc_rsp_page_hdr) +
+ numrec * sizeof(struct nvmf_disc_rsp_page_entry);
+ ret = write(fd, log, len);
+ if (ret < 0)
+ fprintf(stderr, "failed to write to %s: %s\n",
+ cfg.raw, strerror(errno));
+ else
+ printf("Discovery log is saved to %s\n", cfg.raw);
+
+ close(fd);
+}
+
+static char *hostnqn_read_file(void)
+{
+ FILE *f;
+ char hostnqn[NVMF_NQN_SIZE];
+ char *ret = NULL;
+
+ f = fopen(PATH_NVMF_HOSTNQN, "r");
+ if (f == NULL)
+ return false;
+
+ if (fgets(hostnqn, sizeof(hostnqn), f) == NULL ||
+ !strlen(hostnqn))
+ goto out;
+
+ ret = strndup(hostnqn, strcspn(hostnqn, "\n"));
+
+out:
+ fclose(f);
+ return ret;
+}
+
+static char *hostnqn_generate_systemd(void)
+{
+#ifdef HAVE_SYSTEMD
+ sd_id128_t id;
+ char *ret;
+
+ if (sd_id128_get_machine_app_specific(NVME_HOSTNQN_ID, &id) < 0)
+ return NULL;
+
+ if (asprintf(&ret, "nqn.2014-08.org.nvmexpress:uuid:" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(id)) == -1)
+ ret = NULL;
+
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
+/* returns an allocated string or NULL */
+char *hostnqn_read(void)
+{
+ char *ret;
+
+ ret = hostnqn_read_file();
+ if (ret)
+ return ret;
+
+ ret = hostnqn_generate_systemd();
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+static int nvmf_hostnqn_file(void)
+{
+ cfg.hostnqn = hostnqn_read();
+
+ return cfg.hostnqn != NULL;
+}
+
+static int nvmf_hostid_file(void)
+{
+ FILE *f;
+ char hostid[NVMF_HOSTID_SIZE + 1];
+ int ret = false;
+
+ f = fopen(PATH_NVMF_HOSTID, "r");
+ if (f == NULL)
+ return false;
+
+ if (fgets(hostid, sizeof(hostid), f) == NULL)
+ goto out;
+
+ cfg.hostid = strdup(hostid);
+ if (!cfg.hostid)
+ goto out;
+
+ ret = true;
+out:
+ fclose(f);
+ return ret;
+}
+
+static int
+add_bool_argument(char **argstr, int *max_len, char *arg_str, bool arg)
+{
+ int len;
+
+ if (arg) {
+ len = snprintf(*argstr, *max_len, ",%s", arg_str);
+ if (len < 0)
+ return -EINVAL;
+ *argstr += len;
+ *max_len -= len;
+ }
+
+ return 0;
+}
+
+static int
+add_int_argument(char **argstr, int *max_len, char *arg_str, int arg,
+ bool allow_zero)
+{
+ int len;
+
+ if ((arg && !allow_zero) || (arg != -1 && allow_zero)) {
+ len = snprintf(*argstr, *max_len, ",%s=%d", arg_str, arg);
+ if (len < 0)
+ return -EINVAL;
+ *argstr += len;
+ *max_len -= len;
+ }
+
+ return 0;
+}
+
+static int
+add_argument(char **argstr, int *max_len, char *arg_str, char *arg)
+{
+ int len;
+
+ if (arg && strcmp(arg, "none")) {
+ len = snprintf(*argstr, *max_len, ",%s=%s", arg_str, arg);
+ if (len < 0)
+ return -EINVAL;
+ *argstr += len;
+ *max_len -= len;
+ }
+
+ return 0;
+}
+
+static int build_options(char *argstr, int max_len, bool discover)
+{
+ int len;
+
+ if (!cfg.transport) {
+ fprintf(stderr, "need a transport (-t) argument\n");
+ return -EINVAL;
+ }
+
+ if (strncmp(cfg.transport, "loop", 4)) {
+ if (!cfg.traddr) {
+ fprintf(stderr, "need a address (-a) argument\n");
+ return -EINVAL;
+ }
+ }
+
+ /* always specify nqn as first arg - this will init the string */
+ len = snprintf(argstr, max_len, "nqn=%s", cfg.nqn);
+ if (len < 0)
+ return -EINVAL;
+ argstr += len;
+ max_len -= len;
+
+ if (add_argument(&argstr, &max_len, "transport", cfg.transport) ||
+ add_argument(&argstr, &max_len, "traddr", cfg.traddr) ||
+ add_argument(&argstr, &max_len, "host_traddr", cfg.host_traddr) ||
+ add_argument(&argstr, &max_len, "trsvcid", cfg.trsvcid) ||
+ ((cfg.hostnqn || nvmf_hostnqn_file()) &&
+ add_argument(&argstr, &max_len, "hostnqn", cfg.hostnqn)) ||
+ ((cfg.hostid || nvmf_hostid_file()) &&
+ add_argument(&argstr, &max_len, "hostid", cfg.hostid)) ||
+ (!discover &&
+ add_int_argument(&argstr, &max_len, "nr_io_queues",
+ cfg.nr_io_queues, false)) ||
+ add_int_argument(&argstr, &max_len, "nr_write_queues",
+ cfg.nr_write_queues, false) ||
+ add_int_argument(&argstr, &max_len, "nr_poll_queues",
+ cfg.nr_poll_queues, false) ||
+ (!discover &&
+ add_int_argument(&argstr, &max_len, "queue_size",
+ cfg.queue_size, false)) ||
+ (!discover &&
+ add_int_argument(&argstr, &max_len, "keep_alive_tmo",
+ cfg.keep_alive_tmo, false)) ||
+ add_int_argument(&argstr, &max_len, "reconnect_delay",
+ cfg.reconnect_delay, false) ||
+ add_int_argument(&argstr, &max_len, "ctrl_loss_tmo",
+ cfg.ctrl_loss_tmo, false) ||
+ add_int_argument(&argstr, &max_len, "tos",
+ cfg.tos, true) ||
+ add_bool_argument(&argstr, &max_len, "duplicate_connect",
+ cfg.duplicate_connect) ||
+ add_bool_argument(&argstr, &max_len, "disable_sqflow",
+ cfg.disable_sqflow) ||
+ add_bool_argument(&argstr, &max_len, "hdr_digest", cfg.hdr_digest) ||
+ add_bool_argument(&argstr, &max_len, "data_digest", cfg.data_digest))
+ return -EINVAL;
+
+ return 0;
+}
+
+static bool traddr_is_hostname(struct config *cfg)
+{
+ char addrstr[NVMF_TRADDR_SIZE];
+
+ if (!cfg->traddr)
+ return false;
+ if (strcmp(cfg->transport, "tcp") && strcmp(cfg->transport, "rdma"))
+ return false;
+ if (inet_pton(AF_INET, cfg->traddr, addrstr) > 0 ||
+ inet_pton(AF_INET6, cfg->traddr, addrstr) > 0)
+ return false;
+ return true;
+}
+
+static int hostname2traddr(struct config *cfg)
+{
+ struct addrinfo *host_info, hints = {.ai_family = AF_UNSPEC};
+ char addrstr[NVMF_TRADDR_SIZE];
+ const char *p;
+ int ret;
+
+ ret = getaddrinfo(cfg->traddr, NULL, &hints, &host_info);
+ if (ret) {
+ fprintf(stderr, "failed to resolve host %s info\n", cfg->traddr);
+ return ret;
+ }
+
+ switch (host_info->ai_family) {
+ case AF_INET:
+ p = inet_ntop(host_info->ai_family,
+ &(((struct sockaddr_in *)host_info->ai_addr)->sin_addr),
+ addrstr, NVMF_TRADDR_SIZE);
+ break;
+ case AF_INET6:
+ p = inet_ntop(host_info->ai_family,
+ &(((struct sockaddr_in6 *)host_info->ai_addr)->sin6_addr),
+ addrstr, NVMF_TRADDR_SIZE);
+ break;
+ default:
+ fprintf(stderr, "unrecognized address family (%d) %s\n",
+ host_info->ai_family, cfg->traddr);
+ ret = -EINVAL;
+ goto free_addrinfo;
+ }
+
+ if (!p) {
+ fprintf(stderr, "failed to get traddr for %s\n", cfg->traddr);
+ ret = -errno;
+ goto free_addrinfo;
+ }
+ cfg->traddr = strdup(addrstr);
+
+free_addrinfo:
+ freeaddrinfo(host_info);
+ return ret;
+}
+
+static int connect_ctrl(struct nvmf_disc_rsp_page_entry *e)
+{
+ char argstr[BUF_SIZE], *p;
+ const char *transport;
+ bool discover, disable_sqflow = true;
+ int len, ret;
+
+retry:
+ p = argstr;
+ discover = false;
+
+ switch (e->subtype) {
+ case NVME_NQN_DISC:
+ discover = true;
+ case NVME_NQN_NVME:
+ break;
+ default:
+ fprintf(stderr, "skipping unsupported subtype %d\n",
+ e->subtype);
+ return -EINVAL;
+ }
+
+ len = sprintf(p, "nqn=%s", e->subnqn);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+
+ if (cfg.hostnqn && strcmp(cfg.hostnqn, "none")) {
+ len = sprintf(p, ",hostnqn=%s", cfg.hostnqn);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.hostid && strcmp(cfg.hostid, "none")) {
+ len = sprintf(p, ",hostid=%s", cfg.hostid);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.queue_size && !discover) {
+ len = sprintf(p, ",queue_size=%d", cfg.queue_size);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.nr_io_queues && !discover) {
+ len = sprintf(p, ",nr_io_queues=%d", cfg.nr_io_queues);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.nr_write_queues) {
+ len = sprintf(p, ",nr_write_queues=%d", cfg.nr_write_queues);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.nr_poll_queues) {
+ len = sprintf(p, ",nr_poll_queues=%d", cfg.nr_poll_queues);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.host_traddr && strcmp(cfg.host_traddr, "none")) {
+ len = sprintf(p, ",host_traddr=%s", cfg.host_traddr);
+ if (len < 0)
+ return -EINVAL;
+ p+= len;
+ }
+
+ if (cfg.reconnect_delay) {
+ len = sprintf(p, ",reconnect_delay=%d", cfg.reconnect_delay);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.ctrl_loss_tmo) {
+ len = sprintf(p, ",ctrl_loss_tmo=%d", cfg.ctrl_loss_tmo);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.tos != -1) {
+ len = sprintf(p, ",tos=%d", cfg.tos);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.keep_alive_tmo) {
+ len = sprintf(p, ",keep_alive_tmo=%d", cfg.keep_alive_tmo);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ transport = trtype_str(e->trtype);
+ if (!strcmp(transport, "unrecognized")) {
+ fprintf(stderr, "skipping unsupported transport %d\n",
+ e->trtype);
+ return -EINVAL;
+ }
+
+ len = sprintf(p, ",transport=%s", transport);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+
+ if (cfg.hdr_digest) {
+ len = sprintf(p, ",hdr_digest");
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (cfg.data_digest) {
+ len = sprintf(p, ",data_digest");
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ switch (e->trtype) {
+ case NVMF_TRTYPE_RDMA:
+ case NVMF_TRTYPE_TCP:
+ switch (e->adrfam) {
+ case NVMF_ADDR_FAMILY_IP4:
+ case NVMF_ADDR_FAMILY_IP6:
+ /* FALLTHRU */
+ len = sprintf(p, ",traddr=%.*s",
+ space_strip_len(NVMF_TRADDR_SIZE, e->traddr),
+ e->traddr);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+
+ len = sprintf(p, ",trsvcid=%.*s",
+ space_strip_len(NVMF_TRSVCID_SIZE, e->trsvcid),
+ e->trsvcid);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ break;
+ default:
+ fprintf(stderr, "skipping unsupported adrfam\n");
+ return -EINVAL;
+ }
+ break;
+ case NVMF_TRTYPE_FC:
+ switch (e->adrfam) {
+ case NVMF_ADDR_FAMILY_FC:
+ len = sprintf(p, ",traddr=%.*s",
+ space_strip_len(NVMF_TRADDR_SIZE, e->traddr),
+ e->traddr);
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ break;
+ default:
+ fprintf(stderr, "skipping unsupported adrfam\n");
+ return -EINVAL;
+ }
+ break;
+ }
+
+ if (e->treq & NVMF_TREQ_DISABLE_SQFLOW && disable_sqflow) {
+ len = sprintf(p, ",disable_sqflow");
+ if (len < 0)
+ return -EINVAL;
+ p += len;
+ }
+
+ if (discover)
+ ret = do_discover(argstr, true);
+ else
+ ret = add_ctrl(argstr);
+ if (ret == -EINVAL && e->treq & NVMF_TREQ_DISABLE_SQFLOW) {
+ /* disable_sqflow param might not be supported, try without it */
+ disable_sqflow = false;
+ goto retry;
+ }
+ return ret;
+}
+
+static bool should_connect(struct nvmf_disc_rsp_page_entry *entry)
+{
+ int len;
+
+ if (!cfg.matching_only || !cfg.traddr)
+ return true;
+
+ len = space_strip_len(NVMF_TRADDR_SIZE, entry->traddr);
+ return !strncmp(cfg.traddr, entry->traddr, len);
+}
+
+static int connect_ctrls(struct nvmf_disc_rsp_page_hdr *log, int numrec)
+{
+ int i;
+ int instance;
+ int ret = 0;
+
+ for (i = 0; i < numrec; i++) {
+ if (!should_connect(&log->entries[i]))
+ continue;
+
+ instance = connect_ctrl(&log->entries[i]);
+
+ /* clean success */
+ if (instance >= 0)
+ continue;
+
+ /* already connected print message */
+ if (instance == -EALREADY) {
+ const char *traddr = log->entries[i].traddr;
+
+ if (!cfg.quiet)
+ fprintf(stderr,
+ "traddr=%.*s is already connected\n",
+ space_strip_len(NVMF_TRADDR_SIZE,
+ traddr),
+ traddr);
+ continue;
+ }
+
+ /*
+ * don't error out. The Discovery Log may contain
+ * devices that aren't necessarily connectable via
+ * the system/host transport port. Let those items
+ * fail and continue on to the next log element.
+ */
+ }
+
+ return ret;
+}
+
+static void nvmf_get_host_identifiers(int ctrl_instance)
+{
+ char *path;
+
+ if (asprintf(&path, "%s/nvme%d", SYS_NVME, ctrl_instance) < 0)
+ return;
+ cfg.hostnqn = nvme_get_ctrl_attr(path, "hostnqn");
+ cfg.hostid = nvme_get_ctrl_attr(path, "hostid");
+}
+
+static int do_discover(char *argstr, bool connect)
+{
+ struct nvmf_disc_rsp_page_hdr *log = NULL;
+ char *dev_name;
+ int instance, numrec = 0, ret, err;
+ int status = 0;
+
+ if (cfg.device) {
+ struct connect_args cargs;
+
+ memset(&cargs, 0, sizeof(cargs));
+ cargs.subsysnqn = parse_conn_arg(argstr, ',', conarg_nqn);
+ cargs.transport = parse_conn_arg(argstr, ',', conarg_transport);
+ cargs.traddr = parse_conn_arg(argstr, ',', conarg_traddr);
+ cargs.trsvcid = parse_conn_arg(argstr, ',', conarg_trsvcid);
+ cargs.host_traddr = parse_conn_arg(argstr, ',', conarg_host_traddr);
+
+ /*
+ * if the cfg.device passed in matches the connect args
+ * cfg.device is left as-is
+ * else if there exists a controller that matches the
+ * connect args
+ * cfg.device is the matching ctrl name
+ * else if no ctrl matches the connect args
+ * cfg.device is set to null. This will attempt to
+ * create a new ctrl.
+ * endif
+ */
+ if (!ctrl_matches_connectargs(cfg.device, &cargs))
+ cfg.device = find_ctrl_with_connectargs(&cargs);
+
+ free(cargs.subsysnqn);
+ free(cargs.transport);
+ free(cargs.traddr);
+ free(cargs.trsvcid);
+ free(cargs.host_traddr);
+ }
+
+ if (!cfg.device) {
+ instance = add_ctrl(argstr);
+ } else {
+ instance = ctrl_instance(cfg.device);
+ nvmf_get_host_identifiers(instance);
+ }
+ if (instance < 0)
+ return instance;
+
+ if (asprintf(&dev_name, "/dev/nvme%d", instance) < 0)
+ return -errno;
+ ret = nvmf_get_log_page_discovery(dev_name, &log, &numrec, &status);
+ free(dev_name);
+ if (!cfg.device && !cfg.persistent) {
+ err = remove_ctrl(instance);
+ if (err)
+ return err;
+ }
+
+ switch (ret) {
+ case DISC_OK:
+ if (connect)
+ ret = connect_ctrls(log, numrec);
+ else if (cfg.raw)
+ save_discovery_log(log, numrec);
+ else
+ print_discovery_log(log, numrec);
+ break;
+ case DISC_GET_NUMRECS:
+ fprintf(stderr,
+ "Get number of discovery log entries failed.\n");
+ ret = status;
+ break;
+ case DISC_GET_LOG:
+ fprintf(stderr, "Get discovery log entries failed.\n");
+ ret = status;
+ break;
+ case DISC_NO_LOG:
+ fprintf(stdout, "No discovery log entries to fetch.\n");
+ ret = DISC_OK;
+ break;
+ case DISC_RETRY_EXHAUSTED:
+ fprintf(stdout, "Discovery retries exhausted.\n");
+ ret = -EAGAIN;
+ break;
+ case DISC_NOT_EQUAL:
+ fprintf(stderr,
+ "Numrec values of last two get discovery log page not equal\n");
+ ret = -EBADSLT;
+ break;
+ default:
+ fprintf(stderr, "Get discovery log page failed: %d\n", ret);
+ break;
+ }
+
+ return ret;
+}
+
+static int discover_from_conf_file(const char *desc, char *argstr,
+ const struct argconfig_commandline_options *opts, bool connect)
+{
+ FILE *f;
+ char line[256], *ptr, *args, **argv;
+ int argc, err, ret = 0;
+
+ f = fopen(PATH_NVMF_DISC, "r");
+ if (f == NULL) {
+ fprintf(stderr, "No discover params given and no %s conf\n",
+ PATH_NVMF_DISC);
+ return -EINVAL;
+ }
+
+ while (fgets(line, sizeof(line), f) != NULL) {
+ if (line[0] == '#' || line[0] == '\n')
+ continue;
+
+ args = strdup(line);
+ if (!args) {
+ fprintf(stderr, "failed to strdup args\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ argv = calloc(MAX_DISC_ARGS, BUF_SIZE);
+ if (!argv) {
+ fprintf(stderr, "failed to allocate argv vector\n");
+ free(args);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ argc = 0;
+ argv[argc++] = "discover";
+ while ((ptr = strsep(&args, " =\n")) != NULL)
+ argv[argc++] = ptr;
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ goto free_and_continue;
+
+ if (cfg.persistent && !cfg.keep_alive_tmo)
+ cfg.keep_alive_tmo = NVMF_DEF_DISC_TMO;
+
+ if (traddr_is_hostname(&cfg)) {
+ ret = hostname2traddr(&cfg);
+ if (ret)
+ goto out;
+ }
+
+ err = build_options(argstr, BUF_SIZE, true);
+ if (err) {
+ ret = err;
+ goto free_and_continue;
+ }
+
+ err = do_discover(argstr, connect);
+ if (err)
+ ret = err;
+
+free_and_continue:
+ free(args);
+ free(argv);
+ }
+
+out:
+ fclose(f);
+ return ret;
+}
+
+int fabrics_discover(const char *desc, int argc, char **argv, bool connect)
+{
+ char argstr[BUF_SIZE];
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_LIST("transport", 't', &cfg.transport, "transport type"),
+ OPT_LIST("traddr", 'a', &cfg.traddr, "transport address"),
+ OPT_LIST("trsvcid", 's', &cfg.trsvcid, "transport service id (e.g. IP port)"),
+ OPT_LIST("host-traddr", 'w', &cfg.host_traddr, "host traddr (e.g. FC WWN's)"),
+ OPT_LIST("hostnqn", 'q', &cfg.hostnqn, "user-defined hostnqn (if default not used)"),
+ OPT_LIST("hostid", 'I', &cfg.hostid, "user-defined hostid (if default not used)"),
+ OPT_LIST("raw", 'r', &cfg.raw, "raw output file"),
+ OPT_LIST("device", 'd', &cfg.device, "use existing discovery controller device"),
+ OPT_INT("keep-alive-tmo", 'k', &cfg.keep_alive_tmo, "keep alive timeout period in seconds"),
+ OPT_INT("reconnect-delay", 'c', &cfg.reconnect_delay, "reconnect timeout period in seconds"),
+ OPT_INT("ctrl-loss-tmo", 'l', &cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"),
+ OPT_INT("tos", 'T', &cfg.tos, "type of service"),
+ OPT_FLAG("hdr_digest", 'g', &cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"),
+ OPT_FLAG("data_digest", 'G', &cfg.data_digest, "enable transport protocol data digest (TCP transport)"),
+ OPT_INT("nr-io-queues", 'i', &cfg.nr_io_queues, "number of io queues to use (default is core count)"),
+ OPT_INT("nr-write-queues", 'W', &cfg.nr_write_queues, "number of write queues to use (default 0)"),
+ OPT_INT("nr-poll-queues", 'P', &cfg.nr_poll_queues, "number of poll queues to use (default 0)"),
+ OPT_INT("queue-size", 'Q', &cfg.queue_size, "number of io queue elements to use (default 128)"),
+ OPT_FLAG("persistent", 'p', &cfg.persistent, "persistent discovery connection"),
+ OPT_FLAG("quiet", 'S', &cfg.quiet, "suppress already connected errors"),
+ OPT_FLAG("matching", 'm', &cfg.matching_only, "connect only records matching the traddr"),
+ OPT_END()
+ };
+
+ cfg.tos = -1;
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ goto out;
+
+ if (cfg.device && !strcmp(cfg.device, "none"))
+ cfg.device = NULL;
+
+ cfg.nqn = NVME_DISC_SUBSYS_NAME;
+
+ if (!cfg.transport && !cfg.traddr) {
+ ret = discover_from_conf_file(desc, argstr, opts, connect);
+ } else {
+ if (cfg.persistent && !cfg.keep_alive_tmo)
+ cfg.keep_alive_tmo = NVMF_DEF_DISC_TMO;
+
+ if (traddr_is_hostname(&cfg)) {
+ ret = hostname2traddr(&cfg);
+ if (ret)
+ goto out;
+ }
+
+ ret = build_options(argstr, BUF_SIZE, true);
+ if (ret)
+ goto out;
+
+ ret = do_discover(argstr, connect);
+ }
+
+out:
+ return nvme_status_to_errno(ret, true);
+}
+
+int fabrics_connect(const char *desc, int argc, char **argv)
+{
+ char argstr[BUF_SIZE];
+ int instance, ret;
+
+ OPT_ARGS(opts) = {
+ OPT_LIST("transport", 't', &cfg.transport, "transport type"),
+ OPT_LIST("nqn", 'n', &cfg.nqn, "nqn name"),
+ OPT_LIST("traddr", 'a', &cfg.traddr, "transport address"),
+ OPT_LIST("trsvcid", 's', &cfg.trsvcid, "transport service id (e.g. IP port)"),
+ OPT_LIST("host-traddr", 'w', &cfg.host_traddr, "host traddr (e.g. FC WWN's)"),
+ OPT_LIST("hostnqn", 'q', &cfg.hostnqn, "user-defined hostnqn"),
+ OPT_LIST("hostid", 'I', &cfg.hostid, "user-defined hostid (if default not used)"),
+ OPT_INT("nr-io-queues", 'i', &cfg.nr_io_queues, "number of io queues to use (default is core count)"),
+ OPT_INT("nr-write-queues", 'W', &cfg.nr_write_queues, "number of write queues to use (default 0)"),
+ OPT_INT("nr-poll-queues", 'P', &cfg.nr_poll_queues, "number of poll queues to use (default 0)"),
+ OPT_INT("queue-size", 'Q', &cfg.queue_size, "number of io queue elements to use (default 128)"),
+ OPT_INT("keep-alive-tmo", 'k', &cfg.keep_alive_tmo, "keep alive timeout period in seconds"),
+ OPT_INT("reconnect-delay", 'c', &cfg.reconnect_delay, "reconnect timeout period in seconds"),
+ OPT_INT("ctrl-loss-tmo", 'l', &cfg.ctrl_loss_tmo, "controller loss timeout period in seconds"),
+ OPT_INT("tos", 'T', &cfg.tos, "type of service"),
+ OPT_FLAG("duplicate-connect", 'D', &cfg.duplicate_connect, "allow duplicate connections between same transport host and subsystem port"),
+ OPT_FLAG("disable-sqflow", 'd', &cfg.disable_sqflow, "disable controller sq flow control (default false)"),
+ OPT_FLAG("hdr-digest", 'g', &cfg.hdr_digest, "enable transport protocol header digest (TCP transport)"),
+ OPT_FLAG("data-digest", 'G', &cfg.data_digest, "enable transport protocol data digest (TCP transport)"),
+ OPT_END()
+ };
+
+ cfg.tos = -1;
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ goto out;
+
+ if (traddr_is_hostname(&cfg)) {
+ ret = hostname2traddr(&cfg);
+ if (ret)
+ goto out;
+ }
+
+ ret = build_options(argstr, BUF_SIZE, false);
+ if (ret)
+ goto out;
+
+ if (!cfg.nqn) {
+ fprintf(stderr, "need a -n argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ instance = add_ctrl(argstr);
+ if (instance < 0)
+ ret = instance;
+
+out:
+ return nvme_status_to_errno(ret, true);
+}
+
+static int scan_sys_nvme_filter(const struct dirent *d)
+{
+ if (!strcmp(d->d_name, "."))
+ return 0;
+ if (!strcmp(d->d_name, ".."))
+ return 0;
+ return 1;
+}
+
+/*
+ * Returns 1 if disconnect occurred, 0 otherwise.
+ */
+static int disconnect_subsys(char *nqn, char *ctrl)
+{
+ char *sysfs_nqn_path = NULL, *sysfs_del_path = NULL;
+ char subsysnqn[NVMF_NQN_SIZE] = {};
+ int fd, ret = 0;
+
+ if (asprintf(&sysfs_nqn_path, "%s/%s/subsysnqn", SYS_NVME, ctrl) < 0)
+ goto free;
+ if (asprintf(&sysfs_del_path, "%s/%s/delete_controller", SYS_NVME, ctrl) < 0)
+ goto free;
+
+ fd = open(sysfs_nqn_path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n",
+ sysfs_nqn_path, strerror(errno));
+ goto free;
+ }
+
+ if (read(fd, subsysnqn, NVMF_NQN_SIZE) < 0)
+ goto close;
+
+ subsysnqn[strcspn(subsysnqn, "\n")] = '\0';
+ if (strcmp(subsysnqn, nqn))
+ goto close;
+
+ if (!remove_ctrl_by_path(sysfs_del_path))
+ ret = 1;
+ close:
+ close(fd);
+ free:
+ free(sysfs_del_path);
+ free(sysfs_nqn_path);
+ return ret;
+}
+
+/*
+ * Returns the number of controllers successfully disconnected.
+ */
+static int disconnect_by_nqn(char *nqn)
+{
+ struct dirent **devices = NULL;
+ int i, n, ret = 0;
+
+ if (strlen(nqn) > NVMF_NQN_SIZE)
+ return -EINVAL;
+
+ n = scandir(SYS_NVME, &devices, scan_sys_nvme_filter, alphasort);
+ if (n < 0)
+ return n;
+
+ for (i = 0; i < n; i++)
+ ret += disconnect_subsys(nqn, devices[i]->d_name);
+
+ for (i = 0; i < n; i++)
+ free(devices[i]);
+ free(devices);
+
+ return ret;
+}
+
+static int disconnect_by_device(char *device)
+{
+ int instance;
+
+ instance = ctrl_instance(device);
+ if (instance < 0)
+ return instance;
+ return remove_ctrl(instance);
+}
+
+int fabrics_disconnect(const char *desc, int argc, char **argv)
+{
+ const char *nqn = "nqn name";
+ const char *device = "nvme device";
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_LIST("nqn", 'n', &cfg.nqn, nqn),
+ OPT_LIST("device", 'd', &cfg.device, device),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ goto out;
+
+ if (!cfg.nqn && !cfg.device) {
+ fprintf(stderr, "need a -n or -d argument\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (cfg.nqn) {
+ ret = disconnect_by_nqn(cfg.nqn);
+ if (ret < 0)
+ fprintf(stderr, "Failed to disconnect by NQN: %s\n",
+ cfg.nqn);
+ else {
+ printf("NQN:%s disconnected %d controller(s)\n", cfg.nqn, ret);
+ ret = 0;
+ }
+ }
+
+ if (cfg.device) {
+ ret = disconnect_by_device(cfg.device);
+ if (ret)
+ fprintf(stderr,
+ "Failed to disconnect by device name: %s\n",
+ cfg.device);
+ }
+
+out:
+ return nvme_status_to_errno(ret, true);
+}
+
+int fabrics_disconnect_all(const char *desc, int argc, char **argv)
+{
+ struct nvme_topology t = { };
+ int i, j, err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err)
+ goto out;
+
+ err = scan_subsystems(&t, NULL, 0);
+ if (err) {
+ fprintf(stderr, "Failed to scan namespaces\n");
+ goto out;
+ }
+
+ for (i = 0; i < t.nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t.subsystems[i];
+
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ if (!strcmp(c->transport, "pcie"))
+ continue;
+ err = disconnect_by_device(c->name);
+ if (err)
+ goto free;
+ }
+ }
+free:
+ free_topology(&t);
+out:
+ return nvme_status_to_errno(err, true);
+}
diff --git a/fabrics.h b/fabrics.h
new file mode 100644
index 0000000..f5b8eaf
--- /dev/null
+++ b/fabrics.h
@@ -0,0 +1,13 @@
+#ifndef _DISCOVER_H
+#define _DISCOVER_H
+
+#define NVMF_DEF_DISC_TMO 30
+
+extern char *hostnqn_read(void);
+
+extern int fabrics_discover(const char *desc, int argc, char **argv, bool connect);
+extern int fabrics_connect(const char *desc, int argc, char **argv);
+extern int fabrics_disconnect(const char *desc, int argc, char **argv);
+extern int fabrics_disconnect_all(const char *desc, int argc, char **argv);
+
+#endif
diff --git a/linux/lightnvm.h b/linux/lightnvm.h
new file mode 100644
index 0000000..f678ffb
--- /dev/null
+++ b/linux/lightnvm.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 CNEX Labs. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ */
+
+#ifndef _UAPI_LINUX_LIGHTNVM_H
+#define _UAPI_LINUX_LIGHTNVM_H
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <linux/ioctl.h>
+#else /* __KERNEL__ */
+#include <stdio.h>
+#include <sys/ioctl.h>
+#define DISK_NAME_LEN 32
+#endif /* __KERNEL__ */
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define NVM_TTYPE_NAME_MAX 48
+#define NVM_TTYPE_MAX 63
+#define NVM_MMTYPE_LEN 8
+
+#define NVM_CTRL_FILE "/dev/lightnvm/control"
+
+struct nvm_ioctl_info_tgt {
+ __u32 version[3];
+ __u32 reserved;
+ char tgtname[NVM_TTYPE_NAME_MAX];
+};
+
+struct nvm_ioctl_info {
+ __u32 version[3]; /* in/out - major, minor, patch */
+ __u16 tgtsize; /* number of targets */
+ __u16 reserved16; /* pad to 4K page */
+ __u32 reserved[12];
+ struct nvm_ioctl_info_tgt tgts[NVM_TTYPE_MAX];
+};
+
+enum {
+ NVM_DEVICE_ACTIVE = 1 << 0,
+};
+
+struct nvm_ioctl_device_info {
+ char devname[DISK_NAME_LEN];
+ char bmname[NVM_TTYPE_NAME_MAX];
+ __u32 bmversion[3];
+ __u32 flags;
+ __u32 reserved[8];
+};
+
+struct nvm_ioctl_get_devices {
+ __u32 nr_devices;
+ __u32 reserved[31];
+ struct nvm_ioctl_device_info info[31];
+};
+
+struct nvm_ioctl_create_simple {
+ __u32 lun_begin;
+ __u32 lun_end;
+};
+
+struct nvm_ioctl_create_extended {
+ __u16 lun_begin;
+ __u16 lun_end;
+ __u16 over_prov;
+ __u16 rsv;
+};
+
+enum {
+ NVM_CONFIG_TYPE_SIMPLE = 0,
+ NVM_CONFIG_TYPE_EXTENDED = 1,
+};
+
+struct nvm_ioctl_create_conf {
+ __u32 type;
+ union {
+ struct nvm_ioctl_create_simple s;
+ struct nvm_ioctl_create_extended e;
+ };
+};
+
+enum {
+ NVM_TARGET_FACTORY = 1 << 0, /* Init target in factory mode */
+};
+
+struct nvm_ioctl_create {
+ char dev[DISK_NAME_LEN]; /* open-channel SSD device */
+ char tgttype[NVM_TTYPE_NAME_MAX]; /* target type name */
+ char tgtname[DISK_NAME_LEN]; /* dev to expose target as */
+
+ __u32 flags;
+
+ struct nvm_ioctl_create_conf conf;
+};
+
+struct nvm_ioctl_remove {
+ char tgtname[DISK_NAME_LEN];
+
+ __u32 flags;
+};
+
+struct nvm_ioctl_dev_init {
+ char dev[DISK_NAME_LEN]; /* open-channel SSD device */
+ char mmtype[NVM_MMTYPE_LEN]; /* register to media manager */
+
+ __u32 flags;
+};
+
+enum {
+ NVM_FACTORY_ERASE_ONLY_USER = 1 << 0, /* erase only blocks used as
+ * host blks or grown blks */
+ NVM_FACTORY_RESET_HOST_BLKS = 1 << 1, /* remove host blk marks */
+ NVM_FACTORY_RESET_GRWN_BBLKS = 1 << 2, /* remove grown blk marks */
+ NVM_FACTORY_NR_BITS = 1 << 3, /* stops here */
+};
+
+struct nvm_ioctl_dev_factory {
+ char dev[DISK_NAME_LEN];
+
+ __u32 flags;
+};
+
+/* The ioctl type, 'L', 0x20 - 0x2F documented in ioctl-number.txt */
+enum {
+ /* top level cmds */
+ NVM_INFO_CMD = 0x20,
+ NVM_GET_DEVICES_CMD,
+
+ /* device level cmds */
+ NVM_DEV_CREATE_CMD,
+ NVM_DEV_REMOVE_CMD,
+
+ /* Init a device to support LightNVM media managers */
+ NVM_DEV_INIT_CMD,
+
+ /* Factory reset device */
+ NVM_DEV_FACTORY_CMD,
+};
+
+#define NVM_IOCTL 'L' /* 0x4c */
+
+#define NVM_INFO _IOWR(NVM_IOCTL, NVM_INFO_CMD, \
+ struct nvm_ioctl_info)
+#define NVM_GET_DEVICES _IOR(NVM_IOCTL, NVM_GET_DEVICES_CMD, \
+ struct nvm_ioctl_get_devices)
+#define NVM_DEV_CREATE _IOW(NVM_IOCTL, NVM_DEV_CREATE_CMD, \
+ struct nvm_ioctl_create)
+#define NVM_DEV_REMOVE _IOW(NVM_IOCTL, NVM_DEV_REMOVE_CMD, \
+ struct nvm_ioctl_remove)
+#define NVM_DEV_INIT _IOW(NVM_IOCTL, NVM_DEV_INIT_CMD, \
+ struct nvm_ioctl_dev_init)
+#define NVM_DEV_FACTORY _IOW(NVM_IOCTL, NVM_DEV_FACTORY_CMD, \
+ struct nvm_ioctl_dev_factory)
+
+#define NVM_VERSION_MAJOR 1
+#define NVM_VERSION_MINOR 0
+#define NVM_VERSION_PATCHLEVEL 0
+
+#endif
diff --git a/linux/nvme.h b/linux/nvme.h
new file mode 100644
index 0000000..f2c4fdb
--- /dev/null
+++ b/linux/nvme.h
@@ -0,0 +1,1418 @@
+/*
+ * 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 _LINUX_NVME_H
+#define _LINUX_NVME_H
+
+#include <linux/types.h>
+
+#ifdef LIBUUID
+#include <uuid/uuid.h>
+#else
+typedef struct {
+ uint8_t b[16];
+} uuid_t;
+#endif
+
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#else
+#define __force
+#endif
+
+static inline __le16 cpu_to_le16(uint16_t x)
+{
+ return (__force __le16)htole16(x);
+}
+static inline __le32 cpu_to_le32(uint32_t x)
+{
+ return (__force __le32)htole32(x);
+}
+static inline __le64 cpu_to_le64(uint64_t x)
+{
+ return (__force __le64)htole64(x);
+}
+
+static inline uint16_t le16_to_cpu(__le16 x)
+{
+ return le16toh((__force __u16)x);
+}
+static inline uint32_t le32_to_cpu(__le32 x)
+{
+ return le32toh((__force __u32)x);
+}
+static inline uint64_t le64_to_cpu(__le64 x)
+{
+ return le64toh((__force __u64)x);
+}
+
+/* NQN names in commands fields specified one size */
+#define NVMF_NQN_FIELD_LEN 256
+
+/* However the max length of a qualified name is another size */
+#define NVMF_NQN_SIZE 223
+
+#define NVMF_TRSVCID_SIZE 32
+#define NVMF_TRADDR_SIZE 256
+#define NVMF_TSAS_SIZE 256
+
+#define NVME_DISC_SUBSYS_NAME "nqn.2014-08.org.nvmexpress.discovery"
+
+#define NVME_RDMA_IP_PORT 4420
+
+#define NVME_NSID_ALL 0xffffffff
+
+enum nvme_subsys_type {
+ NVME_NQN_DISC = 1, /* Discovery type target subsystem */
+ NVME_NQN_NVME = 2, /* NVME type target subsystem */
+};
+
+/* Address Family codes for Discovery Log Page entry ADRFAM field */
+enum {
+ NVMF_ADDR_FAMILY_PCI = 0, /* PCIe */
+ NVMF_ADDR_FAMILY_IP4 = 1, /* IP4 */
+ NVMF_ADDR_FAMILY_IP6 = 2, /* IP6 */
+ NVMF_ADDR_FAMILY_IB = 3, /* InfiniBand */
+ NVMF_ADDR_FAMILY_FC = 4, /* Fibre Channel */
+ NVMF_ADDR_FAMILY_LOOP = 254, /* Reserved for host usage */
+ NVMF_ADDR_FAMILY_MAX,
+};
+
+/* Transport Type codes for Discovery Log Page entry TRTYPE field */
+enum {
+ NVMF_TRTYPE_RDMA = 1, /* RDMA */
+ NVMF_TRTYPE_FC = 2, /* Fibre Channel */
+ NVMF_TRTYPE_TCP = 3, /* TCP */
+ NVMF_TRTYPE_LOOP = 254, /* Reserved for host usage */
+ NVMF_TRTYPE_MAX,
+};
+
+/* Transport Requirements codes for Discovery Log Page entry TREQ field */
+enum {
+ NVMF_TREQ_NOT_SPECIFIED = 0, /* Not specified */
+ NVMF_TREQ_REQUIRED = 1, /* Required */
+ NVMF_TREQ_NOT_REQUIRED = 2, /* Not Required */
+ NVMF_TREQ_DISABLE_SQFLOW = (1 << 2), /* SQ flow control disable supported */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+ NVMF_RDMA_QPTYPE_CONNECTED = 1, /* Reliable Connected */
+ NVMF_RDMA_QPTYPE_DATAGRAM = 2, /* Reliable Datagram */
+};
+
+/* RDMA QP Service Type codes for Discovery Log Page entry TSAS
+ * RDMA_QPTYPE field
+ */
+enum {
+ NVMF_RDMA_PRTYPE_NOT_SPECIFIED = 1, /* No Provider Specified */
+ NVMF_RDMA_PRTYPE_IB = 2, /* InfiniBand */
+ NVMF_RDMA_PRTYPE_ROCE = 3, /* InfiniBand RoCE */
+ NVMF_RDMA_PRTYPE_ROCEV2 = 4, /* InfiniBand RoCEV2 */
+ NVMF_RDMA_PRTYPE_IWARP = 5, /* IWARP */
+};
+
+/* RDMA Connection Management Service Type codes for Discovery Log Page
+ * entry TSAS RDMA_CMS field
+ */
+enum {
+ NVMF_RDMA_CMS_RDMA_CM = 1, /* Sockets based endpoint addressing */
+};
+
+/* TCP port security type for Discovery Log Page entry TSAS
+ */
+enum {
+ NVMF_TCP_SECTYPE_NONE = 0, /* No Security */
+ NVMF_TCP_SECTYPE_TLS = 1, /* Transport Layer Security */
+};
+
+#define NVME_AQ_DEPTH 32
+#define NVME_NR_AEN_COMMANDS 1
+#define NVME_AQ_BLK_MQ_DEPTH (NVME_AQ_DEPTH - NVME_NR_AEN_COMMANDS)
+
+/*
+ * Subtract one to leave an empty queue entry for 'Full Queue' condition. See
+ * NVM-Express 1.2 specification, section 4.1.2.
+ */
+#define NVME_AQ_MQ_TAG_DEPTH (NVME_AQ_BLK_MQ_DEPTH - 1)
+
+enum {
+ NVME_REG_CAP = 0x0000, /* Controller Capabilities */
+ NVME_REG_VS = 0x0008, /* Version */
+ NVME_REG_INTMS = 0x000c, /* Interrupt Mask Set */
+ NVME_REG_INTMC = 0x0010, /* Interrupt Mask Clear */
+ NVME_REG_CC = 0x0014, /* Controller Configuration */
+ NVME_REG_CSTS = 0x001c, /* Controller Status */
+ NVME_REG_NSSR = 0x0020, /* NVM Subsystem Reset */
+ NVME_REG_AQA = 0x0024, /* Admin Queue Attributes */
+ NVME_REG_ASQ = 0x0028, /* Admin SQ Base Address */
+ NVME_REG_ACQ = 0x0030, /* Admin CQ Base Address */
+ NVME_REG_CMBLOC = 0x0038, /* Controller Memory Buffer Location */
+ NVME_REG_CMBSZ = 0x003c, /* Controller Memory Buffer Size */
+ NVME_REG_BPINFO = 0x0040, /* Boot Partition Information */
+ NVME_REG_BPRSEL = 0x0044, /* Boot Partition Read Select */
+ NVME_REG_BPMBL = 0x0048, /* Boot Partition Memory Buffer Location */
+ NVME_REG_CMBMSC = 0x0050, /* Controller Memory Buffer Memory Space Control */
+ NVME_REG_CMBSTS = 0x0058, /* Controller Memory Buffer Status */
+ NVME_REG_PMRCAP = 0x0e00, /* Persistent Memory Capabilities */
+ NVME_REG_PMRCTL = 0x0e04, /* Persistent Memory Region Control */
+ NVME_REG_PMRSTS = 0x0e08, /* Persistent Memory Region Status */
+ NVME_REG_PMREBS = 0x0e0c, /* Persistent Memory Region Elasticity Buffer Size */
+ NVME_REG_PMRSWTP= 0x0e10, /* Persistent Memory Region Sustained Write Throughput */
+ NVME_REG_PMRMSC = 0x0e14, /* Persistent Memory Region Controller Memory Space Control */
+ NVME_REG_DBS = 0x1000, /* SQ 0 Tail Doorbell */
+};
+
+#define NVME_CAP_MQES(cap) ((cap) & 0xffff)
+#define NVME_CAP_TIMEOUT(cap) (((cap) >> 24) & 0xff)
+#define NVME_CAP_STRIDE(cap) (((cap) >> 32) & 0xf)
+#define NVME_CAP_NSSRC(cap) (((cap) >> 36) & 0x1)
+#define NVME_CAP_MPSMIN(cap) (((cap) >> 48) & 0xf)
+#define NVME_CAP_MPSMAX(cap) (((cap) >> 52) & 0xf)
+
+#define NVME_CMB_BIR(cmbloc) ((cmbloc) & 0x7)
+#define NVME_CMB_OFST(cmbloc) (((cmbloc) >> 12) & 0xfffff)
+#define NVME_CMB_SZ(cmbsz) (((cmbsz) >> 12) & 0xfffff)
+#define NVME_CMB_SZU(cmbsz) (((cmbsz) >> 8) & 0xf)
+
+#define NVME_CMB_WDS(cmbsz) ((cmbsz) & 0x10)
+#define NVME_CMB_RDS(cmbsz) ((cmbsz) & 0x8)
+#define NVME_CMB_LISTS(cmbsz) ((cmbsz) & 0x4)
+#define NVME_CMB_CQS(cmbsz) ((cmbsz) & 0x2)
+#define NVME_CMB_SQS(cmbsz) ((cmbsz) & 0x1)
+
+/*
+ * Submission and Completion Queue Entry Sizes for the NVM command set.
+ * (In bytes and specified as a power of two (2^n)).
+ */
+#define NVME_NVM_IOSQES 6
+#define NVME_NVM_IOCQES 4
+
+enum {
+ NVME_CC_ENABLE = 1 << 0,
+ NVME_CC_CSS_NVM = 0 << 4,
+ NVME_CC_EN_SHIFT = 0,
+ NVME_CC_CSS_SHIFT = 4,
+ NVME_CC_MPS_SHIFT = 7,
+ NVME_CC_AMS_SHIFT = 11,
+ NVME_CC_SHN_SHIFT = 14,
+ NVME_CC_IOSQES_SHIFT = 16,
+ NVME_CC_IOCQES_SHIFT = 20,
+ NVME_CC_AMS_RR = 0 << NVME_CC_AMS_SHIFT,
+ NVME_CC_AMS_WRRU = 1 << NVME_CC_AMS_SHIFT,
+ NVME_CC_AMS_VS = 7 << NVME_CC_AMS_SHIFT,
+ NVME_CC_SHN_NONE = 0 << NVME_CC_SHN_SHIFT,
+ NVME_CC_SHN_NORMAL = 1 << NVME_CC_SHN_SHIFT,
+ NVME_CC_SHN_ABRUPT = 2 << NVME_CC_SHN_SHIFT,
+ NVME_CC_SHN_MASK = 3 << NVME_CC_SHN_SHIFT,
+ NVME_CC_IOSQES = NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT,
+ NVME_CC_IOCQES = NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT,
+ NVME_CSTS_RDY = 1 << 0,
+ NVME_CSTS_CFS = 1 << 1,
+ NVME_CSTS_NSSRO = 1 << 4,
+ NVME_CSTS_PP = 1 << 5,
+ NVME_CSTS_SHST_NORMAL = 0 << 2,
+ NVME_CSTS_SHST_OCCUR = 1 << 2,
+ NVME_CSTS_SHST_CMPLT = 2 << 2,
+ NVME_CSTS_SHST_MASK = 3 << 2,
+};
+
+struct nvme_id_power_state {
+ __le16 max_power; /* centiwatts */
+ __u8 rsvd2;
+ __u8 flags;
+ __le32 entry_lat; /* microseconds */
+ __le32 exit_lat; /* microseconds */
+ __u8 read_tput;
+ __u8 read_lat;
+ __u8 write_tput;
+ __u8 write_lat;
+ __le16 idle_power;
+ __u8 idle_scale;
+ __u8 rsvd19;
+ __le16 active_power;
+ __u8 active_work_scale;
+ __u8 rsvd23[9];
+};
+
+/* idle and active power scales occupy the last 2 bits of the field */
+#define POWER_SCALE(s) ((s) >> 6)
+
+enum {
+ NVME_PS_FLAGS_MAX_POWER_SCALE = 1 << 0,
+ NVME_PS_FLAGS_NON_OP_STATE = 1 << 1,
+};
+
+struct nvme_id_ctrl {
+ __le16 vid;
+ __le16 ssvid;
+ char sn[20];
+ char mn[40];
+ char fr[8];
+ __u8 rab;
+ __u8 ieee[3];
+ __u8 cmic;
+ __u8 mdts;
+ __le16 cntlid;
+ __le32 ver;
+ __le32 rtd3r;
+ __le32 rtd3e;
+ __le32 oaes;
+ __le32 ctratt;
+ __le16 rrls;
+ __u8 rsvd102[9];
+ __u8 cntrltype;
+ char fguid[16];
+ __le16 crdt1;
+ __le16 crdt2;
+ __le16 crdt3;
+ __u8 rsvd134[122];
+ __le16 oacs;
+ __u8 acl;
+ __u8 aerl;
+ __u8 frmw;
+ __u8 lpa;
+ __u8 elpe;
+ __u8 npss;
+ __u8 avscc;
+ __u8 apsta;
+ __le16 wctemp;
+ __le16 cctemp;
+ __le16 mtfa;
+ __le32 hmpre;
+ __le32 hmmin;
+ __u8 tnvmcap[16];
+ __u8 unvmcap[16];
+ __le32 rpmbs;
+ __le16 edstt;
+ __u8 dsto;
+ __u8 fwug;
+ __le16 kas;
+ __le16 hctma;
+ __le16 mntmt;
+ __le16 mxtmt;
+ __le32 sanicap;
+ __le32 hmminds;
+ __le16 hmmaxd;
+ __le16 nsetidmax;
+ __le16 endgidmax;
+ __u8 anatt;
+ __u8 anacap;
+ __le32 anagrpmax;
+ __le32 nanagrpid;
+ __le32 pels;
+ __u8 rsvd356[156];
+ __u8 sqes;
+ __u8 cqes;
+ __le16 maxcmd;
+ __le32 nn;
+ __le16 oncs;
+ __le16 fuses;
+ __u8 fna;
+ __u8 vwc;
+ __le16 awun;
+ __le16 awupf;
+ __u8 nvscc;
+ __u8 nwpc;
+ __le16 acwu;
+ __u8 rsvd534[2];
+ __le32 sgls;
+ __le32 mnan;
+ __u8 rsvd544[224];
+ char subnqn[256];
+ __u8 rsvd1024[768];
+ __le32 ioccsz;
+ __le32 iorcsz;
+ __le16 icdoff;
+ __u8 ctrattr;
+ __u8 msdbd;
+ __u8 rsvd1804[244];
+ struct nvme_id_power_state psd[32];
+ __u8 vs[1024];
+};
+
+enum {
+ NVME_CTRL_ONCS_COMPARE = 1 << 0,
+ NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 1 << 1,
+ NVME_CTRL_ONCS_DSM = 1 << 2,
+ NVME_CTRL_ONCS_WRITE_ZEROES = 1 << 3,
+ NVME_CTRL_ONCS_TIMESTAMP = 1 << 6,
+ NVME_CTRL_VWC_PRESENT = 1 << 0,
+ NVME_CTRL_OACS_SEC_SUPP = 1 << 0,
+ NVME_CTRL_OACS_DIRECTIVES = 1 << 5,
+ NVME_CTRL_OACS_DBBUF_SUPP = 1 << 8,
+ NVME_CTRL_LPA_CMD_EFFECTS_LOG = 1 << 1,
+ NVME_CTRL_CTRATT_128_ID = 1 << 0,
+ NVME_CTRL_CTRATT_NON_OP_PSP = 1 << 1,
+ NVME_CTRL_CTRATT_NVM_SETS = 1 << 2,
+ NVME_CTRL_CTRATT_READ_RECV_LVLS = 1 << 3,
+ NVME_CTRL_CTRATT_ENDURANCE_GROUPS = 1 << 4,
+ NVME_CTRL_CTRATT_PREDICTABLE_LAT = 1 << 5,
+ NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY = 1 << 7,
+ NVME_CTRL_CTRATT_UUID_LIST = 1 << 9,
+};
+
+struct nvme_lbaf {
+ __le16 ms;
+ __u8 ds;
+ __u8 rp;
+};
+
+struct nvme_id_ns {
+ __le64 nsze;
+ __le64 ncap;
+ __le64 nuse;
+ __u8 nsfeat;
+ __u8 nlbaf;
+ __u8 flbas;
+ __u8 mc;
+ __u8 dpc;
+ __u8 dps;
+ __u8 nmic;
+ __u8 rescap;
+ __u8 fpi;
+ __u8 dlfeat;
+ __le16 nawun;
+ __le16 nawupf;
+ __le16 nacwu;
+ __le16 nabsn;
+ __le16 nabo;
+ __le16 nabspf;
+ __le16 noiob;
+ __u8 nvmcap[16];
+ __le16 npwg;
+ __le16 npwa;
+ __le16 npdg;
+ __le16 npda;
+ __le16 nows;
+ __u8 rsvd74[18];
+ __le32 anagrpid;
+ __u8 rsvd96[3];
+ __u8 nsattr;
+ __le16 nvmsetid;
+ __le16 endgid;
+ __u8 nguid[16];
+ __u8 eui64[8];
+ struct nvme_lbaf lbaf[16];
+ __u8 rsvd192[192];
+ __u8 vs[3712];
+};
+
+enum {
+ NVME_ID_CNS_NS = 0x00,
+ NVME_ID_CNS_CTRL = 0x01,
+ NVME_ID_CNS_NS_ACTIVE_LIST = 0x02,
+ NVME_ID_CNS_NS_DESC_LIST = 0x03,
+ NVME_ID_CNS_NVMSET_LIST = 0x04,
+ NVME_ID_CNS_NS_PRESENT_LIST = 0x10,
+ NVME_ID_CNS_NS_PRESENT = 0x11,
+ NVME_ID_CNS_CTRL_NS_LIST = 0x12,
+ NVME_ID_CNS_CTRL_LIST = 0x13,
+ NVME_ID_CNS_SCNDRY_CTRL_LIST = 0x15,
+ NVME_ID_CNS_NS_GRANULARITY = 0x16,
+ NVME_ID_CNS_UUID_LIST = 0x17,
+};
+
+enum {
+ NVME_DIR_IDENTIFY = 0x00,
+ NVME_DIR_STREAMS = 0x01,
+ NVME_DIR_SND_ID_OP_ENABLE = 0x01,
+ NVME_DIR_SND_ST_OP_REL_ID = 0x01,
+ NVME_DIR_SND_ST_OP_REL_RSC = 0x02,
+ NVME_DIR_RCV_ID_OP_PARAM = 0x01,
+ NVME_DIR_RCV_ST_OP_PARAM = 0x01,
+ NVME_DIR_RCV_ST_OP_STATUS = 0x02,
+ NVME_DIR_RCV_ST_OP_RESOURCE = 0x03,
+ NVME_DIR_ENDIR = 0x01,
+};
+
+enum {
+ NVME_NS_FEAT_THIN = 1 << 0,
+ NVME_NS_FLBAS_LBA_MASK = 0xf,
+ NVME_NS_FLBAS_META_EXT = 0x10,
+ NVME_LBAF_RP_BEST = 0,
+ NVME_LBAF_RP_BETTER = 1,
+ NVME_LBAF_RP_GOOD = 2,
+ NVME_LBAF_RP_DEGRADED = 3,
+ NVME_NS_DPC_PI_LAST = 1 << 4,
+ NVME_NS_DPC_PI_FIRST = 1 << 3,
+ NVME_NS_DPC_PI_TYPE3 = 1 << 2,
+ NVME_NS_DPC_PI_TYPE2 = 1 << 1,
+ NVME_NS_DPC_PI_TYPE1 = 1 << 0,
+ NVME_NS_DPS_PI_FIRST = 1 << 3,
+ NVME_NS_DPS_PI_MASK = 0x7,
+ NVME_NS_DPS_PI_TYPE1 = 1,
+ NVME_NS_DPS_PI_TYPE2 = 2,
+ NVME_NS_DPS_PI_TYPE3 = 3,
+};
+
+struct nvme_ns_id_desc {
+ __u8 nidt;
+ __u8 nidl;
+ __le16 reserved;
+};
+
+#define NVME_NIDT_EUI64_LEN 8
+#define NVME_NIDT_NGUID_LEN 16
+#define NVME_NIDT_UUID_LEN 16
+
+enum {
+ NVME_NIDT_EUI64 = 0x01,
+ NVME_NIDT_NGUID = 0x02,
+ NVME_NIDT_UUID = 0x03,
+};
+
+#define NVME_MAX_NVMSET 31
+
+struct nvme_nvmset_attr_entry {
+ __le16 id;
+ __le16 endurance_group_id;
+ __u8 rsvd4[4];
+ __le32 random_4k_read_typical;
+ __le32 opt_write_size;
+ __u8 total_nvmset_cap[16];
+ __u8 unalloc_nvmset_cap[16];
+ __u8 rsvd48[80];
+};
+
+struct nvme_id_nvmset {
+ __u8 nid;
+ __u8 rsvd1[127];
+ struct nvme_nvmset_attr_entry ent[NVME_MAX_NVMSET];
+};
+
+struct nvme_id_ns_granularity_list_entry {
+ __le64 namespace_size_granularity;
+ __le64 namespace_capacity_granularity;
+};
+
+struct nvme_id_ns_granularity_list {
+ __le32 attributes;
+ __u8 num_descriptors;
+ __u8 rsvd[27];
+ struct nvme_id_ns_granularity_list_entry entry[16];
+};
+
+#define NVME_MAX_UUID_ENTRIES 128
+struct nvme_id_uuid_list_entry {
+ __u8 header;
+ __u8 rsvd1[15];
+ __u8 uuid[16];
+};
+
+struct nvme_id_uuid_list {
+ struct nvme_id_uuid_list_entry entry[NVME_MAX_UUID_ENTRIES];
+};
+
+/**
+ * struct nvme_telemetry_log_page_hdr - structure for telemetry log page
+ * @lpi: Log page identifier
+ * @iee_oui: IEEE OUI Identifier
+ * @dalb1: Data area 1 last block
+ * @dalb2: Data area 2 last block
+ * @dalb3: Data area 3 last block
+ * @ctrlavail: Controller initiated data available
+ * @ctrldgn: Controller initiated telemetry Data Generation Number
+ * @rsnident: Reason Identifier
+ * @telemetry_dataarea: Contains telemetry data block
+ *
+ * This structure can be used for both telemetry host-initiated log page
+ * and controller-initiated log page.
+ */
+struct nvme_telemetry_log_page_hdr {
+ __u8 lpi;
+ __u8 rsvd[4];
+ __u8 iee_oui[3];
+ __le16 dalb1;
+ __le16 dalb2;
+ __le16 dalb3;
+ __u8 rsvd1[368];
+ __u8 ctrlavail;
+ __u8 ctrldgn;
+ __u8 rsnident[128];
+ __u8 telemetry_dataarea[0];
+};
+
+struct nvme_endurance_group_log {
+ __u8 critical_warning;
+ __u8 rsvd1[2];
+ __u8 avl_spare;
+ __u8 avl_spare_threshold;
+ __u8 percent_used;
+ __u8 rsvd6[26];
+ __u8 endurance_estimate[16];
+ __u8 data_units_read[16];
+ __u8 data_units_written[16];
+ __u8 media_units_written[16];
+ __u8 host_read_cmds[16];
+ __u8 host_write_cmds[16];
+ __u8 media_data_integrity_err[16];
+ __u8 num_err_info_log_entries[16];
+ __u8 rsvd160[352];
+};
+
+struct nvme_smart_log {
+ __u8 critical_warning;
+ __u8 temperature[2];
+ __u8 avail_spare;
+ __u8 spare_thresh;
+ __u8 percent_used;
+ __u8 endu_grp_crit_warn_sumry;
+ __u8 rsvd7[25];
+ __u8 data_units_read[16];
+ __u8 data_units_written[16];
+ __u8 host_reads[16];
+ __u8 host_writes[16];
+ __u8 ctrl_busy_time[16];
+ __u8 power_cycles[16];
+ __u8 power_on_hours[16];
+ __u8 unsafe_shutdowns[16];
+ __u8 media_errors[16];
+ __u8 num_err_log_entries[16];
+ __le32 warning_temp_time;
+ __le32 critical_comp_time;
+ __le16 temp_sensor[8];
+ __le32 thm_temp1_trans_count;
+ __le32 thm_temp2_trans_count;
+ __le32 thm_temp1_total_time;
+ __le32 thm_temp2_total_time;
+ __u8 rsvd232[280];
+};
+
+struct nvme_self_test_res {
+ __u8 dsts;
+ __u8 seg;
+ __u8 vdi;
+ __u8 rsvd3;
+ __le64 poh;
+ __le32 nsid;
+ __le64 flba;
+ __u8 sct;
+ __u8 sc;
+ __u8 vs[2];
+} __attribute__((packed));
+
+enum {
+ NVME_ST_CODE_SHIFT = 4,
+ NVME_ST_CODE_SHORT_OP = 0x1,
+ NVME_ST_CODE_EXT_OP = 0x2,
+ NVME_ST_CODE_VS = 0xe,
+ NVME_ST_RES_MASK = 0xf,
+ NVME_ST_RES_NO_ERR = 0x0,
+ NVME_ST_RES_ABORTED = 0x1,
+ NVME_ST_RES_CLR = 0x2,
+ NVME_ST_RES_NS_REMOVED = 0x3,
+ NVME_ST_RES_ABORTED_FORMAT = 0x4,
+ NVME_ST_RES_FATAL_ERR = 0x5,
+ NVME_ST_RES_UNKNOWN_SEG_FAIL = 0x6,
+ NVME_ST_RES_KNOWN_SEG_FAIL = 0x7,
+ NVME_ST_RES_ABORTED_UNKNOWN = 0x8,
+ NVME_ST_RES_ABORTED_SANITIZE = 0x9,
+ NVME_ST_RES_NOT_USED = 0xf,
+ NVME_ST_VALID_NSID = 1 << 0,
+ NVME_ST_VALID_FLBA = 1 << 1,
+ NVME_ST_VALID_SCT = 1 << 2,
+ NVME_ST_VALID_SC = 1 << 3,
+ NVME_ST_REPORTS = 20,
+};
+
+struct nvme_self_test_log {
+ __u8 crnt_dev_selftest_oprn;
+ __u8 crnt_dev_selftest_compln;
+ __u8 rsvd[2];
+ struct nvme_self_test_res result[20];
+} __attribute__((packed));
+
+struct nvme_fw_slot_info_log {
+ __u8 afi;
+ __u8 rsvd1[7];
+ __le64 frs[7];
+ __u8 rsvd64[448];
+};
+
+struct nvme_lba_status_desc {
+ __u64 dslba;
+ __u32 nlb;
+ __u8 rsvd_12;
+ __u8 status;
+ __u8 rsvd_15_14[2];
+};
+
+struct nvme_lba_status {
+ __u32 nlsd;
+ __u8 cmpc;
+ __u8 rsvd_7_5[3];
+ struct nvme_lba_status_desc descs[0];
+};
+
+/* NVMe Namespace Write Protect State */
+enum {
+ NVME_NS_NO_WRITE_PROTECT = 0,
+ NVME_NS_WRITE_PROTECT,
+ NVME_NS_WRITE_PROTECT_POWER_CYCLE,
+ NVME_NS_WRITE_PROTECT_PERMANENT,
+};
+
+#define NVME_MAX_CHANGED_NAMESPACES 1024
+
+struct nvme_changed_ns_list_log {
+ __le32 log[NVME_MAX_CHANGED_NAMESPACES];
+};
+
+enum {
+ NVME_CMD_EFFECTS_CSUPP = 1 << 0,
+ NVME_CMD_EFFECTS_LBCC = 1 << 1,
+ NVME_CMD_EFFECTS_NCC = 1 << 2,
+ NVME_CMD_EFFECTS_NIC = 1 << 3,
+ NVME_CMD_EFFECTS_CCC = 1 << 4,
+ NVME_CMD_EFFECTS_CSE_MASK = 3 << 16,
+ NVME_CMD_EFFECTS_UUID_SEL = 1 << 19,
+};
+
+struct nvme_effects_log {
+ __le32 acs[256];
+ __le32 iocs[256];
+ __u8 resv[2048];
+};
+
+enum nvme_ana_state {
+ NVME_ANA_OPTIMIZED = 0x01,
+ NVME_ANA_NONOPTIMIZED = 0x02,
+ NVME_ANA_INACCESSIBLE = 0x03,
+ NVME_ANA_PERSISTENT_LOSS = 0x04,
+ NVME_ANA_CHANGE = 0x0f,
+};
+
+struct nvme_ana_group_desc {
+ __le32 grpid;
+ __le32 nnsids;
+ __le64 chgcnt;
+ __u8 state;
+ __u8 rsvd17[15];
+ __le32 nsids[];
+};
+
+/* flag for the log specific field of the ANA log */
+#define NVME_ANA_LOG_RGO (1 << 0)
+
+struct nvme_ana_rsp_hdr {
+ __le64 chgcnt;
+ __le16 ngrps;
+ __le16 rsvd10[3];
+};
+
+enum {
+ NVME_SMART_CRIT_SPARE = 1 << 0,
+ NVME_SMART_CRIT_TEMPERATURE = 1 << 1,
+ NVME_SMART_CRIT_RELIABILITY = 1 << 2,
+ NVME_SMART_CRIT_MEDIA = 1 << 3,
+ NVME_SMART_CRIT_VOLATILE_MEMORY = 1 << 4,
+};
+
+enum {
+ NVME_AER_ERROR = 0,
+ NVME_AER_SMART = 1,
+ NVME_AER_CSS = 6,
+ NVME_AER_VS = 7,
+};
+
+struct nvme_lba_range_type {
+ __u8 type;
+ __u8 attributes;
+ __u8 rsvd2[14];
+ __u64 slba;
+ __u64 nlb;
+ __u8 guid[16];
+ __u8 rsvd48[16];
+};
+
+enum {
+ NVME_LBART_TYPE_FS = 0x01,
+ NVME_LBART_TYPE_RAID = 0x02,
+ NVME_LBART_TYPE_CACHE = 0x03,
+ NVME_LBART_TYPE_SWAP = 0x04,
+
+ NVME_LBART_ATTRIB_TEMP = 1 << 0,
+ NVME_LBART_ATTRIB_HIDE = 1 << 1,
+};
+
+/* Predictable Latency Mode - Deterministic Threshold Configuration Data */
+struct nvme_plm_config {
+ __le16 enable_event;
+ __u8 rsvd2[30];
+ __le64 dtwin_reads_thresh;
+ __le64 dtwin_writes_thresh;
+ __le64 dtwin_time_thresh;
+ __u8 rsvd56[456];
+};
+
+struct nvme_reservation_status {
+ __le32 gen;
+ __u8 rtype;
+ __u8 regctl[2];
+ __u8 resv5[2];
+ __u8 ptpls;
+ __u8 resv10[13];
+ struct {
+ __le16 cntlid;
+ __u8 rcsts;
+ __u8 resv3[5];
+ __le64 hostid;
+ __le64 rkey;
+ } regctl_ds[];
+};
+
+struct nvme_reservation_status_ext {
+ __le32 gen;
+ __u8 rtype;
+ __u8 regctl[2];
+ __u8 resv5[2];
+ __u8 ptpls;
+ __u8 resv10[14];
+ __u8 resv24[40];
+ struct {
+ __le16 cntlid;
+ __u8 rcsts;
+ __u8 resv3[5];
+ __le64 rkey;
+ __u8 hostid[16];
+ __u8 resv32[32];
+ } regctl_eds[];
+};
+
+enum nvme_async_event_type {
+ NVME_AER_TYPE_ERROR = 0,
+ NVME_AER_TYPE_SMART = 1,
+ NVME_AER_TYPE_NOTICE = 2,
+};
+
+/* I/O commands */
+
+enum nvme_opcode {
+ nvme_cmd_flush = 0x00,
+ nvme_cmd_write = 0x01,
+ nvme_cmd_read = 0x02,
+ nvme_cmd_write_uncor = 0x04,
+ nvme_cmd_compare = 0x05,
+ nvme_cmd_write_zeroes = 0x08,
+ nvme_cmd_dsm = 0x09,
+ nvme_cmd_verify = 0x0c,
+ nvme_cmd_resv_register = 0x0d,
+ nvme_cmd_resv_report = 0x0e,
+ nvme_cmd_resv_acquire = 0x11,
+ nvme_cmd_resv_release = 0x15,
+};
+
+/*
+ * Descriptor subtype - lower 4 bits of nvme_(keyed_)sgl_desc identifier
+ *
+ * @NVME_SGL_FMT_ADDRESS: absolute address of the data block
+ * @NVME_SGL_FMT_OFFSET: relative offset of the in-capsule data block
+ * @NVME_SGL_FMT_TRANSPORT_A: transport defined format, value 0xA
+ * @NVME_SGL_FMT_INVALIDATE: RDMA transport specific remote invalidation
+ * request subtype
+ */
+enum {
+ NVME_SGL_FMT_ADDRESS = 0x00,
+ NVME_SGL_FMT_OFFSET = 0x01,
+ NVME_SGL_FMT_TRANSPORT_A = 0x0A,
+ NVME_SGL_FMT_INVALIDATE = 0x0f,
+};
+
+/*
+ * Descriptor type - upper 4 bits of nvme_(keyed_)sgl_desc identifier
+ *
+ * For struct nvme_sgl_desc:
+ * @NVME_SGL_FMT_DATA_DESC: data block descriptor
+ * @NVME_SGL_FMT_SEG_DESC: sgl segment descriptor
+ * @NVME_SGL_FMT_LAST_SEG_DESC: last sgl segment descriptor
+ *
+ * For struct nvme_keyed_sgl_desc:
+ * @NVME_KEY_SGL_FMT_DATA_DESC: keyed data block descriptor
+ *
+ * Transport-specific SGL types:
+ * @NVME_TRANSPORT_SGL_DATA_DESC: Transport SGL data dlock descriptor
+ */
+enum {
+ NVME_SGL_FMT_DATA_DESC = 0x00,
+ NVME_SGL_FMT_SEG_DESC = 0x02,
+ NVME_SGL_FMT_LAST_SEG_DESC = 0x03,
+ NVME_KEY_SGL_FMT_DATA_DESC = 0x04,
+ NVME_TRANSPORT_SGL_DATA_DESC = 0x05,
+};
+
+struct nvme_sgl_desc {
+ __le64 addr;
+ __le32 length;
+ __u8 rsvd[3];
+ __u8 type;
+};
+
+struct nvme_keyed_sgl_desc {
+ __le64 addr;
+ __u8 length[3];
+ __u8 key[4];
+ __u8 type;
+};
+
+union nvme_data_ptr {
+ struct {
+ __le64 prp1;
+ __le64 prp2;
+ };
+ struct nvme_sgl_desc sgl;
+ struct nvme_keyed_sgl_desc ksgl;
+};
+
+/*
+ * Lowest two bits of our flags field (FUSE field in the spec):
+ *
+ * @NVME_CMD_FUSE_FIRST: Fused Operation, first command
+ * @NVME_CMD_FUSE_SECOND: Fused Operation, second command
+ *
+ * Highest two bits in our flags field (PSDT field in the spec):
+ *
+ * @NVME_CMD_PSDT_SGL_METABUF: Use SGLS for this transfer,
+ * If used, MPTR contains addr of single physical buffer (byte aligned).
+ * @NVME_CMD_PSDT_SGL_METASEG: Use SGLS for this transfer,
+ * If used, MPTR contains an address of an SGL segment containing
+ * exactly 1 SGL descriptor (qword aligned).
+ */
+enum {
+ NVME_CMD_FUSE_FIRST = (1 << 0),
+ NVME_CMD_FUSE_SECOND = (1 << 1),
+
+ NVME_CMD_SGL_METABUF = (1 << 6),
+ NVME_CMD_SGL_METASEG = (1 << 7),
+ NVME_CMD_SGL_ALL = NVME_CMD_SGL_METABUF | NVME_CMD_SGL_METASEG,
+};
+
+enum {
+ NVME_RW_LR = 1 << 15,
+ NVME_RW_FUA = 1 << 14,
+ NVME_RW_DEAC = 1 << 9,
+ NVME_RW_DSM_FREQ_UNSPEC = 0,
+ NVME_RW_DSM_FREQ_TYPICAL = 1,
+ NVME_RW_DSM_FREQ_RARE = 2,
+ NVME_RW_DSM_FREQ_READS = 3,
+ NVME_RW_DSM_FREQ_WRITES = 4,
+ NVME_RW_DSM_FREQ_RW = 5,
+ NVME_RW_DSM_FREQ_ONCE = 6,
+ NVME_RW_DSM_FREQ_PREFETCH = 7,
+ NVME_RW_DSM_FREQ_TEMP = 8,
+ NVME_RW_DSM_LATENCY_NONE = 0 << 4,
+ NVME_RW_DSM_LATENCY_IDLE = 1 << 4,
+ NVME_RW_DSM_LATENCY_NORM = 2 << 4,
+ NVME_RW_DSM_LATENCY_LOW = 3 << 4,
+ NVME_RW_DSM_SEQ_REQ = 1 << 6,
+ NVME_RW_DSM_COMPRESSED = 1 << 7,
+ NVME_RW_PRINFO_PRCHK_REF = 1 << 10,
+ NVME_RW_PRINFO_PRCHK_APP = 1 << 11,
+ NVME_RW_PRINFO_PRCHK_GUARD = 1 << 12,
+ NVME_RW_PRINFO_PRACT = 1 << 13,
+ NVME_RW_DTYPE_STREAMS = 1 << 4,
+};
+
+enum {
+ NVME_DSMGMT_IDR = 1 << 0,
+ NVME_DSMGMT_IDW = 1 << 1,
+ NVME_DSMGMT_AD = 1 << 2,
+};
+
+#define NVME_DSM_MAX_RANGES 256
+
+struct nvme_dsm_range {
+ __le32 cattr;
+ __le32 nlb;
+ __le64 slba;
+};
+
+/* Features */
+struct nvme_feat_auto_pst {
+ __le64 entries[32];
+};
+
+enum {
+ NVME_HOST_MEM_ENABLE = (1 << 0),
+ NVME_HOST_MEM_RETURN = (1 << 1),
+};
+
+/* Admin commands */
+
+enum nvme_admin_opcode {
+ nvme_admin_delete_sq = 0x00,
+ nvme_admin_create_sq = 0x01,
+ nvme_admin_get_log_page = 0x02,
+ nvme_admin_delete_cq = 0x04,
+ nvme_admin_create_cq = 0x05,
+ nvme_admin_identify = 0x06,
+ nvme_admin_abort_cmd = 0x08,
+ nvme_admin_set_features = 0x09,
+ nvme_admin_get_features = 0x0a,
+ nvme_admin_async_event = 0x0c,
+ nvme_admin_ns_mgmt = 0x0d,
+ nvme_admin_activate_fw = 0x10,
+ nvme_admin_download_fw = 0x11,
+ nvme_admin_dev_self_test = 0x14,
+ nvme_admin_ns_attach = 0x15,
+ nvme_admin_keep_alive = 0x18,
+ nvme_admin_directive_send = 0x19,
+ nvme_admin_directive_recv = 0x1a,
+ nvme_admin_virtual_mgmt = 0x1c,
+ nvme_admin_nvme_mi_send = 0x1d,
+ nvme_admin_nvme_mi_recv = 0x1e,
+ nvme_admin_dbbuf = 0x7C,
+ nvme_admin_format_nvm = 0x80,
+ nvme_admin_security_send = 0x81,
+ nvme_admin_security_recv = 0x82,
+ nvme_admin_sanitize_nvm = 0x84,
+ nvme_admin_get_lba_status = 0x86,
+};
+
+enum {
+ NVME_QUEUE_PHYS_CONTIG = (1 << 0),
+ NVME_CQ_IRQ_ENABLED = (1 << 1),
+ NVME_SQ_PRIO_URGENT = (0 << 1),
+ NVME_SQ_PRIO_HIGH = (1 << 1),
+ NVME_SQ_PRIO_MEDIUM = (2 << 1),
+ NVME_SQ_PRIO_LOW = (3 << 1),
+ NVME_FEAT_ARBITRATION = 0x01,
+ NVME_FEAT_POWER_MGMT = 0x02,
+ NVME_FEAT_LBA_RANGE = 0x03,
+ NVME_FEAT_TEMP_THRESH = 0x04,
+ NVME_FEAT_ERR_RECOVERY = 0x05,
+ NVME_FEAT_VOLATILE_WC = 0x06,
+ NVME_FEAT_NUM_QUEUES = 0x07,
+ NVME_FEAT_IRQ_COALESCE = 0x08,
+ NVME_FEAT_IRQ_CONFIG = 0x09,
+ NVME_FEAT_WRITE_ATOMIC = 0x0a,
+ NVME_FEAT_ASYNC_EVENT = 0x0b,
+ NVME_FEAT_AUTO_PST = 0x0c,
+ NVME_FEAT_HOST_MEM_BUF = 0x0d,
+ NVME_FEAT_TIMESTAMP = 0x0e,
+ NVME_FEAT_KATO = 0x0f,
+ NVME_FEAT_HCTM = 0X10,
+ NVME_FEAT_NOPSC = 0X11,
+ NVME_FEAT_RRL = 0x12,
+ NVME_FEAT_PLM_CONFIG = 0x13,
+ NVME_FEAT_PLM_WINDOW = 0x14,
+ NVME_FEAT_HOST_BEHAVIOR = 0x16,
+ NVME_FEAT_SANITIZE = 0x17,
+ NVME_FEAT_SW_PROGRESS = 0x80,
+ NVME_FEAT_HOST_ID = 0x81,
+ NVME_FEAT_RESV_MASK = 0x82,
+ NVME_FEAT_RESV_PERSIST = 0x83,
+ NVME_FEAT_WRITE_PROTECT = 0x84,
+ NVME_LOG_ERROR = 0x01,
+ NVME_LOG_SMART = 0x02,
+ NVME_LOG_FW_SLOT = 0x03,
+ NVME_LOG_CHANGED_NS = 0x04,
+ NVME_LOG_CMD_EFFECTS = 0x05,
+ NVME_LOG_DEVICE_SELF_TEST = 0x06,
+ NVME_LOG_TELEMETRY_HOST = 0x07,
+ NVME_LOG_TELEMETRY_CTRL = 0x08,
+ NVME_LOG_ENDURANCE_GROUP = 0x09,
+ NVME_LOG_ANA = 0x0c,
+ NVME_LOG_DISC = 0x70,
+ NVME_LOG_RESERVATION = 0x80,
+ NVME_LOG_SANITIZE = 0x81,
+ NVME_FWACT_REPL = (0 << 3),
+ NVME_FWACT_REPL_ACTV = (1 << 3),
+ NVME_FWACT_ACTV = (2 << 3),
+};
+
+enum {
+ NVME_NO_LOG_LSP = 0x0,
+ NVME_NO_LOG_LPO = 0x0,
+ NVME_LOG_ANA_LSP_RGO = 0x1,
+ NVME_TELEM_LSP_CREATE = 0x1,
+};
+
+/* Sanitize and Sanitize Monitor/Log */
+enum {
+ /* Sanitize */
+ NVME_SANITIZE_NO_DEALLOC = 0x00000200,
+ NVME_SANITIZE_OIPBP = 0x00000100,
+ NVME_SANITIZE_OWPASS_SHIFT = 0x00000004,
+ NVME_SANITIZE_AUSE = 0x00000008,
+ NVME_SANITIZE_ACT_CRYPTO_ERASE = 0x00000004,
+ NVME_SANITIZE_ACT_OVERWRITE = 0x00000003,
+ NVME_SANITIZE_ACT_BLOCK_ERASE = 0x00000002,
+ NVME_SANITIZE_ACT_EXIT = 0x00000001,
+
+ /* Sanitize Monitor/Log */
+ NVME_SANITIZE_LOG_DATA_LEN = 0x0014,
+ NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED = 0x0100,
+ NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK = 0x00F8,
+ NVME_SANITIZE_LOG_STATUS_MASK = 0x0007,
+ NVME_SANITIZE_LOG_NEVER_SANITIZED = 0x0000,
+ NVME_SANITIZE_LOG_COMPLETED_SUCCESS = 0x0001,
+ NVME_SANITIZE_LOG_IN_PROGESS = 0x0002,
+ NVME_SANITIZE_LOG_COMPLETED_FAILED = 0x0003,
+ NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS = 0x0004,
+};
+
+#define NVME_IDENTIFY_DATA_SIZE 4096
+
+struct nvme_host_mem_buf_desc {
+ __le64 addr;
+ __le32 size;
+ __u32 rsvd;
+};
+
+/* Sanitize Log Page */
+struct nvme_sanitize_log_page {
+ __le16 progress;
+ __le16 status;
+ __le32 cdw10_info;
+ __le32 est_ovrwrt_time;
+ __le32 est_blk_erase_time;
+ __le32 est_crypto_erase_time;
+ __le32 est_ovrwrt_time_with_no_deallocate;
+ __le32 est_blk_erase_time_with_no_deallocate;
+ __le32 est_crypto_erase_time_with_no_deallocate;
+};
+
+/*
+ * Fabrics subcommands.
+ */
+enum nvmf_fabrics_opcode {
+ nvme_fabrics_command = 0x7f,
+};
+
+enum nvmf_capsule_command {
+ nvme_fabrics_type_property_set = 0x00,
+ nvme_fabrics_type_connect = 0x01,
+ nvme_fabrics_type_property_get = 0x04,
+};
+
+/*
+ * The legal cntlid range a NVMe Target will provide.
+ * Note that cntlid of value 0 is considered illegal in the fabrics world.
+ * Devices based on earlier specs did not have the subsystem concept;
+ * therefore, those devices had their cntlid value set to 0 as a result.
+ */
+#define NVME_CNTLID_MIN 1
+#define NVME_CNTLID_MAX 0xffef
+#define NVME_CNTLID_DYNAMIC 0xffff
+
+#define MAX_DISC_LOGS 255
+
+/* Discovery log page entry */
+struct nvmf_disc_rsp_page_entry {
+ __u8 trtype;
+ __u8 adrfam;
+ __u8 subtype;
+ __u8 treq;
+ __le16 portid;
+ __le16 cntlid;
+ __le16 asqsz;
+ __u8 resv8[22];
+ char trsvcid[NVMF_TRSVCID_SIZE];
+ __u8 resv64[192];
+ char subnqn[NVMF_NQN_FIELD_LEN];
+ char traddr[NVMF_TRADDR_SIZE];
+ union tsas {
+ char common[NVMF_TSAS_SIZE];
+ struct rdma {
+ __u8 qptype;
+ __u8 prtype;
+ __u8 cms;
+ __u8 resv3[5];
+ __u16 pkey;
+ __u8 resv10[246];
+ } rdma;
+ struct tcp {
+ __u8 sectype;
+ } tcp;
+ } tsas;
+};
+
+/* Discovery log page header */
+struct nvmf_disc_rsp_page_hdr {
+ __le64 genctr;
+ __le64 numrec;
+ __le16 recfmt;
+ __u8 resv14[1006];
+ struct nvmf_disc_rsp_page_entry entries[0];
+};
+
+struct nvmf_connect_data {
+ uuid_t hostid;
+ __le16 cntlid;
+ char resv4[238];
+ char subsysnqn[NVMF_NQN_FIELD_LEN];
+ char hostnqn[NVMF_NQN_FIELD_LEN];
+ char resv5[256];
+};
+
+struct streams_directive_params {
+ __le16 msl;
+ __le16 nssa;
+ __le16 nsso;
+ __u8 rsvd[10];
+ __le32 sws;
+ __le16 sgs;
+ __le16 nsa;
+ __le16 nso;
+ __u8 rsvd2[6];
+};
+
+struct nvme_effects_log_page {
+ __le32 acs[256];
+ __le32 iocs[256];
+ __u8 resv[2048];
+};
+
+struct nvme_error_log_page {
+ __le64 error_count;
+ __le16 sqid;
+ __le16 cmdid;
+ __le16 status_field;
+ __le16 parm_error_location;
+ __le64 lba;
+ __le32 nsid;
+ __u8 vs;
+ __u8 trtype;
+ __u8 resv[2];
+ __le64 cs;
+ __le16 trtype_spec_info;
+ __u8 resv2[22];
+};
+
+struct nvme_firmware_log_page {
+ __u8 afi;
+ __u8 resv[7];
+ __u64 frs[7];
+ __u8 resv2[448];
+};
+
+struct nvme_host_mem_buffer {
+ __u32 hsize;
+ __u32 hmdlal;
+ __u32 hmdlau;
+ __u32 hmdlec;
+ __u8 rsvd16[4080];
+};
+
+struct nvme_auto_pst {
+ __u32 data;
+ __u32 rsvd32;
+};
+
+struct nvme_timestamp {
+ __u8 timestamp[6];
+ __u8 attr;
+ __u8 rsvd;
+};
+
+struct nvme_controller_list {
+ __le16 num;
+ __le16 identifier[2047];
+};
+
+struct nvme_secondary_controller_entry {
+ __le16 scid; /* Secondary Controller Identifier */
+ __le16 pcid; /* Primary Controller Identifier */
+ __u8 scs; /* Secondary Controller State */
+ __u8 rsvd5[3];
+ __le16 vfn; /* Virtual Function Number */
+ __le16 nvq; /* Number of VQ Flexible Resources Assigned */
+ __le16 nvi; /* Number of VI Flexible Resources Assigned */
+ __u8 rsvd14[18];
+};
+
+struct nvme_secondary_controllers_list {
+ __u8 num;
+ __u8 rsvd[31];
+ struct nvme_secondary_controller_entry sc_entry[127];
+};
+
+struct nvme_bar_cap {
+ __u16 mqes;
+ __u8 ams_cqr;
+ __u8 to;
+ __u16 bps_css_nssrs_dstrd;
+ __u8 mpsmax_mpsmin;
+ __u8 rsvd_cmbs_pmrs;
+};
+
+/*
+ * is_64bit_reg - It checks whether given offset of the controller register is
+ * 64bit or not.
+ * @offset: offset of controller register field in bytes
+ *
+ * It gives true if given offset is 64bit register, otherwise it returns false.
+ *
+ * Notes: This function does not care about transport so that the offset is
+ * not going to be checked inside of this function for the unsupported fields
+ * in a specific transport. For example, BPMBL(Boot Partition Memory Buffer
+ * Location) register is not supported by fabrics, but it can be chcked here.
+ */
+static inline bool is_64bit_reg(__u32 offset)
+{
+ if (offset == NVME_REG_CAP ||
+ offset == NVME_REG_ASQ ||
+ offset == NVME_REG_ACQ ||
+ offset == NVME_REG_BPMBL)
+ return true;
+
+ return false;
+}
+
+enum {
+ NVME_SCT_GENERIC = 0x0,
+ NVME_SCT_CMD_SPECIFIC = 0x1,
+ NVME_SCT_MEDIA = 0x2,
+};
+
+enum {
+ /*
+ * Generic Command Status:
+ */
+ NVME_SC_SUCCESS = 0x0,
+ NVME_SC_INVALID_OPCODE = 0x1,
+ NVME_SC_INVALID_FIELD = 0x2,
+ NVME_SC_CMDID_CONFLICT = 0x3,
+ NVME_SC_DATA_XFER_ERROR = 0x4,
+ NVME_SC_POWER_LOSS = 0x5,
+ NVME_SC_INTERNAL = 0x6,
+ NVME_SC_ABORT_REQ = 0x7,
+ NVME_SC_ABORT_QUEUE = 0x8,
+ NVME_SC_FUSED_FAIL = 0x9,
+ NVME_SC_FUSED_MISSING = 0xa,
+ NVME_SC_INVALID_NS = 0xb,
+ NVME_SC_CMD_SEQ_ERROR = 0xc,
+ NVME_SC_SGL_INVALID_LAST = 0xd,
+ NVME_SC_SGL_INVALID_COUNT = 0xe,
+ NVME_SC_SGL_INVALID_DATA = 0xf,
+ NVME_SC_SGL_INVALID_METADATA = 0x10,
+ NVME_SC_SGL_INVALID_TYPE = 0x11,
+ NVME_SC_CMB_INVALID_USE = 0x12,
+ NVME_SC_PRP_INVALID_OFFSET = 0x13,
+ NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED= 0x14,
+ NVME_SC_OPERATION_DENIED = 0x15,
+ NVME_SC_SGL_INVALID_OFFSET = 0x16,
+
+ NVME_SC_INCONSISTENT_HOST_ID= 0x18,
+ NVME_SC_KEEP_ALIVE_EXPIRED = 0x19,
+ NVME_SC_KEEP_ALIVE_INVALID = 0x1A,
+ NVME_SC_PREEMPT_ABORT = 0x1B,
+ NVME_SC_SANITIZE_FAILED = 0x1C,
+ NVME_SC_SANITIZE_IN_PROGRESS = 0x1D,
+
+ NVME_SC_NS_WRITE_PROTECTED = 0x20,
+ NVME_SC_CMD_INTERRUPTED = 0x21,
+ NVME_SC_TRANSIENT_TRANSPORT = 0x22,
+
+ NVME_SC_LBA_RANGE = 0x80,
+ NVME_SC_CAP_EXCEEDED = 0x81,
+ NVME_SC_NS_NOT_READY = 0x82,
+ NVME_SC_RESERVATION_CONFLICT = 0x83,
+ NVME_SC_FORMAT_IN_PROGRESS = 0x84,
+
+ /*
+ * Command Specific Status:
+ */
+ NVME_SC_CQ_INVALID = 0x100,
+ NVME_SC_QID_INVALID = 0x101,
+ NVME_SC_QUEUE_SIZE = 0x102,
+ NVME_SC_ABORT_LIMIT = 0x103,
+ NVME_SC_ABORT_MISSING = 0x104,
+ NVME_SC_ASYNC_LIMIT = 0x105,
+ NVME_SC_FIRMWARE_SLOT = 0x106,
+ NVME_SC_FIRMWARE_IMAGE = 0x107,
+ NVME_SC_INVALID_VECTOR = 0x108,
+ NVME_SC_INVALID_LOG_PAGE = 0x109,
+ NVME_SC_INVALID_FORMAT = 0x10a,
+ NVME_SC_FW_NEEDS_CONV_RESET = 0x10b,
+ NVME_SC_INVALID_QUEUE = 0x10c,
+ NVME_SC_FEATURE_NOT_SAVEABLE = 0x10d,
+ NVME_SC_FEATURE_NOT_CHANGEABLE = 0x10e,
+ NVME_SC_FEATURE_NOT_PER_NS = 0x10f,
+ NVME_SC_FW_NEEDS_SUBSYS_RESET = 0x110,
+ NVME_SC_FW_NEEDS_RESET = 0x111,
+ NVME_SC_FW_NEEDS_MAX_TIME = 0x112,
+ NVME_SC_FW_ACTIVATE_PROHIBITED = 0x113,
+ NVME_SC_OVERLAPPING_RANGE = 0x114,
+ NVME_SC_NS_INSUFFICIENT_CAP = 0x115,
+ NVME_SC_NS_ID_UNAVAILABLE = 0x116,
+ NVME_SC_NS_ALREADY_ATTACHED = 0x118,
+ NVME_SC_NS_IS_PRIVATE = 0x119,
+ NVME_SC_NS_NOT_ATTACHED = 0x11a,
+ NVME_SC_THIN_PROV_NOT_SUPP = 0x11b,
+ NVME_SC_CTRL_LIST_INVALID = 0x11c,
+ NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS= 0x11d,
+ NVME_SC_BP_WRITE_PROHIBITED = 0x11e,
+ NVME_SC_INVALID_CTRL_ID = 0x11f,
+ NVME_SC_INVALID_SECONDARY_CTRL_STATE= 0x120,
+ NVME_SC_INVALID_NUM_CTRL_RESOURCE = 0x121,
+ NVME_SC_INVALID_RESOURCE_ID = 0x122,
+ NVME_SC_PMR_SAN_PROHIBITED = 0x123,
+ NVME_SC_ANA_INVALID_GROUP_ID= 0x124,
+ NVME_SC_ANA_ATTACH_FAIL = 0x125,
+
+ /*
+ * I/O Command Set Specific - NVM commands:
+ */
+ NVME_SC_BAD_ATTRIBUTES = 0x180,
+ NVME_SC_INVALID_PI = 0x181,
+ NVME_SC_READ_ONLY = 0x182,
+ NVME_SC_ONCS_NOT_SUPPORTED = 0x183,
+
+ /*
+ * I/O Command Set Specific - Fabrics commands:
+ */
+ NVME_SC_CONNECT_FORMAT = 0x180,
+ NVME_SC_CONNECT_CTRL_BUSY = 0x181,
+ NVME_SC_CONNECT_INVALID_PARAM = 0x182,
+ NVME_SC_CONNECT_RESTART_DISC = 0x183,
+ NVME_SC_CONNECT_INVALID_HOST = 0x184,
+
+ NVME_SC_DISCOVERY_RESTART = 0x190,
+ NVME_SC_AUTH_REQUIRED = 0x191,
+
+ /*
+ * Media and Data Integrity Errors:
+ */
+ NVME_SC_WRITE_FAULT = 0x280,
+ NVME_SC_READ_ERROR = 0x281,
+ NVME_SC_GUARD_CHECK = 0x282,
+ NVME_SC_APPTAG_CHECK = 0x283,
+ NVME_SC_REFTAG_CHECK = 0x284,
+ NVME_SC_COMPARE_FAILED = 0x285,
+ NVME_SC_ACCESS_DENIED = 0x286,
+ NVME_SC_UNWRITTEN_BLOCK = 0x287,
+
+ /*
+ * Path-related Errors:
+ */
+ NVME_SC_ANA_PERSISTENT_LOSS = 0x301,
+ NVME_SC_ANA_INACCESSIBLE = 0x302,
+ NVME_SC_ANA_TRANSITION = 0x303,
+
+ NVME_SC_CRD = 0x1800,
+ NVME_SC_DNR = 0x4000,
+};
+
+#define NVME_VS(major, minor, tertiary) \
+ (((major) << 16) | ((minor) << 8) | (tertiary))
+
+#define NVME_MAJOR(ver) ((ver) >> 16)
+#define NVME_MINOR(ver) (((ver) >> 8) & 0xff)
+#define NVME_TERTIARY(ver) ((ver) & 0xff)
+
+#endif /* _LINUX_NVME_H */
diff --git a/linux/nvme_ioctl.h b/linux/nvme_ioctl.h
new file mode 100644
index 0000000..d569414
--- /dev/null
+++ b/linux/nvme_ioctl.h
@@ -0,0 +1,91 @@
+/*
+ * Definitions for the NVM Express ioctl 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 _UAPI_LINUX_NVME_IOCTL_H
+#define _UAPI_LINUX_NVME_IOCTL_H
+
+#include <linux/types.h>
+#include <sys/ioctl.h>
+
+struct nvme_user_io {
+ __u8 opcode;
+ __u8 flags;
+ __u16 control;
+ __u16 nblocks;
+ __u16 rsvd;
+ __u64 metadata;
+ __u64 addr;
+ __u64 slba;
+ __u32 dsmgmt;
+ __u32 reftag;
+ __u16 apptag;
+ __u16 appmask;
+};
+
+struct nvme_passthru_cmd {
+ __u8 opcode;
+ __u8 flags;
+ __u16 rsvd1;
+ __u32 nsid;
+ __u32 cdw2;
+ __u32 cdw3;
+ __u64 metadata;
+ __u64 addr;
+ __u32 metadata_len;
+ __u32 data_len;
+ __u32 cdw10;
+ __u32 cdw11;
+ __u32 cdw12;
+ __u32 cdw13;
+ __u32 cdw14;
+ __u32 cdw15;
+ __u32 timeout_ms;
+ __u32 result;
+};
+
+struct nvme_passthru_cmd64 {
+ __u8 opcode;
+ __u8 flags;
+ __u16 rsvd1;
+ __u32 nsid;
+ __u32 cdw2;
+ __u32 cdw3;
+ __u64 metadata;
+ __u64 addr;
+ __u32 metadata_len;
+ __u32 data_len;
+ __u32 cdw10;
+ __u32 cdw11;
+ __u32 cdw12;
+ __u32 cdw13;
+ __u32 cdw14;
+ __u32 cdw15;
+ __u32 timeout_ms;
+ __u32 rsvd2;
+ __u64 result;
+};
+
+#define nvme_admin_cmd nvme_passthru_cmd
+
+#define NVME_IOCTL_ID _IO('N', 0x40)
+#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_admin_cmd)
+#define NVME_IOCTL_SUBMIT_IO _IOW('N', 0x42, struct nvme_user_io)
+#define NVME_IOCTL_IO_CMD _IOWR('N', 0x43, struct nvme_passthru_cmd)
+#define NVME_IOCTL_RESET _IO('N', 0x44)
+#define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45)
+#define NVME_IOCTL_RESCAN _IO('N', 0x46)
+#define NVME_IOCTL_ADMIN64_CMD _IOWR('N', 0x47, struct nvme_passthru_cmd64)
+#define NVME_IOCTL_IO64_CMD _IOWR('N', 0x48, struct nvme_passthru_cmd64)
+
+#endif /* _UAPI_LINUX_NVME_IOCTL_H */
diff --git a/nvme-builtin.h b/nvme-builtin.h
new file mode 100644
index 0000000..bfb907d
--- /dev/null
+++ b/nvme-builtin.h
@@ -0,0 +1,81 @@
+#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("list-ns", "Send NVMe Identify List, display structure", list_ns)
+ ENTRY("list-ctrl", "Send NVMe Identify Controller List, display structure", list_ctrl)
+ ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl)
+ ENTRY("ns-descs", "Send NVMe Namespace Descriptor List, display structure", ns_descs)
+ ENTRY("id-nvmset", "Send NVMe Identify NVM Set List, display structure", id_nvmset)
+ ENTRY("id-uuid", "Send NVMe Identify UUID List, display structure", id_uuid)
+ ENTRY("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("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("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)
+ 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("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("flush", "Submit a Flush command, return results", flush)
+ ENTRY("compare", "Submit a Compare command, return results", compare)
+ ENTRY("read", "Submit a read command, return results", read_cmd)
+ 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)
+ 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("gen-hostnqn", "Generate NVMeoF host NQN", gen_hostnqn_cmd)
+ ENTRY("show-hostnqn", "Show NVMeoF host NQN", show_hostnqn_cmd)
+ 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)
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/nvme-filters.c b/nvme-filters.c
new file mode 100644
index 0000000..a4133f8
--- /dev/null
+++ b/nvme-filters.c
@@ -0,0 +1,88 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "nvme.h"
+
+/* global, used for controller specific namespace filter */
+int current_index;
+
+int scan_namespace_filter(const struct dirent *d)
+{
+ int i, n;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme"))
+ if (sscanf(d->d_name, "nvme%dn%d", &i, &n) == 2)
+ return 1;
+ return 0;
+}
+
+int scan_ctrl_paths_filter(const struct dirent *d)
+{
+ int id, cntlid, nsid;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme")) {
+ if (sscanf(d->d_name, "nvme%dc%dn%d", &id, &cntlid, &nsid) == 3)
+ return 1;
+ if (sscanf(d->d_name, "nvme%dn%d", &id, &nsid) == 2)
+ return 1;
+ }
+
+ return 0;
+}
+
+int scan_ctrls_filter(const struct dirent *d)
+{
+ int id, nsid;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme")) {
+ if (sscanf(d->d_name, "nvme%dn%d", &id, &nsid) == 2)
+ return 0;
+ if (sscanf(d->d_name, "nvme%dn", &id) == 1)
+ return 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+int scan_subsys_filter(const struct dirent *d)
+{
+ int id;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme-subsys")) {
+ if (sscanf(d->d_name, "nvme-subsys%d", &id) != 1)
+ return 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int scan_dev_filter(const struct dirent *d)
+{
+ int ctrl, ns, part;
+
+ if (d->d_name[0] == '.')
+ return 0;
+
+ if (strstr(d->d_name, "nvme")) {
+ if (sscanf(d->d_name, "nvme%dn%dp%d", &ctrl, &ns, &part) == 3)
+ return 0;
+ if (sscanf(d->d_name, "nvme%dn%d", &ctrl, &ns) == 2)
+ return ctrl == current_index;
+ }
+ return 0;
+}
diff --git a/nvme-ioctl.c b/nvme-ioctl.c
new file mode 100644
index 0000000..39685d6
--- /dev/null
+++ b/nvme-ioctl.c
@@ -0,0 +1,879 @@
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/stat.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 "nvme-ioctl.h"
+
+static int nvme_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 reset on non-controller handle\n");
+ return ENOTBLK;
+ }
+ return 0;
+}
+
+int nvme_subsystem_reset(int fd)
+{
+ int ret;
+
+ ret = nvme_verify_chr(fd);
+ if (ret)
+ return ret;
+ return ioctl(fd, NVME_IOCTL_SUBSYS_RESET);
+}
+
+int nvme_reset_controller(int fd)
+{
+ int ret;
+
+ ret = nvme_verify_chr(fd);
+ if (ret)
+ return ret;
+ return ioctl(fd, NVME_IOCTL_RESET);
+}
+
+int nvme_ns_rescan(int fd)
+{
+ int ret;
+
+ ret = nvme_verify_chr(fd);
+ if (ret)
+ return ret;
+ return ioctl(fd, NVME_IOCTL_RESCAN);
+}
+
+int nvme_get_nsid(int fd)
+{
+ static struct stat nvme_stat;
+ int err = fstat(fd, &nvme_stat);
+
+ if (err < 0)
+ return -errno;
+
+ return ioctl(fd, NVME_IOCTL_ID);
+}
+
+int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
+ struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, ioctl_cmd, cmd);
+}
+
+int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, cmd);
+}
+
+int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd)
+{
+ return ioctl(fd, NVME_IOCTL_IO_CMD, cmd);
+}
+
+int nvme_passthru(int fd, unsigned long ioctl_cmd, __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)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = opcode,
+ .flags = flags,
+ .rsvd1 = rsvd,
+ .nsid = nsid,
+ .cdw2 = cdw2,
+ .cdw3 = cdw3,
+ .metadata = (__u64)(uintptr_t) metadata,
+ .addr = (__u64)(uintptr_t) data,
+ .metadata_len = metadata_len,
+ .data_len = data_len,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw12 = cdw12,
+ .cdw13 = cdw13,
+ .cdw14 = cdw14,
+ .cdw15 = cdw15,
+ .timeout_ms = timeout_ms,
+ .result = 0,
+ };
+ int err;
+
+ err = nvme_submit_passthru(fd, ioctl_cmd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ struct nvme_user_io io = {
+ .opcode = opcode,
+ .flags = 0,
+ .control = control,
+ .nblocks = nblocks,
+ .rsvd = 0,
+ .metadata = (__u64)(uintptr_t) metadata,
+ .addr = (__u64)(uintptr_t) data,
+ .slba = slba,
+ .dsmgmt = dsmgmt,
+ .reftag = reftag,
+ .appmask = appmask,
+ .apptag = apptag,
+ };
+ return ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
+}
+
+int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_read, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_write, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control, __u32 dsmgmt,
+ __u32 reftag, __u16 apptag, __u16 appmask, void *data,
+ void *metadata)
+{
+ return nvme_io(fd, nvme_cmd_compare, slba, nblocks, control, dsmgmt,
+ reftag, apptag, appmask, data, metadata);
+}
+
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_verify,
+ .nsid = nsid,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = nblocks | (control << 16),
+ .cdw14 = reftag,
+ .cdw15 = apptag | (appmask << 16),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_passthru_io(int fd, __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)
+{
+ return nvme_passthru(fd, NVME_IOCTL_IO_CMD, opcode, flags, rsvd, nsid,
+ cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14,
+ cdw15, data_len, data, metadata_len, metadata,
+ timeout_ms, NULL);
+}
+
+int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_write_zeroes,
+ .nsid = nsid,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = nlb | (control << 16),
+ .cdw14 = reftag,
+ .cdw15 = apptag | (appmask << 16),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_write_uncor,
+ .nsid = nsid,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = nlb,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_flush(int fd, __u32 nsid)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_flush,
+ .nsid = nsid,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
+ __u16 nr_ranges)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_dsm,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t) dsm,
+ .data_len = nr_ranges * sizeof(*dsm),
+ .cdw10 = nr_ranges - 1,
+ .cdw11 = cdw11,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs, __u32 *llbas,
+ __u64 *slbas, __u16 nr_ranges)
+{
+ int i;
+ struct nvme_dsm_range *dsm = malloc(nr_ranges * sizeof(*dsm));
+
+ if (!dsm) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ return NULL;
+ }
+ for (i = 0; i < nr_ranges; i++) {
+ dsm[i].cattr = cpu_to_le32(ctx_attrs[i]);
+ dsm[i].nlb = cpu_to_le32(llbas[i]);
+ dsm[i].slba = cpu_to_le64(slbas[i]);
+ }
+ return dsm;
+}
+
+int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
+ bool iekey, __u64 crkey, __u64 nrkey)
+{
+ __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
+ __u32 cdw10 = (racqa & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_acquire,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64)(uintptr_t) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
+ bool iekey, __u64 crkey, __u64 nrkey)
+{
+ __le64 payload[2] = { cpu_to_le64(crkey), cpu_to_le64(nrkey) };
+ __u32 cdw10 = (rrega & 0x7) | (iekey ? 1 << 3 : 0) | cptpl << 30;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_register,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64)(uintptr_t) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
+ bool iekey, __u64 crkey)
+{
+ __le64 payload[1] = { cpu_to_le64(crkey) };
+ __u32 cdw10 = (rrela & 0x7) | (iekey ? 1 << 3 : 0) | rtype << 8;
+
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_release,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .addr = (__u64)(uintptr_t) (payload),
+ .data_len = sizeof(payload),
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_cmd_resv_report,
+ .nsid = nsid,
+ .cdw10 = numd,
+ .cdw11 = cdw11,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = (numd + 1) << 2,
+ };
+
+ return nvme_submit_io_passthru(fd, &cmd);
+}
+
+int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_identify,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = NVME_IDENTIFY_DATA_SIZE,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data)
+{
+ return nvme_identify13(fd, nsid, cdw10, 0, data);
+}
+
+int nvme_identify_ctrl(int fd, void *data)
+{
+ memset(data, 0, sizeof(struct nvme_id_ctrl));
+ return nvme_identify(fd, 0, 1, data);
+}
+
+int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data)
+{
+ int cns = present ? NVME_ID_CNS_NS_PRESENT : NVME_ID_CNS_NS;
+
+ return nvme_identify(fd, nsid, cns, data);
+}
+
+int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data)
+{
+ int cns = all ? NVME_ID_CNS_NS_PRESENT_LIST : NVME_ID_CNS_NS_ACTIVE_LIST;
+
+ return nvme_identify(fd, nsid, cns, data);
+}
+
+int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
+{
+ int cns = nsid ? NVME_ID_CNS_CTRL_NS_LIST : NVME_ID_CNS_CTRL_LIST;
+
+ return nvme_identify(fd, nsid, (cntid << 16) | cns, data);
+}
+
+int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data)
+{
+ return nvme_identify(fd, nsid, (cntid << 16) | NVME_ID_CNS_SCNDRY_CTRL_LIST, data);
+}
+
+int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
+{
+
+ return nvme_identify(fd, nsid, NVME_ID_CNS_NS_DESC_LIST, data);
+}
+
+int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data)
+{
+ return nvme_identify13(fd, 0, NVME_ID_CNS_NVMSET_LIST, nvmset_id, data);
+}
+
+int nvme_identify_ns_granularity(int fd, void *data)
+{
+ return nvme_identify13(fd, 0, NVME_ID_CNS_NS_GRANULARITY, 0, data);
+}
+
+int nvme_identify_uuid(int fd, void *data)
+{
+ return nvme_identify(fd, 0, NVME_ID_CNS_UUID_LIST, data);
+}
+
+int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+ __u16 lsi, bool rae, __u8 uuid_ix, __u32 data_len, void *data)
+{
+ __u32 numd = (data_len >> 2) - 1;
+ __u16 numdu = numd >> 16, numdl = numd & 0xffff;
+ __u32 cdw10 = log_id | (numdl << 16) | (rae ? 1 << 15 : 0) | lsp << 8;
+
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_get_log_page,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ .cdw10 = cdw10,
+ .cdw11 = numdu | (lsi << 16),
+ .cdw12 = lpo & 0xffffffff,
+ .cdw13 = lpo >> 32,
+ .cdw14 = uuid_ix,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp,
+ __u64 lpo, __u16 lsi, bool rae, __u32 data_len,
+ void *data)
+{
+ return nvme_get_log14(fd, nsid, log_id, lsp, lpo, lsi, rae, 0,
+ data_len, data);
+}
+
+int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
+ __u32 data_len, void *data)
+{
+ __u32 offset = 0, xfer_len = data_len;
+ void *ptr = data;
+ int ret;
+
+ /*
+ * 4k is the smallest possible transfer unit, so by
+ * restricting ourselves for 4k transfers we avoid having
+ * to check the MDTS value of the controller.
+ */
+ do {
+ xfer_len = data_len - offset;
+ if (xfer_len > 4096)
+ xfer_len = 4096;
+
+ ret = nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP,
+ offset, 0, rae, xfer_len, ptr);
+ if (ret)
+ return ret;
+
+ offset += xfer_len;
+ ptr += xfer_len;
+ } while (offset < data_len);
+
+ return 0;
+}
+
+int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
+ int ctrl_init, size_t log_page_size, __u64 offset)
+{
+ if (ctrl_init)
+ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_CTRL,
+ NVME_NO_LOG_LSP, offset,
+ 0, 1, log_page_size, lp);
+ if (generate_report)
+ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
+ NVME_TELEM_LSP_CREATE, offset,
+ 0, 1, log_page_size, lp);
+ else
+ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
+ NVME_NO_LOG_LSP, offset,
+ 0, 1, log_page_size, lp);
+}
+
+int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_FW_SLOT, true,
+ sizeof(*fw_log), fw_log);
+}
+
+int nvme_changed_ns_list_log(int fd, struct nvme_changed_ns_list_log *changed_ns_list_log)
+{
+ return nvme_get_log(fd, 0, NVME_LOG_CHANGED_NS, true,
+ sizeof(changed_ns_list_log->log),
+ changed_ns_list_log->log);
+}
+
+int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, false,
+ entries * sizeof(*err_log), err_log);
+}
+
+int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log)
+{
+ return nvme_get_log13(fd, 0, NVME_LOG_ENDURANCE_GROUP, 0, 0, group_id, 0,
+ sizeof(*endurance_log), endurance_log);
+}
+
+int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
+{
+ return nvme_get_log(fd, nsid, NVME_LOG_SMART, false,
+ sizeof(*smart_log), smart_log);
+}
+
+int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo)
+{
+ return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_ANA, rgo, 0, 0,
+ true, ana_log_len, ana_log);
+}
+
+int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_log)
+{
+ return nvme_get_log(fd, nsid, NVME_LOG_DEVICE_SELF_TEST, false,
+ sizeof(*self_test_log), self_test_log);
+}
+
+int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log)
+{
+ return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_CMD_EFFECTS, false,
+ sizeof(*effects_log), effects_log);
+}
+
+int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size)
+{
+ return nvme_get_log(fd, 0, NVME_LOG_DISC, false, size, log);
+}
+
+int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log)
+{
+ return nvme_get_log(fd, 0, NVME_LOG_SANITIZE, false,
+ sizeof(*sanitize_log), sanitize_log);
+}
+
+int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10, __u32 cdw11,
+ __u32 cdw12, __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = opcode,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ .cdw12 = cdw12,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
+ bool save, __u32 data_len, void *data, __u32 *result)
+{
+ __u32 cdw10 = fid | (save ? 1 << 31 : 0);
+
+ return nvme_feature(fd, nvme_admin_set_features, nsid, cdw10, value,
+ cdw12, data_len, data, result);
+}
+
+
+int nvme_get_property(int fd, int offset, uint64_t *value)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_fabrics_command,
+ .nsid = nvme_fabrics_type_property_get,
+ .cdw10 = is_64bit_reg(offset),
+ .cdw11 = offset,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && value)
+ *value = cmd.result;
+ return err;
+}
+
+int nvme_get_properties(int fd, void **pbar)
+{
+ int offset;
+ uint64_t value;
+ int err, size = getpagesize();
+
+ *pbar = malloc(size);
+ if (!*pbar) {
+ fprintf(stderr, "malloc: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ memset(*pbar, 0xff, size);
+ for (offset = NVME_REG_CAP; offset <= NVME_REG_CMBSZ;) {
+ err = nvme_get_property(fd, offset, &value);
+ if (err > 0 && (err & 0xff) == NVME_SC_INVALID_FIELD) {
+ err = 0;
+ value = -1;
+ } else if (err) {
+ free(*pbar);
+ break;
+ }
+ if (is_64bit_reg(offset)) {
+ *(uint64_t *)(*pbar + offset) = value;
+ offset += 8;
+ } else {
+ *(uint32_t *)(*pbar + offset) = value;
+ offset += 4;
+ }
+ }
+
+ return err;
+}
+
+int nvme_set_property(int fd, int offset, uint64_t value)
+{
+ struct nvme_passthru_cmd cmd = {
+ .opcode = nvme_fabrics_command,
+ .nsid = nvme_fabrics_type_property_set,
+ .cdw10 = is_64bit_reg(offset),
+ .cdw11 = offset,
+ .cdw12 = value & 0xffffffff,
+ .cdw13 = value >> 32,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel, __u32 cdw11,
+ __u32 data_len, void *data, __u32 *result)
+{
+ __u32 cdw10 = fid | sel << 8;
+
+ return nvme_feature(fd, nvme_admin_get_features, nsid, cdw10, cdw11,
+ 0, data_len, data, result);
+}
+
+int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
+ __u8 pil, __u8 ms, __u32 timeout)
+{
+ __u32 cdw10 = lbaf | ms << 4 | pi << 5 | pil << 8 | ses << 9;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_format_nvm,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ .timeout_ms = timeout,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, __u8 dps,
+ __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u32 timeout,
+ __u32 *result)
+{
+ struct nvme_id_ns ns = {
+ .nsze = cpu_to_le64(nsze),
+ .ncap = cpu_to_le64(ncap),
+ .flbas = flbas,
+ .dps = dps,
+ .nmic = nmic,
+ .anagrpid = anagrpid,
+ .nvmsetid = nvmsetid,
+ };
+
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_mgmt,
+ .addr = (__u64)(uintptr_t) ((void *)&ns),
+ .cdw10 = 0,
+ .data_len = 0x1000,
+ .timeout_ms = timeout,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_mgmt,
+ .nsid = nsid,
+ .cdw10 = 1,
+ .timeout_ms = timeout,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls, __u16 *ctrlist,
+ bool attach)
+{
+ struct nvme_controller_list cntlist = {
+ .num = cpu_to_le16(num_ctrls),
+ };
+
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_ns_attach,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t)&cntlist,
+ .cdw10 = attach ? 0 : 1,
+ .data_len = 0x1000,
+ };
+ int i;
+
+ for (i = 0; i < num_ctrls; i++)
+ cntlist.identifier[i] = cpu_to_le16(ctrlist[i]);
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_download_fw,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ .cdw10 = (data_len >> 2) - 1,
+ .cdw11 = offset >> 2,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_activate_fw,
+ .cdw10 = (bpid << 31) | (action << 3) | slot,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_security_send,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ .nsid = nsid,
+ .cdw10 = secp << 24 | spsp << 8 | nssf,
+ .cdw11 = tl,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_security_recv,
+ .nsid = nsid,
+ .cdw10 = secp << 24 | spsp << 8 | nssf,
+ .cdw11 = al,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
+ void *data)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_get_lba_status,
+ .addr = (__u64)(uintptr_t) data,
+ .cdw10 = slba & 0xffffffff,
+ .cdw11 = slba >> 32,
+ .cdw12 = mndw,
+ .cdw13 = (atype << 24) | rl,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
+ __u32 data_len, __u32 dw12, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_directive_send,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ .nsid = nsid,
+ .cdw10 = data_len? (data_len >> 2) - 1 : 0,
+ .cdw11 = dspec << 16 | dtype << 8 | doper,
+ .cdw12 = dw12,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
+ __u32 data_len, __u32 dw12, void *data, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_directive_recv,
+ .addr = (__u64)(uintptr_t) data,
+ .data_len = data_len,
+ .nsid = nsid,
+ .cdw10 = data_len? (data_len >> 2) - 1 : 0,
+ .cdw11 = dspec << 16 | dtype << 8 | doper,
+ .cdw12 = dw12,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+ return err;
+}
+
+int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
+ __u8 no_dealloc, __u32 ovrpat)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_sanitize_nvm,
+ .cdw10 = no_dealloc << 9 | oipbp << 8 |
+ owpass << NVME_SANITIZE_OWPASS_SHIFT |
+ ause << 3 | sanact,
+ .cdw11 = ovrpat,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_dev_self_test,
+ .nsid = nsid,
+ .cdw10 = cdw10,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_virtual_mgmt,
+ .cdw10 = cdw10,
+ .cdw11 = cdw11,
+ };
+ int err;
+
+ err = nvme_submit_admin_passthru(fd, &cmd);
+ if (!err && result)
+ *result = cmd.result;
+
+ return err;
+}
diff --git a/nvme-ioctl.h b/nvme-ioctl.h
new file mode 100644
index 0000000..aae4e49
--- /dev/null
+++ b/nvme-ioctl.h
@@ -0,0 +1,155 @@
+#ifndef _NVME_LIB_H
+#define _NVME_LIB_H
+
+#include <linux/types.h>
+#include <stdbool.h>
+#include "linux/nvme_ioctl.h"
+#include "nvme.h"
+
+#define NVME_IOCTL_TIMEOUT 120000 /* in milliseconds */
+
+int nvme_get_nsid(int fd);
+
+/* Generic passthrough */
+int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
+ struct nvme_passthru_cmd *cmd);
+int nvme_submit_admin_passthru(int fd, struct nvme_passthru_cmd *cmd);
+int nvme_submit_io_passthru(int fd, struct nvme_passthru_cmd *cmd);
+
+int nvme_passthru(int fd, unsigned long ioctl_cmd, __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);
+
+
+/* NVME_SUBMIT_IO */
+int nvme_io(int fd, __u8 opcode, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_read(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_write(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+int nvme_compare(int fd, __u64 slba, __u16 nblocks, __u16 control,
+ __u32 dsmgmt, __u32 reftag, __u16 apptag,
+ __u16 appmask, void *data, void *metadata);
+
+/* NVME_IO_CMD */
+int nvme_passthru_io(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
+ __u32 nsid, __u32 cdw2, __u32 cdw3,
+ __u32 cdw10, __u32 cdw11, __u32 cdw12,
+ __u32 cdw13, __u32 cdw14, __u32 cdw15,
+ __u32 data_len, void *data, __u32 metadata_len,
+ void *metadata, __u32 timeout);
+
+int nvme_write_zeros(int fd, __u32 nsid, __u64 slba, __u16 nlb,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
+
+int nvme_write_uncorrectable(int fd, __u32 nsid, __u64 slba, __u16 nlb);
+
+int nvme_verify(int fd, __u32 nsid, __u64 slba, __u16 nblocks,
+ __u16 control, __u32 reftag, __u16 apptag, __u16 appmask);
+
+int nvme_flush(int fd, __u32 nsid);
+
+int nvme_dsm(int fd, __u32 nsid, __u32 cdw11, struct nvme_dsm_range *dsm,
+ __u16 nr_ranges);
+struct nvme_dsm_range *nvme_setup_dsm_range(__u32 *ctx_attrs,
+ __u32 *llbas, __u64 *slbas,
+ __u16 nr_ranges);
+
+int nvme_resv_acquire(int fd, __u32 nsid, __u8 rtype, __u8 racqa,
+ bool iekey, __u64 crkey, __u64 nrkey);
+int nvme_resv_register(int fd, __u32 nsid, __u8 rrega, __u8 cptpl,
+ bool iekey, __u64 crkey, __u64 nrkey);
+int nvme_resv_release(int fd, __u32 nsid, __u8 rtype, __u8 rrela,
+ bool iekey, __u64 crkey);
+int nvme_resv_report(int fd, __u32 nsid, __u32 numd, __u32 cdw11, void *data);
+
+/* NVME_ADMIN_CMD */
+int nvme_identify13(int fd, __u32 nsid, __u32 cdw10, __u32 cdw11, void *data);
+int nvme_identify(int fd, __u32 nsid, __u32 cdw10, void *data);
+int nvme_identify_ctrl(int fd, void *data);
+int nvme_identify_ns(int fd, __u32 nsid, bool present, void *data);
+int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
+int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
+int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
+int nvme_identify_nvmset(int fd, __u16 nvmset_id, void *data);
+int nvme_identify_uuid(int fd, void *data);
+int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
+int nvme_identify_ns_granularity(int fd, void *data);
+int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae,
+ __u32 data_len, void *data);
+int nvme_get_log14(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
+ __u16 group_id, bool rae, __u8 uuid_ix,
+ __u32 data_len, void *data);
+int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp,
+ __u64 lpo, __u16 lsi, bool rae, __u32 data_len,
+ void *data);
+int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
+ int ctrl_gen, size_t log_page_size, __u64 offset);
+int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log);
+int nvme_changed_ns_list_log(int fd,
+ struct nvme_changed_ns_list_log *changed_ns_list_log);
+int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log);
+int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
+int nvme_ana_log(int fd, void *ana_log, size_t ana_log_len, int rgo);
+int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
+int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
+int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
+int nvme_endurance_log(int fd, __u16 group_id,
+ struct nvme_endurance_group_log *endurance_log);
+
+int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10,
+ __u32 cdw11, __u32 cdw12, __u32 data_len, void *data,
+ __u32 *result);
+int nvme_set_feature(int fd, __u32 nsid, __u8 fid, __u32 value, __u32 cdw12,
+ bool save, __u32 data_len, void *data, __u32 *result);
+int nvme_get_feature(int fd, __u32 nsid, __u8 fid, __u8 sel,
+ __u32 cdw11, __u32 data_len, void *data, __u32 *result);
+
+int nvme_format(int fd, __u32 nsid, __u8 lbaf, __u8 ses, __u8 pi,
+ __u8 pil, __u8 ms, __u32 timeout);
+
+int nvme_ns_create(int fd, __u64 nsze, __u64 ncap, __u8 flbas, __u8 dps,
+ __u8 nmic, __u32 anagrpid, __u16 nvmsetid, __u32 timeout,
+ __u32 *result);
+int nvme_ns_delete(int fd, __u32 nsid, __u32 timeout);
+
+int nvme_ns_attachment(int fd, __u32 nsid, __u16 num_ctrls,
+ __u16 *ctrlist, bool attach);
+
+int nvme_fw_download(int fd, __u32 offset, __u32 data_len, void *data);
+int nvme_fw_commit(int fd, __u8 slot, __u8 action, __u8 bpid);
+
+int nvme_sec_send(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 tl, __u32 data_len, void *data, __u32 *result);
+int nvme_sec_recv(int fd, __u32 nsid, __u8 nssf, __u16 spsp,
+ __u8 secp, __u32 al, __u32 data_len, void *data, __u32 *result);
+
+int nvme_subsystem_reset(int fd);
+int nvme_reset_controller(int fd);
+int nvme_ns_rescan(int fd);
+
+int nvme_get_lba_status(int fd, __u64 slba, __u32 mndw, __u8 atype, __u16 rl,
+ void *data);
+int nvme_dir_send(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
+ __u32 data_len, __u32 dw12, void *data, __u32 *result);
+int nvme_dir_recv(int fd, __u32 nsid, __u16 dspec, __u8 dtype, __u8 doper,
+ __u32 data_len, __u32 dw12, void *data, __u32 *result);
+int nvme_get_properties(int fd, void **pbar);
+int nvme_set_property(int fd, int offset, uint64_t value);
+int nvme_get_property(int fd, int offset, uint64_t *value);
+int nvme_sanitize(int fd, __u8 sanact, __u8 ause, __u8 owpass, __u8 oipbp,
+ __u8 no_dealloc, __u32 ovrpat);
+int nvme_self_test_start(int fd, __u32 nsid, __u32 cdw10);
+int nvme_self_test_log(int fd, __u32 nsid, struct nvme_self_test_log *self_test_log);
+int nvme_virtual_mgmt(int fd, __u32 cdw10, __u32 cdw11, __u32 *result);
+#endif /* _NVME_LIB_H */
diff --git a/nvme-lightnvm.c b/nvme-lightnvm.c
new file mode 100644
index 0000000..d81fac6
--- /dev/null
+++ b/nvme-lightnvm.c
@@ -0,0 +1,700 @@
+/*
+ * lightnvm.c -- LightNVM NVMe integration.
+ *
+ * Copyright (c) 2016, CNEX Labs.
+ *
+ * Written by Matias Bjoerling <matias@cnexlabs.com>
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include "nvme-lightnvm.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+
+static int lnvm_open(void)
+{
+ char dev[FILENAME_MAX] = NVM_CTRL_FILE;
+ int fd;
+
+ fd = open(dev, O_WRONLY);
+ if (fd < 0) {
+ printf("Failed to open LightNVM mgmt interface\n");
+ perror(dev);
+ return fd;
+ }
+
+ return fd;
+}
+
+static void lnvm_close(int fd)
+{
+ close(fd);
+}
+
+int lnvm_do_init(char *dev, char *mmtype)
+{
+ struct nvm_ioctl_dev_init init;
+ int fd, ret;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ memset(&init, 0, sizeof(struct nvm_ioctl_dev_init));
+ strncpy(init.dev, dev, DISK_NAME_LEN - 1);
+ strncpy(init.mmtype, mmtype, NVM_MMTYPE_LEN - 1);
+
+ ret = ioctl(fd, NVM_DEV_INIT, &init);
+ switch (errno) {
+ case EINVAL:
+ printf("Initialization failed.\n");
+ break;
+ case EEXIST:
+ printf("Device has already been initialized.\n");
+ break;
+ case 0:
+ break;
+ default:
+ printf("Unknown error occurred (%d)\n", errno);
+ break;
+ }
+
+ lnvm_close(fd);
+
+ return ret;
+}
+
+int lnvm_do_list_devices(void)
+{
+ struct nvm_ioctl_get_devices devs;
+ int fd, ret, i;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ ret = ioctl(fd, NVM_GET_DEVICES, &devs);
+ if (ret) {
+ lnvm_close(fd);
+ return ret;
+ }
+
+ printf("Number of devices: %u\n", devs.nr_devices);
+ printf("%-12s\t%-12s\tVersion\n", "Device", "Block manager");
+
+ for (i = 0; i < devs.nr_devices && i < 31; i++) {
+ struct nvm_ioctl_device_info *info = &devs.info[i];
+
+ printf("%-12s\t%-12s\t(%u,%u,%u)\n", info->devname, info->bmname,
+ info->bmversion[0], info->bmversion[1],
+ info->bmversion[2]);
+ }
+
+ lnvm_close(fd);
+
+ return 0;
+}
+
+int lnvm_do_info(void)
+{
+ struct nvm_ioctl_info c;
+ int fd, ret, i;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ memset(&c, 0, sizeof(struct nvm_ioctl_info));
+ ret = ioctl(fd, NVM_INFO, &c);
+ if (ret) {
+ lnvm_close(fd);
+ return ret;
+ }
+
+ printf("LightNVM (%u,%u,%u). %u target type(s) registered.\n",
+ c.version[0], c.version[1], c.version[2], c.tgtsize);
+ printf("Type\tVersion\n");
+
+ for (i = 0; i < c.tgtsize; i++) {
+ struct nvm_ioctl_info_tgt *tgt = &c.tgts[i];
+
+ printf("%s\t(%u,%u,%u)\n",
+ tgt->tgtname, tgt->version[0], tgt->version[1],
+ tgt->version[2]);
+ }
+
+ lnvm_close(fd);
+ return 0;
+}
+
+int lnvm_do_create_tgt(char *devname, char *tgtname, char *tgttype,
+ int lun_begin, int lun_end,
+ int over_prov, int flags)
+{
+ struct nvm_ioctl_create c;
+ int fd, ret;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ strncpy(c.dev, devname, DISK_NAME_LEN - 1);
+ strncpy(c.tgtname, tgtname, DISK_NAME_LEN - 1);
+ strncpy(c.tgttype, tgttype, NVM_TTYPE_NAME_MAX - 1);
+ c.flags = flags;
+
+ /* Fall back into simple IOCTL version if no extended attributes used */
+ if (over_prov != -1) {
+ c.conf.type = NVM_CONFIG_TYPE_EXTENDED;
+ c.conf.e.lun_begin = lun_begin;
+ c.conf.e.lun_end = lun_end;
+ c.conf.e.over_prov = over_prov;
+ } else {
+ c.conf.type = NVM_CONFIG_TYPE_SIMPLE;
+ c.conf.s.lun_begin = lun_begin;
+ c.conf.s.lun_end = lun_end;
+ }
+
+ ret = ioctl(fd, NVM_DEV_CREATE, &c);
+ if (ret)
+ fprintf(stderr, "Creation of target failed. Please see dmesg.\n");
+
+ lnvm_close(fd);
+ return ret;
+}
+
+int lnvm_do_remove_tgt(char *tgtname)
+{
+ struct nvm_ioctl_remove c;
+ int fd, ret;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ strncpy(c.tgtname, tgtname, DISK_NAME_LEN - 1);
+ c.flags = 0;
+
+ ret = ioctl(fd, NVM_DEV_REMOVE, &c);
+ if (ret)
+ fprintf(stderr, "Remove of target failed. Please see dmesg.\n");
+
+ lnvm_close(fd);
+ return ret;
+}
+
+int lnvm_do_factory_init(char *devname, int erase_only_marked,
+ int clear_host_marks,
+ int clear_bb_marks)
+{
+ struct nvm_ioctl_dev_factory fact;
+ int fd, ret;
+
+ fd = lnvm_open();
+ if (fd < 0)
+ return fd;
+
+ memset(&fact, 0, sizeof(struct nvm_ioctl_dev_factory));
+
+ strncpy(fact.dev, devname, DISK_NAME_LEN - 1);
+ if (erase_only_marked)
+ fact.flags |= NVM_FACTORY_ERASE_ONLY_USER;
+ if (clear_host_marks)
+ fact.flags |= NVM_FACTORY_RESET_HOST_BLKS;
+ if (clear_bb_marks)
+ fact.flags |= NVM_FACTORY_RESET_GRWN_BBLKS;
+
+ ret = ioctl(fd, NVM_DEV_FACTORY, &fact);
+ switch (errno) {
+ case EINVAL:
+ fprintf(stderr, "Factory reset failed.\n");
+ break;
+ case 0:
+ break;
+ default:
+ fprintf(stderr, "Unknown error occurred (%d)\n", errno);
+ break;
+ }
+
+ lnvm_close(fd);
+ return ret;
+}
+
+static void show_lnvm_id_grp(void *t, int human)
+{
+ struct nvme_nvm_id12_group *grp = t;
+ uint32_t mpos = (uint32_t)le32_to_cpu(grp->mpos);
+ uint32_t mccap = (uint32_t)le32_to_cpu(grp->mccap);
+
+ printf(" mtype : %d\n", grp->mtype);
+ if (human) {
+ if (grp->mtype == LNVM_IDFY_GRP_MTYPE_NAND)
+ printf(" NAND Flash Memory\n");
+ else
+ printf(" Reserved\n");
+ }
+ printf(" fmtype : %d\n", grp->fmtype);
+ if (human) {
+ if (grp->fmtype == LNVM_IDFY_GRP_FMTYPE_SLC)
+ printf(" Single bit Level Cell flash (SLC)\n");
+ else if (grp->fmtype == LNVM_IDFY_GRP_FMTYPE_MLC)
+ printf(" Two bit Level Cell flash (MLC)\n");
+ else if (grp->fmtype == LNVM_IDFY_GRP_FMTYPE_TLC)
+ printf(" Three bit Level Cell flash (TLC)\n");
+ else
+ printf(" Reserved\n");
+ }
+ printf(" chnls : %d\n", grp->num_ch);
+ printf(" luns : %d\n", grp->num_lun);
+ printf(" plns : %d\n", grp->num_pln);
+ printf(" blks : %d\n", (uint16_t)le16_to_cpu(grp->num_blk));
+ printf(" pgs : %d\n", (uint16_t)le16_to_cpu(grp->num_pg));
+ printf(" fpg_sz : %d\n", (uint16_t)le16_to_cpu(grp->fpg_sz));
+ printf(" csecs : %d\n", (uint16_t)le16_to_cpu(grp->csecs));
+ printf(" sos : %d\n", (uint16_t)le16_to_cpu(grp->sos));
+ printf(" trdt : %d\n", (uint32_t)le32_to_cpu(grp->trdt));
+ printf(" trdm : %d\n", (uint32_t)le32_to_cpu(grp->trdm));
+ printf(" tprt : %d\n", (uint32_t)le32_to_cpu(grp->tprt));
+ printf(" tprm : %d\n", (uint32_t)le32_to_cpu(grp->tprm));
+ printf(" tbet : %d\n", (uint32_t)le32_to_cpu(grp->tbet));
+ printf(" tbem : %d\n", (uint32_t)le32_to_cpu(grp->tbem));
+ printf(" mpos : %#x\n", mpos);
+ if (human) {
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_SNGL_PLN_RD))
+ printf(" [0]: Single plane read\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_DUAL_PLN_RD))
+ printf(" [1]: Dual plane read\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_QUAD_PLN_RD))
+ printf(" [2]: Quad plane read\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_SNGL_PLN_PRG))
+ printf(" [8]: Single plane program\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_DUAL_PLN_PRG))
+ printf(" [9]: Dual plane program\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_QUAD_PLN_PRG))
+ printf(" [10]: Quad plane program\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_SNGL_PLN_ERS))
+ printf(" [16]: Single plane erase\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_DUAL_PLN_ERS))
+ printf(" [17]: Dual plane erase\n");
+ if (mpos & (1 << LNVM_IDFY_GRP_MPOS_QUAD_PLN_ERS))
+ printf(" [18]: Quad plane erase\n");
+ }
+ printf(" mccap : %#x\n", mccap);
+ if (human) {
+ if (mccap & (1 << LNVM_IDFY_GRP_MCCAP_SLC))
+ printf(" [0]: SLC mode\n");
+ if (mccap & (1 << LNVM_IDFY_GRP_MCCAP_CMD_SUSP))
+ printf(" [1]: Command suspension\n");
+ if (mccap & (1 << LNVM_IDFY_GRP_MCCAP_SCRAMBLE))
+ printf(" [2]: Scramble\n");
+ if (mccap & (1 << LNVM_IDFY_GRP_MCCAP_ENCRYPT))
+ printf(" [3]: Encryption\n");
+ }
+ printf(" cpar : %#x\n", (uint16_t)le16_to_cpu(grp->cpar));
+
+}
+
+static void show_lnvm_ppaf(struct nvme_nvm_addr_format *ppaf)
+{
+ printf("ppaf :\n");
+ printf(" ch offs : %d ch bits : %d\n",
+ ppaf->ch_offset, ppaf->ch_len);
+ printf(" lun offs: %d lun bits : %d\n",
+ ppaf->lun_offset, ppaf->lun_len);
+ printf(" pl offs : %d pl bits : %d\n",
+ ppaf->pln_offset, ppaf->pln_len);
+ printf(" blk offs: %d blk bits : %d\n",
+ ppaf->blk_offset, ppaf->blk_len);
+ printf(" pg offs : %d pg bits : %d\n",
+ ppaf->pg_offset, ppaf->pg_len);
+ printf(" sec offs: %d sec bits : %d\n",
+ ppaf->sect_offset, ppaf->sect_len);
+}
+
+static void show_lnvm_id12_ns(void *t, unsigned int flags)
+{
+ int i;
+ int human = flags & VERBOSE;
+ struct nvme_nvm_id12 *id = t;
+
+ uint32_t cap = (uint32_t) le32_to_cpu(id->cap);
+ uint32_t dom = (uint32_t) le32_to_cpu(id->dom);
+ uint32_t cgrps = id->cgrps;
+
+ if (id->cgrps > 4) {
+ fprintf(stderr, "invalid identify geometry returned\n");
+ return;
+ }
+
+ printf("verid : %#x\n", id->ver_id);
+ printf("vmnt : %#x\n", id->vmnt);
+ if (human) {
+ if (!id->vmnt)
+ printf(" Generic/Enable opcodes as found in this spec.");
+ else
+ printf(" Reserved/Reserved for future opcode configurations");
+ }
+ printf("\n");
+ printf("cgrps : %d\n", id->cgrps);
+ printf("cap : %#x\n", cap);
+ if (human) {
+ if (cap & (1 << LNVM_IDFY_CAP_BAD_BLK_TBL_MGMT))
+ printf(" [0]: Bad block table management\n");
+ if (cap & (1 << LNVM_IDFY_CAP_HYBRID_CMD_SUPP))
+ printf(" [1]: Hybrid command support\n");
+ }
+ printf("dom : %#x\n", dom);
+ if (human) {
+ if (dom & (1 << LNVM_IDFY_DOM_HYBRID_MODE))
+ printf(" [0]: Hybrid mode (L2P MAP is in device)\n");
+ if (dom & (1 << LNVM_IDFY_DOM_ECC_MODE))
+ printf(" [1]: Error Code Correction(ECC) mode\n");
+ }
+ show_lnvm_ppaf(&id->ppaf);
+
+ for (i = 0; i < cgrps; i++) {
+ printf("grp : %d\n", i);
+ show_lnvm_id_grp((void *)&id->groups[i], human);
+ }
+}
+
+static void show_lnvm_id20_ns(struct nvme_nvm_id20 *id, unsigned int flags)
+{
+ int human = flags & VERBOSE;
+ uint32_t mccap = (uint32_t) le32_to_cpu(id->mccap);
+
+ printf("ver_major : %#x\n", id->mjr);
+ printf("ver_minor : %#x\n", id->mnr);
+
+ printf("mccap : %#x\n", mccap);
+ if (human) {
+ if (mccap & (1 << LNVM_IDFY_CAP_VCOPY))
+ printf(" [0]: Vector copy support\n");
+ if (mccap & (1 << LNVM_IDFY_CAP_MRESETS))
+ printf(" [1]: Multiple resets support\n");
+ }
+ printf("wit : %d\n", id->wit);
+
+ printf("lba format\n");
+ printf(" grp len : %d\n", id->lbaf.grp_len);
+ printf(" pu len : %d\n", id->lbaf.pu_len);
+ printf(" chk len : %d\n", id->lbaf.chk_len);
+ printf(" clba len : %d\n", id->lbaf.lba_len);
+
+ printf("geometry\n");
+ printf(" num_grp : %d\n", le16_to_cpu(id->num_grp));
+ printf(" num_pu : %d\n", le16_to_cpu(id->num_pu));
+ printf(" num_chk : %d\n", le32_to_cpu(id->num_chk));
+ printf(" clba : %d\n", le32_to_cpu(id->clba));
+ printf("write req\n");
+ printf(" ws_min : %d\n", le32_to_cpu(id->ws_min));
+ printf(" ws_opt : %d\n", le32_to_cpu(id->ws_opt));
+ printf(" mw_cunits : %d\n", le32_to_cpu(id->mw_cunits));
+ printf(" maxoc : %d\n", le32_to_cpu(id->maxoc));
+ printf(" maxocpu : %d\n", le32_to_cpu(id->maxocpu));
+ printf("perf metrics\n");
+ printf(" trdt (ns) : %d\n", le32_to_cpu(id->trdt));
+ printf(" trdm (ns) : %d\n", le32_to_cpu(id->trdm));
+ printf(" twrt (ns) : %d\n", le32_to_cpu(id->twrt));
+ printf(" twrm (ns) : %d\n", le32_to_cpu(id->twrm));
+ printf(" tcrst (ns) : %d\n", le32_to_cpu(id->tcrst));
+ printf(" tcrsm (ns) : %d\n", le32_to_cpu(id->tcrsm));
+}
+
+static void show_lnvm_id_ns(struct nvme_nvm_id *id, unsigned int flags)
+{
+ switch (id->ver_id) {
+ case 1:
+ show_lnvm_id12_ns((void *) id, flags);
+ break;
+ case 2:
+ show_lnvm_id20_ns((void *) id, flags);
+ break;
+ default:
+ fprintf(stderr, "Version %d not supported.\n",
+ id->ver_id);
+ }
+}
+
+int lnvm_get_identity(int fd, int nsid, struct nvme_nvm_id *nvm_id)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_nvm_admin_identity,
+ .nsid = nsid,
+ .addr = (__u64)(uintptr_t)nvm_id,
+ .data_len = sizeof(struct nvme_nvm_id),
+ };
+
+ return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+}
+
+int lnvm_do_id_ns(int fd, int nsid, unsigned int flags)
+{
+ struct nvme_nvm_id nvm_id;
+ int err;
+
+ err = lnvm_get_identity(fd, nsid, &nvm_id);
+ if (!err) {
+ if (flags & BINARY)
+ d_raw((unsigned char *)&nvm_id, sizeof(nvm_id));
+ else
+ show_lnvm_id_ns(&nvm_id, flags);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x) NSID:%d\n",
+ nvme_status_to_string(err), err, nsid);
+ return err;
+}
+
+static inline const char *print_chunk_state(__u8 cs)
+{
+ switch (cs) {
+ case 1 << 0: return "FREE";
+ case 1 << 1: return "CLOSED";
+ case 1 << 2: return "OPEN";
+ case 1 << 3: return "OFFLINE";
+ default: return "UNKNOWN";
+ }
+}
+
+static inline const char *print_chunk_type(__u8 ct)
+{
+ switch (ct & 0xF) {
+ case 1 << 0: return "SEQWRITE_REQ";
+ case 1 << 1: return "RANDWRITE_ALLOWED";
+ default: return "UNKNOWN";
+ }
+}
+
+static inline const char *print_chunk_attr(__u8 ct)
+{
+ switch (ct & 0xF0) {
+ case 1 << 4: return "DEVIATED";
+ default: return "NONE";
+ }
+}
+
+static void show_lnvm_chunk_log(struct nvme_nvm_chunk_desc *chunk_log,
+ __u32 data_len)
+{
+ int nr_entry = data_len / sizeof(struct nvme_nvm_chunk_desc);
+ int idx;
+
+ printf("Total chunks in namespace: %d\n", nr_entry);
+ for (idx = 0; idx < nr_entry; idx++) {
+ struct nvme_nvm_chunk_desc *desc = &chunk_log[idx];
+
+ printf(" [%5d] { ", idx);
+ printf("SLBA: 0x%016"PRIx64, le64_to_cpu(desc->slba));
+ printf(", WP: 0x%016"PRIx64, le64_to_cpu(desc->wp));
+ printf(", CNLB: 0x%016"PRIx64, le64_to_cpu(desc->cnlb));
+ printf(", State: %-8s", print_chunk_state(desc->cs));
+ printf(", Type: %-20s", print_chunk_type(desc->ct));
+ printf(", Attr: %-8s", print_chunk_attr(desc->ct));
+ printf(", WLI: %4d }\n", desc->wli);
+ }
+}
+
+int lnvm_do_chunk_log(int fd, __u32 nsid, __u32 data_len, void *data,
+ unsigned int flags)
+{
+ int err;
+
+ err = nvme_get_log13(fd, nsid, NVM_LID_CHUNK_INFO, 0, 0, 0,
+ false, data_len, data);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x) NSID:%d\n",
+ nvme_status_to_string(err), err, nsid);
+
+ goto out;
+ } else if (err < 0) {
+ err = -errno;
+ perror("nvme_get_log13");
+
+ goto out;
+ }
+
+ if (flags & BINARY)
+ d_raw(data, data_len);
+ else
+ show_lnvm_chunk_log(data, data_len);
+
+out:
+ return err;
+}
+
+static void show_lnvm_bbtbl(struct nvme_nvm_bb_tbl *tbl)
+{
+ printf("verid : %#x\n", (uint16_t)le16_to_cpu(tbl->verid));
+ printf("tblks : %d\n", (uint32_t)le32_to_cpu(tbl->tblks));
+ printf("tfact : %d\n", (uint32_t)le32_to_cpu(tbl->tfact));
+ printf("tgrown : %d\n", (uint32_t)le32_to_cpu(tbl->tgrown));
+ printf("tdresv : %d\n", (uint32_t)le32_to_cpu(tbl->tdresv));
+ printf("thresv : %d\n", (uint32_t)le32_to_cpu(tbl->thresv));
+ printf("Use raw output to retrieve table.\n");
+}
+
+static int __lnvm_do_get_bbtbl(int fd, struct nvme_nvm_id12 *id,
+ struct ppa_addr ppa,
+ unsigned int flags)
+{
+ struct nvme_nvm_id12_group *grp = &id->groups[0];
+ int bbtblsz = ((uint16_t)le16_to_cpu(grp->num_blk) * grp->num_pln);
+ int bufsz = bbtblsz + sizeof(struct nvme_nvm_bb_tbl);
+ struct nvme_nvm_bb_tbl *bbtbl;
+ int err;
+
+ bbtbl = calloc(1, bufsz);
+ if (!bbtbl)
+ return -ENOMEM;
+
+ struct nvme_nvm_getbbtbl cmd = {
+ .opcode = nvme_nvm_admin_get_bb_tbl,
+ .nsid = cpu_to_le32(1),
+ .addr = (__u64)(uintptr_t)bbtbl,
+ .data_len = bufsz,
+ .ppa = cpu_to_le64(ppa.ppa),
+ };
+ void *tmp = &cmd;
+ struct nvme_passthru_cmd *nvme_cmd = tmp;
+
+ err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, nvme_cmd);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ free(bbtbl);
+ return err;
+ }
+
+ if (flags & BINARY)
+ d_raw((unsigned char *)&bbtbl->blk, bbtblsz);
+ else {
+ printf("LightNVM Bad Block Stats:\n");
+ show_lnvm_bbtbl(bbtbl);
+ }
+
+ free(bbtbl);
+ return 0;
+}
+
+int lnvm_do_get_bbtbl(int fd, int nsid, int lunid, int chid, unsigned int flags)
+{
+ struct nvme_nvm_id12 nvm_id;
+ struct ppa_addr ppa;
+ int err;
+ void *tmp = &nvm_id;
+
+ err = lnvm_get_identity(fd, nsid, (struct nvme_nvm_id *)tmp);
+ if (err) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+ }
+
+ if (nvm_id.ver_id != 1) {
+ fprintf(stderr, "Get bad block table not supported on version %d\n",
+ nvm_id.ver_id);
+ return -EINVAL;
+ }
+
+ if (chid >= nvm_id.groups[0].num_ch ||
+ lunid >= nvm_id.groups[0].num_lun) {
+ fprintf(stderr, "Out of bound channel id or LUN id\n");
+ return -EINVAL;
+ }
+
+ ppa.ppa = 0;
+ ppa.g.lun = lunid;
+ ppa.g.ch = chid;
+
+ ppa = generic_to_dev_addr(&nvm_id.ppaf, ppa);
+
+ return __lnvm_do_get_bbtbl(fd, &nvm_id, ppa, flags);
+}
+
+static int __lnvm_do_set_bbtbl(int fd, struct ppa_addr ppa, __u8 value)
+{
+ int err;
+
+ struct nvme_nvm_setbbtbl cmd = {
+ .opcode = nvme_nvm_admin_set_bb_tbl,
+ .nsid = cpu_to_le32(1),
+ .ppa = cpu_to_le64(ppa.ppa),
+ .nlb = cpu_to_le16(0),
+ .value = value,
+ };
+ void *tmp = &cmd;
+ struct nvme_passthru_cmd *nvme_cmd = tmp;
+
+ err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD, nvme_cmd);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+ }
+ return 0;
+}
+
+int lnvm_do_set_bbtbl(int fd, int nsid,
+ int chid, int lunid, int plnid, int blkid,
+ __u8 value)
+{
+ struct nvme_nvm_id12 nvm_id;
+ struct ppa_addr ppa;
+ int err;
+ void *tmp = &nvm_id;
+
+ err = lnvm_get_identity(fd, nsid, (struct nvme_nvm_id *)tmp);
+ if (err) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+ }
+
+ if (nvm_id.ver_id != 1) {
+ fprintf(stderr, "Set bad block table not supported on version %d\n",
+ nvm_id.ver_id);
+ return -EINVAL;
+ }
+
+ if (chid >= nvm_id.groups[0].num_ch ||
+ lunid >= nvm_id.groups[0].num_lun ||
+ plnid >= nvm_id.groups[0].num_pln ||
+ blkid >= le16_to_cpu(nvm_id.groups[0].num_blk)) {
+ fprintf(stderr, "Out of bound channel id, LUN id, plane id, or"\
+ "block id\n");
+ return -EINVAL;
+ }
+
+ ppa.ppa = 0;
+ ppa.g.lun = lunid;
+ ppa.g.ch = chid;
+ ppa.g.pl = plnid;
+ ppa.g.blk = blkid;
+
+ ppa = generic_to_dev_addr(&nvm_id.ppaf, ppa);
+
+ return __lnvm_do_set_bbtbl(fd, ppa, value);
+}
diff --git a/nvme-lightnvm.h b/nvme-lightnvm.h
new file mode 100644
index 0000000..19660b7
--- /dev/null
+++ b/nvme-lightnvm.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2016 CNEX Labs. All rights reserved.
+ *
+ * Author: Matias Bjoerling <matias@cnexlabs.com>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
+ * USA.
+ */
+
+#ifndef NVME_LIGHTNVM_H_
+#define NVME_LIGHTNVM_H_
+
+#include "linux/lightnvm.h"
+
+enum nvme_nvm_admin_opcode {
+ nvme_nvm_admin_identity = 0xe2,
+ nvme_nvm_admin_get_bb_tbl = 0xf2,
+ nvme_nvm_admin_set_bb_tbl = 0xf1,
+};
+
+struct nvme_nvm_identity {
+ __u8 opcode;
+ __u8 flags;
+ __le16 command_id;
+ __le32 nsid;
+ __le64 rsvd[2];
+ __le64 prp1;
+ __le64 prp2;
+ __le32 chnl_off;
+ __le32 rsvd11[5];
+};
+
+struct nvme_nvm_setbbtbl {
+ __u8 opcode;
+ __u8 flags;
+ __le16 rsvd1;
+ __le32 nsid;
+ __le32 cdw2;
+ __le32 cdw3;
+ __le64 metadata;
+ __u64 addr;
+ __le32 metadata_len;
+ __le32 data_len;
+ __le64 ppa;
+ __le16 nlb;
+ __u8 value;
+ __u8 rsvd2;
+ __le32 cdw14;
+ __le32 cdw15;
+ __le32 timeout_ms;
+ __le32 result;
+};
+
+struct nvme_nvm_getbbtbl {
+ __u8 opcode;
+ __u8 flags;
+ __le16 rsvd1;
+ __le32 nsid;
+ __le32 cdw2;
+ __le32 cdw3;
+ __u64 metadata;
+ __u64 addr;
+ __u32 metadata_len;
+ __u32 data_len;
+ __le64 ppa;
+ __le32 cdw12;
+ __le32 cdw13;
+ __le32 cdw14;
+ __le32 cdw15;
+ __le32 timeout_ms;
+ __le32 result;
+};
+
+struct nvme_nvm_command {
+ union {
+ struct nvme_nvm_identity identity;
+ struct nvme_nvm_getbbtbl get_bb;
+ };
+};
+
+struct nvme_nvm_completion {
+ __le64 result; /* Used by LightNVM to return ppa completions */
+ __le16 sq_head; /* how much of this queue may be reclaimed */
+ __le16 sq_id; /* submission queue that generated this entry */
+ __le16 command_id; /* of the command which completed */
+ __le16 status; /* did the command fail, and if so, why? */
+};
+
+#define NVME_NVM_LP_MLC_PAIRS 886
+struct nvme_nvm_lp_mlc {
+ __le16 num_pairs;
+ __u8 pairs[NVME_NVM_LP_MLC_PAIRS];
+};
+
+struct nvme_nvm_lp_tbl {
+ __u8 id[8];
+ struct nvme_nvm_lp_mlc mlc;
+};
+
+struct nvme_nvm_id12_group {
+ __u8 mtype;
+ __u8 fmtype;
+ __le16 res16;
+ __u8 num_ch;
+ __u8 num_lun;
+ __u8 num_pln;
+ __u8 rsvd1;
+ __le16 num_blk;
+ __le16 num_pg;
+ __le16 fpg_sz;
+ __le16 csecs;
+ __le16 sos;
+ __le16 rsvd2;
+ __le32 trdt;
+ __le32 trdm;
+ __le32 tprt;
+ __le32 tprm;
+ __le32 tbet;
+ __le32 tbem;
+ __le32 mpos;
+ __le32 mccap;
+ __le16 cpar;
+ __u8 reserved[10];
+ struct nvme_nvm_lp_tbl lptbl;
+} __attribute__((packed));
+
+struct nvme_nvm_addr_format {
+ __u8 ch_offset;
+ __u8 ch_len;
+ __u8 lun_offset;
+ __u8 lun_len;
+ __u8 pln_offset;
+ __u8 pln_len;
+ __u8 blk_offset;
+ __u8 blk_len;
+ __u8 pg_offset;
+ __u8 pg_len;
+ __u8 sect_offset;
+ __u8 sect_len;
+ __u8 res[4];
+} __attribute__((packed));
+
+enum {
+ LNVM_IDFY_CAP_BAD_BLK_TBL_MGMT = 0,
+ LNVM_IDFY_CAP_HYBRID_CMD_SUPP = 1,
+ LNVM_IDFY_CAP_VCOPY = 0,
+ LNVM_IDFY_CAP_MRESETS = 1,
+ LNVM_IDFY_DOM_HYBRID_MODE = 0,
+ LNVM_IDFY_DOM_ECC_MODE = 1,
+ LNVM_IDFY_GRP_MTYPE_NAND = 0,
+ LNVM_IDFY_GRP_FMTYPE_SLC = 0,
+ LNVM_IDFY_GRP_FMTYPE_MLC = 1,
+ LNVM_IDFY_GRP_FMTYPE_TLC = 2,
+ LNVM_IDFY_GRP_MPOS_SNGL_PLN_RD = 0,
+ LNVM_IDFY_GRP_MPOS_DUAL_PLN_RD = 1,
+ LNVM_IDFY_GRP_MPOS_QUAD_PLN_RD = 2,
+ LNVM_IDFY_GRP_MPOS_SNGL_PLN_PRG = 8,
+ LNVM_IDFY_GRP_MPOS_DUAL_PLN_PRG = 9,
+ LNVM_IDFY_GRP_MPOS_QUAD_PLN_PRG = 10,
+ LNVM_IDFY_GRP_MPOS_SNGL_PLN_ERS = 16,
+ LNVM_IDFY_GRP_MPOS_DUAL_PLN_ERS = 17,
+ LNVM_IDFY_GRP_MPOS_QUAD_PLN_ERS = 18,
+ LNVM_IDFY_GRP_MCCAP_SLC = 0,
+ LNVM_IDFY_GRP_MCCAP_CMD_SUSP = 1,
+ LNVM_IDFY_GRP_MCCAP_SCRAMBLE = 2,
+ LNVM_IDFY_GRP_MCCAP_ENCRYPT = 3,
+};
+
+struct nvme_nvm_id12 {
+ __u8 ver_id;
+ __u8 vmnt;
+ __u8 cgrps;
+ __u8 res;
+ __le32 cap;
+ __le32 dom;
+ struct nvme_nvm_addr_format ppaf;
+ __u8 resv[228];
+ struct nvme_nvm_id12_group groups[4];
+} __attribute__((packed));
+
+struct nvme_nvm_id20_addrf {
+ __u8 grp_len;
+ __u8 pu_len;
+ __u8 chk_len;
+ __u8 lba_len;
+ __u8 resv[4];
+} __attribute__((packed));
+
+struct nvme_nvm_id20 {
+ __u8 mjr;
+ __u8 mnr;
+ __u8 resv[6];
+
+ struct nvme_nvm_id20_addrf lbaf;
+
+ __le32 mccap;
+ __u8 resv2[12];
+
+ __u8 wit;
+ __u8 resv3[31];
+
+ /* Geometry */
+ __le16 num_grp;
+ __le16 num_pu;
+ __le32 num_chk;
+ __le32 clba;
+ __u8 resv4[52];
+
+ /* Write data requirements */
+ __le32 ws_min;
+ __le32 ws_opt;
+ __le32 mw_cunits;
+ __le32 maxoc;
+ __le32 maxocpu;
+ __u8 resv5[44];
+
+ /* Performance related metrics */
+ __le32 trdt;
+ __le32 trdm;
+ __le32 twrt;
+ __le32 twrm;
+ __le32 tcrst;
+ __le32 tcrsm;
+ __u8 resv6[40];
+
+ /* Reserved area */
+ __u8 resv7[2816];
+
+ /* Vendor specific */
+ __u8 vs[1024];
+} __attribute__((packed));
+
+struct nvme_nvm_id {
+ __u8 ver_id;
+ __u8 resv[4095];
+} __attribute__((packed));
+
+enum {
+ NVM_LID_CHUNK_INFO = 0xCA,
+};
+
+struct nvme_nvm_chunk_desc {
+ __u8 cs;
+ __u8 ct;
+ __u8 wli;
+ __u8 rsvd_7_3[5];
+ __u64 slba;
+ __u64 cnlb;
+ __u64 wp;
+};
+
+struct nvme_nvm_bb_tbl {
+ __u8 tblid[4];
+ __le16 verid;
+ __le16 revid;
+ __le32 rvsd1;
+ __le32 tblks;
+ __le32 tfact;
+ __le32 tgrown;
+ __le32 tdresv;
+ __le32 thresv;
+ __le32 rsvd2[8];
+ __u8 blk[0];
+};
+
+#define NVM_BLK_BITS (16)
+#define NVM_PG_BITS (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS (8)
+#define NVM_LUN_BITS (8)
+#define NVM_CH_BITS (7)
+
+struct ppa_addr {
+ /* Generic structure for all addresses */
+ union {
+ struct {
+ __u64 blk : NVM_BLK_BITS;
+ __u64 pg : NVM_PG_BITS;
+ __u64 sec : NVM_SEC_BITS;
+ __u64 pl : NVM_PL_BITS;
+ __u64 lun : NVM_LUN_BITS;
+ __u64 ch : NVM_CH_BITS;
+ __u64 reserved : 1;
+ } g;
+
+ __u64 ppa;
+ };
+};
+
+static inline struct ppa_addr generic_to_dev_addr(
+ struct nvme_nvm_addr_format *ppaf, struct ppa_addr r)
+{
+ struct ppa_addr l;
+
+ l.ppa = ((__u64)r.g.blk) << ppaf->blk_offset;
+ l.ppa |= ((__u64)r.g.pg) << ppaf->pg_offset;
+ l.ppa |= ((__u64)r.g.sec) << ppaf->sect_offset;
+ l.ppa |= ((__u64)r.g.pl) << ppaf->pln_offset;
+ l.ppa |= ((__u64)r.g.lun) << ppaf->lun_offset;
+ l.ppa |= ((__u64)r.g.ch) << ppaf->ch_offset;
+
+ return l;
+}
+
+int lnvm_get_identity(int fd, int nsid, struct nvme_nvm_id *nvm_id);
+
+int lnvm_do_init(char *, char *);
+int lnvm_do_list_devices(void);
+int lnvm_do_info(void);
+int lnvm_do_create_tgt(char *, char *, char *, int, int, int, int);
+int lnvm_do_remove_tgt(char *);
+int lnvm_do_factory_init(char *, int, int, int);
+int lnvm_do_id_ns(int, int, unsigned int);
+int lnvm_do_chunk_log(int, __u32, __u32, void *, unsigned int);
+int lnvm_do_get_bbtbl(int, int, int, int, unsigned int);
+int lnvm_do_set_bbtbl(int, int, int, int, int, int, __u8);
+
+#endif
diff --git a/nvme-models.c b/nvme-models.c
new file mode 100644
index 0000000..9b5077d
--- /dev/null
+++ b/nvme-models.c
@@ -0,0 +1,338 @@
+#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 = find_data(data);
+ if (!data)
+ 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)
+ 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 %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));
+}
+
+static void format_all(char *save, char *vendor, char *device)
+{
+ if (device_top && device_mid && device_final)
+ 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;
+ 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 */
+ if(!read(fd, save, savesz - 1))
+ ret = 1;
+
+ 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';
+ 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 !line ? strdup("NULL") : strdup("Unknown Device");
+}
diff --git a/nvme-models.h b/nvme-models.h
new file mode 100644
index 0000000..72983ea
--- /dev/null
+++ b/nvme-models.h
@@ -0,0 +1,6 @@
+#ifndef NVME_MODEL_H
+#define NVME_MODEL_H
+
+char *nvme_product_name(int id);
+
+#endif
diff --git a/nvme-print.c b/nvme-print.c
new file mode 100644
index 0000000..30fca29
--- /dev/null
+++ b/nvme-print.c
@@ -0,0 +1,4706 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "nvme-print.h"
+#include "util/json.h"
+#include "nvme-models.h"
+#include "util/suffix.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 long double int128_to_double(__u8 *data)
+{
+ int i;
+ long double result = 0;
+
+ for (i = 0; i < 16; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+ return result;
+}
+
+static const char *nvme_ana_state_to_string(enum nvme_ana_state state)
+{
+ switch (state) {
+ case NVME_ANA_OPTIMIZED:
+ return "optimized";
+ case NVME_ANA_NONOPTIMIZED:
+ return "non-optimized";
+ case NVME_ANA_INACCESSIBLE:
+ return "inaccessible";
+ case NVME_ANA_PERSISTENT_LOSS:
+ return "persistent-loss";
+ case NVME_ANA_CHANGE:
+ return "change";
+ }
+ return "invalid state";
+}
+
+static 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_activate_fw: return "Firmware Commit";
+ case nvme_admin_download_fw: 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 "NVMEe-MI Send";
+ case nvme_admin_nvme_mi_recv: return "NVMEe-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";
+ }
+ } 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";
+ }
+ }
+
+ return "Unknown";
+}
+
+static const char *fw_to_string(__u64 fw)
+{
+ static char ret[9];
+ char *c = (char *)&fw;
+ int i;
+
+ for (i = 0; i < 8; i++)
+ ret[i] = c[i] >= '!' && c[i] <= '~' ? c[i] : '.';
+ ret[i] = '\0';
+ return ret;
+}
+
+static const char *get_sanitize_log_sstat_status_str(__u16 status)
+{
+ const char *str;
+
+ switch (status & NVME_SANITIZE_LOG_STATUS_MASK) {
+ case NVME_SANITIZE_LOG_NEVER_SANITIZED:
+ str = "NVM Subsystem has never been sanitized.";
+ break;
+ case NVME_SANITIZE_LOG_COMPLETED_SUCCESS:
+ str = "Most Recent Sanitize Command Completed Successfully.";
+ break;
+ case NVME_SANITIZE_LOG_IN_PROGESS:
+ str = "Sanitize in Progress.";
+ break;
+ case NVME_SANITIZE_LOG_COMPLETED_FAILED:
+ str = "Most Recent Sanitize Command Failed.";
+ break;
+ case NVME_SANITIZE_LOG_ND_COMPLETED_SUCCESS:
+ str = "Most Recent Sanitize Command (No-Deallocate After Sanitize) Completed Successfully.";
+ break;
+ default:
+ str = "Unknown.";
+ }
+
+ return str;
+}
+
+static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int mode)
+{
+ char nguid_buf[2 * sizeof(ns->nguid) + 1],
+ eui64_buf[2 * sizeof(ns->eui64) + 1];
+ char *nguid = nguid_buf, *eui64 = eui64_buf;
+ struct json_object *root;
+ struct json_array *lbafs;
+ int i;
+
+ long double nvmcap = int128_to_double(ns->nvmcap);
+
+ root = json_create_object();
+
+ json_object_add_value_uint(root, "nsze", le64_to_cpu(ns->nsze));
+ json_object_add_value_uint(root, "ncap", le64_to_cpu(ns->ncap));
+ json_object_add_value_uint(root, "nuse", le64_to_cpu(ns->nuse));
+ json_object_add_value_int(root, "nsfeat", ns->nsfeat);
+ json_object_add_value_int(root, "nlbaf", ns->nlbaf);
+ json_object_add_value_int(root, "flbas", ns->flbas);
+ json_object_add_value_int(root, "mc", ns->mc);
+ json_object_add_value_int(root, "dpc", ns->dpc);
+ json_object_add_value_int(root, "dps", ns->dps);
+ json_object_add_value_int(root, "nmic", ns->nmic);
+ json_object_add_value_int(root, "rescap", ns->rescap);
+ json_object_add_value_int(root, "fpi", ns->fpi);
+ json_object_add_value_int(root, "nawun", le16_to_cpu(ns->nawun));
+ json_object_add_value_int(root, "nawupf", le16_to_cpu(ns->nawupf));
+ json_object_add_value_int(root, "nacwu", le16_to_cpu(ns->nacwu));
+ json_object_add_value_int(root, "nabsn", le16_to_cpu(ns->nabsn));
+ json_object_add_value_int(root, "nabo", le16_to_cpu(ns->nabo));
+ json_object_add_value_int(root, "nabspf", le16_to_cpu(ns->nabspf));
+ json_object_add_value_int(root, "noiob", le16_to_cpu(ns->noiob));
+ json_object_add_value_float(root, "nvmcap", nvmcap);
+ json_object_add_value_int(root, "nsattr", ns->nsattr);
+ json_object_add_value_int(root, "nvmsetid", le16_to_cpu(ns->nvmsetid));
+
+ if (ns->nsfeat & 0x10) {
+ json_object_add_value_int(root, "npwg", le16_to_cpu(ns->npwg));
+ json_object_add_value_int(root, "npwa", le16_to_cpu(ns->npwa));
+ json_object_add_value_int(root, "npdg", le16_to_cpu(ns->npdg));
+ json_object_add_value_int(root, "npda", le16_to_cpu(ns->npda));
+ json_object_add_value_int(root, "nows", le16_to_cpu(ns->nows));
+ }
+
+ json_object_add_value_int(root, "anagrpid", le32_to_cpu(ns->anagrpid));
+ json_object_add_value_int(root, "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]);
+
+ json_object_add_value_string(root, "eui64", eui64_buf);
+ json_object_add_value_string(root, "nguid", nguid_buf);
+
+ lbafs = json_create_array();
+ json_object_add_value_array(root, "lbafs", lbafs);
+
+ for (i = 0; i <= ns->nlbaf; i++) {
+ struct json_object *lbaf = json_create_object();
+
+ json_object_add_value_int(lbaf, "ms",
+ le16_to_cpu(ns->lbaf[i].ms));
+ json_object_add_value_int(lbaf, "ds", ns->lbaf[i].ds);
+ json_object_add_value_int(lbaf, "rp", ns->lbaf[i].rp);
+
+ json_array_add_value_object(lbafs, lbaf);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
+ void (*vs)(__u8 *vs, struct json_object *root))
+{
+ struct json_object *root;
+ struct json_array *psds;
+
+ long double tnvmcap = int128_to_double(ctrl->tnvmcap);
+ long double unvmcap = int128_to_double(ctrl->unvmcap);
+
+ 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);
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "vid", le16_to_cpu(ctrl->vid));
+ json_object_add_value_int(root, "ssvid", le16_to_cpu(ctrl->ssvid));
+ json_object_add_value_string(root, "sn", sn);
+ json_object_add_value_string(root, "mn", mn);
+ json_object_add_value_string(root, "fr", fr);
+ json_object_add_value_int(root, "rab", ctrl->rab);
+ json_object_add_value_int(root, "ieee", ieee);
+ json_object_add_value_int(root, "cmic", ctrl->cmic);
+ json_object_add_value_int(root, "mdts", ctrl->mdts);
+ json_object_add_value_int(root, "cntlid", le16_to_cpu(ctrl->cntlid));
+ json_object_add_value_uint(root, "ver", le32_to_cpu(ctrl->ver));
+ json_object_add_value_uint(root, "rtd3r", le32_to_cpu(ctrl->rtd3r));
+ json_object_add_value_uint(root, "rtd3e", le32_to_cpu(ctrl->rtd3e));
+ json_object_add_value_uint(root, "oaes", le32_to_cpu(ctrl->oaes));
+ json_object_add_value_int(root, "ctratt", le32_to_cpu(ctrl->ctratt));
+ json_object_add_value_int(root, "rrls", le16_to_cpu(ctrl->rrls));
+ json_object_add_value_int(root, "crdt1", le16_to_cpu(ctrl->crdt1));
+ json_object_add_value_int(root, "crdt2", le16_to_cpu(ctrl->crdt2));
+ json_object_add_value_int(root, "crdt3", le16_to_cpu(ctrl->crdt3));
+ json_object_add_value_int(root, "oacs", le16_to_cpu(ctrl->oacs));
+ json_object_add_value_int(root, "acl", ctrl->acl);
+ json_object_add_value_int(root, "aerl", ctrl->aerl);
+ json_object_add_value_int(root, "frmw", ctrl->frmw);
+ json_object_add_value_int(root, "lpa", ctrl->lpa);
+ json_object_add_value_int(root, "elpe", ctrl->elpe);
+ json_object_add_value_int(root, "npss", ctrl->npss);
+ json_object_add_value_int(root, "avscc", ctrl->avscc);
+ json_object_add_value_int(root, "apsta", ctrl->apsta);
+ json_object_add_value_int(root, "wctemp", le16_to_cpu(ctrl->wctemp));
+ json_object_add_value_int(root, "cctemp", le16_to_cpu(ctrl->cctemp));
+ json_object_add_value_int(root, "mtfa", le16_to_cpu(ctrl->mtfa));
+ json_object_add_value_uint(root, "hmpre", le32_to_cpu(ctrl->hmpre));
+ json_object_add_value_uint(root, "hmmin", le32_to_cpu(ctrl->hmmin));
+ json_object_add_value_float(root, "tnvmcap", tnvmcap);
+ json_object_add_value_float(root, "unvmcap", unvmcap);
+ json_object_add_value_uint(root, "rpmbs", le32_to_cpu(ctrl->rpmbs));
+ json_object_add_value_int(root, "edstt", le16_to_cpu(ctrl->edstt));
+ json_object_add_value_int(root, "dsto", ctrl->dsto);
+ json_object_add_value_int(root, "fwug", ctrl->fwug);
+ json_object_add_value_int(root, "kas", le16_to_cpu(ctrl->kas));
+ json_object_add_value_int(root, "hctma", le16_to_cpu(ctrl->hctma));
+ json_object_add_value_int(root, "mntmt", le16_to_cpu(ctrl->mntmt));
+ json_object_add_value_int(root, "mxtmt", le16_to_cpu(ctrl->mxtmt));
+ json_object_add_value_int(root, "sanicap", le32_to_cpu(ctrl->sanicap));
+ json_object_add_value_int(root, "hmminds", le32_to_cpu(ctrl->hmminds));
+ json_object_add_value_int(root, "hmmaxd", le16_to_cpu(ctrl->hmmaxd));
+ json_object_add_value_int(root, "nsetidmax",
+ le16_to_cpu(ctrl->nsetidmax));
+
+ json_object_add_value_int(root, "anatt",ctrl->anatt);
+ json_object_add_value_int(root, "anacap", ctrl->anacap);
+ json_object_add_value_int(root, "anagrpmax",
+ le32_to_cpu(ctrl->anagrpmax));
+ json_object_add_value_int(root, "nanagrpid",
+ le32_to_cpu(ctrl->nanagrpid));
+ json_object_add_value_int(root, "sqes", ctrl->sqes);
+ json_object_add_value_int(root, "cqes", ctrl->cqes);
+ json_object_add_value_int(root, "maxcmd", le16_to_cpu(ctrl->maxcmd));
+ json_object_add_value_uint(root, "nn", le32_to_cpu(ctrl->nn));
+ json_object_add_value_int(root, "oncs", le16_to_cpu(ctrl->oncs));
+ json_object_add_value_int(root, "fuses", le16_to_cpu(ctrl->fuses));
+ json_object_add_value_int(root, "fna", ctrl->fna);
+ json_object_add_value_int(root, "vwc", ctrl->vwc);
+ json_object_add_value_int(root, "awun", le16_to_cpu(ctrl->awun));
+ json_object_add_value_int(root, "awupf", le16_to_cpu(ctrl->awupf));
+ json_object_add_value_int(root, "nvscc", ctrl->nvscc);
+ json_object_add_value_int(root, "nwpc", ctrl->nwpc);
+ json_object_add_value_int(root, "acwu", le16_to_cpu(ctrl->acwu));
+ json_object_add_value_int(root, "sgls", le32_to_cpu(ctrl->sgls));
+
+ if (strlen(subnqn))
+ json_object_add_value_string(root, "subnqn", subnqn);
+
+ json_object_add_value_int(root, "ioccsz", le32_to_cpu(ctrl->ioccsz));
+ json_object_add_value_int(root, "iorcsz", le32_to_cpu(ctrl->iorcsz));
+ json_object_add_value_int(root, "icdoff", le16_to_cpu(ctrl->icdoff));
+ json_object_add_value_int(root, "ctrattr", ctrl->ctrattr);
+ json_object_add_value_int(root, "msdbd", ctrl->msdbd);
+
+ psds = json_create_array();
+ json_object_add_value_array(root, "psds", psds);
+
+ for (i = 0; i <= ctrl->npss; i++) {
+ struct json_object *psd = json_create_object();
+
+ json_object_add_value_int(psd, "max_power",
+ le16_to_cpu(ctrl->psd[i].max_power));
+ json_object_add_value_int(psd, "flags", ctrl->psd[i].flags);
+ json_object_add_value_uint(psd, "entry_lat",
+ le32_to_cpu(ctrl->psd[i].entry_lat));
+ json_object_add_value_uint(psd, "exit_lat",
+ le32_to_cpu(ctrl->psd[i].exit_lat));
+ json_object_add_value_int(psd, "read_tput",
+ ctrl->psd[i].read_tput);
+ json_object_add_value_int(psd, "read_lat",
+ ctrl->psd[i].read_lat);
+ json_object_add_value_int(psd, "write_tput",
+ ctrl->psd[i].write_tput);
+ json_object_add_value_int(psd, "write_lat",
+ ctrl->psd[i].write_lat);
+ json_object_add_value_int(psd, "idle_power",
+ le16_to_cpu(ctrl->psd[i].idle_power));
+ json_object_add_value_int(psd, "idle_scale",
+ ctrl->psd[i].idle_scale);
+ json_object_add_value_int(psd, "active_power",
+ le16_to_cpu(ctrl->psd[i].active_power));
+ json_object_add_value_int(psd, "active_work_scale",
+ ctrl->psd[i].active_work_scale);
+
+ json_array_add_value_object(psds, psd);
+ }
+
+ if(vs)
+ vs(ctrl->vs, root);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_error_log(struct nvme_error_log_page *err_log, int entries)
+{
+ struct json_object *root;
+ struct json_array *errors;
+ int i;
+
+ root = json_create_object();
+ errors = json_create_array();
+ json_object_add_value_array(root, "errors", errors);
+
+ for (i = 0; i < entries; i++) {
+ struct json_object *error = json_create_object();
+
+ json_object_add_value_uint(error, "error_count",
+ le64_to_cpu(err_log[i].error_count));
+ json_object_add_value_int(error, "sqid",
+ le16_to_cpu(err_log[i].sqid));
+ json_object_add_value_int(error, "cmdid",
+ le16_to_cpu(err_log[i].cmdid));
+ json_object_add_value_int(error, "status_field",
+ le16_to_cpu(err_log[i].status_field));
+ json_object_add_value_int(error, "parm_error_location",
+ le16_to_cpu(err_log[i].parm_error_location));
+ json_object_add_value_uint(error, "lba",
+ le64_to_cpu(err_log[i].lba));
+ json_object_add_value_uint(error, "nsid",
+ le32_to_cpu(err_log[i].nsid));
+ json_object_add_value_int(error, "vs", err_log[i].vs);
+ json_object_add_value_int(error, "trtype", err_log[i].trtype);
+ json_object_add_value_uint(error, "cs",
+ le64_to_cpu(err_log[i].cs));
+ json_object_add_value_int(error, "trtype_spec_info",
+ le16_to_cpu(err_log[i].trtype_spec_info));
+
+ json_array_add_value_object(errors, error);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_nvme_resv_report(struct nvme_reservation_status *status,
+ int bytes, __u32 cdw11)
+{
+ struct json_object *root;
+ struct json_array *rcs;
+ int i, j, regctl, entries;
+
+ regctl = status->regctl[0] | (status->regctl[1] << 8);
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "gen", le32_to_cpu(status->gen));
+ json_object_add_value_int(root, "rtype", status->rtype);
+ json_object_add_value_int(root, "regctl", regctl);
+ json_object_add_value_int(root, "ptpls", status->ptpls);
+
+ rcs = json_create_array();
+ /* check Extended Data Structure bit */
+ if ((cdw11 & 0x1) == 0) {
+ /*
+ * if status buffer was too small, don't loop past the end of
+ * the buffer
+ */
+ entries = (bytes - 24) / 24;
+ if (entries < regctl)
+ regctl = entries;
+
+ json_object_add_value_array(root, "regctls", rcs);
+ for (i = 0; i < regctl; i++) {
+ struct json_object *rc = json_create_object();
+
+ json_object_add_value_int(rc, "cntlid",
+ le16_to_cpu(status->regctl_ds[i].cntlid));
+ json_object_add_value_int(rc, "rcsts",
+ status->regctl_ds[i].rcsts);
+ json_object_add_value_uint(rc, "hostid",
+ le64_to_cpu(status->regctl_ds[i].hostid));
+ json_object_add_value_uint(rc, "rkey",
+ le64_to_cpu(status->regctl_ds[i].rkey));
+
+ json_array_add_value_object(rcs, rc);
+ }
+ } else {
+ struct nvme_reservation_status_ext *ext_status = (struct nvme_reservation_status_ext *)status;
+ 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;
+
+ json_object_add_value_array(root, "regctlext", rcs);
+ for (i = 0; i < regctl; i++) {
+ struct json_object *rc = json_create_object();
+
+ json_object_add_value_int(rc, "cntlid",
+ le16_to_cpu(ext_status->regctl_eds[i].cntlid));
+ json_object_add_value_int(rc, "rcsts",
+ ext_status->regctl_eds[i].rcsts);
+ json_object_add_value_uint(rc, "rkey",
+ le64_to_cpu(ext_status->regctl_eds[i].rkey));
+ for (j = 0; j < 16; j++)
+ sprintf(hostid + j * 2, "%02x",
+ ext_status->regctl_eds[i].hostid[j]);
+
+ json_object_add_value_string(rc, "hostid", hostid);
+ json_array_add_value_object(rcs, rc);
+ }
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname)
+{
+ struct json_object *root;
+ struct json_object *fwsi;
+ char fmt[21];
+ char str[32];
+ int i;
+
+ root = json_create_object();
+ fwsi = json_create_object();
+
+ json_object_add_value_int(fwsi, "Active Firmware Slot (afi)",
+ fw_log->afi);
+ for (i = 0; i < 7; i++) {
+ if (fw_log->frs[i]) {
+ snprintf(fmt, sizeof(fmt), "Firmware Rev Slot %d",
+ i + 1);
+ snprintf(str, sizeof(str), "%"PRIu64" (%s)",
+ (uint64_t)fw_log->frs[i],
+ fw_to_string(fw_log->frs[i]));
+ json_object_add_value_string(fwsi, fmt, str);
+ }
+ }
+ json_object_add_value_object(root, devname, fwsi);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_changed_ns_list_log(struct nvme_changed_ns_list_log *log,
+ const char *devname)
+{
+ struct json_object *root;
+ struct json_object *nsi;
+ char fmt[32];
+ char str[32];
+ __u32 nsid;
+ int i;
+
+ if (log->log[0] == cpu_to_le32(0xffffffff))
+ return;
+
+ root = json_create_object();
+ nsi = json_create_object();
+
+ json_object_add_value_string(root, "Changed Namespace List Log",
+ devname);
+
+ for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) {
+ nsid = le32_to_cpu(log->log[i]);
+
+ if (nsid == 0)
+ break;
+
+ snprintf(fmt, sizeof(fmt), "[%4u]", i + 1);
+ snprintf(str, sizeof(str), "%#x", nsid);
+ json_object_add_value_string(nsi, fmt, str);
+ }
+
+ json_object_add_value_object(root, devname, nsi);
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+static void json_endurance_log(struct nvme_endurance_group_log *endurance_group,
+ __u16 group_id)
+{
+ struct json_object *root;
+
+ long double endurance_estimate =
+ int128_to_double(endurance_group->endurance_estimate);
+ long double data_units_read =
+ int128_to_double(endurance_group->data_units_read);
+ long double data_units_written =
+ int128_to_double(endurance_group->data_units_written);
+ long double media_units_written =
+ int128_to_double(endurance_group->media_units_written);
+ long double host_read_cmds =
+ int128_to_double(endurance_group->host_read_cmds);
+ long double host_write_cmds =
+ int128_to_double(endurance_group->host_write_cmds);
+ long double media_data_integrity_err =
+ int128_to_double(endurance_group->media_data_integrity_err);
+ long double num_err_info_log_entries =
+ int128_to_double(endurance_group->num_err_info_log_entries);
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "critical_warning",
+ endurance_group->critical_warning);
+ json_object_add_value_int(root, "avl_spare",
+ endurance_group->avl_spare);
+ json_object_add_value_int(root, "avl_spare_threshold",
+ endurance_group->avl_spare_threshold);
+ json_object_add_value_int(root, "percent_used",
+ endurance_group->percent_used);
+ json_object_add_value_float(root, "endurance_estimate",
+ endurance_estimate);
+ json_object_add_value_float(root, "data_units_read", data_units_read);
+ json_object_add_value_float(root, "data_units_written",
+ data_units_written);
+ json_object_add_value_float(root, "mediate_write_commands",
+ media_units_written);
+ json_object_add_value_float(root, "host_read_cmds", host_read_cmds);
+ json_object_add_value_float(root, "host_write_cmds", host_write_cmds);
+ json_object_add_value_float(root, "media_data_integrity_err",
+ media_data_integrity_err);
+ json_object_add_value_float(root, "num_err_info_log_entries",
+ num_err_info_log_entries);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ enum nvme_print_flags flags)
+{
+ int c, human = flags & VERBOSE;
+ struct json_object *root;
+ char key[21];
+
+ unsigned int temperature = ((smart->temperature[1] << 8) |
+ smart->temperature[0]);
+
+ long double data_units_read = int128_to_double(smart->data_units_read);
+ long double data_units_written = int128_to_double(smart->data_units_written);
+ long double host_read_commands = int128_to_double(smart->host_reads);
+ long double host_write_commands = int128_to_double(smart->host_writes);
+ long double controller_busy_time = int128_to_double(smart->ctrl_busy_time);
+ long double power_cycles = int128_to_double(smart->power_cycles);
+ long double power_on_hours = int128_to_double(smart->power_on_hours);
+ long double unsafe_shutdowns = int128_to_double(smart->unsafe_shutdowns);
+ long double media_errors = int128_to_double(smart->media_errors);
+ long double num_err_log_entries = int128_to_double(smart->num_err_log_entries);
+
+ root = json_create_object();
+
+ if (human) {
+ struct json_object *crt = json_create_object();
+
+ json_object_add_value_int(crt, "value", smart->critical_warning);
+ json_object_add_value_int(crt, "available_spare", smart->critical_warning & 0x01);
+ json_object_add_value_int(crt, "temp_threshold", (smart->critical_warning & 0x02) >> 1);
+ json_object_add_value_int(crt, "reliability_degraded", (smart->critical_warning & 0x04) >> 2);
+ json_object_add_value_int(crt, "ro", (smart->critical_warning & 0x08) >> 3);
+ json_object_add_value_int(crt, "vmbu_failed", (smart->critical_warning & 0x10) >> 4);
+ json_object_add_value_int(crt, "pmr_ro", (smart->critical_warning & 0x20) >> 5);
+
+ json_object_add_value_object(root, "critical_warning", crt);
+ } else
+ json_object_add_value_int(root, "critical_warning",
+ smart->critical_warning);
+
+ json_object_add_value_int(root, "temperature", temperature);
+ json_object_add_value_int(root, "avail_spare", smart->avail_spare);
+ json_object_add_value_int(root, "spare_thresh", smart->spare_thresh);
+ json_object_add_value_int(root, "percent_used", smart->percent_used);
+ json_object_add_value_int(root, "endurance_grp_critical_warning_summary",
+ smart->endu_grp_crit_warn_sumry);
+ json_object_add_value_float(root, "data_units_read", data_units_read);
+ json_object_add_value_float(root, "data_units_written",
+ data_units_written);
+ json_object_add_value_float(root, "host_read_commands",
+ host_read_commands);
+ json_object_add_value_float(root, "host_write_commands",
+ host_write_commands);
+ json_object_add_value_float(root, "controller_busy_time",
+ controller_busy_time);
+ json_object_add_value_float(root, "power_cycles", power_cycles);
+ json_object_add_value_float(root, "power_on_hours", power_on_hours);
+ json_object_add_value_float(root, "unsafe_shutdowns", unsafe_shutdowns);
+ json_object_add_value_float(root, "media_errors", media_errors);
+ json_object_add_value_float(root, "num_err_log_entries",
+ num_err_log_entries);
+ json_object_add_value_uint(root, "warning_temp_time",
+ le32_to_cpu(smart->warning_temp_time));
+ json_object_add_value_uint(root, "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);
+ json_object_add_value_int(root, key, temp);
+ }
+
+ json_object_add_value_uint(root, "thm_temp1_trans_count",
+ le32_to_cpu(smart->thm_temp1_trans_count));
+ json_object_add_value_uint(root, "thm_temp2_trans_count",
+ le32_to_cpu(smart->thm_temp2_trans_count));
+ json_object_add_value_uint(root, "thm_temp1_total_time",
+ le32_to_cpu(smart->thm_temp1_total_time));
+ json_object_add_value_uint(root, "thm_temp2_total_time",
+ le32_to_cpu(smart->thm_temp2_total_time));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname)
+{
+ int offset = sizeof(struct nvme_ana_rsp_hdr);
+ struct nvme_ana_rsp_hdr *hdr = ana_log;
+ struct nvme_ana_group_desc *ana_desc;
+ struct json_array *desc_list;
+ struct json_array *ns_list;
+ struct json_object *desc;
+ struct json_object *nsid;
+ struct json_object *root;
+ size_t nsid_buf_size;
+ void *base = ana_log;
+ __u32 nr_nsids;
+ int i, j;
+
+ root = json_create_object();
+ json_object_add_value_string(root,
+ "Asynchronous Namespace Access Log for NVMe device",
+ devname);
+ json_object_add_value_uint(root, "chgcnt",
+ le64_to_cpu(hdr->chgcnt));
+ json_object_add_value_uint(root, "ngrps", le16_to_cpu(hdr->ngrps));
+
+ desc_list = json_create_array();
+ 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);
+ json_object_add_value_uint(desc, "grpid",
+ le32_to_cpu(ana_desc->grpid));
+ json_object_add_value_uint(desc, "nnsids",
+ le32_to_cpu(ana_desc->nnsids));
+ json_object_add_value_uint(desc, "chgcnt",
+ le64_to_cpu(ana_desc->chgcnt));
+ json_object_add_value_string(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();
+ json_object_add_value_uint(nsid, "nsid",
+ le32_to_cpu(ana_desc->nsids[j]));
+ json_array_add_value_object(ns_list, nsid);
+ }
+ json_object_add_value_array(desc, "NSIDS", ns_list);
+ offset += nsid_buf_size;
+ json_array_add_value_object(desc_list, desc);
+ }
+
+ json_object_add_value_array(root, "ANA DESC LIST ", desc_list);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_self_test_log(struct nvme_self_test_log *self_test)
+{
+ struct json_object *valid_attrs;
+ struct json_object *root;
+ struct json_array *valid;
+ int i;
+
+ root = json_create_object();
+ json_object_add_value_int(root, "Current Device Self-Test Operation",
+ self_test->crnt_dev_selftest_oprn);
+ json_object_add_value_int(root, "Current Device Self-Test Completion",
+ self_test->crnt_dev_selftest_compln);
+ valid = json_create_array();
+
+ for (i = 0; i < NVME_ST_REPORTS; i++) {
+ valid_attrs = json_create_object();
+ json_object_add_value_int(valid_attrs, "Self test result",
+ self_test->result[i].dsts & 0xf);
+ if ((self_test->result[i].dsts & 0xf) == 0xf)
+ goto add;
+ json_object_add_value_int(valid_attrs, "Self test code",
+ self_test->result[i].dsts >> 4);
+ json_object_add_value_int(valid_attrs, "Segment number",
+ self_test->result[i].seg);
+ json_object_add_value_int(valid_attrs, "Valid Diagnostic Information",
+ self_test->result[i].vdi);
+ json_object_add_value_uint(valid_attrs, "Power on hours",
+ le64_to_cpu(self_test->result[i].poh));
+ if (self_test->result[i].vdi & NVME_ST_VALID_NSID)
+ json_object_add_value_int(valid_attrs, "Namespace Identifier",
+ le32_to_cpu(self_test->result[i].nsid));
+ if (self_test->result[i].vdi & NVME_ST_VALID_FLBA)
+ json_object_add_value_uint(valid_attrs, "Failing LBA",
+ le64_to_cpu(self_test->result[i].flba));
+ if (self_test->result[i].vdi & NVME_ST_VALID_SCT)
+ json_object_add_value_int(valid_attrs, "Status Code Type",
+ self_test->result[i].sct);
+ if (self_test->result[i].vdi & NVME_ST_VALID_SC)
+ json_object_add_value_int(valid_attrs, "Status Code",
+ self_test->result[i].sc);
+ json_object_add_value_int(valid_attrs, "Vendor Specific",
+ (self_test->result[i].vs[1] << 8) |
+ (self_test->result[i].vs[0]));
+add:
+ json_array_add_value_object(valid, valid_attrs);
+ }
+ json_object_add_value_array(root, "List of Valid Reports", valid);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_effects_log(struct nvme_effects_log_page *effects_log)
+{
+ struct json_object *root;
+ unsigned int opcode;
+ char key[128];
+ __u32 effect;
+
+ root = json_create_object();
+
+ for (opcode = 0; opcode < 256; opcode++) {
+ sprintf(key, "ACS%d (%s)", opcode,
+ nvme_cmd_to_string(1, opcode));
+ effect = le32_to_cpu(effects_log->acs[opcode]);
+ json_object_add_value_uint(root, key, effect);
+ }
+
+ for (opcode = 0; opcode < 256; opcode++) {
+ sprintf(key, "IOCS%d (%s)", opcode,
+ nvme_cmd_to_string(0, opcode));
+ effect = le32_to_cpu(effects_log->iocs[opcode]);
+ json_object_add_value_uint(root, key, effect);
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
+ const char *devname)
+{
+ struct json_object *root;
+ struct json_object *dev;
+ struct json_object *sstat;
+ const char *status_str;
+ char str[128];
+ __u16 status = le16_to_cpu(sanitize_log->status);
+
+ root = json_create_object();
+ dev = json_create_object();
+ sstat = json_create_object();
+
+ json_object_add_value_int(dev, "sprog",
+ le16_to_cpu(sanitize_log->progress));
+ json_object_add_value_int(sstat, "global_erased",
+ (status & NVME_SANITIZE_LOG_GLOBAL_DATA_ERASED) >> 8);
+ json_object_add_value_int(sstat, "no_cmplted_passes",
+ (status & NVME_SANITIZE_LOG_NUM_CMPLTED_PASS_MASK) >> 3);
+
+ status_str = get_sanitize_log_sstat_status_str(status);
+ sprintf(str, "(%d) %s", status & NVME_SANITIZE_LOG_STATUS_MASK,
+ status_str);
+ json_object_add_value_string(sstat, "status", str);
+
+ json_object_add_value_object(dev, "sstat", sstat);
+ json_object_add_value_uint(dev, "cdw10_info",
+ le32_to_cpu(sanitize_log->cdw10_info));
+ json_object_add_value_uint(dev, "time_over_write",
+ le32_to_cpu(sanitize_log->est_ovrwrt_time));
+ json_object_add_value_uint(dev, "time_block_erase",
+ le32_to_cpu(sanitize_log->est_blk_erase_time));
+ json_object_add_value_uint(dev, "time_crypto_erase",
+ le32_to_cpu(sanitize_log->est_crypto_erase_time));
+
+ json_object_add_value_uint(dev, "time_over_write_no_dealloc",
+ le32_to_cpu(sanitize_log->est_ovrwrt_time_with_no_deallocate));
+ json_object_add_value_uint(dev, "time_block_erase_no_dealloc",
+ le32_to_cpu(sanitize_log->est_blk_erase_time_with_no_deallocate));
+ json_object_add_value_uint(dev, "time_crypto_erase_no_dealloc",
+ le32_to_cpu(sanitize_log->est_crypto_erase_time_with_no_deallocate));
+
+ json_object_add_value_object(root, devname, dev);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void nvme_show_subsystem(struct nvme_subsystem *s)
+{
+ int i;
+
+ printf("%s - NQN=%s\n", s->name, s->subsysnqn);
+ printf("\\\n");
+
+ for (i = 0; i < s->nr_ctrls; i++) {
+ printf(" +- %s %s %s %s %s\n", s->ctrls[i].name,
+ s->ctrls[i].transport,
+ s->ctrls[i].address,
+ s->ctrls[i].state,
+ s->ctrls[i].ana_state ? : "");
+ }
+}
+
+static void json_print_nvme_subsystem_list(struct nvme_topology *t)
+{
+ struct json_object *subsystem_attrs, *path_attrs;
+ struct json_array *subsystems, *paths;
+ struct json_object *root;
+ int i, j;
+
+ root = json_create_object();
+ subsystems = json_create_array();
+
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ subsystem_attrs = json_create_object();
+ json_object_add_value_string(subsystem_attrs,
+ "Name", s->name);
+ json_object_add_value_string(subsystem_attrs,
+ "NQN", s->subsysnqn);
+
+ json_array_add_value_object(subsystems, subsystem_attrs);
+
+ paths = json_create_array();
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ path_attrs = json_create_object();
+ json_object_add_value_string(path_attrs, "Name",
+ c->name);
+ json_object_add_value_string(path_attrs, "Transport",
+ c->transport);
+ json_object_add_value_string(path_attrs, "Address",
+ c->address);
+ json_object_add_value_string(path_attrs, "State",
+ c->state);
+ if (c->ana_state)
+ json_object_add_value_string(path_attrs,
+ "ANAState", c->ana_state);
+ json_array_add_value_object(paths, path_attrs);
+ }
+ if (j)
+ json_object_add_value_array(subsystem_attrs, "Paths",
+ paths);
+ }
+
+ if (i)
+ json_object_add_value_array(root, "Subsystems", subsystems);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_subsystem_list(struct nvme_topology *t,
+ enum nvme_print_flags flags)
+{
+ int i;
+
+ if (flags & JSON)
+ return json_print_nvme_subsystem_list(t);
+
+ for (i = 0; i < t->nr_subsystems; i++)
+ nvme_show_subsystem(&t->subsystems[i]);
+}
+
+static void nvme_show_registers_cap(struct nvme_bar_cap *cap)
+{
+ printf("\tController Memory Buffer Supported (CMBS): The Controller Memory Buffer is %s\n",
+ ((cap->rsvd_cmbs_pmrs & 0x02) >> 1) ? "Supported" :
+ "Not Supported");
+ printf("\tPersistent Memory Region Supported (PMRS): The Persistent Memory Region is %s\n",
+ (cap->rsvd_cmbs_pmrs & 0x01) ? "Supported" : "Not Supported");
+ printf("\tMemory Page Size Maximum (MPSMAX): %u bytes\n",
+ 1 << (12 + ((cap->mpsmax_mpsmin & 0xf0) >> 4)));
+ printf("\tMemory Page Size Minimum (MPSMIN): %u bytes\n",
+ 1 << (12 + (cap->mpsmax_mpsmin & 0x0f)));
+ printf("\tBoot Partition Support (BPS): %s\n",
+ (cap->bps_css_nssrs_dstrd & 0x2000) ? "Yes":"No");
+ printf("\tCommand Sets Supported (CSS): NVM command set is %s\n",
+ (cap->bps_css_nssrs_dstrd & 0x0020) ? "supported":"not supported");
+ printf("\tNVM Subsystem Reset Supported (NSSRS): %s\n",
+ (cap->bps_css_nssrs_dstrd & 0x0010) ? "Yes":"No");
+ printf("\tDoorbell Stride (DSTRD): %u bytes\n",
+ 1 << (2 + (cap->bps_css_nssrs_dstrd & 0x000f)));
+ 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_cqr & 0x02) ? "supported":"not supported");
+ printf("\tContiguous Queues Required (CQR): %s\n",
+ (cap->ams_cqr & 0x01) ? "Yes":"No");
+ printf("\tMaximum Queue Entries Supported (MQES): %u\n\n",
+ cap->mqes + 1);
+}
+
+static void nvme_show_registers_version(__u32 vs)
+{
+ printf("\tNVMe specification %d.%d\n\n", (vs & 0xffff0000) >> 16,
+ (vs & 0x0000ff00) >> 8);
+}
+
+static void nvme_show_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");
+ }
+}
+
+static void nvme_show_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");
+ }
+}
+
+static void nvme_show_registers_cc(__u32 cc)
+{
+ 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));
+ nvme_show_registers_cc_shn((cc & 0x0000c000) >> NVME_CC_SHN_SHIFT);
+ nvme_show_registers_cc_ams((cc & 0x00003800) >> NVME_CC_AMS_SHIFT);
+ printf("\tMemory Page Size (MPS): %u bytes\n",
+ 1 << (12 + ((cc & 0x00000780) >> NVME_CC_MPS_SHIFT)));
+ printf("\tI/O Command Sets Selected (CSS): %s\n",
+ (cc & 0x00000070) ? "Reserved":"NVM Command Set");
+ printf("\tEnable (EN): %s\n\n",
+ (cc & 0x00000001) ? "Yes":"No");
+}
+
+static void nvme_show_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");
+ }
+}
+
+static void nvme_show_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");
+ nvme_show_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 nvme_show_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 nvme_show_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 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";
+ }
+}
+
+static void nvme_show_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 nvme_show_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");
+ }
+}
+
+static void nvme_show_registers_bpinfo(__u32 bpinfo)
+{
+ if (bpinfo == 0) {
+ printf("\tBoot Partition feature is not supported\n\n");
+ return;
+ }
+
+ printf("\tActive Boot Partition ID (ABPID): %u\n",
+ (bpinfo & 0x80000000) >> 31);
+ nvme_show_registers_bpinfo_brs((bpinfo & 0x03000000) >> 24);
+ printf("\tBoot Partition Size (BPSZ): %u\n",
+ bpinfo & 0x00007fff);
+}
+
+static void nvme_show_registers_bprsel(__u32 bprsel)
+{
+ if (bprsel == 0) {
+ printf("\tBoot Partition feature is not supported\n\n");
+ return;
+ }
+
+ printf("\tBoot Partition Identifier (BPID): %u\n",
+ (bprsel & 0x80000000) >> 31);
+ printf("\tBoot Partition Read Offset (BPROF): %x\n",
+ (bprsel & 0x3ffffc00) >> 10);
+ printf("\tBoot Partition Read Size (BPRSZ): %x\n",
+ bprsel & 0x000003ff);
+}
+
+static void nvme_show_registers_bpmbl(uint64_t bpmbl)
+{
+ if (bpmbl == 0) {
+ printf("\tBoot Partition feature is not supported\n\n");
+ return;
+ }
+
+ printf("\tBoot Partition Memory Buffer Base Address (BMBBA): %"PRIx64"\n",
+ bpmbl);
+}
+
+static void nvme_show_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 nvme_show_registers_cmbsts(__u32 cmbsts)
+{
+ printf("\tController Base Address Invalid (CBAI): %x\n\n",
+ (cmbsts & 0x00000001));
+}
+
+static void nvme_show_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 nvme_show_registers_pmrctl(__u32 pmrctl)
+{
+ printf("\tEnable (EN): PMR is %s\n", (pmrctl & 0x00000001) ?
+ "READY" : "Disabled");
+}
+
+static 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";
+ }
+}
+
+static void nvme_show_registers_pmrsts(__u32 pmrsts, __u32 pmrctl)
+{
+ printf("\tController Base Address Invalid (CBAI): %x\n",
+ (pmrsts & 0x00001000) >> 12);
+ printf("\tHealth Status (HSTS): %s\n",
+ 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 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";
+ }
+}
+
+static void nvme_show_registers_pmrebs(__u32 pmrebs)
+{
+ printf("\tPMR Elasticity Buffer Size Base (PMRWBZ): %x\n", (pmrebs & 0xffffff00) >> 8);
+ printf("\tRead Bypass Behavior : memory reads not conflicting with memory writes "\
+ "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 nvme_show_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 nvme_show_registers_pmrmsc(uint64_t pmrmsc)
+{
+ printf("\tController Base Address (CBA) : %" PRIx64 "\n",
+ (pmrmsc & 0xfffffffffffff000) >> 12);
+ printf("\tController Memory Space Enable (CMSE) : %" PRIx64 "\n\n",
+ (pmrmsc & 0x0000000000000002) >> 1);
+}
+
+static inline uint32_t mmio_read32(void *addr)
+{
+ __le32 *p = addr;
+
+ return le32_to_cpu(*p);
+}
+
+/* Access 64-bit registers as 2 32-bit; Some devices fail 64-bit MMIO. */
+static inline __u64 mmio_read64(void *addr)
+{
+ __le32 *p = addr;
+
+ return le32_to_cpu(*p) | ((uint64_t)le32_to_cpu(*(p + 1)) << 32);
+}
+
+static void json_ctrl_registers(void *bar)
+{
+ uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc;
+ uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc,
+ bpinfo, bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp;
+ struct json_object *root;
+
+ 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);
+ 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);
+ pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC);
+
+ root = json_create_object();
+ json_object_add_value_uint(root, "cap", cap);
+ json_object_add_value_int(root, "vs", vs);
+ json_object_add_value_int(root, "intms", intms);
+ json_object_add_value_int(root, "intmc", intmc);
+ json_object_add_value_int(root, "cc", cc);
+ json_object_add_value_int(root, "csts", csts);
+ json_object_add_value_int(root, "nssr", nssr);
+ json_object_add_value_int(root, "aqa", aqa);
+ json_object_add_value_uint(root, "asq", asq);
+ json_object_add_value_uint(root, "acq", acq);
+ json_object_add_value_int(root, "cmbloc", cmbloc);
+ json_object_add_value_int(root, "cmbsz", cmbsz);
+ json_object_add_value_int(root, "bpinfo", bpinfo);
+ json_object_add_value_int(root, "bprsel", bprsel);
+ json_object_add_value_uint(root, "bpmbl", bpmbl);
+ json_object_add_value_uint(root, "cmbmsc", cmbmsc);
+ json_object_add_value_int(root, "cmbsts", cmbsts);
+ json_object_add_value_int(root, "pmrcap", pmrcap);
+ json_object_add_value_int(root, "pmrctl", pmrctl);
+ json_object_add_value_int(root, "pmrsts", pmrsts);
+ json_object_add_value_int(root, "pmrebs", pmrebs);
+ json_object_add_value_int(root, "pmrswtp", pmrswtp);
+ json_object_add_value_uint(root, "pmrmsc", pmrmsc);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags)
+{
+ const unsigned int reg_size = 0x50; /* 00h to 4Fh */
+ uint64_t cap, asq, acq, bpmbl, cmbmsc, pmrmsc;
+ uint32_t vs, intms, intmc, cc, csts, nssr, aqa, cmbsz, cmbloc, bpinfo,
+ bprsel, cmbsts, pmrcap, pmrctl, pmrsts, pmrebs, pmrswtp;
+ int human = flags & VERBOSE;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)bar, reg_size);
+ if (flags & JSON)
+ return json_ctrl_registers(bar);
+
+ 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);
+ 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);
+ pmrmsc = mmio_read64(bar + NVME_REG_PMRMSC);
+
+ if (human) {
+ if (cap != 0xffffffff) {
+ printf("cap : %"PRIx64"\n", cap);
+ nvme_show_registers_cap((struct nvme_bar_cap *)&cap);
+ }
+ if (vs != 0xffffffff) {
+ printf("version : %x\n", vs);
+ nvme_show_registers_version(vs);
+ }
+ if (cc != 0xffffffff) {
+ printf("cc : %x\n", cc);
+ nvme_show_registers_cc(cc);
+ }
+ if (csts != 0xffffffff) {
+ printf("csts : %x\n", csts);
+ nvme_show_registers_csts(csts);
+ }
+ if (nssr != 0xffffffff) {
+ printf("nssr : %x\n", nssr);
+ printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n",
+ nssr);
+ }
+ 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);
+ nvme_show_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);
+ nvme_show_registers_cmbloc(cmbloc, cmbsz);
+
+ printf("cmbsz : %x\n", cmbsz);
+ nvme_show_registers_cmbsz(cmbsz);
+
+ printf("bpinfo : %x\n", bpinfo);
+ nvme_show_registers_bpinfo(bpinfo);
+
+ printf("bprsel : %x\n", bprsel);
+ nvme_show_registers_bprsel(bprsel);
+
+ printf("bpmbl : %"PRIx64"\n", bpmbl);
+ nvme_show_registers_bpmbl(bpmbl);
+
+ printf("cmbmsc : %"PRIx64"\n", cmbmsc);
+ nvme_show_registers_cmbmsc(cmbmsc);
+
+ printf("cmbsts : %x\n", cmbsts);
+ nvme_show_registers_cmbsts(cmbsts);
+
+ printf("pmrcap : %x\n", pmrcap);
+ nvme_show_registers_pmrcap(pmrcap);
+
+ printf("pmrctl : %x\n", pmrctl);
+ nvme_show_registers_pmrctl(pmrctl);
+
+ printf("pmrsts : %x\n", pmrsts);
+ nvme_show_registers_pmrsts(pmrsts, pmrctl);
+
+ printf("pmrebs : %x\n", pmrebs);
+ nvme_show_registers_pmrebs(pmrebs);
+
+ printf("pmrswtp : %x\n", pmrswtp);
+ nvme_show_registers_pmrswtp(pmrswtp);
+
+ printf("pmrmsc : %"PRIx64"\n", pmrmsc);
+ nvme_show_registers_pmrmsc(pmrmsc);
+ }
+ } 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 (!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("pmrmsc : %"PRIx64"\n", pmrmsc);
+ }
+ }
+}
+
+void nvme_show_single_property(int offset, uint64_t value64, int human)
+{
+ uint32_t value32;
+
+ if (!human) {
+ if (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),
+ (uint32_t) value64);
+
+ return;
+ }
+
+ value32 = (uint32_t) value64;
+
+ switch (offset) {
+ case NVME_REG_CAP:
+ printf("cap : %"PRIx64"\n", value64);
+ nvme_show_registers_cap((struct nvme_bar_cap *)&value64);
+ break;
+
+ case NVME_REG_VS:
+ printf("version : %x\n", value32);
+ nvme_show_registers_version(value32);
+ break;
+
+ case NVME_REG_CC:
+ printf("cc : %x\n", value32);
+ nvme_show_registers_cc(value32);
+ break;
+
+ case NVME_REG_CSTS:
+ printf("csts : %x\n", value32);
+ nvme_show_registers_csts(value32);
+ break;
+
+ case NVME_REG_NSSR:
+ printf("nssr : %x\n", value32);
+ printf("\tNVM Subsystem Reset Control (NSSRC): %u\n\n",
+ value32);
+ break;
+
+ default:
+ printf("unknown property: 0x%02x (%s), value: %"PRIx64"\n",
+ offset, nvme_register_to_string(offset), value64);
+ break;
+ }
+}
+
+void nvme_show_relatives(const char *name)
+{
+ unsigned id, i, nsid = NVME_NSID_ALL;
+ char *path = NULL;
+ bool block = true;
+ int ret;
+
+ ret = sscanf(name, "nvme%dn%d", &id, &nsid);
+ switch (ret) {
+ case 1:
+ if (asprintf(&path, "/sys/class/nvme/%s", name) < 0)
+ path = NULL;
+ block = false;
+ break;
+ case 2:
+ if (asprintf(&path, "/sys/block/%s/device", name) < 0)
+ path = NULL;
+ break;
+ default:
+ return;
+ }
+
+ if (!path)
+ return;
+
+ if (block) {
+ struct nvme_topology t = { };
+ char *subsysnqn;
+ int err;
+
+ subsysnqn = get_nvme_subsnqn(path);
+ if (!subsysnqn) {
+ free(path);
+ return;
+ }
+ err = scan_subsystems(&t, subsysnqn, 0);
+ if (err || t.nr_subsystems != 1) {
+ free(subsysnqn);
+ free(path);
+ return;
+ }
+
+ fprintf(stderr, "Namespace %s has parent controller(s):", name);
+ for (i = 0; i < t.subsystems[0].nr_ctrls; i++)
+ fprintf(stderr, "%s%s", i ? ", " : "",
+ t.subsystems[0].ctrls[i].name);
+ fprintf(stderr, "\n\n");
+ free(subsysnqn);
+ free_topology(&t);
+ } else {
+ struct dirent **paths;
+ bool comma = false;
+ int n, ns, cntlid;
+
+ n = scandir(path, &paths, scan_ctrl_paths_filter, alphasort);
+ if (n < 0) {
+ free(path);
+ return;
+ }
+
+ fprintf(stderr, "Controller %s has child namespace(s):", name);
+ for (i = 0; i < n; i++) {
+ if (sscanf(paths[i]->d_name, "nvme%dc%dn%d",
+ &id, &cntlid, &ns) != 3) {
+ if (sscanf(paths[i]->d_name, "nvme%dn%d",
+ &id, &ns) != 2) {
+ continue;
+ }
+ }
+ fprintf(stderr, "%snvme%dn%d", comma ? ", " : "", id,
+ ns);
+ comma = true;
+ }
+ fprintf(stderr, "\n\n");
+ free(paths);
+ }
+ free(path);
+}
+
+void d(unsigned char *buf, int len, int width, int group)
+{
+ int i, offset = 0, line_done = 0;
+ char ascii[32 + 1];
+
+ assert(width < sizeof(ascii));
+ printf(" ");
+ for (i = 0; i <= 15; i++)
+ printf("%3x", i);
+ for (i = 0; i < len; i++) {
+ line_done = 0;
+ if (i % width == 0)
+ printf( "\n%04x:", offset);
+ if (i % group == 0)
+ printf( " %02x", buf[i]);
+ else
+ printf( "%02x", buf[i]);
+ ascii[i % width] = (buf[i] >= '!' && buf[i] <= '~') ? buf[i] : '.';
+ if (((i + 1) % width) == 0) {
+ ascii[i % width + 1] = '\0';
+ printf( " \"%.*s\"", width, ascii);
+ offset += width;
+ line_done = 1;
+ }
+ }
+ if (!line_done) {
+ unsigned b = width - (i % width);
+ ascii[i % width + 1] = '\0';
+ printf( " %*s \"%.*s\"",
+ 2 * b + b / group + (b % group ? 1 : 0), "",
+ width, ascii);
+ }
+ printf( "\n");
+}
+
+void d_raw(unsigned char *buf, unsigned len)
+{
+ unsigned i;
+ for (i = 0; i < len; i++)
+ putchar(*(buf+i));
+}
+
+void nvme_show_status(__u16 status)
+{
+ fprintf(stderr, "NVMe status: %s(%#x)\n", nvme_status_to_string(status),
+ status);
+}
+
+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 const char *nvme_uuid_to_string(uuid_t uuid)
+{
+ /* large enough to hold uuid str (37) + null-termination byte */
+ static char uuid_str[40];
+#ifdef LIBUUID
+ uuid_unparse_lower(uuid, uuid_str);
+#else
+ static const char *hex_digits = "0123456789abcdef";
+ char *p = &uuid_str[0];
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ *p++ = hex_digits[(uuid.b[i] & 0xf0) >> 4];
+ *p++ = hex_digits[uuid.b[i] & 0x0f];
+ if (i == 3 || i == 5 || i == 7 || i == 9)
+ *p++ = '-';
+ }
+ *p = '\0';
+#endif
+ return uuid_str;
+}
+
+static void nvme_show_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 nvme_show_id_ctrl_oaes(__le32 ctrl_oaes)
+{
+ __u32 oaes = le32_to_cpu(ctrl_oaes);
+ __u32 rsvd0 = (oaes & 0xFFFF8000) >> 15;
+ __u32 nace = (oaes & 0x100) >> 8;
+ __u32 fan = (oaes & 0x200) >> 9;
+ __u32 anacn = (oaes & 0x800) >> 11;
+ __u32 plealcn = (oaes & 0x1000) >> 12;
+ __u32 lbasin = (oaes & 0x2000) >> 13;
+ __u32 egealpcn = (oaes & 0x4000) >> 14;
+ __u32 rsvd1 = oaes & 0xFF;
+
+ if (rsvd0)
+ printf(" [31:10] : %#x\tReserved\n", rsvd0);
+ 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 ");
+ 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 (rsvd1)
+ printf(" [7:0] : %#x\tReserved\n", rsvd1);
+ printf("\n");
+}
+
+static void nvme_show_id_ctrl_ctratt(__le32 ctrl_ctratt)
+{
+ __u32 ctratt = le32_to_cpu(ctrl_ctratt);
+ __u32 rsvd = ctratt >> 10;
+ __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 ng = (ctratt & NVME_CTRL_CTRATT_NAMESPACE_GRANULARITY) >> 7;
+ __u32 uuidlist = (ctratt & NVME_CTRL_CTRATT_UUID_LIST) >> 9;
+ __u32 rsvd6 = (ctratt & 0x00000040) >> 6;
+ __u32 rsvd8 = (ctratt & 0x00000100) >> 8;
+
+ if (rsvd)
+ printf(" [31:10] : %#x\tReserved\n", rsvd);
+
+ printf(" [9:9] : %#x\tUUID List %sSupported\n",
+ uuidlist, uuidlist ? "" : "Not ");
+ if (rsvd8)
+ printf(" [8:8] : %#x\tReserved\n", rsvd8);
+ printf(" [7:7] : %#x\tNamespace Granularity %sSupported\n",
+ ng, ng ? "" : "Not ");
+ if (rsvd6)
+ printf(" [6:6] : %#x\tReserved\n", rsvd6);
+ 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 nvme_show_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 nvme_show_id_ctrl_oacs(__le16 ctrl_oacs)
+{
+ __u16 oacs = le16_to_cpu(ctrl_oacs);
+ __u16 rsvd = (oacs & 0xFC00) >> 10;
+ __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:9] : %#x\tReserved\n", rsvd);
+ 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 nvme_show_id_ctrl_frmw(__u8 frmw)
+{
+ __u8 rsvd = (frmw & 0xE0) >> 5;
+ __u8 fawr = (frmw & 0x10) >> 4;
+ __u8 nfws = (frmw & 0xE) >> 1;
+ __u8 s1ro = frmw & 0x1;
+
+ if (rsvd)
+ printf(" [7:5] : %#x\tReserved\n", rsvd);
+ 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 nvme_show_id_ctrl_lpa(__u8 lpa)
+{
+ __u8 rsvd = (lpa & 0xE0) >> 5;
+ __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:4] : %#x\tReserved\n", rsvd);
+ 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 nvme_show_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 nvme_show_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 nvme_show_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 nvme_show_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 nvme_show_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 nvme_show_id_ctrl_anacap(__u8 anacap)
+{
+ __u8 nz = (anacap & 0x80) >> 7;
+ __u8 grpid_change = (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_change, grpid_change ? "" : "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 nvme_show_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 nvme_show_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 nvme_show_id_ctrl_oncs(__le16 ctrl_oncs)
+{
+ __u16 oncs = le16_to_cpu(ctrl_oncs);
+ __u16 rsvd = (oncs & 0xFF00) >> 8;
+ __u16 vrfy = (oncs & 0x80) >> 7;
+ __u16 tmst = (oncs & 0x40) >> 6;
+ __u16 resv = (oncs & 0x20) >> 5;
+ __u16 save = (oncs & 0x10) >> 4;
+ __u16 wzro = (oncs & 0x8) >> 3;
+ __u16 dsms = (oncs & 0x4) >> 2;
+ __u16 wunc = (oncs & 0x2) >> 1;
+ __u16 cmp = oncs & 0x1;
+
+ if (rsvd)
+ printf(" [15:8] : %#x\tReserved\n", rsvd);
+ 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 nvme_show_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 nvme_show_id_ctrl_fna(__u8 fna)
+{
+ __u8 rsvd = (fna & 0xF8) >> 3;
+ __u8 cese = (fna & 0x4) >> 2;
+ __u8 cens = (fna & 0x2) >> 1;
+ __u8 fmns = fna & 0x1;
+ if (rsvd)
+ printf(" [7:3] : %#x\tReserved\n", rsvd);
+ printf(" [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 nvme_show_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 nvme_show_id_ctrl_nvscc(__u8 nvscc)
+{
+ __u8 rsvd = (nvscc & 0xFE) >> 1;
+ __u8 fmt = nvscc & 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 nvme_show_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 nvme_show_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 rsvd1 = (sgls & 0xFFF8) >> 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 ");
+ if (rsvd1)
+ printf(" [15: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 nvme_show_id_ctrl_ctrattr(__u8 ctrattr)
+{
+ __u8 rsvd = (ctrattr & 0xFE) >> 1;
+ __u8 scm = ctrattr & 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 nvme_show_id_ns_nsfeat(__u8 nsfeat)
+{
+ __u8 rsvd = (nsfeat & 0xE0) >> 5;
+ __u8 ioopt = (nsfeat & 0x10) >> 4;
+ __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(" [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 nvme_show_id_ns_flbas(__u8 flbas)
+{
+ __u8 rsvd = (flbas & 0xE0) >> 5;
+ __u8 mdedata = (flbas & 0x10) >> 4;
+ __u8 lbaf = flbas & 0xF;
+ if (rsvd)
+ printf(" [7:5] : %#x\tReserved\n", rsvd);
+ printf(" [4:4] : %#x\tMetadata Transferred %s\n",
+ mdedata, mdedata ? "at End of Data LBA" : "in Separate Contiguous Buffer");
+ printf(" [3:0] : %#x\tCurrent LBA Format Selected\n", lbaf);
+ printf("\n");
+}
+
+static void nvme_show_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 nvme_show_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 8 Bytes of Metadata %sSupported\n",
+ pil8, pil8 ? "" : "Not ");
+ printf(" [3:3] : %#x\tProtection Information Transferred as First 8 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 nvme_show_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 8 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 nvme_show_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 nvme_show_id_ns_rescap(__u8 rescap)
+{
+ __u8 rsvd = (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;
+ if (rsvd)
+ printf(" [7:7] : %#x\tReserved\n", rsvd);
+ 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 nvme_show_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 nvme_show_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");
+}
+
+void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ enum nvme_print_flags flags)
+{
+ int human = flags & VERBOSE;
+ int vs = flags & VS;
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)ns, sizeof(*ns));
+ if (flags & JSON)
+ return json_nvme_id_ns(ns, flags);
+
+ 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)
+ nvme_show_id_ns_nsfeat(ns->nsfeat);
+ printf("nlbaf : %d\n", ns->nlbaf);
+ printf("flbas : %#x\n", ns->flbas);
+ if (human)
+ nvme_show_id_ns_flbas(ns->flbas);
+ printf("mc : %#x\n", ns->mc);
+ if (human)
+ nvme_show_id_ns_mc(ns->mc);
+ printf("dpc : %#x\n", ns->dpc);
+ if (human)
+ nvme_show_id_ns_dpc(ns->dpc);
+ printf("dps : %#x\n", ns->dps);
+ if (human)
+ nvme_show_id_ns_dps(ns->dps);
+ printf("nmic : %#x\n", ns->nmic);
+ if (human)
+ nvme_show_id_ns_nmic(ns->nmic);
+ printf("rescap : %#x\n", ns->rescap);
+ if (human)
+ nvme_show_id_ns_rescap(ns->rescap);
+ printf("fpi : %#x\n", ns->fpi);
+ if (human)
+ nvme_show_id_ns_fpi(ns->fpi);
+ printf("dlfeat : %d\n", ns->dlfeat);
+ if (human)
+ nvme_show_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 : %.0Lf\n", int128_to_double(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("nsattr : %u\n", ns->nsattr);
+ printf("nvmsetid: %d\n", le16_to_cpu(ns->nvmsetid));
+ printf("anagrpid: %u\n", le32_to_cpu(ns->anagrpid));
+ printf("endgid : %d\n", le16_to_cpu(ns->endgid));
+
+ printf("nguid : ");
+ 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");
+
+ for (i = 0; i <= ns->nlbaf; 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 == (ns->flbas & 0xf) ? "(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 == (ns->flbas & 0xf) ? "(in use)" : "");
+ }
+ if (vs) {
+ printf("vs[]:\n");
+ d(ns->vs, sizeof(ns->vs), 16, 1);
+ }
+}
+
+
+static void json_nvme_id_ns_descs(void *data)
+{
+ /* large enough to hold uuid str (37) or nguid str (32) + zero byte */
+ char json_str[40];
+ char *json_str_p;
+
+ union {
+ __u8 eui64[NVME_NIDT_EUI64_LEN];
+ __u8 nguid[NVME_NIDT_NGUID_LEN];
+
+#ifdef LIBUUID
+ uuid_t uuid;
+#endif
+ } desc;
+
+ struct json_object *root;
+ struct json_array *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;
+
+#ifdef LIBUUID
+ case NVME_NIDT_UUID:
+ memcpy(desc.uuid, data + off, sizeof(desc.uuid));
+ uuid_unparse_lower(desc.uuid, json_str);
+ len = sizeof(desc.uuid);
+ nidt_name = "uuid";
+ break;
+#endif
+ default:
+ /* Skip unnkown types */
+ len = cur->nidl;
+ break;
+ }
+
+ if (nidt_name) {
+ struct json_object *elem = json_create_object();
+
+ json_object_add_value_int(elem, "loc", pos);
+ json_object_add_value_int(elem, "nidt", (int)cur->nidt);
+ json_object_add_value_int(elem, "nidl", (int)cur->nidl);
+ json_object_add_value_string(elem, "type", nidt_name);
+ json_object_add_value_string(elem, nidt_name, json_str);
+
+ if (!json_array) {
+ json_array = json_create_array();
+ }
+ json_array_add_value_object(json_array, elem);
+ }
+
+ len += sizeof(*cur);
+ }
+
+ root = json_create_object();
+
+ if (json_array)
+ json_object_add_value_array(root, "ns-descs", json_array);
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags)
+{
+ int pos, len = 0;
+ int i;
+#ifdef LIBUUID
+ uuid_t uuid;
+ char uuid_str[37];
+#endif
+ __u8 eui64[8];
+ __u8 nguid[16];
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)data, 0x1000);
+ if (flags & JSON)
+ return json_nvme_id_ns_descs(data);
+
+ 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;
+#ifdef LIBUUID
+ case NVME_NIDT_UUID:
+ memcpy(uuid, data + pos + sizeof(*cur), 16);
+ uuid_unparse_lower(uuid, uuid_str);
+ printf("uuid : %s\n", uuid_str);
+ len = sizeof(uuid);
+ break;
+#endif
+ default:
+ /* Skip unnkown types */
+ len = cur->nidl;
+ break;
+ }
+
+ len += sizeof(*cur);
+ }
+}
+
+static void print_ps_power_and_scale(__le16 ctr_power, __u8 scale)
+{
+ __u16 power = le16_to_cpu(ctr_power);
+
+ switch (scale & 0x3) {
+ case 0:
+ /* Not reported for this power state */
+ printf("-");
+ break;
+
+ case 1:
+ /* Units of 0.0001W */
+ printf("%01u.%04uW", power / 10000, power % 10000);
+ break;
+
+ case 2:
+ /* Units of 0.01W */
+ printf("%01u.%02uW", power / 100, power % 100);
+ break;
+
+ default:
+ printf("reserved");
+ }
+}
+
+static void nvme_show_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].max_power);
+
+ printf("ps %4d : mp:", i);
+
+ if (ctrl->psd[i].flags & NVME_PS_FLAGS_MAX_POWER_SCALE)
+ 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_PS_FLAGS_NON_OP_STATE)
+ 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].entry_lat),
+ le32_to_cpu(ctrl->psd[i].exit_lat),
+ ctrl->psd[i].read_tput, ctrl->psd[i].read_lat,
+ ctrl->psd[i].write_tput, ctrl->psd[i].write_lat);
+ print_ps_power_and_scale(ctrl->psd[i].idle_power,
+ POWER_SCALE(ctrl->psd[i].idle_scale));
+ printf(" active_power:");
+ print_ps_power_and_scale(ctrl->psd[i].active_power,
+ POWER_SCALE(ctrl->psd[i].active_work_scale));
+ printf("\n");
+
+ }
+}
+
+void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, enum nvme_print_flags flags,
+ void (*vendor_show)(__u8 *vs, struct json_object *root))
+{
+ int human = flags & VERBOSE, vs = flags & VS;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)ctrl, sizeof(*ctrl));
+ else if (flags & JSON)
+ return json_nvme_id_ctrl(ctrl, flags, vendor_show);
+
+ 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)
+ nvme_show_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)
+ nvme_show_id_ctrl_oaes(ctrl->oaes);
+ printf("ctratt : %#x\n", le32_to_cpu(ctrl->ctratt));
+ if (human)
+ nvme_show_id_ctrl_ctratt(ctrl->ctratt);
+ printf("rrls : %#x\n", le16_to_cpu(ctrl->rrls));
+ printf("cntrltype : %d\n", ctrl->cntrltype);
+ if (human)
+ nvme_show_id_ctrl_cntrltype(ctrl->cntrltype);
+ printf("fguid : %-.*s\n", (int)sizeof(ctrl->fguid), 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("oacs : %#x\n", le16_to_cpu(ctrl->oacs));
+ if (human)
+ nvme_show_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)
+ nvme_show_id_ctrl_frmw(ctrl->frmw);
+ printf("lpa : %#x\n", ctrl->lpa);
+ if (human)
+ nvme_show_id_ctrl_lpa(ctrl->lpa);
+ printf("elpe : %d\n", ctrl->elpe);
+ printf("npss : %d\n", ctrl->npss);
+ printf("avscc : %#x\n", ctrl->avscc);
+ if (human)
+ nvme_show_id_ctrl_avscc(ctrl->avscc);
+ printf("apsta : %#x\n", ctrl->apsta);
+ if (human)
+ nvme_show_id_ctrl_apsta(ctrl->apsta);
+ printf("wctemp : %d\n", le16_to_cpu(ctrl->wctemp));
+ printf("cctemp : %d\n", le16_to_cpu(ctrl->cctemp));
+ printf("mtfa : %d\n", le16_to_cpu(ctrl->mtfa));
+ printf("hmpre : %d\n", le32_to_cpu(ctrl->hmpre));
+ printf("hmmin : %d\n", le32_to_cpu(ctrl->hmmin));
+ printf("tnvmcap : %.0Lf\n", int128_to_double(ctrl->tnvmcap));
+ printf("unvmcap : %.0Lf\n", int128_to_double(ctrl->unvmcap));
+ printf("rpmbs : %#x\n", le32_to_cpu(ctrl->rpmbs));
+ if (human)
+ nvme_show_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)
+ nvme_show_id_ctrl_hctma(ctrl->hctma);
+ printf("mntmt : %d\n", le16_to_cpu(ctrl->mntmt));
+ printf("mxtmt : %d\n", le16_to_cpu(ctrl->mxtmt));
+ printf("sanicap : %#x\n", le32_to_cpu(ctrl->sanicap));
+ if (human)
+ nvme_show_id_ctrl_sanicap(ctrl->sanicap);
+ printf("hmminds : %d\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)
+ nvme_show_id_ctrl_anacap(ctrl->anacap);
+ printf("anagrpmax : %d\n", ctrl->anagrpmax);
+ printf("nanagrpid : %d\n", le32_to_cpu(ctrl->nanagrpid));
+ printf("pels : %d\n", le32_to_cpu(ctrl->pels));
+ printf("sqes : %#x\n", ctrl->sqes);
+ if (human)
+ nvme_show_id_ctrl_sqes(ctrl->sqes);
+ printf("cqes : %#x\n", ctrl->cqes);
+ if (human)
+ nvme_show_id_ctrl_cqes(ctrl->cqes);
+ printf("maxcmd : %d\n", le16_to_cpu(ctrl->maxcmd));
+ printf("nn : %d\n", le32_to_cpu(ctrl->nn));
+ printf("oncs : %#x\n", le16_to_cpu(ctrl->oncs));
+ if (human)
+ nvme_show_id_ctrl_oncs(ctrl->oncs);
+ printf("fuses : %#x\n", le16_to_cpu(ctrl->fuses));
+ if (human)
+ nvme_show_id_ctrl_fuses(ctrl->fuses);
+ printf("fna : %#x\n", ctrl->fna);
+ if (human)
+ nvme_show_id_ctrl_fna(ctrl->fna);
+ printf("vwc : %#x\n", ctrl->vwc);
+ if (human)
+ nvme_show_id_ctrl_vwc(ctrl->vwc);
+ printf("awun : %d\n", le16_to_cpu(ctrl->awun));
+ printf("awupf : %d\n", le16_to_cpu(ctrl->awupf));
+ printf("nvscc : %d\n", ctrl->nvscc);
+ if (human)
+ nvme_show_id_ctrl_nvscc(ctrl->nvscc);
+ printf("nwpc : %d\n", ctrl->nwpc);
+ if (human)
+ nvme_show_id_ctrl_nwpc(ctrl->nwpc);
+ printf("acwu : %d\n", le16_to_cpu(ctrl->acwu));
+ printf("sgls : %#x\n", le32_to_cpu(ctrl->sgls));
+ if (human)
+ nvme_show_id_ctrl_sgls(ctrl->sgls);
+ printf("mnan : %d\n", le32_to_cpu(ctrl->mnan));
+ printf("subnqn : %-.*s\n", (int)sizeof(ctrl->subnqn), ctrl->subnqn);
+ printf("ioccsz : %d\n", le32_to_cpu(ctrl->ioccsz));
+ printf("iorcsz : %d\n", le32_to_cpu(ctrl->iorcsz));
+ printf("icdoff : %d\n", le16_to_cpu(ctrl->icdoff));
+ printf("ctrattr : %#x\n", ctrl->ctrattr);
+ if (human)
+ nvme_show_id_ctrl_ctrattr(ctrl->ctrattr);
+ printf("msdbd : %d\n", ctrl->msdbd);
+
+ nvme_show_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);
+ }
+}
+
+void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode)
+{
+ __nvme_show_id_ctrl(ctrl, mode, NULL);
+}
+
+static void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset)
+{
+ __u32 nent = nvmset->nid;
+ struct json_array *entries;
+ struct json_object *root;
+ int i;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "nid", nent);
+
+ entries = json_create_array();
+ for (i = 0; i < nent; i++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry, "nvmset_id",
+ le16_to_cpu(nvmset->ent[i].id));
+ json_object_add_value_int(entry, "endurance_group_id",
+ le16_to_cpu(nvmset->ent[i].endurance_group_id));
+ json_object_add_value_int(entry, "random_4k_read_typical",
+ le32_to_cpu(nvmset->ent[i].random_4k_read_typical));
+ json_object_add_value_int(entry, "optimal_write_size",
+ le32_to_cpu(nvmset->ent[i].opt_write_size));
+ json_object_add_value_float(entry, "total_nvmset_cap",
+ int128_to_double(nvmset->ent[i].total_nvmset_cap));
+ json_object_add_value_float(entry, "unalloc_nvmset_cap",
+ int128_to_double(nvmset->ent[i].unalloc_nvmset_cap));
+ json_array_add_value_object(entries, entry);
+ }
+
+ json_object_add_value_array(root, "NVMSet", entries);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id,
+ enum nvme_print_flags flags)
+{
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)nvmset, sizeof(*nvmset));
+ if (flags & JSON)
+ return json_nvme_id_nvmset(nvmset);
+
+ 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].id));
+ printf("enduracne_group_id : %d\n",
+ le16_to_cpu(nvmset->ent[i].endurance_group_id));
+ printf("random_4k_read_typical : %u\n",
+ le32_to_cpu(nvmset->ent[i].random_4k_read_typical));
+ printf("optimal_write_size : %u\n",
+ le32_to_cpu(nvmset->ent[i].opt_write_size));
+ printf("total_nvmset_cap : %.0Lf\n",
+ int128_to_double(nvmset->ent[i].total_nvmset_cap));
+ printf("unalloc_nvmset_cap : %.0Lf\n",
+ int128_to_double(nvmset->ent[i].unalloc_nvmset_cap));
+ printf(".................\n");
+ }
+}
+
+static void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list,
+ __u32 count)
+{
+ const struct nvme_secondary_controller_entry *sc_entry = &sc_list->sc_entry[0];
+ __u32 nent = min(sc_list->num, count);
+ struct json_array *entries;
+ struct json_object *root;
+ int i;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "num", nent);
+
+ entries = json_create_array();
+ for (i = 0; i < nent; i++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_int(entry,
+ "secondary-controller-identifier",
+ le16_to_cpu(sc_entry[i].scid));
+ json_object_add_value_int(entry,
+ "primary-controller-identifier",
+ le16_to_cpu(sc_entry[i].pcid));
+ json_object_add_value_int(entry, "secondary-controller-state",
+ sc_entry[i].scs);
+ json_object_add_value_int(entry, "virtual-function-number",
+ le16_to_cpu(sc_entry[i].vfn));
+ json_object_add_value_int(entry, "num-virtual-queues",
+ le16_to_cpu(sc_entry[i].nvq));
+ json_object_add_value_int(entry, "num-virtual-interrupts",
+ le16_to_cpu(sc_entry[i].nvi));
+ json_array_add_value_object(entries, entry);
+ }
+
+ json_object_add_value_array(root, "secondary-controllers", entries);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_list_secondary_ctrl(
+ const struct nvme_secondary_controllers_list *sc_list,
+ __u32 count, enum nvme_print_flags flags)
+{
+ const struct nvme_secondary_controller_entry *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;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)sc_list, sizeof(*sc_list));
+ if (flags & JSON)
+ return json_nvme_list_secondary_ctrl(sc_list, entries);
+
+ 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 json_nvme_id_ns_granularity_list(
+ const struct nvme_id_ns_granularity_list *glist)
+{
+ int i;
+ struct json_object *root;
+ struct json_array *entries;
+
+ root = json_create_object();
+
+ json_object_add_value_int(root, "attributes", glist->attributes);
+ json_object_add_value_int(root, "num-descriptors",
+ glist->num_descriptors);
+
+ entries = json_create_array();
+ for (i = 0; i <= glist->num_descriptors; i++) {
+ struct json_object *entry = json_create_object();
+
+ json_object_add_value_uint(entry, "namespace-size-granularity",
+ le64_to_cpu(glist->entry[i].namespace_size_granularity));
+ json_object_add_value_uint(entry, "namespace-capacity-granularity",
+ le64_to_cpu(glist->entry[i].namespace_capacity_granularity));
+ json_array_add_value_object(entries, entry);
+ }
+
+ json_object_add_value_array(root, "namespace-granularity-list", entries);
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist,
+ enum nvme_print_flags flags)
+{
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)glist, sizeof(*glist));
+ if (flags & JSON)
+ return json_nvme_id_ns_granularity_list(glist);
+
+ 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].namespace_size_granularity));
+ printf(" NCG : Namespace Capacity Granularity : 0x%"PRIx64"\n",
+ le64_to_cpu(glist->entry[i].namespace_capacity_granularity));
+ }
+}
+
+static void json_nvme_id_uuid_list(const struct nvme_id_uuid_list *uuid_list)
+{
+ struct json_object *root;
+ struct json_array *entries;
+ int i;
+
+ root = json_create_object();
+ entries = json_create_array();
+ /* The 0th entry is reserved */
+ for (i = 1; i < NVME_MAX_UUID_ENTRIES; i++) {
+ uuid_t uuid;
+ 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));
+ json_object_add_value_int(entry, "association",
+ uuid_list->entry[i].header & 0x3);
+ json_object_add_value_string(entry, "uuid",
+ nvme_uuid_to_string(uuid));
+ json_array_add_value_object(entries, entry);
+ }
+ json_object_add_value_array(root, "UUID-list", entries);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list,
+ enum nvme_print_flags flags)
+{
+ int i, human = flags & VERBOSE;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)uuid_list, sizeof(*uuid_list));
+ if (flags & JSON)
+ return json_nvme_id_uuid_list(uuid_list);
+
+ /* The 0th entry is reserved */
+ printf("NVME Identify UUID:\n");
+ for (i = 1; i < NVME_MAX_UUID_ENTRIES; i++) {
+ uuid_t uuid;
+ 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, sizeof(zero_uuid)) == 0)
+ break;
+ memcpy(&uuid, uuid_list->entry[i].uuid, sizeof(uuid));
+ 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);
+ printf(".................\n");
+ printf("association : 0x%x %s\n", identifier_association, association);
+ printf("UUID : %s", nvme_uuid_to_string(uuid));
+ if (memcmp(uuid_list->entry[i].uuid, invalid_uuid,
+ sizeof(zero_uuid)) == 0)
+ printf(" (Invalid UUID)");
+ printf("\n.................\n");
+ }
+}
+
+static 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)
+{
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)err_log,
+ entries * sizeof(*err_log));
+ else if (flags & JSON)
+ return json_error_log(err_log, entries);
+
+ printf("Error Log Entries for device:%s entries:%d\n", devname,
+ entries);
+ printf(".................\n");
+ for (i = 0; i < entries; i++) {
+ 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", err_log[i].status_field,
+ nvme_status_to_string(
+ le16_to_cpu(err_log[i].status_field) >> 1));
+ 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("cs : %#"PRIx64"\n",
+ le64_to_cpu(err_log[i].cs));
+ printf("trtype_spec_info: %#x\n", err_log[i].trtype_spec_info);
+ printf(".................\n");
+ }
+}
+
+void nvme_show_resv_report(struct nvme_reservation_status *status, int bytes,
+ __u32 cdw11, enum nvme_print_flags flags)
+{
+ int i, j, regctl, entries;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)status, bytes);
+ else if (flags & JSON)
+ return json_nvme_resv_report(status, bytes, cdw11);
+
+ regctl = status->regctl[0] | (status->regctl[1] << 8);
+
+ printf("\nNVME Reservation status:\n\n");
+ printf("gen : %d\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 ((cdw11 & 0x1) == 0) {
+ /*
+ * 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 {
+ struct nvme_reservation_status_ext *ext_status =
+ (struct nvme_reservation_status_ext *)status;
+ /* 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(ext_status->regctl_eds[i].cntlid));
+ printf(" rcsts : %x\n",
+ ext_status->regctl_eds[i].rcsts);
+ printf(" rkey : %"PRIx64"\n",
+ le64_to_cpu(ext_status->regctl_eds[i].rkey));
+ printf(" hostid : ");
+ for (j = 0; j < 16; j++)
+ printf("%x",
+ ext_status->regctl_eds[i].hostid[j]);
+ printf("\n");
+ }
+ }
+ printf("\n");
+}
+
+void nvme_show_fw_log(struct nvme_firmware_log_page *fw_log,
+ const char *devname, enum nvme_print_flags flags)
+{
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)fw_log, sizeof(*fw_log));
+ if (flags & JSON)
+ return json_fw_log(fw_log, devname);
+
+ printf("Firmware Log for device:%s\n", devname);
+ printf("afi : %#x\n", fw_log->afi);
+ for (i = 0; i < 7; i++) {
+ if (fw_log->frs[i])
+ printf("frs%d : %#016"PRIx64" (%s)\n", i + 1,
+ (uint64_t)fw_log->frs[i],
+ fw_to_string(fw_log->frs[i]));
+ }
+}
+
+void nvme_show_changed_ns_list_log(struct nvme_changed_ns_list_log *log,
+ const char *devname,
+ enum nvme_print_flags flags)
+{
+ __u32 nsid;
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)log, sizeof(*log));
+ else if (flags & JSON)
+ return json_changed_ns_list_log(log, devname);
+
+ if (log->log[0] != cpu_to_le32(0XFFFFFFFF)) {
+ for (i = 0; i < NVME_MAX_CHANGED_NAMESPACES; i++) {
+ nsid = le32_to_cpu(log->log[i]);
+ if (nsid == 0)
+ break;
+
+ printf("[%4u]:%#x\n", i, nsid);
+ }
+ } else
+ printf("more than %d ns changed\n",
+ NVME_MAX_CHANGED_NAMESPACES);
+}
+
+static void nvme_show_effects_log_human(__u32 effect)
+{
+ const char *set = "+";
+ const char *clr = "-";
+
+ printf(" CSUPP+");
+ printf(" LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr);
+ printf(" NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr);
+ printf(" NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr);
+ printf(" CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr);
+ printf(" USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr);
+
+ if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0)
+ printf(" No command restriction\n");
+ else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 1)
+ printf(" No other command for same namespace\n");
+ else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 2)
+ printf(" No other command for any namespace\n");
+ else
+ printf(" Reserved CSE\n");
+}
+
+void nvme_show_effects_log(struct nvme_effects_log_page *effects,
+ unsigned int flags)
+{
+ int i, human = flags & VERBOSE;
+ __u32 effect;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)effects, sizeof(*effects));
+ else if (flags & JSON)
+ return json_effects_log(effects);
+
+ printf("Admin Command Set\n");
+ for (i = 0; i < 256; i++) {
+ effect = le32_to_cpu(effects->acs[i]);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ printf("ACS%-6d[%-32s] %08x", i,
+ nvme_cmd_to_string(1, i), effect);
+ if (human)
+ nvme_show_effects_log_human(effect);
+ else
+ printf("\n");
+ }
+ }
+ printf("\nNVM Command Set\n");
+ for (i = 0; i < 256; i++) {
+ effect = le32_to_cpu(effects->iocs[i]);
+ if (effect & NVME_CMD_EFFECTS_CSUPP) {
+ printf("IOCS%-5d[%-32s] %08x", i,
+ nvme_cmd_to_string(0, i), effect);
+ if (human)
+ nvme_show_effects_log_human(effect);
+ else
+ printf("\n");
+ }
+ }
+}
+
+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;
+}
+
+void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
+ __u16 group_id, const char *devname,
+ enum nvme_print_flags flags)
+{
+ if (flags & BINARY)
+ return d_raw((unsigned char *)endurance_log,
+ sizeof(*endurance_log));
+ else if (flags & JSON)
+ return json_endurance_log(endurance_log, group_id);
+
+ 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("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("endurance_estimate : %'.0Lf\n",
+ int128_to_double(endurance_log->endurance_estimate));
+ printf("data_units_read : %'.0Lf\n",
+ int128_to_double(endurance_log->data_units_read));
+ printf("data_units_written : %'.0Lf\n",
+ int128_to_double(endurance_log->data_units_written));
+ printf("media_units_written : %'.0Lf\n",
+ int128_to_double(endurance_log->media_units_written));
+ printf("host_read_cmds : %'.0Lf\n",
+ int128_to_double(endurance_log->host_read_cmds));
+ printf("host_write_cmds : %'.0Lf\n",
+ int128_to_double(endurance_log->host_write_cmds));
+ printf("media_data_integrity_err: %'.0Lf\n",
+ int128_to_double(endurance_log->media_data_integrity_err));
+ printf("num_err_info_log_entries: %'.0Lf\n",
+ int128_to_double(endurance_log->num_err_info_log_entries));
+}
+
+void nvme_show_smart_log(struct nvme_smart_log *smart, unsigned int nsid,
+ const char *devname, enum nvme_print_flags flags)
+{
+ /* convert temperature from Kelvin to Celsius */
+ int temperature = ((smart->temperature[1] << 8) |
+ smart->temperature[0]) - 273;
+ int i, human = flags & VERBOSE;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)smart, sizeof(*smart));
+ else if (flags & JSON)
+ return json_smart_log(smart, nsid, flags);
+
+ 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 : %d C\n",
+ 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 : %'.0Lf\n",
+ int128_to_double(smart->data_units_read));
+ printf("data_units_written : %'.0Lf\n",
+ int128_to_double(smart->data_units_written));
+ printf("host_read_commands : %'.0Lf\n",
+ int128_to_double(smart->host_reads));
+ printf("host_write_commands : %'.0Lf\n",
+ int128_to_double(smart->host_writes));
+ printf("controller_busy_time : %'.0Lf\n",
+ int128_to_double(smart->ctrl_busy_time));
+ printf("power_cycles : %'.0Lf\n",
+ int128_to_double(smart->power_cycles));
+ printf("power_on_hours : %'.0Lf\n",
+ int128_to_double(smart->power_on_hours));
+ printf("unsafe_shutdowns : %'.0Lf\n",
+ int128_to_double(smart->unsafe_shutdowns));
+ printf("media_errors : %'.0Lf\n",
+ int128_to_double(smart->media_errors));
+ printf("num_err_log_entries : %'.0Lf\n",
+ int128_to_double(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 : %d C\n", i + 1,
+ temp - 273);
+ }
+ 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));
+}
+
+void nvme_show_ana_log(struct nvme_ana_rsp_hdr *ana_log, const char *devname,
+ enum nvme_print_flags flags, size_t len)
+{
+ int offset = sizeof(struct nvme_ana_rsp_hdr);
+ struct nvme_ana_rsp_hdr *hdr = ana_log;
+ struct nvme_ana_group_desc *desc;
+ size_t nsid_buf_size;
+ void *base = ana_log;
+ __u32 nr_nsids;
+ int i, j;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)ana_log, len);
+ else if (flags & JSON)
+ return json_ana_log(ana_log, devname);
+
+ printf("Asynchronous 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 nvme_show_self_test_result(struct nvme_self_test_res *res,
+ enum nvme_print_flags flags)
+{
+ 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_RES_NOT_USED] = "Entry not used (does not contain a result)",
+ };
+ __u8 op, code;
+
+ op = res->dsts & NVME_ST_RES_MASK;
+ printf(" Operation Result : %#x", op);
+ if (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_RES_NOT_USED)
+ return;
+
+ code = res->dsts >> NVME_ST_CODE_SHIFT;
+ printf(" Self Test Code : %x", code);
+
+ if (flags & VERBOSE) {
+ switch (code) {
+ case NVME_ST_CODE_SHORT_OP:
+ printf(" Short device self-test operation");
+ break;
+ case NVME_ST_CODE_EXT_OP:
+ 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_RES_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_NSID)
+ printf(" Namespace Identifier : %#x\n",
+ le32_to_cpu(res->nsid));
+ if (res->vdi & NVME_ST_VALID_FLBA)
+ printf(" Failing LBA : %#"PRIx64"\n",
+ (uint64_t)le64_to_cpu(res->flba));
+ if (res->vdi & NVME_ST_VALID_SCT)
+ printf(" Status Code Type : %#x\n", res->sct);
+ if (res->vdi & NVME_ST_VALID_SC) {
+ printf(" Status Code : %#x", res->sc);
+ if (flags & VERBOSE)
+ printf(" %s", nvme_status_to_string(
+ (res->sct & 7) << 8 | res->sc));
+ printf("\n");
+ }
+ printf(" Vendor Specific : %#x %#x\n",
+ res->vs[0], res->vs[1]);
+}
+
+void nvme_show_self_test_log(struct nvme_self_test_log *self_test, const char *devname,
+ enum nvme_print_flags flags)
+{
+ int i;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)self_test, sizeof(*self_test));
+ if (flags & JSON)
+ return json_self_test_log(self_test);
+
+ printf("Device Self Test Log for NVME device:%s\n", devname);
+ printf("Current operation : %#x\n", self_test->crnt_dev_selftest_oprn);
+ printf("Current Completion : %u%%\n", self_test->crnt_dev_selftest_compln);
+ for (i = 0; i < NVME_ST_REPORTS; i++) {
+ printf("Self Test Result[%d]:\n", i);
+ nvme_show_self_test_result(&self_test->result[i], flags);
+ }
+}
+
+static void nvme_show_sanitize_log_sprog(__u32 sprog)
+{
+ double percent;
+
+ percent = (((double)sprog * 100) / 0x10000);
+ printf("\t(%f%%)\n", percent);
+}
+
+static void nvme_show_sanitize_log_sstat(__u16 status)
+{
+ const char *str = get_sanitize_log_sstat_status_str(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_LOG_NUM_CMPLTED_PASS_MASK) >> 3);
+
+ printf("\t [8]\t");
+ if (status & NVME_SANITIZE_LOG_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 nvme_show_estimate_sanitize_time(const char *text, uint32_t value)
+{
+ printf("%s: %u%s\n", text, value,
+ value == 0xffffffff ? " (No time period reported)" : "");
+}
+
+void nvme_show_sanitize_log(struct nvme_sanitize_log_page *sanitize,
+ const char *devname, enum nvme_print_flags flags)
+{
+ int human = flags & VERBOSE;
+ __u16 status = le16_to_cpu(sanitize->status) & NVME_SANITIZE_LOG_STATUS_MASK;
+
+ if (flags & BINARY)
+ d_raw((unsigned char *)sanitize, sizeof(*sanitize));
+ else if (flags & JSON) {
+ json_sanitize_log(sanitize, devname);
+ return;
+ }
+
+ printf("Sanitize Progress (SPROG) : %u",
+ le16_to_cpu(sanitize->progress));
+
+ if (human && status == NVME_SANITIZE_LOG_IN_PROGESS)
+ nvme_show_sanitize_log_sprog(le16_to_cpu(sanitize->progress));
+ else
+ printf("\n");
+
+ printf("Sanitize Status (SSTAT) : %#x\n",
+ le16_to_cpu(sanitize->status));
+ if (human)
+ nvme_show_sanitize_log_sstat(le16_to_cpu(sanitize->status));
+
+ printf("Sanitize Command Dword 10 Information (SCDW10) : %#x\n",
+ le32_to_cpu(sanitize->cdw10_info));
+ nvme_show_estimate_sanitize_time("Estimated Time For Overwrite ",
+ le32_to_cpu(sanitize->est_ovrwrt_time));
+ nvme_show_estimate_sanitize_time("Estimated Time For Block Erase ",
+ le32_to_cpu(sanitize->est_blk_erase_time));
+ nvme_show_estimate_sanitize_time("Estimated Time For Crypto Erase ",
+ le32_to_cpu(sanitize->est_crypto_erase_time));
+ nvme_show_estimate_sanitize_time("Estimated Time For Overwrite (No-Deallocate) ",
+ le32_to_cpu(sanitize->est_ovrwrt_time_with_no_deallocate));
+ nvme_show_estimate_sanitize_time("Estimated Time For Block Erase (No-Deallocate) ",
+ le32_to_cpu(sanitize->est_blk_erase_time_with_no_deallocate));
+ nvme_show_estimate_sanitize_time("Estimated Time For Crypto Erase (No-Deallocate)",
+ le32_to_cpu(sanitize->est_crypto_erase_time_with_no_deallocate));
+}
+
+const char *nvme_feature_to_string(int feature)
+{
+ switch (feature) {
+ case NVME_FEAT_ARBITRATION: return "Arbitration";
+ case NVME_FEAT_POWER_MGMT: return "Power Management";
+ case NVME_FEAT_LBA_RANGE: return "LBA Range Type";
+ case NVME_FEAT_TEMP_THRESH: return "Temperature Threshold";
+ case NVME_FEAT_ERR_RECOVERY: return "Error Recovery";
+ case NVME_FEAT_VOLATILE_WC: return "Volatile Write Cache";
+ case NVME_FEAT_NUM_QUEUES: return "Number of Queues";
+ case NVME_FEAT_IRQ_COALESCE: return "Interrupt Coalescing";
+ case NVME_FEAT_IRQ_CONFIG: return "Interrupt Vector Configuration";
+ case NVME_FEAT_WRITE_ATOMIC: return "Write Atomicity Normal";
+ case NVME_FEAT_ASYNC_EVENT: return "Async Event Configuration";
+ case NVME_FEAT_AUTO_PST: return "Autonomous Power State Transition";
+ case NVME_FEAT_HOST_MEM_BUF: return "Host Memory Buffer";
+ case NVME_FEAT_KATO: return "Keep Alive Timer";
+ case NVME_FEAT_NOPSC: return "Non-Operational Power State Config";
+ case NVME_FEAT_RRL: return "Read Recovery Level";
+ case NVME_FEAT_PLM_CONFIG: return "Predicatable Latency Mode Config";
+ case NVME_FEAT_PLM_WINDOW: return "Predicatable Latency Mode Window";
+ case NVME_FEAT_SW_PROGRESS: return "Software Progress";
+ case NVME_FEAT_HOST_ID: return "Host Identifier";
+ case NVME_FEAT_RESV_MASK: return "Reservation Notification Mask";
+ case NVME_FEAT_RESV_PERSIST: return "Reservation Persistence";
+ case NVME_FEAT_TIMESTAMP: return "Timestamp";
+ case NVME_FEAT_WRITE_PROTECT: return "Namespce Write Protect";
+ case NVME_FEAT_HCTM: return "Host Controlled Thermal Management";
+ case NVME_FEAT_HOST_BEHAVIOR: return "Host Behavior";
+ case NVME_FEAT_SANITIZE: return "Sanitize";
+ default: return "Unknown";
+ }
+}
+
+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";
+ default: return "Reserved";
+ }
+}
+
+void nvme_show_select_result(__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");
+}
+
+const char *nvme_status_to_string(__u32 status)
+{
+ switch (status & 0x3ff) {
+ case NVME_SC_SUCCESS:
+ return "SUCCESS: The command completed successfully";
+ case NVME_SC_INVALID_OPCODE:
+ return "INVALID_OPCODE: The associated command opcode field is not valid";
+ case NVME_SC_INVALID_FIELD:
+ return "INVALID_FIELD: A reserved coded value or an unsupported value in a defined field";
+ case NVME_SC_CMDID_CONFLICT:
+ return "CMDID_CONFLICT: The command identifier is already in use";
+ case NVME_SC_DATA_XFER_ERROR:
+ return "DATA_XFER_ERROR: Error while trying to transfer the data or metadata";
+ case NVME_SC_POWER_LOSS:
+ return "POWER_LOSS: Command aborted due to power loss notification";
+ case NVME_SC_INTERNAL:
+ return "INTERNAL: The command was not completed successfully due to an internal error";
+ case NVME_SC_ABORT_REQ:
+ return "ABORT_REQ: The command was aborted due to a Command Abort request";
+ case NVME_SC_ABORT_QUEUE:
+ return "ABORT_QUEUE: The command was aborted due to a Delete I/O Submission Queue request";
+ case NVME_SC_FUSED_FAIL:
+ return "FUSED_FAIL: The command was aborted due to the other command in a fused operation failing";
+ case NVME_SC_FUSED_MISSING:
+ return "FUSED_MISSING: The command was aborted due to a Missing Fused Command";
+ case NVME_SC_INVALID_NS:
+ return "INVALID_NS: The namespace or the format of that namespace is invalid";
+ case NVME_SC_CMD_SEQ_ERROR:
+ return "CMD_SEQ_ERROR: The command was aborted due to a protocol violation in a multicommand sequence";
+ case NVME_SC_SGL_INVALID_LAST:
+ return "SGL_INVALID_LAST: The command includes an invalid SGL Last Segment or SGL Segment descriptor.";
+ case NVME_SC_SGL_INVALID_COUNT:
+ return "SGL_INVALID_COUNT: There is an SGL Last Segment descriptor or an SGL Segment descriptor in a location other than the last descriptor of a segment based on the length indicated.";
+ case NVME_SC_SGL_INVALID_DATA:
+ return "SGL_INVALID_DATA: This may occur if the length of a Data SGL is too short.";
+ case NVME_SC_SGL_INVALID_METADATA:
+ return "SGL_INVALID_METADATA: This may occur if the length of a Metadata SGL is too short";
+ case NVME_SC_SGL_INVALID_TYPE:
+ return "SGL_INVALID_TYPE: The type of an SGL Descriptor is a type that is not supported by the controller.";
+ case NVME_SC_CMB_INVALID_USE:
+ return "CMB_INVALID_USE: The attempted use of the Controller Memory Buffer is not supported by the controller.";
+ case NVME_SC_PRP_INVALID_OFFSET:
+ return "PRP_INVALID_OFFSET: The Offset field for a PRP entry is invalid.";
+ case NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED:
+ return "ATOMIC_WRITE_UNIT_EXCEEDED: The length specified exceeds the atomic write unit size.";
+ case NVME_SC_OPERATION_DENIED:
+ return "OPERATION_DENIED: The command was denied due to lack of access rights.";
+ case NVME_SC_SGL_INVALID_OFFSET:
+ return "SGL_INVALID_OFFSET: The offset specified in a descriptor is invalid.";
+ case NVME_SC_INCONSISTENT_HOST_ID:
+ return "INCONSISTENT_HOST_ID: The NVM subsystem detected the simultaneous use of 64-bit and 128-bit Host Identifier values on different controllers.";
+ case NVME_SC_KEEP_ALIVE_EXPIRED:
+ return "KEEP_ALIVE_EXPIRED: The Keep Alive Timer expired.";
+ case NVME_SC_KEEP_ALIVE_INVALID:
+ return "KEEP_ALIVE_INVALID: The Keep Alive Timeout value specified is invalid.";
+ case NVME_SC_PREEMPT_ABORT:
+ return "PREEMPT_ABORT: The command was aborted due to a Reservation Acquire command with the Reservation Acquire Action (RACQA) set to 010b (Preempt and Abort).";
+ case NVME_SC_SANITIZE_FAILED:
+ return "SANITIZE_FAILED: The most recent sanitize operation failed and no recovery actions has been successfully completed";
+ case NVME_SC_SANITIZE_IN_PROGRESS:
+ return "SANITIZE_IN_PROGRESS: The requested function is prohibited while a sanitize operation is in progress";
+ case NVME_SC_LBA_RANGE:
+ return "LBA_RANGE: The command references a LBA that exceeds the size of the namespace";
+ case NVME_SC_NS_WRITE_PROTECTED:
+ return "NS_WRITE_PROTECTED: The command is prohibited while the namespace is write protected by the host.";
+ case NVME_SC_TRANSIENT_TRANSPORT:
+ return "TRANSIENT_TRANSPORT: A transient transport error was detected.";
+ case NVME_SC_CAP_EXCEEDED:
+ return "CAP_EXCEEDED: The execution of the command has caused the capacity of the namespace to be exceeded";
+ case NVME_SC_NS_NOT_READY:
+ return "NS_NOT_READY: The namespace is not ready to be accessed as a result of a condition other than a condition that is reported as an Asymmetric Namespace Access condition";
+ case NVME_SC_RESERVATION_CONFLICT:
+ return "RESERVATION_CONFLICT: The command was aborted due to a conflict with a reservation held on the accessed namespace";
+ case NVME_SC_FORMAT_IN_PROGRESS:
+ return "FORMAT_IN_PROGRESS: A Format NVM command is in progress on the namespace.";
+ case NVME_SC_CQ_INVALID:
+ return "CQ_INVALID: The Completion Queue identifier specified in the command does not exist";
+ case NVME_SC_QID_INVALID:
+ return "QID_INVALID: The creation of the I/O Completion Queue failed due to an invalid queue identifier specified as part of the command. An invalid queue identifier is one that is currently in use or one that is outside the range supported by the controller";
+ case NVME_SC_QUEUE_SIZE:
+ return "QUEUE_SIZE: The host attempted to create an I/O Completion Queue with an invalid number of entries";
+ case NVME_SC_ABORT_LIMIT:
+ return "ABORT_LIMIT: The number of concurrently outstanding Abort commands has exceeded the limit indicated in the Identify Controller data structure";
+ case NVME_SC_ABORT_MISSING:
+ return "ABORT_MISSING: The abort command is missing";
+ case NVME_SC_ASYNC_LIMIT:
+ return "ASYNC_LIMIT: The number of concurrently outstanding Asynchronous Event Request commands has been exceeded";
+ case NVME_SC_FIRMWARE_SLOT:
+ return "FIRMWARE_SLOT: The firmware slot indicated is invalid or read only. This error is indicated if the firmware slot exceeds the number supported";
+ case NVME_SC_FIRMWARE_IMAGE:
+ return "FIRMWARE_IMAGE: The firmware image specified for activation is invalid and not loaded by the controller";
+ case NVME_SC_INVALID_VECTOR:
+ return "INVALID_VECTOR: The creation of the I/O Completion Queue failed due to an invalid interrupt vector specified as part of the command";
+ case NVME_SC_INVALID_LOG_PAGE:
+ return "INVALID_LOG_PAGE: The log page indicated is invalid. This error condition is also returned if a reserved log page is requested";
+ case NVME_SC_INVALID_FORMAT:
+ return "INVALID_FORMAT: The LBA Format specified is not supported. This may be due to various conditions";
+ case NVME_SC_FW_NEEDS_CONV_RESET:
+ return "FW_NEEDS_CONVENTIONAL_RESET: The firmware commit was successful, however, activation of the firmware image requires a conventional reset";
+ case NVME_SC_INVALID_QUEUE:
+ return "INVALID_QUEUE: This error indicates that it is invalid to delete the I/O Completion Queue specified. The typical reason for this error condition is that there is an associated I/O Submission Queue that has not been deleted.";
+ case NVME_SC_FEATURE_NOT_SAVEABLE:
+ return "FEATURE_NOT_SAVEABLE: The Feature Identifier specified does not support a saveable value";
+ case NVME_SC_FEATURE_NOT_CHANGEABLE:
+ return "FEATURE_NOT_CHANGEABLE: The Feature Identifier is not able to be changed";
+ case NVME_SC_FEATURE_NOT_PER_NS:
+ return "FEATURE_NOT_PER_NS: The Feature Identifier specified is not namespace specific. The Feature Identifier settings apply across all namespaces";
+ case NVME_SC_FW_NEEDS_SUBSYS_RESET:
+ return "FW_NEEDS_SUBSYSTEM_RESET: The firmware commit was successful, however, activation of the firmware image requires an NVM Subsystem";
+ case NVME_SC_FW_NEEDS_RESET:
+ return "FW_NEEDS_RESET: The firmware commit was successful; however, the image specified does not support being activated without a reset";
+ case NVME_SC_FW_NEEDS_MAX_TIME:
+ return "FW_NEEDS_MAX_TIME_VIOLATION: The image specified if activated immediately would exceed the Maximum Time for Firmware Activation (MTFA) value reported in Identify Controller. To activate the firmware, the Firmware Commit command needs to be re-issued and the image activated using a reset";
+ case NVME_SC_FW_ACTIVATE_PROHIBITED:
+ return "FW_ACTIVATION_PROHIBITED: The image specified is being prohibited from activation by the controller for vendor specific reasons";
+ case NVME_SC_OVERLAPPING_RANGE:
+ return "OVERLAPPING_RANGE: This error is indicated if the firmware image has overlapping ranges";
+ case NVME_SC_NS_INSUFFICIENT_CAP:
+ return "NS_INSUFFICIENT_CAPACITY: Creating the namespace requires more free space than is currently available. The Command Specific Information field of the Error Information Log specifies the total amount of NVM capacity required to create the namespace in bytes";
+ case NVME_SC_NS_ID_UNAVAILABLE:
+ return "NS_ID_UNAVAILABLE: The number of namespaces supported has been exceeded";
+ case NVME_SC_NS_ALREADY_ATTACHED:
+ return "NS_ALREADY_ATTACHED: The controller is already attached to the namespace specified";
+ case NVME_SC_NS_IS_PRIVATE:
+ return "NS_IS_PRIVATE: The namespace is private and is already attached to one controller";
+ case NVME_SC_NS_NOT_ATTACHED:
+ return "NS_NOT_ATTACHED: The request to detach the controller could not be completed because the controller is not attached to the namespace";
+ case NVME_SC_THIN_PROV_NOT_SUPP:
+ return "THIN_PROVISIONING_NOT_SUPPORTED: Thin provisioning is not supported by the controller";
+ case NVME_SC_CTRL_LIST_INVALID:
+ return "CONTROLLER_LIST_INVALID: The controller list provided is invalid";
+ case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
+ return "DEVICE_SELF_TEST_IN_PROGRESS: The controller or NVM subsystem already has a device self-test operation in process.";
+ case NVME_SC_BP_WRITE_PROHIBITED:
+ return "BOOT PARTITION WRITE PROHIBITED: The command is trying to modify a Boot Partition while it is locked";
+ case NVME_SC_INVALID_CTRL_ID:
+ return "INVALID_CTRL_ID: An invalid Controller Identifier was specified.";
+ case NVME_SC_INVALID_SECONDARY_CTRL_STATE:
+ return "INVALID_SECONDARY_CTRL_STATE: The action requested for the secondary controller is invalid based on the current state of the secondary controller and its primary controller.";
+ case NVME_SC_INVALID_NUM_CTRL_RESOURCE:
+ return "INVALID_NUM_CTRL_RESOURCE: The specified number of Flexible Resources is invalid";
+ case NVME_SC_INVALID_RESOURCE_ID:
+ return "INVALID_RESOURCE_ID: At least one of the specified resource identifiers was invalid";
+ case NVME_SC_ANA_INVALID_GROUP_ID:
+ return "ANA_INVALID_GROUP_ID: The specified ANA Group Identifier (ANAGRPID) is not supported in the submitted command.";
+ case NVME_SC_ANA_ATTACH_FAIL:
+ return "ANA_ATTACH_FAIL: The controller is not attached to the namespace as a result of an ANA condition";
+ case NVME_SC_BAD_ATTRIBUTES:
+ return "BAD_ATTRIBUTES: Bad attributes were given";
+ case NVME_SC_WRITE_FAULT:
+ return "WRITE_FAULT: The write data could not be committed to the media";
+ case NVME_SC_READ_ERROR:
+ return "READ_ERROR: The read data could not be recovered from the media";
+ case NVME_SC_GUARD_CHECK:
+ return "GUARD_CHECK: The command was aborted due to an end-to-end guard check failure";
+ case NVME_SC_APPTAG_CHECK:
+ return "APPTAG_CHECK: The command was aborted due to an end-to-end application tag check failure";
+ case NVME_SC_REFTAG_CHECK:
+ return "REFTAG_CHECK: The command was aborted due to an end-to-end reference tag check failure";
+ case NVME_SC_COMPARE_FAILED:
+ return "COMPARE_FAILED: The command failed due to a miscompare during a Compare command";
+ case NVME_SC_ACCESS_DENIED:
+ return "ACCESS_DENIED: Access to the namespace and/or LBA range is denied due to lack of access rights";
+ case NVME_SC_UNWRITTEN_BLOCK:
+ return "UNWRITTEN_BLOCK: The command failed due to an attempt to read from an LBA range containing a deallocated or unwritten logical block";
+ case NVME_SC_ANA_PERSISTENT_LOSS:
+ return "ASYMMETRIC_NAMESPACE_ACCESS_PERSISTENT_LOSS: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Persistent Loss state";
+ case NVME_SC_ANA_INACCESSIBLE:
+ return "ASYMMETRIC_NAMESPACE_ACCESS_INACCESSIBLE: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace being in the ANA Inaccessible state";
+ case NVME_SC_ANA_TRANSITION:
+ return "ASYMMETRIC_NAMESPACE_ACCESS_TRANSITION: The requested function (e.g., command) is not able to be performed as a result of the relationship between the controller and the namespace transitioning between Asymmetric Namespace Access states";
+ case NVME_SC_CMD_INTERRUPTED:
+ return "CMD_INTERRUPTED: Command processing was interrupted and the controller is unable to successfully complete the command. The host should retry the command.";
+ case NVME_SC_PMR_SAN_PROHIBITED:
+ return "Sanitize Prohibited While Persistent Memory Region is Enabled: A sanitize operation is prohibited while the Persistent Memory Region is enabled.";
+ default:
+ return "Unknown";
+ }
+}
+
+static 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)
+{
+ int i, j;
+
+ for (i = 0; i <= nr_ranges; i++) {
+ printf("\ttype : %#x - %s\n", lbrt[i].type,
+ nvme_feature_lba_type_to_string(lbrt[i].type));
+ printf("\tattributes : %#x - %s, %s\n", lbrt[i].attributes,
+ (lbrt[i].attributes & 0x0001) ?
+ "LBA range may be overwritten" :
+ "LBA range should not be overwritten",
+ ((lbrt[i].attributes & 0x0002) >> 1) ?
+ "LBA range should be hidden from the OS/EFI/BIOS" :
+ "LBA range should be visible from the OS/EFI/BIOS");
+ printf("\tslba : %#"PRIx64"\n", (uint64_t)(lbrt[i].slba));
+ printf("\tnlb : %#"PRIx64"\n", (uint64_t)(lbrt[i].nlb));
+ printf("\tguid : ");
+ for (j = 0; j < 16; j++)
+ printf("%02x", lbrt[i].guid[j]);
+ printf("\n");
+ }
+}
+
+
+static 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";
+ }
+}
+
+static 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";
+ }
+}
+
+static 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";
+ }
+}
+
+static void nvme_show_auto_pst(struct nvme_auto_pst *apst)
+{
+ int i;
+
+ printf( "\tAuto PST Entries");
+ printf("\t.................\n");
+ for (i = 0; i < 32; i++) {
+ printf("\tEntry[%2d] \n", i);
+ printf("\t.................\n");
+ printf("\tIdle Time Prior to Transition (ITPT): %u ms\n",
+ (apst[i].data & 0xffffff00) >> 8);
+ printf("\tIdle Transition Power State (ITPS): %u\n",
+ (apst[i].data & 0x000000f8) >> 3);
+ printf("\t.................\n");
+ }
+}
+
+static void nvme_show_timestamp(struct nvme_timestamp *ts)
+{
+ struct tm *tm;
+ char buffer[32];
+ time_t timestamp = int48_to_long(ts->timestamp) / 1000;
+
+ tm = localtime(&timestamp);
+ strftime(buffer, sizeof(buffer), "%c %Z", tm);
+
+ printf("\tThe timestamp is : %"PRIu64" (%s)\n",
+ int48_to_long(ts->timestamp), 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 nvme_show_host_mem_buffer(struct nvme_host_mem_buffer *hmb)
+{
+ printf("\tHost Memory Descriptor List Entry Count (HMDLEC): %u\n",
+ hmb->hmdlec);
+ printf("\tHost Memory Descriptor List Address (HMDLAU): 0x%x\n",
+ hmb->hmdlau);
+ printf("\tHost Memory Descriptor List Address (HMDLAL): 0x%x\n",
+ hmb->hmdlal);
+ printf("\tHost Memory Buffer Size (HSIZE): %u\n",
+ hmb->hsize);
+}
+
+static void nvme_directive_show_fields(__u8 dtype, __u8 doper,
+ unsigned int result, unsigned char *buf)
+{
+ __u8 *field = buf;
+ int count, i;
+
+ switch (dtype) {
+ case NVME_DIR_IDENTIFY:
+ switch (doper) {
+ case NVME_DIR_RCV_ID_OP_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("\tDirective status \n");
+ printf("\t\tIdentify Directive : %s\n",
+ (*(field + 32) & 0x1) ? "enabled" : "disabled");
+ printf("\t\tStream Directive : %s\n",
+ (*(field + 32) & 0x2) ? "enabled" : "disabled");
+ break;
+ default:
+ fprintf(stderr,
+ "invalid directive operations for Identify Directives\n");
+ }
+ break;
+ case NVME_DIR_STREAMS:
+ switch (doper) {
+ case NVME_DIR_RCV_ST_OP_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("\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("\tNamespece Streams Allocated (NSA): %u\n",
+ *(__u16 *) (field + 22));
+ printf("\tNamespace Streams Open (NSO): %u\n",
+ *(__u16 *) (field + 24));
+ break;
+ case NVME_DIR_RCV_ST_OP_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_DIR_RCV_ST_OP_RESOURCE:
+ printf("\tNamespace Streams Allocated (NSA): %u\n",
+ result & 0xffff);
+ break;
+ default:
+ fprintf(stderr,
+ "invalid directive operations for Streams Directives\n");
+ }
+ break;
+ default:
+ fprintf(stderr, "invalid directive type\n");
+ break;
+ }
+ return;
+}
+
+void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len, enum nvme_print_flags flags)
+{
+ if (flags & BINARY) {
+ if (buf)
+ return d_raw(buf, len);
+ return;
+ }
+
+ printf("dir-receive: type:%#x operation:%#x spec:%#x nsid:%#x result:%#x\n",
+ type, oper, spec, nsid, result);
+ if (flags & VERBOSE)
+ nvme_directive_show_fields(type, oper, result, buf);
+ else if (buf)
+ d(buf, len, 16, 1);
+}
+
+static const char *nvme_plm_window(__u32 plm)
+{
+ switch (plm & 0x7) {
+ case 1:
+ return "Deterministic Window (DTWIN)";
+ case 2:
+ return "Non-deterministic Window (NDWIN)";
+ default:
+ return "Reserved";
+ }
+}
+
+static void nvme_show_plm_config(struct nvme_plm_config *plmcfg)
+{
+ printf("\tEnable Event :%04x\n", le16_to_cpu(plmcfg->enable_event));
+ printf("\tDTWIN Reads Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_reads_thresh));
+ printf("\tDTWIN Writes Threshold:%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_writes_thresh));
+ printf("\tDTWIN Time Threshold :%"PRIu64"\n", le64_to_cpu(plmcfg->dtwin_time_thresh));
+}
+
+void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf)
+{
+ __u8 field;
+ uint64_t ull;
+
+ switch (fid) {
+ case NVME_FEAT_ARBITRATION:
+ printf("\tHigh Priority Weight (HPW): %u\n", ((result & 0xff000000) >> 24) + 1);
+ printf("\tMedium Priority Weight (MPW): %u\n", ((result & 0x00ff0000) >> 16) + 1);
+ 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_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_LBA_RANGE:
+ field = result & 0x0000003f;
+ printf("\tNumber of LBA Ranges (NUM): %u\n", field + 1);
+ nvme_show_lba_range((struct nvme_lba_range_type *)buf, field);
+ break;
+ case NVME_FEAT_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): %d C\n", (result & 0x0000ffff) - 273);
+ break;
+ case NVME_FEAT_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_VOLATILE_WC:
+ printf("\tVolatile Write Cache Enable (WCE): %s\n", (result & 0x00000001) ? "Enabled":"Disabled");
+ break;
+ case NVME_FEAT_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_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_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_WRITE_ATOMIC:
+ printf("\tDisable Normal (DN): %s\n", (result & 0x00000001) ? "True":"False");
+ break;
+ case NVME_FEAT_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_AUTO_PST:
+ printf("\tAutonomous Power State Transition Enable (APSTE): %s\n", (result & 0x00000001) ? "Enabled":"Disabled");
+ nvme_show_auto_pst((struct nvme_auto_pst *)buf);
+ break;
+ case NVME_FEAT_HOST_MEM_BUF:
+ printf("\tMemory Return (MR): %s\n", ((result & 0x00000002) >> 1) ? "True":"False");
+ printf("\tEnable Host Memory (EHM): %s\n", (result & 0x00000001) ? "Enabled":"Disabled");
+ nvme_show_host_mem_buffer((struct nvme_host_mem_buffer *)buf);
+ break;
+ case NVME_FEAT_SW_PROGRESS:
+ printf("\tPre-boot Software Load Count (PBSLC): %u\n", result & 0x000000ff);
+ break;
+ case NVME_FEAT_PLM_CONFIG:
+ printf("\tPredictable Latency Window Enabled: %s\n", result & 0x1 ? "True":"False");
+ nvme_show_plm_config((struct nvme_plm_config *)buf);
+ break;
+ case NVME_FEAT_PLM_WINDOW:
+ printf("\tWindow Select: %s", nvme_plm_window(result));
+ break;
+ case NVME_FEAT_HOST_ID:
+ ull = buf[7]; ull <<= 8; ull |= buf[6]; ull <<= 8; ull |= buf[5]; ull <<= 8;
+ ull |= buf[4]; ull <<= 8; ull |= buf[3]; ull <<= 8; ull |= buf[2]; ull <<= 8;
+ ull |= buf[1]; ull <<= 8; ull |= buf[0];
+ printf("\tHost Identifier (HOSTID): %" PRIu64 "\n", ull);
+ break;
+ case NVME_FEAT_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_RESV_PERSIST:
+ printf("\tPersist Through Power Loss (PTPL): %s\n", (result & 0x00000001) ? "True":"False");
+ break;
+ case NVME_FEAT_WRITE_PROTECT:
+ printf("\tNamespace Write Protect: %s\n", result != NVME_NS_NO_WRITE_PROTECT ? "True" : "False");
+ break;
+ case NVME_FEAT_TIMESTAMP:
+ nvme_show_timestamp((struct nvme_timestamp *)buf);
+ break;
+ case NVME_FEAT_HCTM:
+ printf("\tThermal Management Temperature 1 (TMT1) : %u Kelvin\n", (result >> 16));
+ printf("\tThermal Management Temperature 2 (TMT2) : %u Kelvin\n", (result & 0x0000ffff));
+ break;
+ case NVME_FEAT_KATO:
+ printf("\tKeep Alive Timeout (KATO) in milliseconds: %u\n", result);
+ break;
+ case NVME_FEAT_NOPSC:
+ printf("\tNon-Operational Power State Permissive Mode Enable (NOPPME): %s\n", (result & 1) ? "True" : "False");
+ break;
+ case NVME_FEAT_HOST_BEHAVIOR:
+ printf("\tHost Behavior Support: %s\n", (buf[0] & 0x1) ? "True" : "False");
+ break;
+ }
+}
+
+void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len,
+ enum nvme_print_flags flags)
+{
+ int idx;
+
+ if (flags & BINARY)
+ return d_raw((unsigned char *)list, len);
+
+ printf("Number of LBA Status Descriptors(NLSD): %" PRIu64 "\n",
+ le64_to_cpu(list->nlsd));
+ printf("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;
+ }
+
+ 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 nvme_show_list_item(struct nvme_namespace *n)
+{
+ long long lba = 1 << n->ns.lbaf[(n->ns.flbas & 0x0f)].ds;
+ double nsze = le64_to_cpu(n->ns.nsze) * lba;
+ double nuse = le64_to_cpu(n->ns.nuse) * 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);
+
+ char usage[128];
+ char format[128];
+
+ sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix,
+ nsze, s_suffix);
+ sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix,
+ le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms));
+ printf("/dev/%-11s %-*.*s %-*.*s %-9d %-26s %-16s %-.*s\n", n->name,
+ (int)sizeof(n->ctrl->id.sn), (int)sizeof(n->ctrl->id.sn), n->ctrl->id.sn,
+ (int)sizeof(n->ctrl->id.mn), (int)sizeof(n->ctrl->id.mn), n->ctrl->id.mn,
+ n->nsid, usage, format, (int)sizeof(n->ctrl->id.fr), n->ctrl->id.fr);
+}
+
+static void nvme_show_simple_list(struct nvme_topology *t)
+{
+ int i, j, k;
+
+ printf("%-16s %-20s %-40s %-9s %-26s %-16s %-8s\n",
+ "Node", "SN", "Model", "Namespace", "Usage", "Format", "FW Rev");
+ printf("%-.16s %-.20s %-.40s %-.9s %-.26s %-.16s %-.8s\n", dash, dash,
+ dash, dash, dash, dash, dash);
+
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct nvme_namespace *n = &c->namespaces[k];
+ nvme_show_list_item(n);
+ }
+ }
+
+ for (j = 0; j < s->nr_namespaces; j++) {
+ struct nvme_namespace *n = &s->namespaces[j];
+ nvme_show_list_item(n);
+ }
+ }
+}
+
+static void nvme_show_details_ns(struct nvme_namespace *n, bool ctrl)
+{
+ long long lba = 1 << n->ns.lbaf[(n->ns.flbas & 0x0f)].ds;
+ double nsze = le64_to_cpu(n->ns.nsze) * lba;
+ double nuse = le64_to_cpu(n->ns.nuse) * 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);
+
+ char usage[128];
+ char format[128];
+
+ sprintf(usage,"%6.2f %2sB / %6.2f %2sB", nuse, u_suffix,
+ nsze, s_suffix);
+ sprintf(format,"%3.0f %2sB + %2d B", (double)lba, l_suffix,
+ le16_to_cpu(n->ns.lbaf[(n->ns.flbas & 0x0f)].ms));
+
+ printf("%-12s %-8x %-26s %-16s ", n->name, n->nsid, usage, format);
+
+ if (ctrl)
+ printf("%s", n->ctrl->name);
+ else {
+ struct nvme_subsystem *s = n->ctrl->subsys;
+ int i;
+
+ for (i = 0; i < s->nr_ctrls; i++)
+ printf("%s%s", i ? ", " : "", s->ctrls[i].name);
+ }
+ printf("\n");
+}
+
+static void nvme_show_detailed_list(struct nvme_topology *t)
+{
+ int i, j, k;
+
+ printf("NVM Express Subsystems\n\n");
+ printf("%-16s %-96s %-.16s\n", "Subsystem", "Subsystem-NQN", "Controllers");
+ printf("%-.16s %-.96s %-.16s\n", dash, dash, dash);
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ printf("%-16s %-96s ", s->name, s->subsysnqn);
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ printf("%s%s", j ? ", " : "", c->name);
+ }
+ printf("\n");
+ };
+
+ printf("\nNVM Express Controllers\n\n");
+ printf("%-8s %-20s %-40s %-8s %-6s %-14s %-12s %-16s\n", "Device",
+ "SN", "MN", "FR", "TxPort", "Address", "Subsystem", "Namespaces");
+ printf("%-.8s %-.20s %-.40s %-.8s %-.6s %-.14s %-.12s %-.16s\n", dash, dash,
+ dash, dash, dash, dash, dash, dash);
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ for (j = 0; j < s->nr_ctrls; j++) {
+ bool comma = false;
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ printf("%-8s %-.20s %-.40s %-.8s %-6s %-14s %-12s ",
+ c->name, c->id.sn, c->id.mn, c->id.fr,
+ c->transport, c->address, s->name);
+
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct nvme_namespace *n = &c->namespaces[k];
+ printf("%s%s", comma ? ", " : "", n->name);
+ comma = true;
+ }
+ for (k = 0; k < s->nr_namespaces; k++) {
+ struct nvme_namespace *n = &s->namespaces[k];
+ printf("%s%s", comma ? ", " : "", n->name);
+ comma = true;
+ }
+ printf("\n");
+ }
+ }
+
+ printf("\nNVM Express Namespaces\n\n");
+ printf("%-12s %-8s %-26s %-16s %-16s\n", "Device", "NSID", "Usage", "Format", "Controllers");
+ printf("%-.12s %-.8s %-.26s %-.16s %-.16s\n", dash, dash, dash, dash, dash);
+
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct nvme_namespace *n = &c->namespaces[k];
+ nvme_show_details_ns(n, true);
+ }
+ }
+ for (j = 0; j < s->nr_namespaces; j++) {
+ struct nvme_namespace *n = &s->namespaces[j];
+ nvme_show_details_ns(n, false);
+ }
+ }
+}
+
+static void json_detail_ns(struct nvme_namespace *n, struct json_object *ns_attrs)
+{
+ long long lba;
+ double nsze, nuse;
+
+ lba = 1 << n->ns.lbaf[(n->ns.flbas & 0x0f)].ds;
+ nsze = le64_to_cpu(n->ns.nsze) * lba;
+ nuse = le64_to_cpu(n->ns.nuse) * lba;
+
+ json_object_add_value_string(ns_attrs, "NameSpace", n->name);
+ json_object_add_value_uint(ns_attrs, "NSID", n->nsid);
+
+ json_object_add_value_uint(ns_attrs, "UsedBytes", nuse);
+ json_object_add_value_uint(ns_attrs, "MaximumLBA",
+ le64_to_cpu(n->ns.nsze));
+ json_object_add_value_uint(ns_attrs, "PhysicalSize", nsze);
+ json_object_add_value_uint(ns_attrs, "SectorSize", lba);
+}
+
+static void json_detail_list(struct nvme_topology *t)
+{
+ int i, j, k;
+ struct json_object *root;
+ struct json_array *devices;
+ char formatter[41] = { 0 };
+
+ root = json_create_object();
+ devices = json_create_array();
+
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+ struct json_object *subsys_attrs;
+ struct json_array *namespaces, *ctrls;
+
+ subsys_attrs = json_create_object();
+ json_object_add_value_string(subsys_attrs, "Subsystem", s->name);
+ json_object_add_value_string(subsys_attrs, "SubsystemNQN", s->subsysnqn);
+
+ ctrls = json_create_array();
+ json_object_add_value_array(subsys_attrs, "Controllers", ctrls);
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct json_object *ctrl_attrs = json_create_object();
+ struct nvme_ctrl *c = &s->ctrls[j];
+ struct json_array *namespaces;
+
+ json_object_add_value_string(ctrl_attrs, "Controller", c->name);
+ json_object_add_value_string(ctrl_attrs, "Transport", c->transport);
+ json_object_add_value_string(ctrl_attrs, "Address", c->address);
+ json_object_add_value_string(ctrl_attrs, "State", c->state);
+ if (c->hostnqn)
+ json_object_add_value_string(ctrl_attrs, "HostNQN", c->hostnqn);
+ if (c->hostid)
+ json_object_add_value_string(ctrl_attrs, "HostID", c->hostid);
+
+ format(formatter, sizeof(formatter), c->id.fr, sizeof(c->id.fr));
+ json_object_add_value_string(ctrl_attrs, "Firmware", formatter);
+
+ format(formatter, sizeof(formatter), c->id.mn, sizeof(c->id.mn));
+ json_object_add_value_string(ctrl_attrs, "ModelNumber", formatter);
+
+ format(formatter, sizeof(formatter), c->id.sn, sizeof(c->id.sn));
+ json_object_add_value_string(ctrl_attrs, "SerialNumber", formatter);
+
+ namespaces = json_create_array();
+
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct json_object *ns_attrs = json_create_object();
+ struct nvme_namespace *n = &c->namespaces[k];
+
+ json_detail_ns(n, ns_attrs);
+ json_array_add_value_object(namespaces, ns_attrs);
+ }
+ if (k)
+ json_object_add_value_array(ctrl_attrs, "Namespaces", namespaces);
+ else
+ json_free_array(namespaces);
+
+ json_array_add_value_object(ctrls, ctrl_attrs);
+ }
+
+ namespaces = json_create_array();
+ for (k = 0; k < s->nr_namespaces; k++) {
+ struct json_object *ns_attrs = json_create_object();
+ struct nvme_namespace *n = &s->namespaces[k];
+
+ json_detail_ns(n, ns_attrs);
+ json_array_add_value_object(namespaces, ns_attrs);
+ }
+ if (k)
+ json_object_add_value_array(subsys_attrs, "Namespaces", namespaces);
+ else
+ json_free_array(namespaces);
+
+ json_array_add_value_object(devices, subsys_attrs);
+ }
+
+ json_object_add_value_array(root, "Devices", devices);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_simple_ns(struct nvme_namespace *n, struct json_array *devices)
+{
+ struct json_object *device_attrs;
+ char formatter[41] = { 0 };
+ double nsze, nuse;
+ int index = -1;
+ long long lba;
+ char *devnode;
+
+ if (asprintf(&devnode, "/dev/%s", n->name) < 0)
+ return;
+
+ device_attrs = json_create_object();
+ json_object_add_value_int(device_attrs, "NameSpace", n->nsid);
+
+ json_object_add_value_string(device_attrs, "DevicePath", devnode);
+ free(devnode);
+
+ format(formatter, sizeof(formatter),
+ n->ctrl->id.fr,
+ sizeof(n->ctrl->id.fr));
+
+ json_object_add_value_string(device_attrs, "Firmware", formatter);
+
+ if (sscanf(n->ctrl->name, "nvme%d", &index) == 1)
+ json_object_add_value_int(device_attrs, "Index", index);
+
+ format(formatter, sizeof(formatter),
+ n->ctrl->id.mn,
+ sizeof(n->ctrl->id.mn));
+
+ json_object_add_value_string(device_attrs, "ModelNumber", formatter);
+
+ if (index >= 0 && !strcmp(n->ctrl->transport, "pcie")) {
+ char *product = nvme_product_name(index);
+
+ json_object_add_value_string(device_attrs, "ProductName", product);
+ free((void*)product);
+ }
+
+ format(formatter, sizeof(formatter),
+ n->ctrl->id.sn,
+ sizeof(n->ctrl->id.sn));
+
+ json_object_add_value_string(device_attrs, "SerialNumber", formatter);
+
+ lba = 1 << n->ns.lbaf[(n->ns.flbas & 0x0f)].ds;
+ nsze = le64_to_cpu(n->ns.nsze) * lba;
+ nuse = le64_to_cpu(n->ns.nuse) * lba;
+
+ json_object_add_value_uint(device_attrs, "UsedBytes", nuse);
+ json_object_add_value_uint(device_attrs, "MaximumLBA",
+ le64_to_cpu(n->ns.nsze));
+ json_object_add_value_uint(device_attrs, "PhysicalSize", nsze);
+ json_object_add_value_uint(device_attrs, "SectorSize", lba);
+
+ json_array_add_value_object(devices, device_attrs);
+}
+
+static void json_simple_list(struct nvme_topology *t)
+{
+ struct json_object *root;
+ struct json_array *devices;
+ int i, j, k;
+
+ root = json_create_object();
+ devices = json_create_array();
+ for (i = 0; i < t->nr_subsystems; i++) {
+ struct nvme_subsystem *s = &t->subsystems[i];
+
+ for (j = 0; j < s->nr_ctrls; j++) {
+ struct nvme_ctrl *c = &s->ctrls[j];
+
+ for (k = 0; k < c->nr_namespaces; k++) {
+ struct nvme_namespace *n = &c->namespaces[k];
+ json_simple_ns(n, devices);
+ }
+ }
+
+ for (j = 0; j < s->nr_namespaces; j++) {
+ struct nvme_namespace *n = &s->namespaces[j];
+ json_simple_ns(n, devices);
+ }
+ }
+ json_object_add_value_array(root, "Devices", devices);
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static void json_print_list_items(struct nvme_topology *t,
+ enum nvme_print_flags flags)
+{
+ if (flags & VERBOSE)
+ json_detail_list(t);
+ else
+ json_simple_list(t);
+}
+
+void nvme_show_list_items(struct nvme_topology *t, enum nvme_print_flags flags)
+{
+ if (flags & JSON)
+ json_print_list_items(t, flags);
+ else if (flags & VERBOSE)
+ nvme_show_detailed_list(t);
+ else
+ nvme_show_simple_list(t);
+}
diff --git a/nvme-print.h b/nvme-print.h
new file mode 100644
index 0000000..2a6f5ee
--- /dev/null
+++ b/nvme-print.h
@@ -0,0 +1,67 @@
+#ifndef NVME_PRINT_H
+#define NVME_PRINT_H
+
+#include "nvme.h"
+#include "util/json.h"
+#include <inttypes.h>
+
+void d(unsigned char *buf, int len, int width, int group);
+void d_raw(unsigned char *buf, unsigned len);
+uint64_t int48_to_long(__u8 *data);
+
+void nvme_show_status(__u16 status);
+void nvme_show_relatives(const char *name);
+
+void __nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode,
+ void (*vendor_show)(__u8 *vs, struct json_object *root));
+void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode);
+void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid,
+ enum nvme_print_flags flags);
+void nvme_show_resv_report(struct nvme_reservation_status *status, int bytes, __u32 cdw11,
+ enum nvme_print_flags flags);
+void nvme_show_lba_range(struct nvme_lba_range_type *lbrt, int nr_ranges);
+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_rsp_hdr *ana_log, const char *devname,
+ enum nvme_print_flags flags, size_t len);
+void nvme_show_self_test_log(struct nvme_self_test_log *self_test, const char *devname,
+ enum nvme_print_flags flags);
+void nvme_show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname,
+ enum nvme_print_flags flags);
+void nvme_show_effects_log(struct nvme_effects_log_page *effects, unsigned int flags);
+void nvme_show_changed_ns_list_log(struct nvme_changed_ns_list_log *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_ctrl_registers(void *bar, bool fabrics, enum nvme_print_flags flags);
+void nvme_show_single_property(int offset, uint64_t prop, int human);
+void nvme_show_id_ns_descs(void *data, unsigned nsid, enum nvme_print_flags flags);
+void nvme_show_lba_status(struct nvme_lba_status *list, unsigned long len,
+ enum nvme_print_flags flags);
+void nvme_show_list_items(struct nvme_topology *t, enum nvme_print_flags flags);
+void nvme_show_subsystem_list(struct nvme_topology *t,
+ enum nvme_print_flags flags);
+void nvme_show_id_nvmset(struct nvme_id_nvmset *nvmset, unsigned nvmset_id,
+ enum nvme_print_flags flags);
+void nvme_show_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list,
+ __u32 count, enum nvme_print_flags flags);
+void nvme_show_id_ns_granularity_list(const struct nvme_id_ns_granularity_list *glist,
+ enum nvme_print_flags flags);
+void nvme_show_id_uuid_list(const struct nvme_id_uuid_list *uuid_list,
+ enum nvme_print_flags flags);
+
+void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf);
+void nvme_directive_show(__u8 type, __u8 oper, __u16 spec, __u32 nsid, __u32 result,
+ void *buf, __u32 len, enum nvme_print_flags flags);
+void nvme_show_select_result(__u32 result);
+
+const char *nvme_status_to_string(__u32 status);
+const char *nvme_select_to_string(int sel);
+const char *nvme_feature_to_string(int feature);
+const char *nvme_register_to_string(int reg);
+
+#endif
diff --git a/nvme-status.c b/nvme-status.c
new file mode 100644
index 0000000..1b060dc
--- /dev/null
+++ b/nvme-status.c
@@ -0,0 +1,167 @@
+#include <linux/types.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include "nvme.h"
+#include "nvme-status.h"
+
+static inline __u8 nvme_generic_status_to_errno(__u16 status)
+{
+ switch (status) {
+ case NVME_SC_INVALID_OPCODE:
+ case NVME_SC_INVALID_FIELD:
+ case NVME_SC_INVALID_NS:
+ case NVME_SC_SGL_INVALID_LAST:
+ case NVME_SC_SGL_INVALID_COUNT:
+ case NVME_SC_SGL_INVALID_DATA:
+ case NVME_SC_SGL_INVALID_METADATA:
+ case NVME_SC_SGL_INVALID_TYPE:
+ case NVME_SC_SGL_INVALID_OFFSET:
+ case NVME_SC_CMB_INVALID_USE:
+ case NVME_SC_PRP_INVALID_OFFSET:
+ return EINVAL;
+ case NVME_SC_CMDID_CONFLICT:
+ return EADDRINUSE;
+ case NVME_SC_DATA_XFER_ERROR:
+ case NVME_SC_INTERNAL:
+ case NVME_SC_SANITIZE_FAILED:
+ return EIO;
+ case NVME_SC_POWER_LOSS:
+ case NVME_SC_ABORT_REQ:
+ case NVME_SC_ABORT_QUEUE:
+ case NVME_SC_FUSED_FAIL:
+ case NVME_SC_FUSED_MISSING:
+ return EWOULDBLOCK;
+ case NVME_SC_CMD_SEQ_ERROR:
+ return EILSEQ;
+ case NVME_SC_SANITIZE_IN_PROGRESS:
+ case NVME_SC_FORMAT_IN_PROGRESS:
+ return EINPROGRESS;
+ case NVME_SC_NS_WRITE_PROTECTED:
+ case NVME_SC_NS_NOT_READY:
+ case NVME_SC_RESERVATION_CONFLICT:
+ return EACCES;
+ case NVME_SC_LBA_RANGE:
+ return EREMOTEIO;
+ case NVME_SC_CAP_EXCEEDED:
+ return ENOSPC;
+ case NVME_SC_OPERATION_DENIED:
+ return EPERM;
+ }
+
+ return EIO;
+}
+
+static inline __u8 nvme_cmd_specific_status_to_errno(__u16 status)
+{
+ switch (status) {
+ case NVME_SC_CQ_INVALID:
+ case NVME_SC_QID_INVALID:
+ case NVME_SC_QUEUE_SIZE:
+ case NVME_SC_FIRMWARE_SLOT:
+ case NVME_SC_FIRMWARE_IMAGE:
+ case NVME_SC_INVALID_VECTOR:
+ case NVME_SC_INVALID_LOG_PAGE:
+ case NVME_SC_INVALID_FORMAT:
+ case NVME_SC_INVALID_QUEUE:
+ case NVME_SC_NS_INSUFFICIENT_CAP:
+ case NVME_SC_NS_ID_UNAVAILABLE:
+ case NVME_SC_CTRL_LIST_INVALID:
+ case NVME_SC_BAD_ATTRIBUTES:
+ case NVME_SC_INVALID_PI:
+ case NVME_SC_INVALID_CTRL_ID:
+ case NVME_SC_INVALID_SECONDARY_CTRL_STATE:
+ case NVME_SC_INVALID_NUM_CTRL_RESOURCE:
+ case NVME_SC_INVALID_RESOURCE_ID:
+ case NVME_SC_ANA_INVALID_GROUP_ID:
+ return EINVAL;
+ case NVME_SC_ABORT_LIMIT:
+ case NVME_SC_ASYNC_LIMIT:
+ return EDQUOT;
+ case NVME_SC_FW_NEEDS_CONV_RESET:
+ case NVME_SC_FW_NEEDS_SUBSYS_RESET:
+ case NVME_SC_FW_NEEDS_MAX_TIME:
+ return ERESTART;
+ case NVME_SC_FEATURE_NOT_SAVEABLE:
+ case NVME_SC_FEATURE_NOT_CHANGEABLE:
+ case NVME_SC_FEATURE_NOT_PER_NS:
+ case NVME_SC_FW_ACTIVATE_PROHIBITED:
+ case NVME_SC_NS_IS_PRIVATE:
+ case NVME_SC_BP_WRITE_PROHIBITED:
+ case NVME_SC_READ_ONLY:
+ case NVME_SC_PMR_SAN_PROHIBITED:
+ return EPERM;
+ case NVME_SC_OVERLAPPING_RANGE:
+ case NVME_SC_NS_NOT_ATTACHED:
+ return ENOSPC;
+ case NVME_SC_NS_ALREADY_ATTACHED:
+ return EALREADY;
+ case NVME_SC_THIN_PROV_NOT_SUPP:
+ case NVME_SC_ONCS_NOT_SUPPORTED:
+ return EOPNOTSUPP;
+ case NVME_SC_DEVICE_SELF_TEST_IN_PROGRESS:
+ return EINPROGRESS;
+ }
+
+ return EIO;
+}
+
+static inline __u8 nvme_fabrics_status_to_errno(__u16 status)
+{
+ switch (status) {
+ case NVME_SC_CONNECT_FORMAT:
+ case NVME_SC_CONNECT_INVALID_PARAM:
+ return EINVAL;
+ case NVME_SC_CONNECT_CTRL_BUSY:
+ return EBUSY;
+ case NVME_SC_CONNECT_RESTART_DISC:
+ return ERESTART;
+ case NVME_SC_CONNECT_INVALID_HOST:
+ return ECONNREFUSED;
+ case NVME_SC_DISCOVERY_RESTART:
+ return EAGAIN;
+ case NVME_SC_AUTH_REQUIRED:
+ return EPERM;
+ }
+
+ return EIO;
+}
+
+/*
+ * nvme_status_to_errno - It converts given status to errno mapped
+ * @status: >= 0 for nvme status field in completion queue entry,
+ * < 0 for linux internal errors
+ * @fabrics: true if given status is for fabrics
+ *
+ * Notes: This function will convert a given status to an errno mapped
+ */
+__u8 nvme_status_to_errno(int status, bool fabrics)
+{
+ __u8 sct;
+
+ if (!status)
+ return 0;
+
+ if (status < 0)
+ return ECOMM;
+
+ /*
+ * The actual status code is enough with masking 0xff, but we need to
+ * cover status code type which is 3bits with 0x7ff.
+ */
+ status &= 0x7ff;
+
+ sct = nvme_status_type(status);
+ if (sct == NVME_SCT_GENERIC)
+ return nvme_generic_status_to_errno(status);
+ else if (sct == NVME_SCT_CMD_SPECIFIC && !fabrics)
+ return nvme_cmd_specific_status_to_errno(status);
+ else if (sct == NVME_SCT_CMD_SPECIFIC && fabrics)
+ return nvme_fabrics_status_to_errno(status);
+
+ /*
+ * Media, integrity related status, and the others will be mapped to
+ * EIO.
+ */
+ return EIO;
+}
diff --git a/nvme-status.h b/nvme-status.h
new file mode 100644
index 0000000..92a474c
--- /dev/null
+++ b/nvme-status.h
@@ -0,0 +1,14 @@
+#include <linux/types.h>
+#include <stdbool.h>
+
+/*
+ * nvme_status_type - It gives SCT(Status Code Type) in status field in
+ * completion queue entry.
+ * @status: status field located at DW3 in completion queue entry
+ */
+static inline __u8 nvme_status_type(__u16 status)
+{
+ return (status & 0x700) >> 8;
+}
+
+__u8 nvme_status_to_errno(int status, bool fabrics);
diff --git a/nvme-topology.c b/nvme-topology.c
new file mode 100644
index 0000000..d24ef6b
--- /dev/null
+++ b/nvme-topology.c
@@ -0,0 +1,608 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "nvme.h"
+#include "nvme-ioctl.h"
+
+static const char *dev = "/dev/";
+static const char *subsys_dir = "/sys/class/nvme-subsystem/";
+
+char *get_nvme_subsnqn(char *path)
+{
+ char sspath[320], *subsysnqn;
+ int fd, ret;
+
+ snprintf(sspath, sizeof(sspath), "%s/subsysnqn", path);
+
+ fd = open(sspath, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n",
+ sspath, strerror(errno));
+ return NULL;
+ }
+
+ subsysnqn = calloc(1, 256);
+ if (!subsysnqn)
+ goto close_fd;
+
+ ret = read(fd, subsysnqn, 256);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to read %s: %s\n", sspath,
+ strerror(errno));
+ free(subsysnqn);
+ subsysnqn = NULL;
+ } else if (subsysnqn[strlen(subsysnqn) - 1] == '\n') {
+ subsysnqn[strlen(subsysnqn) - 1] = '\0';
+ }
+
+close_fd:
+ close(fd);
+ return subsysnqn;
+}
+
+char *nvme_get_ctrl_attr(char *path, const char *attr)
+{
+ char *attrpath, *value;
+ ssize_t ret;
+ int fd, i;
+
+ ret = asprintf(&attrpath, "%s/%s", path, attr);
+ if (ret < 0)
+ return NULL;
+
+ value = calloc(1, 1024);
+ if (!value)
+ goto err_free_path;
+
+ fd = open(attrpath, O_RDONLY);
+ if (fd < 0)
+ goto err_free_value;
+
+ ret = read(fd, value, 1024);
+ if (ret < 0) {
+ fprintf(stderr, "read :%s :%s\n", attrpath, strerror(errno));
+ goto err_close_fd;
+ }
+
+ if (value[strlen(value) - 1] == '\n')
+ value[strlen(value) - 1] = '\0';
+
+ for (i = 0; i < strlen(value); i++) {
+ if (value[i] == ',' )
+ value[i] = ' ';
+ }
+
+ close(fd);
+ free(attrpath);
+ return value;
+err_close_fd:
+ close(fd);
+err_free_value:
+ free(value);
+err_free_path:
+ free(attrpath);
+ return NULL;
+}
+
+static char *path_trim_last(char *path, char needle)
+{
+ int i;
+ i = strlen(path);
+ if (i>0 && path[i-1] == needle) // remove trailing slash
+ path[--i] = 0;
+ for (; i>0; i--)
+ if (path[i] == needle) {
+ path[i] = 0;
+ return path+i+1;
+ }
+ return NULL;
+}
+
+static void legacy_get_pci_bdf(char *node, char *bdf)
+{
+ int ret;
+ char path[264], nodetmp[264];
+ struct stat st;
+ char *p, *__path = path;
+
+ bdf[0] = 0;
+ strcpy(nodetmp, node);
+ p = path_trim_last(nodetmp, '/');
+ sprintf(path, "/sys/block/%s/device", p);
+ ret = readlink(path, nodetmp, sizeof(nodetmp));
+ if (ret <= 0)
+ return;
+ nodetmp[ret] = 0;
+ /* The link value is either "device -> ../../../0000:86:00.0" or "device -> ../../nvme0" */
+ (void) path_trim_last(path, '/');
+ sprintf(path+strlen(path), "/%s/device", nodetmp);
+ ret = stat(path, &st);
+ if (ret < 0)
+ return;
+ if ((st.st_mode & S_IFLNK) == 0) {
+ /* follow the second link to get the PCI address */
+ ret = readlink(path, __path, sizeof(path));
+ if (ret <= 0)
+ return;
+ path[ret] = 0;
+ }
+ else
+ (void) path_trim_last(path, '/');
+
+ p = path_trim_last(path, '/');
+ if (p && strlen(p) == 12)
+ strcpy(bdf, p);
+}
+
+static int scan_namespace(struct nvme_namespace *n)
+{
+ int ret, fd;
+ char *path;
+
+ ret = asprintf(&path, "%s%s", dev, n->name);
+ if (ret < 0)
+ return ret;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto free;
+
+ n->nsid = nvme_get_nsid(fd);
+ if (n->nsid < 0)
+ goto close_fd;
+
+ ret = nvme_identify_ns(fd, n->nsid, 0, &n->ns);
+ if (ret < 0)
+ goto close_fd;
+close_fd:
+ close(fd);
+free:
+ free(path);
+ return 0;
+}
+
+static char *get_nvme_ctrl_path_ana_state(char *path, int nsid)
+{
+ struct dirent **paths;
+ char *ana_state;
+ int i, n;
+
+ ana_state = calloc(1, 16);
+ if (!ana_state)
+ return NULL;
+
+ n = scandir(path, &paths, scan_ctrl_paths_filter, alphasort);
+ if (n <= 0) {
+ free(ana_state);
+ return NULL;
+ }
+ for (i = 0; i < n; i++) {
+ int id, cntlid, ns, fd;
+ char *ctrl_path;
+ ssize_t ret;
+
+ if (sscanf(paths[i]->d_name, "nvme%dc%dn%d",
+ &id, &cntlid, &ns) != 3) {
+ if (sscanf(paths[i]->d_name, "nvme%dn%d",
+ &id, &ns) != 2) {
+ continue;
+ }
+ }
+ if (ns != nsid)
+ continue;
+
+ ret = asprintf(&ctrl_path, "%s/%s/ana_state",
+ path, paths[i]->d_name);
+ if (ret < 0) {
+ free(ana_state);
+ ana_state = NULL;
+ break;
+ }
+ fd = open(ctrl_path, O_RDONLY);
+ if (fd < 0) {
+ free(ctrl_path);
+ free(ana_state);
+ ana_state = NULL;
+ break;
+ }
+ ret = read(fd, ana_state, 16);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to read ANA state from %s\n",
+ ctrl_path);
+ free(ana_state);
+ ana_state = NULL;
+ } else if (ana_state[strlen(ana_state) - 1] == '\n')
+ ana_state[strlen(ana_state) - 1] = '\0';
+ close(fd);
+ free(ctrl_path);
+ break;
+ }
+ for (i = 0; i < n; i++)
+ free(paths[i]);
+ free(paths);
+ return ana_state;
+}
+
+static int scan_ctrl(struct nvme_ctrl *c, char *p, __u32 ns_instance)
+{
+ struct nvme_namespace *n;
+ struct dirent **ns;
+ char *path;
+ int i, fd, ret;
+
+ ret = asprintf(&path, "%s/%s", p, c->name);
+ if (ret < 0)
+ return ret;
+
+ c->address = nvme_get_ctrl_attr(path, "address");
+ c->transport = nvme_get_ctrl_attr(path, "transport");
+ c->state = nvme_get_ctrl_attr(path, "state");
+ c->hostnqn = nvme_get_ctrl_attr(path, "hostnqn");
+ c->hostid = nvme_get_ctrl_attr(path, "hostid");
+
+ if (ns_instance)
+ c->ana_state = get_nvme_ctrl_path_ana_state(path, ns_instance);
+
+ ret = scandir(path, &ns, scan_namespace_filter, alphasort);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
+ return errno;
+ }
+
+ c->nr_namespaces = ret;
+ c->namespaces = calloc(c->nr_namespaces, sizeof(*n));
+ for (i = 0; i < c->nr_namespaces; i++) {
+ n = &c->namespaces[i];
+ n->name = strdup(ns[i]->d_name);
+ n->ctrl = c;
+ scan_namespace(n);
+ }
+
+ while (i--)
+ free(ns[i]);
+ free(ns);
+ free(path);
+
+ ret = asprintf(&path, "%s%s", dev, c->name);
+ if (ret < 0)
+ return ret;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open %s\n", path);
+ goto free;
+ }
+
+ ret = nvme_identify_ctrl(fd, &c->id);
+ if (ret < 0)
+ goto close_fd;
+close_fd:
+ close(fd);
+free:
+ free(path);
+ return 0;
+}
+
+static int scan_subsystem(struct nvme_subsystem *s, __u32 ns_instance)
+{
+ struct dirent **ctrls, **ns;
+ struct nvme_namespace *n;
+ struct nvme_ctrl *c;
+ int i, ret;
+ char *path;
+
+ ret = asprintf(&path, "%s%s", subsys_dir, s->name);
+ if (ret < 0)
+ return ret;
+
+ s->subsysnqn = get_nvme_subsnqn(path);
+ ret = scandir(path, &ctrls, scan_ctrls_filter, alphasort);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
+ return errno;
+ }
+ s->nr_ctrls = ret;
+ s->ctrls = calloc(s->nr_ctrls, sizeof(*c));
+ for (i = 0; i < s->nr_ctrls; i++) {
+ c = &s->ctrls[i];
+ c->name = strdup(ctrls[i]->d_name);
+ c->subsys = s;
+ scan_ctrl(c, path, ns_instance);
+ }
+
+ while (i--)
+ free(ctrls[i]);
+ free(ctrls);
+
+ ret = scandir(path, &ns, scan_namespace_filter, alphasort);
+ if (ret == -1) {
+ fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
+ return errno;
+ }
+
+ s->nr_namespaces = ret;
+ s->namespaces = calloc(s->nr_namespaces, sizeof(*n));
+ for (i = 0; i < s->nr_namespaces; i++) {
+ n = &s->namespaces[i];
+ n->name = strdup(ns[i]->d_name);
+ n->ctrl = &s->ctrls[0];
+ scan_namespace(n);
+ }
+
+ while (i--)
+ free(ns[i]);
+ free(ns);
+
+ free(path);
+ return 0;
+}
+
+static int verify_legacy_ns(struct nvme_namespace *n)
+{
+ struct nvme_ctrl *c = n->ctrl;
+ struct nvme_id_ctrl id;
+ char *path;
+ int ret, fd;
+
+ ret = asprintf(&path, "%s%s", dev, n->name);
+ if (ret < 0)
+ return ret;
+
+ if (!n->ctrl->transport && !n->ctrl->address) {
+ char tmp_address[64] = "";
+ legacy_get_pci_bdf(path, tmp_address);
+ if (tmp_address[0]) {
+ if (asprintf(&n->ctrl->transport, "pcie") < 0)
+ return -1;
+ if (asprintf(&n->ctrl->address, "%s", tmp_address) < 0)
+ return -1;
+ }
+ }
+
+ fd = open(path, O_RDONLY);
+ free (path);
+
+ if (fd < 0)
+ return fd;
+
+ ret = nvme_identify_ctrl(fd, &id);
+ close(fd);
+
+ if (ret)
+ return ret;
+
+ if (memcmp(id.mn, c->id.mn, sizeof(id.mn)) ||
+ memcmp(id.sn, c->id.sn, sizeof(id.sn)))
+ return -ENODEV;
+ return 0;
+}
+
+/*
+ * For pre-subsystem enabled kernel. Topology information is limited, but we can
+ * assume controller names are always a prefix to their namespaces, i.e. nvme0
+ * is the controller to nvme0n1 for such older kernels. We will also assume
+ * every controller is its own subsystem.
+ */
+static int legacy_list(struct nvme_topology *t)
+{
+ struct nvme_ctrl *c;
+ struct nvme_subsystem *s;
+ struct nvme_namespace *n;
+ struct dirent **devices, **namespaces;
+ int ret = 0, fd, i;
+ char *path;
+
+ t->nr_subsystems = scandir(dev, &devices, scan_ctrls_filter, alphasort);
+ if (t->nr_subsystems < 0) {
+ fprintf(stderr, "no NVMe device(s) detected.\n");
+ return t->nr_subsystems;
+ }
+
+ t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
+ for (i = 0; i < t->nr_subsystems; i++) {
+ int j;
+
+ s = &t->subsystems[i];
+ s->nr_ctrls = 1;
+ s->ctrls = calloc(s->nr_ctrls, sizeof(*c));
+ s->name = strdup(devices[i]->d_name);
+ s->subsysnqn = strdup(s->name);
+ s->nr_namespaces = 0;
+
+ c = s->ctrls;
+ c->name = strdup(s->name);
+ sscanf(c->name, "nvme%d", &current_index);
+ c->nr_namespaces = scandir(dev, &namespaces, scan_dev_filter,
+ alphasort);
+ c->namespaces = calloc(c->nr_namespaces, sizeof(*n));
+
+ ret = asprintf(&path, "%s%s", dev, c->name);
+ if (ret < 0)
+ continue;
+ ret = 0;
+
+ fd = open(path, O_RDONLY);
+ if (fd > 0) {
+ nvme_identify_ctrl(fd, &c->id);
+ close(fd);
+ }
+ free(path);
+
+ for (j = 0; j < c->nr_namespaces; j++) {
+ n = &c->namespaces[j];
+ n->name = strdup(namespaces[j]->d_name);
+ n->ctrl = c;
+ scan_namespace(n);
+ ret = verify_legacy_ns(n);
+ if (ret)
+ goto free;
+ }
+ while (j--)
+ free(namespaces[j]);
+ free(namespaces);
+ }
+
+free:
+ while (i--)
+ free(devices[i]);
+ free(devices);
+ return ret;
+}
+
+static void free_ctrl(struct nvme_ctrl *c)
+{
+ int i;
+
+ for (i = 0; i < c->nr_namespaces; i++) {
+ struct nvme_namespace *n = &c->namespaces[i];
+ free(n->name);
+ }
+ free(c->name);
+ free(c->transport);
+ free(c->address);
+ free(c->state);
+ free(c->hostnqn);
+ free(c->hostid);
+ free(c->ana_state);
+ free(c->namespaces);
+}
+
+static void free_subsystem(struct nvme_subsystem *s)
+{
+ int i;
+
+ for (i = 0; i < s->nr_ctrls; i++)
+ free_ctrl(&s->ctrls[i]);
+ for (i = 0; i < s->nr_namespaces; i++) {
+ struct nvme_namespace *n = &s->namespaces[i];
+ free(n->name);
+ }
+ free(s->name);
+ free(s->subsysnqn);
+ free(s->ctrls);
+ free(s->namespaces);
+}
+
+int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
+ __u32 ns_instance)
+{
+ struct nvme_subsystem *s;
+ struct dirent **subsys;
+ int i, j = 0;
+
+ t->nr_subsystems = scandir(subsys_dir, &subsys, scan_subsys_filter,
+ alphasort);
+ if (t->nr_subsystems < 0)
+ return legacy_list(t);
+
+ t->subsystems = calloc(t->nr_subsystems, sizeof(*s));
+ for (i = 0; i < t->nr_subsystems; i++) {
+ s = &t->subsystems[j];
+ s->name = strdup(subsys[i]->d_name);
+ scan_subsystem(s, ns_instance);
+
+ if (!subsysnqn || !strcmp(s->subsysnqn, subsysnqn))
+ j++;
+ else
+ free_subsystem(s);
+ }
+ t->nr_subsystems = j;
+
+ while (i--)
+ free(subsys[i]);
+ free(subsys);
+ return 0;
+}
+
+void free_topology(struct nvme_topology *t)
+{
+ int i;
+
+ for (i = 0; i < t->nr_subsystems; i++)
+ free_subsystem(&t->subsystems[i]);
+ free(t->subsystems);
+}
+
+char *nvme_char_from_block(char *dev)
+{
+ char *path = NULL;
+ char buf[256] = {0};
+ int ret, id, nsid;
+
+ ret = sscanf(dev, "nvme%dn%d", &id, &nsid);
+ switch (ret) {
+ case 1:
+ return strdup(dev);
+ break;
+ case 2:
+ if (asprintf(&path, "/sys/block/%s/device", dev) < 0)
+ path = NULL;
+ break;
+ default:
+ fprintf(stderr, "%s is not an nvme device\n", dev);
+ return NULL;
+ }
+
+ if (!path)
+ return NULL;
+
+ ret = readlink(path, buf, sizeof(buf));
+ if (ret > 0) {
+ char *r = strdup(basename(buf));
+
+ free(path);
+ if (sscanf(r, "nvme%d", &id) != 1) {
+ fprintf(stderr, "%s is not a physical nvme controller\n", r);
+ free(r);
+ r = NULL;
+ }
+ return r;
+ }
+
+ free(path);
+ ret = asprintf(&path, "nvme%d", id);
+ if (ret < 0)
+ return NULL;
+ return path;
+}
+
+void *mmap_registers(const char *dev)
+{
+ int fd;
+ char *base, path[512];
+ void *membase;
+
+ base = nvme_char_from_block((char *)dev);
+ if (!base)
+ return NULL;
+
+ sprintf(path, "/sys/class/nvme/%s/device/resource0", base);
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ sprintf(path, "/sys/class/misc/%s/device/resource0", base);
+ fd = open(path, O_RDONLY);
+ }
+ if (fd < 0) {
+ fprintf(stderr, "%s did not find a pci resource, open failed %s\n",
+ base, strerror(errno));
+ free(base);
+ return NULL;
+ }
+
+ membase = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
+ if (membase == MAP_FAILED) {
+ fprintf(stderr, "%s failed to map. ", base);
+ fprintf(stderr, "Did your kernel enable CONFIG_IO_STRICT_DEVMEM?\n");
+ membase = NULL;
+ }
+
+ free(base);
+ close(fd);
+ return membase;
+}
+
diff --git a/nvme.c b/nvme.c
new file mode 100644
index 0000000..107f012
--- /dev/null
+++ b/nvme.c
@@ -0,0 +1,4841 @@
+/*
+ * nvme.c -- 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 <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>
+
+#ifdef LIBHUGETLBFS
+#include <hugetlbfs.h>
+#endif
+
+#include <linux/fs.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "common.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "nvme-status.h"
+#include "nvme-lightnvm.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "fabrics.h"
+
+#define CREATE_CMD
+#include "nvme-builtin.h"
+
+static struct stat nvme_stat;
+const char *devicename;
+
+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) or an nvme block device "\
+ "(ex: /dev/nvme0n1).",
+ .extensions = &builtin,
+};
+
+static const char *output_format = "Output format: normal|json|binary";
+static const char *output_format_no_binary = "Output format: normal|json";
+
+static void *__nvme_alloc(size_t len, bool *huge)
+{
+ void *p;
+
+ if (!posix_memalign(&p, getpagesize(), len)) {
+ *huge = false;
+ memset(p, 0, len);
+ return p;
+ }
+ return NULL;
+}
+
+#ifdef LIBHUGETLBFS
+#define HUGE_MIN 0x80000
+
+static void nvme_free(void *p, bool huge)
+{
+ if (huge)
+ free_hugepage_region(p);
+ else
+ free(p);
+}
+
+static void *nvme_alloc(size_t len, bool *huge)
+{
+ void *p;
+
+ if (len < HUGE_MIN)
+ return __nvme_alloc(len, huge);
+
+ p = get_hugepage_region(len, GHR_DEFAULT);
+ if (!p)
+ return __nvme_alloc(len, huge);
+
+ *huge = true;
+ return p;
+}
+#else
+static void nvme_free(void *p, bool huge)
+{
+ free(p);
+}
+
+static void *nvme_alloc(size_t len, bool *huge)
+{
+ return __nvme_alloc(len, huge);
+}
+#endif
+
+static int open_dev(char *dev)
+{
+ int err, fd;
+
+ devicename = basename(dev);
+ err = open(dev, O_RDONLY);
+ if (err < 0)
+ goto perror;
+ fd = err;
+
+ err = fstat(fd, &nvme_stat);
+ if (err < 0) {
+ close(fd);
+ goto perror;
+ }
+ if (!S_ISCHR(nvme_stat.st_mode) && !S_ISBLK(nvme_stat.st_mode)) {
+ fprintf(stderr, "%s is not a block or character device\n", dev);
+ close(fd);
+ return -ENODEV;
+ }
+ return fd;
+perror:
+ perror(dev);
+ return err;
+}
+
+static int check_arg_dev(int argc, char **argv)
+{
+ if (optind >= argc) {
+ errno = EINVAL;
+ perror(argv[0]);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int get_dev(int argc, char **argv)
+{
+ int ret;
+
+ ret = check_arg_dev(argc, argv);
+ if (ret)
+ return ret;
+
+ return open_dev(argv[optind]);
+}
+
+int parse_and_open(int argc, char **argv, const char *desc,
+ const struct argconfig_commandline_options *opts)
+{
+ int ret;
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret)
+ return ret;
+
+ ret = get_dev(argc, argv);
+ if (ret < 0)
+ argconfig_print_help(desc, opts);
+
+ return ret;
+}
+
+enum nvme_print_flags validate_output_format(char *format)
+{
+ if (!format)
+ return -EINVAL;
+ if (!strcmp(format, "normal"))
+ return NORMAL;
+ if (!strcmp(format, "json"))
+ return JSON;
+ if (!strcmp(format, "binary"))
+ return BINARY;
+ return -EINVAL;
+}
+
+static int get_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_smart_log smart_log;
+ const char *desc = "Retrieve SMART log for the given device "\
+ "(or optionally a namespace) in either decoded format "\
+ "(default) or binary.";
+ const char *namespace = "(optional) desired namespace";
+ const char *raw = "output in binary format";
+ const char *human_readable = "show info in readable format";
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ int raw_binary;
+ char *output_format;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .output_format = "normal",
+ };
+
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ 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 = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_smart_log(fd, cfg.namespace_id, &smart_log);
+ if (!err)
+ nvme_show_smart_log(&smart_log, cfg.namespace_id, devicename,
+ flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("smart log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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.";
+ void *ana_log;
+ int err, fd;
+ int groups = 0; /* Right now get all the per ANA group NSIDS */
+ size_t ana_log_len;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err) {
+ fprintf(stderr, "ERROR : nvme_identify_ctrl() failed 0x%x\n",
+ err);
+ goto close_fd;
+ }
+
+ ana_log_len = sizeof(struct nvme_ana_rsp_hdr) +
+ 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 = malloc(ana_log_len);
+ if (!ana_log) {
+ perror("malloc");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_ana_log(fd, ana_log, ana_log_len, groups ? NVME_ANA_LOG_RGO : 0);
+ if (!err) {
+ nvme_show_ana_log(ana_log, devicename, flags, ana_log_len);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("ana-log");
+ free(ana_log);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 all. Valid options are 1, 2, 3.";
+ const size_t bs = 512;
+ struct nvme_telemetry_log_page_hdr *hdr;
+ size_t full_size, offset = bs;
+ int err = 0, fd, output;
+ void *page_log;
+
+ struct config {
+ char *file_name;
+ __u32 host_gen;
+ int ctrl_init;
+ int data_area;
+ };
+ struct config cfg = {
+ .file_name = NULL,
+ .host_gen = 1,
+ .ctrl_init = 0,
+ .data_area = 3,
+ };
+
+ OPT_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_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.file_name) {
+ fprintf(stderr, "Please provide an output file!\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ cfg.host_gen = !!cfg.host_gen;
+ hdr = malloc(bs);
+ page_log = malloc(bs);
+ if (!hdr || !page_log) {
+ fprintf(stderr, "Failed to allocate %zu bytes for log: %s\n",
+ bs, strerror(errno));
+ err = -ENOMEM;
+ goto free_mem;
+ }
+ memset(hdr, 0, bs);
+
+ output = open(cfg.file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ fprintf(stderr, "Failed to open output file %s: %s!\n",
+ cfg.file_name, strerror(errno));
+ err = output;
+ goto free_mem;
+ }
+
+ err = nvme_get_telemetry_log(fd, hdr, cfg.host_gen, cfg.ctrl_init, bs, 0);
+ 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;
+ }
+
+ switch (cfg.data_area) {
+ case 1:
+ full_size = (le16_to_cpu(hdr->dalb1) * bs) + offset;
+ break;
+ case 2:
+ full_size = (le16_to_cpu(hdr->dalb2) * bs) + offset;
+ break;
+ case 3:
+ full_size = (le16_to_cpu(hdr->dalb3) * bs) + offset;
+ break;
+ default:
+ fprintf(stderr, "Invalid data area requested\n");
+ err = -EINVAL;
+ goto close_output;
+ }
+
+ /*
+ * Continuously pull data until the offset hits the end of the last
+ * block.
+ */
+ while (offset != full_size) {
+ err = nvme_get_telemetry_log(fd, page_log, 0, cfg.ctrl_init, bs, offset);
+ 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 *) page_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(page_log);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_endurance_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_endurance_group_log endurance_log;
+ const char *desc = "Retrieves endurance groups log page and prints the log.";
+ const char *group_id = "The endurance group identifier";
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ char *output_format;
+ __u16 group_id;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .group_id = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_UINT("group-id", 'g', &cfg.group_id, group_id),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_endurance_log(fd, cfg.group_id, &endurance_log);
+ if (!err)
+ nvme_show_endurance_log(&endurance_log, cfg.group_id, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("endurance log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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.";
+ const char *raw = "show log in binary format";
+ const char *human_readable = "show log in readable format";
+ struct nvme_effects_log_page effects;
+
+ int err, fd;
+ enum nvme_print_flags flags;
+
+ struct config {
+ int raw_binary;
+ int human_readable;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_effects_log(fd, &effects);
+ if (!err)
+ nvme_show_effects_log(&effects, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("effects log page");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+ struct nvme_error_log_page *err_log;
+ struct nvme_id_ctrl ctrl;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u32 log_entries;
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .log_entries = 64,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("log-entries", 'e', &cfg.log_entries, log_entries),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.log_entries) {
+ fprintf(stderr, "non-zero log-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err < 0) {
+ perror("identify controller");
+ goto close_fd;
+ } else if (err) {
+ fprintf(stderr, "could not identify controller\n");
+ err = -ENODEV;
+ goto close_fd;
+ }
+
+ cfg.log_entries = min(cfg.log_entries, ctrl.elpe + 1);
+ err_log = calloc(cfg.log_entries, sizeof(struct nvme_error_log_page));
+ if (!err_log) {
+ fprintf(stderr, "could not alloc buffer for error log\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_error_log(fd, cfg.log_entries, err_log);
+ if (!err)
+ nvme_show_error_log(err_log, cfg.log_entries, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("error log");
+ free(err_log);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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.";
+ const char *raw = "use binary output";
+ struct nvme_firmware_log_page fw_log;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_fw_log(fd, &fw_log);
+ if (!err)
+ nvme_show_fw_log(&fw_log, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("fw log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_changed_ns_list_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_changed_ns_list_log changed_ns_list_log;
+ const char *desc = "Retrieve Changed Namespaces log for the given device "\
+ "in either decoded format "\
+ "(default) or binary.";
+ const char *raw = "output in binary format";
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_changed_ns_list_log(fd, &changed_ns_list_log);
+ if (!err)
+ nvme_show_changed_ns_list_log(&changed_ns_list_log, devicename,
+ flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("changed ns list log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int get_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve desired number of bytes "\
+ "from a given log on a specified device in either "\
+ "hex-dump (default) or binary format";
+ const char *namespace_id = "desired namespace";
+ 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 *lsp = "log specific field";
+ const char *lpo = "log page offset specifies the location within a log page from where to start returning data";
+ const char *rae = "retain an asynchronous event";
+ const char *raw = "output in raw format";
+ const char *uuid_index = "UUID index";
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 log_id;
+ __u32 log_len;
+ __u32 aen;
+ __u64 lpo;
+ __u8 lsp;
+ __u8 uuid_index;
+ int rae;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .log_id = 0xffffffff,
+ .log_len = 0,
+ .lpo = NVME_NO_LOG_LPO,
+ .lsp = NVME_NO_LOG_LSP,
+ .rae = 0,
+ .uuid_index = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("log-id", 'i', &cfg.log_id, log_id),
+ OPT_UINT("log-len", 'l', &cfg.log_len, log_len),
+ OPT_UINT("aen", 'a', &cfg.aen, aen),
+ OPT_LONG("lpo", 'o', &cfg.lpo, lpo),
+ OPT_BYTE("lsp", 's', &cfg.lsp, lsp),
+ 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_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.aen) {
+ cfg.log_len = 4096;
+ cfg.log_id = (cfg.aen >> 16) & 0xff;
+ }
+
+ if (cfg.log_id > 0xff) {
+ fprintf(stderr, "Invalid log identifier: %d. Valid range: 0-255\n", cfg.log_id);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.log_len) {
+ fprintf(stderr, "non-zero log-len is required param\n");
+ err = -EINVAL;
+ } else {
+ unsigned char *log;
+
+ log = malloc(cfg.log_len);
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log: %s\n",
+ strerror(errno));
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_get_log14(fd, cfg.namespace_id, cfg.log_id,
+ cfg.lsp, cfg.lpo, 0, cfg.rae,
+ cfg.uuid_index, cfg.log_len, log);
+ if (!err) {
+ if (!cfg.raw_binary) {
+ printf("Device:%s log-id:%d namespace-id:%#x\n",
+ devicename, cfg.log_id,
+ cfg.namespace_id);
+ d(log, cfg.log_len, 16, 1);
+ } else
+ d_raw((unsigned char *)log, cfg.log_len);
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("log page");
+ free(log);
+ }
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int sanitize_log(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Retrieve sanitize log and show it.";
+ const char *raw = "show log in binary format";
+ const char *human_readable = "show log in readable format";
+ struct nvme_sanitize_log_page sanitize_log;
+ enum nvme_print_flags flags;
+ int fd, err;
+
+ struct config {
+ int raw_binary;
+ int human_readable;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_sanitize_log(fd, &sanitize_log);
+ if (!err)
+ nvme_show_sanitize_log(&sanitize_log, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("sanitize status log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+ const char *namespace_id = "optional namespace attached to controller";
+ int err, i, fd;
+ struct nvme_controller_list *cntlist;
+
+ struct config {
+ __u16 cntid;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .cntid = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (posix_memalign((void *)&cntlist, getpagesize(), 0x1000)) {
+ fprintf(stderr, "can not allocate controller list payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ctrl_list(fd, cfg.namespace_id, cfg.cntid, cntlist);
+ if (!err) {
+ __u16 num = le16_to_cpu(cntlist->num);
+
+ for (i = 0; i < (min(num, 2048)); i++)
+ printf("[%4u]:%#x\n", i, le16_to_cpu(cntlist->identifier[i]));
+ }
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("id controller list");
+
+ free(cntlist);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 *all = "show all namespaces in the subsystem, whether attached or inactive";
+ int err, i, fd;
+ __le32 ns_list[1024];
+
+ struct config {
+ __u32 namespace_id;
+ int all;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FLAG("all", 'a', &cfg.all, all),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ err = -EINVAL;
+ fprintf(stderr, "invalid nsid parameter\n");
+ goto close_fd;
+ }
+
+ err = nvme_identify_ns_list(fd, cfg.namespace_id - 1, !!cfg.all,
+ ns_list);
+ if (!err) {
+ for (i = 0; i < 1024; i++)
+ if (ns_list[i])
+ printf("[%4u]:%#x\n", i, le32_to_cpu(ns_list[i]));
+ } else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("id namespace list");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+ const char *timeout = "timeout value, in milliseconds";
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 timeout;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .timeout = NVME_IOCTL_TIMEOUT,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id == 0) {
+ err = -EINVAL;
+ goto close_fd;
+ }
+ else if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_ns_delete(fd, cfg.namespace_id, cfg.timeout);
+ if (!err)
+ printf("%s: Success, deleted nsid:%d\n", cmd->name,
+ cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("delete namespace");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int nvme_attach_ns(int argc, char **argv, int attach, const char *desc, struct command *cmd)
+{
+ int err, num, i, fd, list[2048];
+ __u16 ctrlist[2048];
+
+ const char *namespace_id = "namespace to attach";
+ const char *cont = "optional comma-sep controller id list";
+
+ struct config {
+ char *cntlist;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .cntlist = "",
+ .namespace_id = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LIST("controllers", 'c', &cfg.cntlist, cont),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ fprintf(stderr, "%s: namespace-id parameter required\n",
+ cmd->name);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ 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) {
+ fprintf(stderr, "%s: controller id list is malformed\n",
+ cmd->name);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ for (i = 0; i < num; i++)
+ ctrlist[i] = (uint16_t)list[i];
+
+ err = nvme_ns_attachment(fd, cfg.namespace_id, num, ctrlist, attach);
+
+ if (!err)
+ printf("%s: Success, nsid:%d\n", cmd->name, cfg.namespace_id);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror(attach ? "attach namespace" : "detach namespace");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 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";
+ const char *ncap = "capacity of ns";
+ const char *flbas = "FLBA size";
+ const char *dps = "data protection capabilities";
+ const char *nmic = "multipath and sharing capabilities";
+ const char *anagrpid = "ANA Group Identifier";
+ const char *nvmsetid = "NVM Set Identifier";
+ const char *timeout = "timeout value, in milliseconds";
+ const char *bs = "target block size";
+
+ int err = 0, fd, i;
+ struct nvme_id_ns ns;
+ __u32 nsid;
+
+ struct config {
+ __u64 nsze;
+ __u64 ncap;
+ __u8 flbas;
+ __u8 dps;
+ __u8 nmic;
+ __u32 anagrpid;
+ __u16 nvmsetid;
+ __u64 bs;
+ __u32 timeout;
+ };
+
+ struct config cfg = {
+ .flbas = 0xff,
+ .anagrpid = 0,
+ .nvmsetid = 0,
+ .bs = 0x00,
+ .timeout = NVME_IOCTL_TIMEOUT,
+ };
+
+ OPT_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_SUFFIX("block-size", 'b', &cfg.bs, bs),
+ OPT_UINT("timeout", 't', &cfg.timeout, timeout),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.flbas != 0xff && cfg.bs != 0x00) {
+ fprintf(stderr,
+ "Invalid specification of both FLBAS and Block Size, please specify only one\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.bs) {
+ if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) {
+ fprintf(stderr,
+ "Invalid value for block size (%"PRIu64"). Block size must be a power of two\n",
+ (uint64_t)cfg.bs);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ err = nvme_identify_ns(fd, NVME_NSID_ALL, 0, &ns);
+ if (err) {
+ if (err < 0)
+ perror("identify-namespace");
+ else {
+ fprintf(stderr, "identify failed\n");
+ nvme_show_status(err);
+ }
+ goto close_fd;
+ }
+ for (i = 0; i < 16; ++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");
+
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_ns_create(fd, cfg.nsze, cfg.ncap, cfg.flbas, cfg.dps, cfg.nmic,
+ cfg.anagrpid, cfg.nvmsetid, cfg.timeout, &nsid);
+ if (!err)
+ printf("%s: Success, created nsid:%d\n", cmd->name, nsid);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("create namespace");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int list_subsys(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ struct nvme_topology t = { };
+ enum nvme_print_flags flags;
+ char *subsysnqn = NULL;
+ const char *desc = "Retrieve information for subsystems";
+ const char *verbose = "Increase output verbosity";
+ __u32 ns_instance = 0;
+ int err;
+
+ struct config {
+ char *output_format;
+ int verbose;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .verbose = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err < 0)
+ goto ret;
+
+ devicename = NULL;
+ if (optind < argc) {
+ char path[512];
+ int id;
+
+ devicename = basename(argv[optind]);
+ if (sscanf(devicename, "nvme%dn%d", &id, &ns_instance) != 2) {
+ fprintf(stderr, "%s is not a NVMe namespace device\n",
+ argv[optind]);
+ err = -EINVAL;
+ goto ret;
+ }
+ sprintf(path, "/sys/block/%s/device", devicename);
+ subsysnqn = get_nvme_subsnqn(path);
+ if (!subsysnqn) {
+ fprintf(stderr, "Cannot read subsys NQN from %s\n",
+ devicename);
+ err = -EINVAL;
+ goto ret;
+ }
+ optind++;
+ }
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto free;
+ if (flags != JSON && flags != NORMAL) {
+ err = -EINVAL;
+ goto free;
+ }
+ if (cfg.verbose)
+ flags |= VERBOSE;
+
+ err = scan_subsystems(&t, subsysnqn, ns_instance);
+ if (err) {
+ fprintf(stderr, "Failed to scan namespaces\n");
+ goto free;
+ }
+ nvme_show_subsystem_list(&t, flags);
+free:
+ free_topology(&t);
+ if (subsysnqn)
+ free(subsysnqn);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve basic information for all NVMe namespaces";
+ const char *verbose = "Increase output verbosity";
+ struct nvme_topology t = { };
+ enum nvme_print_flags flags;
+ int err = 0;
+
+ struct config {
+ char *output_format;
+ int verbose;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ .verbose = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format_no_binary),
+ OPT_FLAG("verbose", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ err = argconfig_parse(argc, argv, desc, opts);
+ if (err < 0)
+ return err;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ return err;
+ if (flags != JSON && flags != NORMAL) {
+ fprintf(stderr, "Invalid output format\n");
+ return -EINVAL;
+ }
+ if (cfg.verbose)
+ flags |= VERBOSE;
+
+ err = scan_subsystems(&t, NULL, 0);
+ if (err) {
+ fprintf(stderr, "Failed to scan namespaces\n");
+ return err;
+ }
+
+ nvme_show_list_items(&t, flags);
+ free_topology(&t);
+ return 0;
+}
+
+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";
+ const char *raw = "show identify in binary format";
+ const char *human_readable = "show identify in readable format";
+ enum nvme_print_flags flags;
+ struct nvme_id_ctrl ctrl;
+ int err, fd;
+
+ struct config {
+ int vendor_specific;
+ int raw_binary;
+ int human_readable;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific),
+ 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 = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.vendor_specific)
+ flags |= VS;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (!err)
+ __nvme_show_id_ctrl(&ctrl, flags, vs);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify controller");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ return __id_ctrl(argc, argv, cmd, plugin, NULL);
+}
+
+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";
+ const char *namespace_id = "identifier of desired namespace";
+ enum nvme_print_flags flags;
+ int err, fd;
+ void *nsdescs;
+
+ struct config {
+ __u32 namespace_id;
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .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("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ if (posix_memalign(&nsdescs, getpagesize(), 0x1000)) {
+ fprintf(stderr, "can not allocate controller list payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ns_descs(fd, 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
+ perror("identify namespace");
+ free(nsdescs);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an 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 attaced (1.2 devices only)";
+ const char *vendor_specific = "dump binary vendor fields";
+ const char *raw = "show identify in binary format";
+ const char *human_readable = "show identify in readable format";
+ const char *namespace_id = "identifier of desired namespace";
+
+ enum nvme_print_flags flags;
+ struct nvme_id_ns ns;
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ int vendor_specific;
+ int raw_binary;
+ int human_readable;
+ int force;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FLAG("force", 'f', &cfg.force, force),
+ OPT_FLAG("vendor-specific", 'v', &cfg.vendor_specific, vendor_specific),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.vendor_specific)
+ flags |= VS;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ else if (!cfg.namespace_id) {
+ fprintf(stderr,
+ "Error: requesting namespace-id from non-block device\n");
+ err = -ENOTBLK;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_identify_ns(fd, cfg.namespace_id, cfg.force, &ns);
+ if (!err)
+ nvme_show_id_ns(&ns, cfg.namespace_id, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify namespace");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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.";
+
+ struct nvme_id_ns_granularity_list *granularity_list;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (posix_memalign((void *)&granularity_list, getpagesize(), NVME_IDENTIFY_DATA_SIZE)) {
+ fprintf(stderr, "can not allocate granularity list payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_identify_ns_granularity(fd, granularity_list);
+ if (!err)
+ nvme_show_id_ns_granularity_list(granularity_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify namespace granularity");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+
+ struct nvme_id_nvmset nvmset;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u16 nvmset_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .nvmset_id = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("nvmset_id", 'i', &cfg.nvmset_id, nvmset_id),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ err = nvme_identify_nvmset(fd, cfg.nvmset_id, &nvmset);
+ if (!err)
+ nvme_show_id_nvmset(&nvmset, cfg.nvmset_id, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify nvm set list");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+
+ struct nvme_id_uuid_list uuid_list;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ int raw_binary;
+ int human_readable;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_identify_uuid(fd, &uuid_list);
+ if (!err)
+ nvme_show_id_uuid_list(&uuid_list, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("identify UUID list");
+close_fd:
+ close(fd);
+ return err;
+}
+
+static int get_ns_id(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0, nsid, fd;
+ const char *desc = "Get namespce ID of a the block device.";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ nsid = nvme_get_nsid(fd);
+ if (nsid <= 0) {
+ perror(devicename);
+ err = errno;
+ goto close_fd;
+ }
+ err = 0;
+ printf("%s: namespace-id:%d\n", devicename, nsid);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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)";
+ int fd, err;
+ __u32 result;
+
+ struct config {
+ int cntlid;
+ int rt;
+ int act;
+ __u32 cdw10;
+ __u32 cdw11;
+ };
+
+ struct config cfg = {
+ .cntlid = 0,
+ .rt = 0,
+ .act = 0,
+ .cdw10 = 0,
+ .cdw11 = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("cntlid", 'c', &cfg.cntlid, cntlid),
+ OPT_UINT("rt", 'r', &cfg.rt, rt),
+ OPT_UINT("act", 'a', &cfg.act, act),
+ OPT_UINT("nr", 'n', &cfg.cdw11, nr),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ cfg.cdw10 = cfg.cntlid << 16;
+ cfg.cdw10 = cfg.cdw10 | (cfg.rt << 8);
+ cfg.cdw10 = cfg.cdw10 | cfg.act;
+
+ err = nvme_virtual_mgmt(fd, cfg.cdw10, cfg.cdw11, &result);
+ if (!err) {
+ printf("success, Number of Resources allocated:%#x\n", result);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else
+ perror("virt-mgmt");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Show secondary controller list associated with the primary controller "\
+ "of the given device.";
+ const char *controller = "lowest controller identifier to display";
+ const char *namespace_id = "optional namespace attached to controller";
+ const char *num_entries = "number of entries to retrieve";
+
+ struct nvme_secondary_controllers_list *sc_list;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u16 cntid;
+ __u32 num_entries;
+ __u32 namespace_id;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .cntid = 0,
+ .namespace_id = 0,
+ .output_format = "normal",
+ .num_entries = ARRAY_SIZE(sc_list->sc_entry),
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SHRT("cntid", 'c', &cfg.cntid, controller),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("num-entries", 'e', &cfg.num_entries, num_entries),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (!cfg.num_entries) {
+ fprintf(stderr, "non-zero num-entries is required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (posix_memalign((void *)&sc_list, getpagesize(), sizeof(*sc_list))) {
+ fprintf(stderr, "can not allocate controller list payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_identify_secondary_ctrl_list(fd, cfg.namespace_id, 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
+ perror("id secondary controller list");
+
+ free(sc_list);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 : "\
+ "\n1h 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\n";
+ int fd, err;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 cdw10;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .cdw10 = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("self-test-code", 's', &cfg.cdw10, self_test_code),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = nvme_self_test_start(fd, cfg.namespace_id, cfg.cdw10);
+ if (!err) {
+ if ((cfg.cdw10 & 0xf) == 0xf)
+ printf("Aborting device self-test operation\n");
+ else
+ printf("Device self-test started\n");
+ } else if (err > 0) {
+ nvme_show_status(err);
+ } else
+ perror("Device self-test");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 *namespace_id = "Indicate the namespace from which the self-test "\
+ "log has to be obtained";
+ const char *verbose = "Increase output verbosity";
+
+ struct nvme_self_test_log self_test_log;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ char *output_format;
+ int verbose;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ .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("verbose", 'v', &cfg.verbose, verbose),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.verbose)
+ flags |= VERBOSE;
+
+ err = nvme_self_test_log(fd, cfg.namespace_id, &self_test_log);
+ if (!err)
+ nvme_show_self_test_log(&self_test_log, devicename, flags);
+ else if (err > 0)
+ nvme_show_status(err);
+ else
+ perror("self test log");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 "\
+ "behaviour of the feature. Each Feature has three possible "\
+ "settings: default, saveable, and current. If a Feature is "\
+ "saveable, it may be modified by set-feature. Default values "\
+ "are vendor-specific and not changeable. Use set-feature to "\
+ "change saveable Features.";
+ const char *raw = "show feature in binary format";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *feature_id = "feature identifier";
+ const char *sel = "[0-3]: current/default/saved/supported";
+ const char *data_len = "buffer len if data is returned through host memory buffer";
+ const char *cdw11 = "dword 11 for interrupt vector config";
+ const char *human_readable = "show feature in readable format";
+ int err, fd;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u8 sel;
+ __u32 cdw11;
+ __u32 data_len;
+ int raw_binary;
+ int human_readable;
+ };
+
+ 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 = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.sel > 7) {
+ fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ switch (cfg.feature_id) {
+ case NVME_FEAT_LBA_RANGE:
+ cfg.data_len = 4096;
+ break;
+ case NVME_FEAT_AUTO_PST:
+ cfg.data_len = 256;
+ break;
+ case NVME_FEAT_HOST_MEM_BUF:
+ cfg.data_len = 4096;
+ break;
+ case NVME_FEAT_HOST_ID:
+ cfg.data_len = 8;
+ /* check for Extended Host Identifier */
+ if (cfg.cdw11 & 0x1)
+ cfg.data_len = 16;
+ break;
+ case NVME_FEAT_PLM_CONFIG:
+ cfg.data_len = 512;
+ break;
+ case NVME_FEAT_TIMESTAMP:
+ cfg.data_len = 8;
+ break;
+ case NVME_FEAT_HOST_BEHAVIOR:
+ cfg.data_len = 512;
+ break;
+ }
+
+ if (cfg.sel == 3)
+ cfg.data_len = 0;
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
+ cfg.data_len, buf, &result);
+ if (!err) {
+ if (!cfg.raw_binary || !buf) {
+ printf("get-feature:%#02x (%s), %s value:%#08x\n", cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id),
+ nvme_select_to_string(cfg.sel), result);
+ if (cfg.sel == 3)
+ nvme_show_select_result(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) {
+ nvme_show_status(err);
+ } else
+ perror("get-feature");
+
+ if (buf)
+ free(buf);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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";
+ int err, fd, fw_fd = -1;
+ unsigned int fw_size;
+ struct stat sb;
+ void *fw_buf, *buf;
+ bool huge;
+
+ struct config {
+ char *fw;
+ __u32 xfer;
+ __u32 offset;
+ };
+
+ struct config cfg = {
+ .fw = "",
+ .xfer = 4096,
+ .offset = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FILE("fw", 'f', &cfg.fw, fw),
+ OPT_UINT("xfer", 'x', &cfg.xfer, xfer),
+ OPT_UINT("offset", 'o', &cfg.offset, offset),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ cfg.offset <<= 2;
+ if (fw_fd < 0) {
+ fprintf(stderr, "Failed to open firmware file %s: %s\n",
+ cfg.fw, strerror(errno));
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ goto close_fw_fd;
+ }
+
+ fw_size = sb.st_size;
+ if (fw_size & 0x3) {
+ fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
+ err = -EINVAL;
+ goto close_fw_fd;
+ }
+
+ fw_buf = nvme_alloc(fw_size, &huge);
+ if (!fw_buf) {
+ fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ err = -ENOMEM;
+ goto close_fw_fd;
+ }
+
+ buf = fw_buf;
+ if (cfg.xfer == 0 || cfg.xfer % 4096)
+ cfg.xfer = 4096;
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size))) {
+ err = -errno;
+ fprintf(stderr, "read :%s :%s\n", cfg.fw, strerror(errno));
+ goto free;
+ }
+
+ while (fw_size > 0) {
+ cfg.xfer = min(cfg.xfer, fw_size);
+
+ err = nvme_fw_download(fd, cfg.offset, cfg.xfer, fw_buf);
+ if (err < 0) {
+ perror("fw-download");
+ break;
+ } else if (err != 0) {
+ nvme_show_status(err);
+ break;
+ }
+ fw_buf += cfg.xfer;
+ fw_size -= cfg.xfer;
+ cfg.offset += cfg.xfer;
+ }
+ if (!err)
+ printf("Firmware download success\n");
+
+free:
+ nvme_free(buf, huge);
+close_fw_fd:
+ close(fw_fd);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static char *nvme_fw_status_reset_type(__u32 status)
+{
+ switch (status & 0x3ff) {
+ 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 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)";
+ int err, fd;
+
+ struct config {
+ __u8 slot;
+ __u8 action;
+ __u8 bpid;
+ };
+
+ struct config cfg = {
+ .slot = 0,
+ .action = 0,
+ .bpid = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("slot", 's', &cfg.slot, slot),
+ OPT_BYTE("action", 'a', &cfg.action, action),
+ OPT_BYTE("bpid", 'b', &cfg.bpid, bpid),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.slot > 7) {
+ fprintf(stderr, "invalid slot:%d\n", cfg.slot);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.action > 7 || cfg.action == 4 || cfg.action == 5) {
+ fprintf(stderr, "invalid action:%d\n", cfg.action);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.bpid > 1) {
+ fprintf(stderr, "invalid boot partition id:%d\n", cfg.bpid);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_fw_commit(fd, cfg.slot, cfg.action, cfg.bpid);
+ if (err < 0)
+ perror("fw-commit");
+ else if (err != 0)
+ switch (err & 0x3ff) {
+ 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(err));
+ break;
+ default:
+ nvme_show_status(err);
+ break;
+ }
+ 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");
+ }
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int subsystem_reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Resets the NVMe subsystem\n";
+ int err, fd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = nvme_subsystem_reset(fd);
+ if (err < 0) {
+ if (errno == ENOTTY)
+ fprintf(stderr,
+ "Subsystem-reset: NVM Subsystem Reset not supported.\n");
+ else
+ perror("Subsystem-reset");
+ }
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int reset(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Resets the NVMe controller\n";
+ int err, fd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = nvme_reset_controller(fd);
+ if (err < 0)
+ perror("Reset");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int ns_rescan(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Rescans the NVMe namespaces\n";
+ int err, fd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = nvme_ns_rescan(fd);
+ if (err < 0)
+ perror("Namespace Rescan");
+
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int sanitize(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.";
+ const char *ovrpat_desc = "Overwrite pattern.";
+
+ int fd, ret;
+
+ struct config {
+ int no_dealloc;
+ int oipbp;
+ __u8 owpass;
+ int ause;
+ __u8 sanact;
+ __u32 ovrpat;
+ };
+
+ struct config cfg = {
+ .no_dealloc = 0,
+ .oipbp = 0,
+ .owpass = 0,
+ .ause = 0,
+ .sanact = 0,
+ .ovrpat = 0,
+ };
+
+ OPT_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),
+ OPT_UINT("ovrpat", 'p', &cfg.ovrpat, ovrpat_desc),
+ OPT_END()
+ };
+
+ ret = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ switch (cfg.sanact) {
+ case NVME_SANITIZE_ACT_CRYPTO_ERASE:
+ case NVME_SANITIZE_ACT_BLOCK_ERASE:
+ case NVME_SANITIZE_ACT_EXIT:
+ case NVME_SANITIZE_ACT_OVERWRITE:
+ break;
+ default:
+ fprintf(stderr, "Invalid Sanitize Action\n");
+ ret = -EINVAL;
+ goto close_fd;
+ }
+
+ if (cfg.sanact == NVME_SANITIZE_ACT_EXIT) {
+ if (cfg.ause || cfg.no_dealloc) {
+ fprintf(stderr, "SANACT is Exit Failure Mode\n");
+ ret = -EINVAL;
+ goto close_fd;
+ }
+ }
+
+ if (cfg.sanact == NVME_SANITIZE_ACT_OVERWRITE) {
+ if (cfg.owpass > 16) {
+ fprintf(stderr, "OWPASS out of range [0-16]\n");
+ ret = -EINVAL;
+ goto close_fd;
+ }
+ } else {
+ if (cfg.owpass || cfg.oipbp || cfg.ovrpat) {
+ fprintf(stderr, "SANACT is not Overwrite\n");
+ ret = -EINVAL;
+ goto close_fd;
+ }
+ }
+
+ ret = nvme_sanitize(fd, cfg.sanact, cfg.ause, cfg.owpass, cfg.oipbp,
+ cfg.no_dealloc, cfg.ovrpat);
+ if (ret < 0)
+ perror("sanitize");
+ else if (ret > 0)
+ nvme_show_status(ret);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(ret, false);
+}
+
+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 "\
+ "in binary or human-readable format";
+ const char *human_readable = "show info in readable format in case of "\
+ "output_format == normal";
+
+ enum nvme_print_flags flags;
+ bool fabrics = true;
+ int fd, err;
+ void *bar;
+
+ struct config {
+ int human_readable;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .human_readable = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ err = nvme_get_properties(fd, &bar);
+ if (err) {
+ bar = mmap_registers(devicename);
+ fabrics = false;
+ if (bar)
+ err = 0;
+ }
+ if (!bar)
+ goto close_fd;
+
+ nvme_show_ctrl_registers(bar, fabrics, flags);
+ if (fabrics)
+ free(bar);
+ else
+ munmap(bar, getpagesize());
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 "\
+ "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";
+
+ int fd, err;
+ uint64_t value;
+
+ struct config {
+ int offset;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .offset = -1,
+ .human_readable = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("offset", 'o', &cfg.offset, offset),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.offset == -1) {
+ fprintf(stderr, "offset required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_get_property(fd, cfg.offset, &value);
+ if (err < 0) {
+ perror("get-property");
+ } else if (!err) {
+ nvme_show_single_property(cfg.offset, value, cfg.human_readable);
+ } else if (err > 0) {
+ nvme_show_status(err);
+ }
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 ove Fabric";
+ const char *offset = "the offset of the property";
+ const char *value = "the value of the property to be set";
+ int fd, err;
+
+ struct config {
+ int offset;
+ int value;
+ };
+
+ struct config cfg = {
+ .offset = -1,
+ .value = -1,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("offset", 'o', &cfg.offset, offset),
+ OPT_UINT("value", 'v', &cfg.value, value),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.offset == -1) {
+ fprintf(stderr, "offset required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.value == -1) {
+ fprintf(stderr, "value required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_set_property(fd, cfg.offset, cfg.value);
+ if (err < 0) {
+ perror("set-property");
+ } 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);
+ }
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int format(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Re-format a specified namespace on the "\
+ "given device. Can erase all data in namespace (user "\
+ "data erase) or delete data encryption key if specified. "\
+ "Can also be used to change LBAF to change the namespaces reported physical block format.";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *lbaf = "LBA format to apply (required)";
+ const char *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 *timeout = "timeout value, in milliseconds";
+ const char *bs = "target block size";
+ const char *force = "The \"I know what I'm doing\" flag, skip confirmation before sending command";
+ struct nvme_id_ns ns;
+ struct nvme_id_ctrl ctrl;
+ int err, fd, i;
+ __u8 prev_lbaf = 0;
+ __u8 lbads = 0;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 timeout;
+ __u8 lbaf;
+ __u8 ses;
+ __u8 pi;
+ __u8 pil;
+ __u8 ms;
+ __u64 bs;
+ int reset;
+ int force;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .timeout = 600000,
+ .lbaf = 0xff,
+ .ses = 0,
+ .pi = 0,
+ .reset = 0,
+ .force = 0,
+ .bs = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ 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", 'f', &cfg.force, force),
+ OPT_SUFFIX("block-size", 'b', &cfg.bs, bs),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.lbaf != 0xff && cfg.bs !=0) {
+ fprintf(stderr,
+ "Invalid specification of both LBAF and Block Size, please specify only one\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.bs) {
+ if ((cfg.bs & (~cfg.bs + 1)) != cfg.bs) {
+ fprintf(stderr,
+ "Invalid value for block size (%"PRIu64"), must be a power of two\n",
+ (uint64_t) cfg.bs);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err) {
+ perror("identify-ctrl");
+ goto close_fd;
+ }
+
+ 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) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+ }
+
+ if (cfg.namespace_id == 0) {
+ fprintf(stderr,
+ "Invalid namespace ID, "
+ "specify a namespace to format or use '-n 0xffffffff' "
+ "to format all namespaces on this controller.\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (cfg.namespace_id != NVME_NSID_ALL) {
+ err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns);
+ if (err) {
+ if (err < 0)
+ perror("identify-namespace");
+ else {
+ fprintf(stderr, "identify failed\n");
+ nvme_show_status(err);
+ }
+ goto close_fd;
+ }
+ prev_lbaf = ns.flbas & 0xf;
+
+ if (cfg.bs) {
+ for (i = 0; i < 16; ++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 block size %"PRIu64"(LBAF %u) not found\n",
+ (uint64_t)cfg.bs, lbads);
+ fprintf(stderr,
+ "Please correct block size, or specify LBAF directly\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ } 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) {
+ fprintf(stderr, "invalid secure erase settings:%d\n", cfg.ses);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.lbaf > 15) {
+ fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.pi > 7) {
+ fprintf(stderr, "invalid pi:%d\n", cfg.pi);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.pil > 1) {
+ fprintf(stderr, "invalid pil:%d\n", cfg.pil);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.ms > 1) {
+ fprintf(stderr, "invalid ms:%d\n", cfg.ms);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.force) {
+ fprintf(stderr, "You are about to format %s, namespace %#x%s.\n",
+ devicename, cfg.namespace_id,
+ cfg.namespace_id == NVME_NSID_ALL ? "(ALL namespaces)" : "");
+ nvme_show_relatives(devicename);
+ 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|-f] option to suppress this warning.\n");
+ sleep(10);
+ fprintf(stderr, "Sending format operation ... \n");
+ }
+
+ err = nvme_format(fd, cfg.namespace_id, cfg.lbaf, cfg.ses, cfg.pi,
+ cfg.pil, cfg.ms, cfg.timeout);
+ if (err < 0)
+ perror("format");
+ else if (err != 0)
+ nvme_show_status(err);
+ else {
+ printf("Success formatting namespace:%x\n", cfg.namespace_id);
+ if (cfg.lbaf != prev_lbaf && ioctl(fd, BLKRRPART) < 0) {
+ fprintf(stderr, "failed to re-read partition table\n");
+ err = -errno;
+ goto close_fd;
+ }
+
+ if (cfg.reset && S_ISCHR(nvme_stat.st_mode))
+ nvme_reset_controller(fd);
+ }
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 *namespace_id = "desired namespace";
+ const char *feature_id = "feature identifier (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 *cdw12 = "feature cdw12, if used";
+ const char *save = "specifies that the controller shall save the attribute";
+ int err;
+ __u32 result;
+ void *buf = NULL;
+ int fd, ffd = STDIN_FILENO;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ __u32 cdw12;
+ __u32 data_len;
+ int 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("cdw12", 'c', &cfg.cdw12, cdw12),
+ 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 = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
+ cfg.data_len = 4096;
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ fprintf(stderr, "can not allocate feature payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ if (buf) {
+ if (strlen(cfg.file)) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd <= 0) {
+ fprintf(stderr, "Failed to open file %s: %s\n",
+ cfg.file, strerror(errno));
+ err = -EINVAL;
+ goto free;
+ }
+ }
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read data buffer from input"
+ " file: %s\n", strerror(errno));
+ goto close_ffd;
+ }
+ }
+
+ err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
+ cfg.cdw12, cfg.save, cfg.data_len, buf, &result);
+ if (err < 0) {
+ perror("set-feature");
+ } else if (!err) {
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id), cfg.value);
+ if (buf) {
+ if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
+ nvme_show_lba_range((struct nvme_lba_range_type *)buf,
+ result);
+ else
+ d(buf, cfg.data_len, 16, 1);
+ }
+ } else if (err > 0)
+ nvme_show_status(err);
+
+close_ffd:
+ close(ffd);
+free:
+ if (buf)
+ free(buf);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 "\
+ "a controller. Security Receives for the same protocol should be "\
+ "performed after Security Sends. The security protocol field "\
+ "associates Security Sends (security-send) and Security Receives "\
+ "(security-recv).";
+ const char *file = "transfer payload";
+ const char *secp = "security protocol (cf. SPC-4)";
+ const char *spsp = "security-protocol-specific (cf. SPC-4)";
+ const char *tl = "transfer length (cf. SPC-4)";
+ const char *namespace_id = "desired namespace";
+ const char *nssf = "NVMe Security Specific Field";
+ int err, fd, sec_fd = -1;
+ void *sec_buf;
+ unsigned int sec_size;
+ __u32 result;
+
+ struct config {
+ __u32 namespace_id;
+ char *file;
+ __u8 nssf;
+ __u8 secp;
+ __u16 spsp;
+ __u32 tl;
+ };
+
+ struct config cfg = {
+ .file = "",
+ .secp = 0,
+ .spsp = 0,
+ .tl = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ 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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ sec_fd = open(cfg.file, O_RDONLY);
+ if (sec_fd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n",
+ cfg.file, strerror(errno));
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = fstat(sec_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ goto close_sec_fd;
+ }
+
+ sec_size = sb.st_size;
+ if (posix_memalign(&sec_buf, getpagesize(), sec_size)) {
+ fprintf(stderr, "No memory for security size:%d\n", sec_size);
+ err = -ENOMEM;
+ goto close_sec_fd;
+ }
+
+ err = read(sec_fd, sec_buf, sec_size);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "Failed to read data from security file"
+ " %s with %s\n", cfg.file, strerror(errno));
+ goto free;
+ }
+
+ err = nvme_sec_send(fd, cfg.namespace_id, cfg.nssf, cfg.spsp, cfg.secp,
+ cfg.tl, sec_size, sec_buf, &result);
+ if (err < 0)
+ perror("security-send");
+ else if (err != 0)
+ fprintf(stderr, "NVME Security Send Command Error:%d\n", err);
+ else
+ printf("NVME Security Send Command Success:%d\n", result);
+
+free:
+ free(sec_buf);
+close_sec_fd:
+ close(sec_fd);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 *raw = "show directive in binary format";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *data_len = "buffer len (if) data is returned";
+ const char *dtype = "directive type";
+ const char *dspec = "directive specification associated with directive type";
+ const char *doper = "directive operation";
+ const char *endir = "directive enable";
+ const char *ttype = "target directive type to be enabled/disabled";
+ const char *human_readable = "show directive in readable format";
+ int err, fd;
+ __u32 result;
+ __u32 dw12 = 0;
+ void *buf = NULL;
+ int ffd = STDIN_FILENO;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 data_len;
+ __u16 dspec;
+ __u8 dtype;
+ __u8 doper;
+ __u16 endir;
+ __u8 ttype;
+ int raw_binary;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .file = "",
+ .namespace_id = 1,
+ .data_len = 0,
+ .dspec = 0,
+ .dtype = 0,
+ .ttype = 0,
+ .doper = 0,
+ .endir = 1,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_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),
+ 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),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ switch (cfg.dtype) {
+ case NVME_DIR_IDENTIFY:
+ switch (cfg.doper) {
+ case NVME_DIR_SND_ID_OP_ENABLE:
+ if (!cfg.ttype) {
+ fprintf(stderr, "target-dir required param\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ dw12 = cfg.ttype << 8 | cfg.endir;
+ break;
+ default:
+ fprintf(stderr, "invalid directive operations for Identify Directives\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ break;
+ case NVME_DIR_STREAMS:
+ switch (cfg.doper) {
+ case NVME_DIR_SND_ST_OP_REL_ID:
+ case NVME_DIR_SND_ST_OP_REL_RSC:
+ break;
+ default:
+ fprintf(stderr, "invalid directive operations for Streams Directives\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ break;
+ default:
+ fprintf(stderr, "invalid directive type\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ if (buf) {
+ if (strlen(cfg.file)) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd <= 0) {
+ fprintf(stderr, "Failed to open file %s: %s\n",
+ cfg.file, strerror(errno));
+ err = -EINVAL;
+ goto free;
+ }
+ }
+ err = read(ffd, (void *)buf, cfg.data_len);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read data buffer from input"
+ " file %s\n", strerror(errno));
+ goto close_ffd;
+ }
+ }
+
+ err = nvme_dir_send(fd, cfg.namespace_id, cfg.dspec, cfg.dtype, cfg.doper,
+ cfg.data_len, dw12, buf, &result);
+ if (err < 0) {
+ perror("dir-send");
+ goto close_ffd;
+ }
+ 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);
+
+close_ffd:
+ close(ffd);
+free:
+ if (buf)
+ free(buf);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int write_uncor(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err, fd;
+ const char *desc = "The Write Uncorrectable command is used to set a "\
+ "range of logical blocks to invalid.";
+ const char *namespace_id = "desired namespace";
+ const char *start_block = "64-bit LBA of first block to access";
+ const char *block_count = "number of blocks (zeroes based) on device to access";
+
+ struct config {
+ __u64 start_block;
+ __u32 namespace_id;
+ __u16 block_count;
+ };
+
+ struct config cfg = {
+ .start_block = 0,
+ .namespace_id = 0,
+ .block_count = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_write_uncorrectable(fd, cfg.namespace_id, cfg.start_block,
+ cfg.block_count);
+ if (err < 0)
+ perror("write uncorrectable");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Write Uncorrectable Success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int write_zeroes(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err, fd;
+ __u16 control = 0;
+ const char *desc = "The Write Zeroes command is used to set a "\
+ "range of logical blocks to zero.";
+ const char *namespace_id = "desired namespace";
+ const char *start_block = "64-bit LBA of first block to access";
+ const char *block_count = "number of blocks (zeroes based) on device to access";
+ const char *limited_retry = "limit media access attempts";
+ const char *force = "force device to commit data before command completes";
+ const char *prinfo = "PI and check field";
+ const char *ref_tag = "reference tag (for end to end PI)";
+ const char *app_tag_mask = "app tag mask (for end to end PI)";
+ const char *app_tag = "app tag (for end to end PI)";
+ const char *deac = "Set DEAC bit, requesting controller to deallocate specified logical blocks";
+
+ struct config {
+ __u64 start_block;
+ __u32 namespace_id;
+ __u32 ref_tag;
+ __u16 app_tag;
+ __u16 app_tag_mask;
+ __u16 block_count;
+ __u8 prinfo;
+ int deac;
+ int limited_retry;
+ int force_unit_access;
+ };
+
+ struct config cfg = {
+ .start_block = 0,
+ .block_count = 0,
+ .prinfo = 0,
+ .ref_tag = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_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),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask),
+ OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.prinfo > 0xf) {
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_RW_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_RW_FUA;
+ if (cfg.deac)
+ control |= NVME_RW_DEAC;
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_write_zeros(fd, cfg.namespace_id, cfg.start_block, cfg.block_count,
+ control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask);
+ if (err < 0)
+ perror("write-zeroes");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Write Zeroes Success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 "\
+ "indicate attributes for ranges of logical blocks. This includes attributes "\
+ "for discarding unused blocks, data read and write frequency, access size, and other "\
+ "information that may be used to optimize performance and reliability.";
+ const char *namespace_id = "identifier of desired namespace";
+ 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";
+
+ int err, fd;
+ uint16_t nr, nc, nb, ns;
+ int ctx_attrs[256] = {0,};
+ int nlbs[256] = {0,};
+ unsigned long long slbas[256] = {0,};
+ struct nvme_dsm_range *dsm;
+
+ struct config {
+ char *ctx_attrs;
+ char *blocks;
+ char *slbas;
+ int ad;
+ int idw;
+ int idr;
+ __u32 cdw11;
+ __u32 namespace_id;
+ };
+
+ struct config cfg = {
+ .ctx_attrs = "",
+ .blocks = "",
+ .slbas = "",
+ .namespace_id = 0,
+ .ad = 0,
+ .idw = 0,
+ .idr = 0,
+ .cdw11 = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ 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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ nc = argconfig_parse_comma_sep_array(cfg.ctx_attrs, ctx_attrs, ARRAY_SIZE(ctx_attrs));
+ nb = argconfig_parse_comma_sep_array(cfg.blocks, nlbs, ARRAY_SIZE(nlbs));
+ ns = argconfig_parse_comma_sep_array_long(cfg.slbas, slbas, ARRAY_SIZE(slbas));
+ nr = max(nc, max(nb, ns));
+ if (!nr || nr > 256) {
+ fprintf(stderr, "No range definition provided\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+ if (!cfg.cdw11)
+ cfg.cdw11 = (cfg.ad << 2) | (cfg.idw << 1) | (cfg.idr << 0);
+
+ dsm = nvme_setup_dsm_range((__u32 *)ctx_attrs, (__u32 *)nlbs, (__u64 *)slbas, nr);
+ if (!dsm) {
+ fprintf(stderr, "failed to allocate data set payload\n");
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_dsm(fd, cfg.namespace_id, cfg.cdw11, dsm, nr);
+ if (err < 0)
+ perror("data-set management");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe DSM: success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int flush(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Commit data and metadata associated with "\
+ "given namespaces to nonvolatile media. Applies to all commands "\
+ "finished before the flush was submitted. Additional data may also be "\
+ "flushed by the controller, from any namespace, depending on controller and "\
+ "associated namespace status.";
+ const char *namespace_id = "identifier of desired namespace";
+ int err, fd;
+
+ 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()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_flush(fd, cfg.namespace_id);
+ if (err < 0)
+ perror("flush");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVMe Flush: success\n");
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int resv_acquire(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Obtain a reservation on a given "\
+ "namespace. Only one reservation is allowed at a time on a "\
+ "given namespace, though multiple controllers may register "\
+ "with that namespace. Namespace reservation will abort with "\
+ "status Reservation Conflict if the given namespace is "\
+ "already reserved.";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *crkey = "current reservation key";
+ const char *prkey = "pre-empt reservation key";
+ const char *rtype = "reservation type";
+ const char *racqa = "reservation acquiry action";
+ const char *iekey = "ignore existing res. key";
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 crkey;
+ __u64 prkey;
+ __u8 rtype;
+ __u8 racqa;
+ int iekey;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .crkey = 0,
+ .prkey = 0,
+ .rtype = 0,
+ .racqa = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LONG("crkey", 'c', &cfg.crkey, crkey),
+ OPT_LONG("prkey", 'p', &cfg.prkey, prkey),
+ OPT_BYTE("rtype", 't', &cfg.rtype, rtype),
+ OPT_BYTE("racqa", 'a', &cfg.racqa, racqa),
+ OPT_FLAG("iekey", 'i', &cfg.iekey, iekey),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+ if (cfg.racqa > 7) {
+ fprintf(stderr, "invalid racqa:%d\n", cfg.racqa);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_resv_acquire(fd, cfg.namespace_id, cfg.rtype, cfg.racqa,
+ !!cfg.iekey, cfg.crkey, cfg.prkey);
+ if (err < 0)
+ perror("reservation acquire");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation Acquire success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int resv_register(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Register, de-register, or "\
+ "replace a controller's reservation on a given namespace. "\
+ "Only one reservation at a time is allowed on any namespace.";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *crkey = "current reservation key";
+ const char *iekey = "ignore existing res. key";
+ const char *nrkey = "new reservation key";
+ const char *rrega = "reservation registration action";
+ const char *cptpl = "change persistence through power loss setting";
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u64 crkey;
+ __u64 nrkey;
+ __u8 rrega;
+ __u8 cptpl;
+ int iekey;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .crkey = 0,
+ .nrkey = 0,
+ .rrega = 0,
+ .cptpl = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LONG("crkey", 'c', &cfg.crkey, crkey),
+ OPT_LONG("nrkey", 'k', &cfg.nrkey, nrkey),
+ OPT_BYTE("rrega", 'r', &cfg.rrega, rrega),
+ OPT_BYTE("cptpl", 'p', &cfg.cptpl, cptpl),
+ OPT_FLAG("iekey", 'i', &cfg.iekey, iekey),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+ if (cfg.cptpl > 3) {
+ fprintf(stderr, "invalid cptpl:%d\n", cfg.cptpl);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (cfg.rrega > 7) {
+ fprintf(stderr, "invalid rrega:%d\n", cfg.rrega);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_resv_register(fd, cfg.namespace_id, cfg.rrega, cfg.cptpl,
+ !!cfg.iekey, cfg.crkey, cfg.nrkey);
+ if (err < 0)
+ perror("reservation register");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int resv_release(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Releases reservation held on a "\
+ "namespace by the given controller. If rtype != current reservation"\
+ "type, release will fails. If the given controller holds no "\
+ "reservation on the namespace or is not the namespace's current "\
+ "reservation holder, the release command completes with no "\
+ "effect. If the reservation type is not Write Exclusive or "\
+ "Exclusive Access, all registrants on the namespace except "\
+ "the issuing controller are notified.";
+ const char *namespace_id = "desired namespace";
+ const char *crkey = "current reservation key";
+ const char *iekey = "ignore existing res. key";
+ const char *rtype = "reservation type";
+ const char *rrela = "reservation release action";
+ int err, fd;
+
+ 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,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_LONG("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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+ if (cfg.rrela > 7) {
+ fprintf(stderr, "invalid rrela:%d\n", cfg.rrela);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ err = nvme_resv_release(fd, cfg.namespace_id, cfg.rtype, cfg.rrela,
+ !!cfg.iekey, cfg.crkey);
+ if (err < 0)
+ perror("reservation release");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Reservation Release success\n");
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int resv_report(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Returns Reservation Status data "\
+ "structure describing any existing reservations on and the "\
+ "status of a given namespace. Namespace Reservation Status "\
+ "depends on the number of controllers registered for that "\
+ "namespace.";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *numd = "number of dwords to transfer";
+ const char *cdw11 = "command dword 11 value";
+ const char *raw = "dump output in binary format";
+
+ struct nvme_reservation_status *status;
+ enum nvme_print_flags flags;
+ int err, fd, size;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 numd;
+ __u32 cdw11;
+ int raw_binary;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .numd = 0,
+ .cdw11 = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("numd", 'd', &cfg.numd, numd),
+ OPT_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ if (!cfg.numd || cfg.numd >= (0x1000 >> 2))
+ cfg.numd = (0x1000 >> 2) - 1;
+ if (cfg.numd < 3)
+ cfg.numd = 3;
+
+ size = (cfg.numd + 1) << 2;
+
+ if (posix_memalign((void **)&status, getpagesize(), size)) {
+ fprintf(stderr, "No memory for resv report:%d\n", size);
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ memset(status, 0, size);
+
+ err = nvme_resv_report(fd, cfg.namespace_id, cfg.numd, cfg.cdw11, status);
+ if (!err)
+ nvme_show_resv_report(status, size, cfg.cdw11, flags);
+ else if (err > 0)
+ fprintf(stderr, "NVME IO command error:%04x\n", err);
+ else
+ perror("reservation report");
+ free(status);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static 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, *mbuffer = NULL;
+ int err = 0;
+ int dfd, mfd, fd;
+ int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT;
+ int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
+ __u16 control = 0;
+ __u32 dsmgmt = 0;
+ int phys_sector_size = 0;
+ long long buffer_size = 0;
+ bool huge;
+
+ const char *start_block = "64-bit addr of first block to access";
+ const char *block_count = "number of blocks (zeroes based) on device to access";
+ const char *data_size = "size of data in bytes";
+ const char *metadata_size = "size of metadata in bytes";
+ const char *ref_tag = "reference tag (for end to end PI)";
+ const char *data = "data file";
+ const char *metadata = "metadata file";
+ const char *prinfo = "PI and check field";
+ const char *app_tag_mask = "app tag mask (for end to end PI)";
+ const char *app_tag = "app tag (for end to end PI)";
+ const char *limited_retry = "limit num. media access attempts";
+ const char *latency = "output latency statistics";
+ const char *force = "force device to commit data before command completes";
+ const char *show = "show command before sending";
+ const char *dry = "show command instead of sending";
+ const char *dtype = "directive type (for write-only)";
+ const char *dspec = "directive specific (for write-only)";
+ const char *dsm = "dataset management attributes (lower 16 bits)";
+
+ struct config {
+ __u64 start_block;
+ __u16 block_count;
+ __u64 data_size;
+ __u64 metadata_size;
+ __u32 ref_tag;
+ char *data;
+ char *metadata;
+ __u8 prinfo;
+ __u8 dtype;
+ __u16 dspec;
+ __u16 dsmgmt;
+ __u16 app_tag_mask;
+ __u16 app_tag;
+ int limited_retry;
+ int force_unit_access;
+ int show;
+ int dry_run;
+ int latency;
+ };
+
+ struct config cfg = {
+ .start_block = 0,
+ .block_count = 0,
+ .data_size = 0,
+ .metadata_size = 0,
+ .ref_tag = 0,
+ .data = "",
+ .metadata = "",
+ .prinfo = 0,
+ .app_tag_mask = 0,
+ .app_tag = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_SUFFIX("data-size", 'z', &cfg.data_size, data_size),
+ OPT_SUFFIX("metadata-size", 'y', &cfg.metadata_size, metadata_size),
+ OPT_UINT("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_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
+ OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force),
+ OPT_BYTE("dir-type", 'T', &cfg.dtype, dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec),
+ OPT_SHRT("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_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ dfd = mfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO;
+ if (cfg.prinfo > 0xf) {
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ dsmgmt = cfg.dsmgmt;
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_RW_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_RW_FUA;
+ if (cfg.dtype) {
+ if (cfg.dtype > 0xf) {
+ fprintf(stderr, "Invalid directive type, %x\n",
+ cfg.dtype);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ control |= cfg.dtype << 4;
+ dsmgmt |= ((__u32)cfg.dspec) << 16;
+ }
+
+ if (strlen(cfg.data)) {
+ dfd = open(cfg.data, flags, mode);
+ if (dfd < 0) {
+ perror(cfg.data);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ mfd = dfd;
+ }
+ if (strlen(cfg.metadata)) {
+ mfd = open(cfg.metadata, flags, mode);
+ if (mfd < 0) {
+ perror(cfg.metadata);
+ err = -EINVAL;
+ goto close_dfd;
+ }
+ }
+
+ if (!cfg.data_size) {
+ fprintf(stderr, "data size not provided\n");
+ err = -EINVAL;
+ goto close_mfd;
+ }
+
+ if (ioctl(fd, BLKPBSZGET, &phys_sector_size) < 0)
+ goto close_mfd;
+
+ buffer_size = (cfg.block_count + 1) * phys_sector_size;
+ if (cfg.data_size < buffer_size) {
+ fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n",
+ buffer_size);
+ } else {
+ buffer_size = cfg.data_size;
+ }
+
+ buffer = nvme_alloc(buffer_size, &huge);
+ if (!buffer) {
+ fprintf(stderr, "can not allocate io payload\n");
+ err = -ENOMEM;
+ goto close_mfd;
+ }
+
+ if (cfg.metadata_size) {
+ mbuffer = malloc(cfg.metadata_size);
+ if (!mbuffer) {
+ fprintf(stderr, "can not allocate io metadata "
+ "payload: %s\n", strerror(errno));
+ err = -ENOMEM;
+ goto free_buffer;
+ }
+ memset(mbuffer, 0, cfg.metadata_size);
+ }
+
+ if ((opcode & 1)) {
+ err = read(dfd, (void *)buffer, cfg.data_size);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read data buffer from input"
+ " file %s\n", strerror(errno));
+ goto free_mbuffer;
+ }
+ }
+
+ if ((opcode & 1) && cfg.metadata_size) {
+ err = read(mfd, (void *)mbuffer, cfg.metadata_size);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read meta-data buffer from"
+ " input file %s\n", strerror(errno));
+ goto free_mbuffer;
+ }
+ }
+
+ if (cfg.show) {
+ printf("opcode : %02x\n", opcode);
+ printf("flags : %02x\n", 0);
+ printf("control : %04x\n", control);
+ printf("nblocks : %04x\n", cfg.block_count);
+ printf("rsvd : %04x\n", 0);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer);
+ printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer);
+ printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block);
+ printf("dsmgmt : %08x\n", dsmgmt);
+ printf("reftag : %08x\n", cfg.ref_tag);
+ printf("apptag : %04x\n", cfg.app_tag);
+ printf("appmask : %04x\n", cfg.app_tag_mask);
+ }
+ if (cfg.dry_run)
+ goto free_mbuffer;
+
+ gettimeofday(&start_time, NULL);
+ err = nvme_io(fd, opcode, cfg.start_block, cfg.block_count, control, dsmgmt,
+ cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask, buffer, mbuffer);
+ gettimeofday(&end_time, NULL);
+ if (cfg.latency)
+ printf(" latency: %s: %llu us\n",
+ command, elapsed_utime(start_time, end_time));
+ if (err < 0)
+ perror("submit-io");
+ else if (err)
+ nvme_show_status(err);
+ else {
+ if (!(opcode & 1) && write(dfd, (void *)buffer, cfg.data_size) < 0) {
+ fprintf(stderr, "write: %s: failed to write buffer to output file\n",
+ strerror(errno));
+ err = -EINVAL;
+ } else if (!(opcode & 1) && cfg.metadata_size &&
+ write(mfd, (void *)mbuffer, cfg.metadata_size) < 0) {
+ fprintf(stderr, "write: %s: failed to write meta-data buffer to output file\n",
+ strerror(errno));
+ err = -EINVAL;
+ } else
+ fprintf(stderr, "%s: Success\n", command);
+ }
+
+free_mbuffer:
+ if (cfg.metadata_size)
+ free(mbuffer);
+free_buffer:
+ nvme_free(buffer, huge);
+close_mfd:
+ if (strlen(cfg.metadata))
+ close(mfd);
+close_dfd:
+ close(dfd);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int compare(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Compare specified logical blocks on "\
+ "device with specified data buffer; return failure if buffer "\
+ "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 "\
+ "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 "\
+ "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)
+{
+ int err, fd;
+ __u16 control = 0;
+ const char *desc = "Verify specified logical blocks on the given device.";
+ const char *namespace_id = "desired namespace";
+ const char *start_block = "64-bit LBA of first block to access";
+ const char *block_count = "number of blocks (zeroes based) on device to access";
+ const char *limited_retry = "limit media access attempts";
+ const char *force = "force device to commit cached data before performing the verify operation";
+ const char *prinfo = "PI and check field";
+ const char *ref_tag = "reference tag (for end to end PI)";
+ const char *app_tag_mask = "app tag mask (for end to end PI)";
+ const char *app_tag = "app tag (for end to end PI)";
+
+ struct config {
+ __u64 start_block;
+ __u32 namespace_id;
+ __u32 ref_tag;
+ __u16 app_tag;
+ __u16 app_tag_mask;
+ __u16 block_count;
+ __u8 prinfo;
+ int limited_retry;
+ int force_unit_access;
+ };
+
+ struct config cfg = {
+ .namespace_id = 0,
+ .start_block = 0,
+ .block_count = 0,
+ .prinfo = 0,
+ .ref_tag = 0,
+ .app_tag = 0,
+ .app_tag_mask = 0,
+ .limited_retry = 0,
+ .force_unit_access = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_SUFFIX("start-block", 's', &cfg.start_block, start_block),
+ OPT_SHRT("block-count", 'c', &cfg.block_count, block_count),
+ OPT_FLAG("limited-retry", 'l', &cfg.limited_retry, limited_retry),
+ OPT_FLAG("force-unit-access", 'f', &cfg.force_unit_access, force),
+ OPT_BYTE("prinfo", 'p', &cfg.prinfo, prinfo),
+ OPT_UINT("ref-tag", 'r', &cfg.ref_tag, ref_tag),
+ OPT_SHRT("app-tag", 'a', &cfg.app_tag, app_tag),
+ OPT_SHRT("app-tag-mask", 'm', &cfg.app_tag_mask, app_tag_mask),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto err;
+
+ if (cfg.prinfo > 0xf) {
+ err = EINVAL;
+ goto close_fd;
+ }
+
+ control |= (cfg.prinfo << 10);
+ if (cfg.limited_retry)
+ control |= NVME_RW_LR;
+ if (cfg.force_unit_access)
+ control |= NVME_RW_FUA;
+
+ if (!cfg.namespace_id) {
+ cfg.namespace_id = nvme_get_nsid(fd);
+ if (cfg.namespace_id < 0) {
+ err = cfg.namespace_id;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_verify(fd, cfg.namespace_id, cfg.start_block, cfg.block_count,
+ control, cfg.ref_tag, cfg.app_tag, cfg.app_tag_mask);
+ if (err < 0)
+ perror("verify");
+ else if (err != 0)
+ nvme_show_status(err);
+ else
+ printf("NVME Verify Success\n");
+
+close_fd:
+ close(fd);
+err:
+ 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 "\
+ "previously submitted security-sends. Results, and association "\
+ "between Security Send and Receive, depend on the security "\
+ "protocol field as they are defined by the security protocol "\
+ "used. A Security Receive must follow a Security Send made with "\
+ "the same security protocol.";
+ const char *size = "size of buffer (prints to stdout on success)";
+ const char *secp = "security protocol (cf. SPC-4)";
+ const char *spsp = "security-protocol-specific (cf. SPC-4)";
+ const char *al = "allocation length (cf. SPC-4)";
+ const char *raw = "dump output in binary format";
+ const char *namespace_id = "desired namespace";
+ const char *nssf = "NVMe Security Specific Field";
+ int err, fd;
+ void *sec_buf = NULL;
+ __u32 result;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 size;
+ __u8 secp;
+ __u8 nssf;
+ __u16 spsp;
+ __u32 al;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .size = 0,
+ .secp = 0,
+ .spsp = 0,
+ .al = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ 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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.size) {
+ if (posix_memalign(&sec_buf, getpagesize(), cfg.size)) {
+ fprintf(stderr, "No memory for security size:%d\n",
+ cfg.size);
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ }
+
+ err = nvme_sec_recv(fd, cfg.namespace_id, cfg.nssf, cfg.spsp,
+ cfg.secp, cfg.al, cfg.size, sec_buf, &result);
+ if (err < 0)
+ perror("security receive");
+ else if (err != 0)
+ fprintf(stderr, "NVME Security Receive Command Error:%d\n",
+ err);
+ else {
+ if (!cfg.raw_binary) {
+ printf("NVME Security Receive Command Success:%d\n",
+ result);
+ d(sec_buf, cfg.size, 16, 1);
+ } else if (cfg.size)
+ d_raw((unsigned char *)sec_buf, cfg.size);
+ }
+
+ free(sec_buf);
+
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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 the"\
+ " 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";
+
+ enum nvme_print_flags flags;
+ unsigned long buf_len;
+ int err, fd;
+ void *buf;
+
+ struct config {
+ __u64 slba;
+ __u32 mndw;
+ __u8 atype;
+ __u16 rl;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .slba = 0,
+ .mndw = 0,
+ .atype = 0,
+ .rl = 0,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ 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_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto err;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (!cfg.atype) {
+ fprintf(stderr, "action type (--action) has to be given\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ buf_len = (cfg.mndw + 1) * 4;
+ buf = calloc(1, buf_len);
+ if (!buf) {
+ err = -ENOMEM;
+ goto close_fd;
+ }
+
+ err = nvme_get_lba_status(fd, cfg.slba, cfg.mndw, cfg.atype, cfg.rl,
+ buf);
+ if (!err)
+ nvme_show_lba_status(buf, buf_len, flags);
+ else if (err > 0)
+ fprintf(stderr, "NVME command error:%04x\n", err);
+ else
+ perror("get lba status");
+ free(buf);
+close_fd:
+ close(fd);
+err:
+ return nvme_status_to_errno(err, false);
+}
+
+static int dir_receive(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Read directive parameters of the "\
+ "specified directive type.";
+ const char *raw = "show directive in binary format";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *data_len = "buffer len (if) data is returned";
+ const char *dtype = "directive type";
+ const char *dspec = "directive specification associated with directive type";
+ const char *doper = "directive operation";
+ const char *nsr = "namespace stream requested";
+ const char *human_readable = "show directive in readable format";
+
+ enum nvme_print_flags flags = NORMAL;
+ int err, fd;
+ __u32 result;
+ __u32 dw12 = 0;
+ void *buf = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 data_len;
+ __u16 dspec;
+ __u8 dtype;
+ __u8 doper;
+ __u16 nsr; /* dw12 for NVME_DIR_ST_RCVOP_STATUS */
+ int raw_binary;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .data_len = 0,
+ .dspec = 0,
+ .dtype = 0,
+ .doper = 0,
+ .nsr = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_UINT("data-len", 'l', &cfg.data_len, data_len),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_BYTE("dir-type", 'D', &cfg.dtype, dtype),
+ OPT_SHRT("dir-spec", 'S', &cfg.dspec, dspec),
+ 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),
+ OPT_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ switch (cfg.dtype) {
+ case NVME_DIR_IDENTIFY:
+ switch (cfg.doper) {
+ case NVME_DIR_RCV_ID_OP_PARAM:
+ if (!cfg.data_len)
+ cfg.data_len = 4096;
+ break;
+ default:
+ fprintf(stderr, "invalid directive operations for Identify Directives\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ break;
+ case NVME_DIR_STREAMS:
+ switch (cfg.doper) {
+ case NVME_DIR_RCV_ST_OP_PARAM:
+ if (!cfg.data_len)
+ cfg.data_len = 32;
+ break;
+ case NVME_DIR_RCV_ST_OP_STATUS:
+ if (!cfg.data_len)
+ cfg.data_len = 128 * 1024;
+ break;
+ case NVME_DIR_RCV_ST_OP_RESOURCE:
+ dw12 = cfg.nsr;
+ break;
+ default:
+ fprintf(stderr, "invalid directive operations for Streams Directives\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+ break;
+ default:
+ fprintf(stderr, "invalid directive type\n");
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)) {
+ err = -ENOMEM;
+ goto close_fd;
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ err = nvme_dir_recv(fd, cfg.namespace_id, cfg.dspec, cfg.dtype, cfg.doper,
+ cfg.data_len, dw12, buf, &result);
+ 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)
+ perror("dir-receive");
+
+ if (cfg.data_len)
+ free(buf);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+static int passthru(int argc, char **argv, int ioctl_cmd, const char *desc, struct command *cmd)
+{
+ void *data = NULL, *metadata = NULL;
+ int err = 0, wfd = STDIN_FILENO, fd;
+ __u32 result;
+ bool huge;
+
+ struct 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;
+ int raw_binary;
+ int show_command;
+ int dry_run;
+ int read;
+ int write;
+ __u8 prefill;
+ };
+
+ struct config cfg = {
+ .opcode = 0,
+ .flags = 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 = "",
+ .prefill = 0,
+ };
+
+ const char *opcode = "opcode (required)";
+ const char *flags = "command flags";
+ const char *rsvd = "value for reserved field";
+ const char *namespace_id = "desired namespace";
+ const char *data_len = "data I/O length (bytes)";
+ const char *metadata_len = "metadata seg. length (bytes)";
+ const char *timeout = "timeout value, in milliseconds";
+ const char *cdw2 = "command dword 2 value";
+ const char *cdw3 = "command dword 3 value";
+ const char *cdw10 = "command dword 10 value";
+ const char *cdw11 = "command dword 11 value";
+ const char *cdw12 = "command dword 12 value";
+ const char *cdw13 = "command dword 13 value";
+ const char *cdw14 = "command dword 14 value";
+ const char *cdw15 = "command dword 15 value";
+ const char *input = "write/send file (default stdin)";
+ const char *raw_binary = "dump output in binary format";
+ const char *show = "print command before sending";
+ const char *dry = "show command instead of sending";
+ const char *re = "set dataflow direction to receive";
+ const char *wr = "set dataflow direction to send";
+ const char *prefill = "prefill buffers with known byte-value, default 0";
+
+ OPT_ARGS(opts) = {
+ OPT_BYTE("opcode", 'o', &cfg.opcode, opcode),
+ OPT_BYTE("flags", 'f', &cfg.flags, flags),
+ OPT_BYTE("prefill", 'p', &cfg.prefill, prefill),
+ OPT_SHRT("rsvd", 'R', &cfg.rsvd, rsvd),
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ 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_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary),
+ 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_END()
+ };
+
+ err = fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ goto ret;
+
+ if (strlen(cfg.input_file)){
+ wfd = open(cfg.input_file, O_RDONLY,
+ S_IRUSR | S_IRGRP | S_IROTH);
+ if (wfd < 0) {
+ perror(cfg.input_file);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ }
+
+ if (cfg.metadata_len) {
+ metadata = malloc(cfg.metadata_len);
+ if (!metadata) {
+ fprintf(stderr, "can not allocate metadata "
+ "payload: %s\n", strerror(errno));
+ err = -ENOMEM;
+ goto close_wfd;
+ }
+ memset(metadata, cfg.prefill, cfg.metadata_len);
+ }
+ if (cfg.data_len) {
+ data = nvme_alloc(cfg.data_len, &huge);
+ if (!data) {
+ fprintf(stderr, "can not allocate data payload\n");
+ err = -ENOMEM;
+ goto free_metadata;
+ }
+
+ if (cfg.write && !(cfg.opcode & 0x01)) {
+ fprintf(stderr, "warning: write flag set but write direction bit is not set in the opcode\n");
+ }
+
+ if (cfg.read && !(cfg.opcode & 0x02)) {
+ fprintf(stderr, "warning: read flag set but read direction bit is not set in the opcode\n");
+ }
+
+ memset(data, cfg.prefill, cfg.data_len);
+ if (!cfg.read && !cfg.write) {
+ fprintf(stderr, "data direction not given\n");
+ err = -EINVAL;
+ goto free_data;
+ } else if (cfg.write) {
+ if (read(wfd, data, cfg.data_len) < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to read write buffer "
+ "%s\n", strerror(errno));
+ goto free_data;
+ }
+ }
+ }
+
+ if (cfg.show_command) {
+ 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)metadata);
+ 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)
+ goto free_data;
+
+ err = nvme_passthru(fd, ioctl_cmd, cfg.opcode, cfg.flags, cfg.rsvd,
+ cfg.namespace_id, cfg.cdw2, cfg.cdw3, cfg.cdw10,
+ cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, cfg.cdw15,
+ cfg.data_len, data, cfg.metadata_len, metadata,
+ cfg.timeout, &result);
+ if (err < 0)
+ perror("passthru");
+ else if (err)
+ nvme_show_status(err);
+ else {
+ if (!cfg.raw_binary) {
+ fprintf(stderr, "NVMe command result:%08x\n", result);
+ if (data && cfg.read && !err)
+ d((unsigned char *)data, cfg.data_len, 16, 1);
+ } else if (data && cfg.read)
+ d_raw((unsigned char *)data, cfg.data_len);
+ }
+free_data:
+ if (cfg.data_len)
+ nvme_free(data, huge);
+free_metadata:
+ if (cfg.metadata_len)
+ free(metadata);
+close_wfd:
+ if (strlen(cfg.input_file))
+ close(wfd);
+close_fd:
+ close(fd);
+ret:
+ return nvme_status_to_errno(err, false);
+}
+
+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, NVME_IOCTL_IO_CMD, desc, cmd);
+}
+
+static int admin_passthru(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send a user-defined Admin command to the specified "\
+ "device via IOCTL passthrough, return results.";
+ return passthru(argc, argv, NVME_IOCTL_ADMIN_CMD, desc, cmd);
+}
+
+#ifdef LIBUUID
+static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ uuid_t uuid;
+ char uuid_str[37]; /* e.g. 1b4e28ba-2fa1-11d2-883f-0016d3cca427 + \0 */
+
+ uuid_generate_random(uuid);
+ uuid_unparse_lower(uuid, uuid_str);
+ printf("nqn.2014-08.org.nvmexpress:uuid:%s\n", uuid_str);
+ return 0;
+}
+#else
+static int gen_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ fprintf(stderr, "\"%s\" not supported. Install lib uuid and rebuild.\n",
+ command->name);
+ return -ENOTSUP;
+}
+#endif
+
+static int show_hostnqn_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ char *hostnqn;
+
+ hostnqn = hostnqn_read();
+ if (hostnqn) {
+ fputs(hostnqn, stdout);
+ free(hostnqn);
+ return 0;
+ } else {
+ fprintf(stderr, "hostnqn is not available -- use nvme gen-hostnqn\n");
+ return -ENOENT;
+ }
+}
+
+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 fabrics_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 fabrics_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 fabrics_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 fabrics_disconnect(desc, argc, argv);
+}
+
+static int disconnect_all_cmd(int argc, char **argv, struct command *command, struct plugin *plugin)
+{
+ const char *desc = "Disconnect from all connected NVMeoF subsystems";
+ return fabrics_disconnect_all(desc, argc, argv);
+}
+
+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;
+}
diff --git a/nvme.control.in b/nvme.control.in
new file mode 100644
index 0000000..46714d4
--- /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..017148a
--- /dev/null
+++ b/nvme.h
@@ -0,0 +1,110 @@
+/*
+ * 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 <endian.h>
+
+#include "plugin.h"
+#include "util/json.h"
+#include "util/argconfig.h"
+#include "linux/nvme.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 */
+};
+
+struct nvme_subsystem;
+struct nvme_ctrl;
+
+struct nvme_namespace {
+ char *name;
+ struct nvme_ctrl *ctrl;
+
+ unsigned nsid;
+ struct nvme_id_ns ns;
+};
+
+struct nvme_ctrl {
+ char *name;
+ struct nvme_subsystem *subsys;
+
+ char *address;
+ char *transport;
+ char *state;
+ char *ana_state;
+ char *traddr;
+ char *trsvcid;
+ char *host_traddr;
+ char *hostnqn;
+ char *hostid;
+
+ struct nvme_id_ctrl id;
+
+ int nr_namespaces;
+ struct nvme_namespace *namespaces;
+};
+
+struct nvme_subsystem {
+ char *name;
+ char *subsysnqn;
+
+ int nr_ctrls;
+ struct nvme_ctrl *ctrls;
+
+ int nr_namespaces;
+ struct nvme_namespace *namespaces;
+};
+
+struct nvme_topology {
+ int nr_subsystems;
+ struct nvme_subsystem *subsystems;
+};
+
+#define SYS_NVME "/sys/class/nvme"
+
+void register_extension(struct plugin *plugin);
+int parse_and_open(int argc, char **argv, const char *desc,
+ const struct argconfig_commandline_options *clo);
+
+extern const char *devicename;
+
+enum nvme_print_flags validate_output_format(char *format);
+int __id_ctrl(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin, void (*vs)(__u8 *vs, struct json_object *root));
+char *nvme_char_from_block(char *block);
+void *mmap_registers(const char *dev);
+
+extern int current_index;
+int scan_namespace_filter(const struct dirent *d);
+int scan_ctrl_paths_filter(const struct dirent *d);
+int scan_ctrls_filter(const struct dirent *d);
+int scan_subsys_filter(const struct dirent *d);
+int scan_dev_filter(const struct dirent *d);
+
+int scan_subsystems(struct nvme_topology *t, const char *subsysnqn,
+ __u32 ns_instance);
+void free_topology(struct nvme_topology *t);
+char *get_nvme_subsnqn(char *path);
+char *nvme_get_ctrl_attr(char *path, const char *attr);
+
+#endif /* _NVME_H */
diff --git a/nvme.spec.in b/nvme.spec.in
new file mode 100644
index 0000000..74e681e
--- /dev/null
+++ b/nvme.spec.in
@@ -0,0 +1,71 @@
+Name: nvme
+Version: @@VERSION@@
+Release: 1%{?dist}
+Summary: Core nvme tools
+License: GPL
+Group: Development/Tools
+URL: https://github.com/linux-nvme/nvme-cli/
+Source: nvme-@@VERSION@@.tar.gz
+Provides: nvme
+Requires(post): util-linux
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+NVMe is a fast, scalable, direct attached storage interface. The nvme
+cli rpm installs core management tools with minimal dependencies.
+
+%prep
+%setup
+
+%build
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install-spec DESTDIR=%{buildroot} PREFIX=/usr
+
+%files
+%defattr(-,root,root)
+%doc Documentation/nvme*.1
+%{_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
+%{_sysconfdir}/udev/rules.d/70-nvmf-autoconnect.rules
+%{_sysconfdir}/udev/rules.d/71-nvmf-iopolicy-netapp.rules
+%{_libdir}/dracut/dracut.conf.d/70-nvmf-autoconnect.conf
+%{_libdir}/systemd/system/nvmf-connect@.service
+%{_libdir}/systemd/system/nvmefc-boot-connections.service
+%{_libdir}/systemd/system/nvmf-connect.target
+%{_libdir}/systemd/system/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 $(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..41ea83c
--- /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 b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service
new file mode 100644
index 0000000..33ab8c1
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmefc-boot-connections.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Auto-connect to subsystems on FC-NVME devices found during boot
+ConditionPathExists=/sys/class/fc/fc_udev_device/nvme_discovery
+
+[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 b/nvmf-autoconnect/systemd/nvmf-autoconnect.service
new file mode 100644
index 0000000..2690467
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-autoconnect.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Connect NVMe-oF subsystems automatically during boot
+ConditionPathExists=/etc/nvme/discovery.conf
+After=network.target
+Before=remote-fs-pre.target
+
+[Service]
+Type=oneshot
+ExecStart=/usr/sbin/nvme connect-all
+
+[Install]
+WantedBy=default.target
diff --git a/nvmf-autoconnect/systemd/nvmf-connect.target b/nvmf-autoconnect/systemd/nvmf-connect.target
new file mode 100644
index 0000000..f64a37c
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-connect.target
@@ -0,0 +1,2 @@
+[Unit]
+Description=All instances of nvmf-autoconnect daemon
diff --git a/nvmf-autoconnect/systemd/nvmf-connect@.service b/nvmf-autoconnect/systemd/nvmf-connect@.service
new file mode 100644
index 0000000..5fbf081
--- /dev/null
+++ b/nvmf-autoconnect/systemd/nvmf-connect@.service
@@ -0,0 +1,14 @@
+#
+# Unit file used by 70-nvmf-autoconnect.rules.
+#
+
+[Unit]
+Description=NVMf auto-connect scan upon nvme discovery controller Events
+After=syslog.target
+PartOf=nvmf-connect.target
+Requires=nvmf-connect.target
+
+[Service]
+Type=simple
+Environment="CONNECT_ARGS=%i"
+ExecStart=/bin/sh -c "nvme connect-all --matching --quiet `/bin/echo -e '${CONNECT_ARGS}'`"
diff --git a/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules
new file mode 100644
index 0000000..cbbebc5
--- /dev/null
+++ b/nvmf-autoconnect/udev-rules/70-nvmf-autoconnect.rules
@@ -0,0 +1,19 @@
+#
+# nvmf-autoconnect.rules:
+# Handles udev events which invoke automatically scan via discovery
+# controller and connect to elements in the discovery log.
+#
+#
+
+# 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}=="*", \
+ RUN+="/bin/systemctl --no-block start 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}.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+="/bin/systemctl --no-block start nvmf-connect@--device=none\t--transport=fc\t--traddr=$env{NVMEFC_TRADDR}\t--trsvcid=none\t--host-traddr=$env{NVMEFC_HOST_TRADDR}.service"
diff --git a/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules b/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules
new file mode 100644
index 0000000..aefd9d4
--- /dev/null
+++ b/nvmf-autoconnect/udev-rules/71-nvmf-iopolicy-netapp.rules
@@ -0,0 +1,3 @@
+# Enable round-robin for NetApp ONTAP and NetApp E-Series
+ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{model}=="NetApp ONTAP Controller", ATTR{iopolicy}="round-robin"
+ACTION=="add", SUBSYSTEM=="nvme-subsystem", ATTR{model}=="NetApp E-Series", ATTR{iopolicy}="round-robin"
diff --git a/plugin.c b/plugin.c
new file mode 100644
index 0000000..c7d6b2e
--- /dev/null
+++ b/plugin.c
@@ -0,0 +1,188 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "plugin.h"
+#include "util/argconfig.h"
+
+static int version(struct plugin *plugin)
+{
+ struct program *prog = plugin->parent;
+
+ if (plugin->name)
+ printf("%s %s version %s\n", prog->name, plugin->name, prog->version);
+ else
+ printf("%s version %s\n", prog->name, prog->version);
+ 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;
+}
+
+void usage(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 i = 0;
+ unsigned padding = 15;
+ unsigned curr_length = 0;
+ printf("%s-%s\n", prog->name, prog->version);
+
+ usage(plugin);
+
+ printf("\n");
+ print_word_wrapped(prog->desc, 0, 0);
+ printf("\n");
+
+ if (plugin->desc) {
+ printf("\n");
+ print_word_wrapped(plugin->desc, 0, 0);
+ 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++)
+ if (padding < (curr_length = 2 + strlen(plugin->commands[i]->name)))
+ 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)
+{
+ unsigned i = 0;
+ char *str = argv[0];
+ char use[0x100];
+
+ struct plugin *extension;
+ struct program *prog = plugin->parent;
+
+ 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(plugin);
+
+ for (; 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;
+
+ return (cmd->fn(argc, argv, cmd, 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..91079fb
--- /dev/null
+++ b/plugin.h
@@ -0,0 +1,36 @@
+#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;
+ 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 usage(struct plugin *plugin);
+void general_help(struct plugin *plugin);
+int handle_plugin(int argc, char **argv, struct plugin *plugin);
+
+#endif
diff --git a/plugins/dera/dera-nvme.c b/plugins/dera/dera-nvme.c
new file mode 100644
index 0000000..dbb40cc
--- /dev/null
+++ b/plugins/dera/dera-nvme.c
@@ -0,0 +1,211 @@
+#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 "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.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_passthru(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+ if (!err && result) {
+ *result = cmd.result;
+ }
+
+ return err;
+}
+
+static int get_status(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int fd, err;
+ struct nvme_dera_smart_info_log log;
+ enum dera_device_status state = DEVICE_STATUS_FATAL_ERROR;
+ char *desc = "Get the Dera device status";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, 0xffffffff, 0xc0, false, sizeof(log), &log);
+ if (err) {
+ goto exit;
+ }
+
+ const char* dev_status[] = {
+ "Normal",
+ "Quick Rebuilding",
+ "Full Rebuilding",
+ "Raw Rebuilding",
+ "Card Read Only",
+ "Fatal Error",
+ "Busy",
+ "Low Level Format",
+ "Firmware Committing",
+ "Over Temperature" };
+
+ const char *volt_status[] = {
+ "Normal",
+ "Initial Low",
+ "Runtime Low",
+ };
+
+ err = nvme_dera_get_device_status(fd, &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 >= 0 && 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)
+ fprintf(stderr, "\nNVMe status:%s(0x%x)\n", nvme_status_to_string(err), err);
+
+ return err;
+}
+
diff --git a/plugins/dera/dera-nvme.h b/plugins/dera/dera-nvme.h
new file mode 100644
index 0000000..dc54fab
--- /dev/null
+++ b/plugins/dera/dera-nvme.h
@@ -0,0 +1,17 @@
+#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"),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Dera SMART Log, show it", get_status, "stat")
+ )
+);
+
+#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..482ea0d
--- /dev/null
+++ b/plugins/huawei/huawei-nvme.c
@@ -0,0 +1,374 @@
+/*
+ * 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 "linux/nvme_ioctl.h"
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "json.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+#include <sys/ioctl.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;
+ int nsid;
+ struct nvme_id_ns ns;
+ unsigned 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;
+ item->nsid = nvme_get_nsid(fd);
+ err = nvme_identify_ns(fd, item->nsid, 0, &item->ns);
+ if (err)
+ return err;
+
+ err = fstat(fd, &nvme_stat_info);
+ if (err < 0)
+ return err;
+
+ strcpy(item->node, node);
+ 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 len)
+{
+ struct json_object *root;
+ struct json_array *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)
+{
+ long long int lba = 1 << list_item.ns.lbaf[(list_item.ns.flbas & 0x0f)].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 len, unsigned 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 len, unsigned 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 len)
+{
+ unsigned 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, fd, ret;
+ unsigned int huawei_num = 0;
+ int 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()
+ };
+
+ argconfig_parse(argc, argv, desc, opts);
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt != JSON && fmt != NORMAL)
+ return -EINVAL;
+
+ n = scandir("/dev", &devices, scan_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");
+ return ENOMEM;
+ }
+
+ for (i = 0; i < n; i++) {
+ snprintf(path, sizeof(path), "/dev/%s", devices[i]->d_name);
+ fd = open(path, O_RDONLY);
+ ret = huawei_get_nvme_info(fd, &list_items[huawei_num], path);
+ if (ret)
+ return ret;
+ if (list_items[huawei_num].huawei_device == true) {
+ huawei_num++;
+ }
+ }
+
+ 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);
+ }
+
+ for (i = 0; i < n; i++)
+ free(devices[i]);
+ free(devices);
+ free(list_items);
+
+ return 0;
+}
+
+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..7aac90c
--- /dev/null
+++ b/plugins/huawei/huawei-nvme.h
@@ -0,0 +1,18 @@
+#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"),
+ 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/intel/intel-nvme.c b/plugins/intel/intel-nvme.c
new file mode 100644
index 0000000..8217c46
--- /dev/null
+++ b/plugins/intel/intel-nvme.c
@@ -0,0 +1,1316 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "json.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "intel-nvme.h"
+
+struct __attribute__((packed)) nvme_additional_smart_log_item {
+ __u8 key;
+ __u8 _kp[2];
+ __u8 norm;
+ __u8 _np;
+ union __attribute__((packed)) {
+ __u8 raw[6];
+ struct __attribute__((packed)) wear_level {
+ __le16 min;
+ __le16 max;
+ __le16 avg;
+ } wear_level;
+ struct __attribute__((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_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_float(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);
+
+ json_object_add_value_object(root, "Device stats", dev_stats);
+
+ json_print_object(root, NULL);
+ json_free_object(root);
+}
+
+static void show_intel_smart_log(struct nvme_additional_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 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));
+}
+
+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;
+ int err, fd;
+
+ struct config {
+ __u32 namespace_id;
+ int raw_binary;
+ int 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (cfg.json)
+ show_intel_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
+ else if (!cfg.raw_binary)
+ show_intel_smart_log(&smart_log, cfg.namespace_id, devicename);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ 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";
+
+ char log[512];
+ int err, fd;
+
+ struct config {
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, 0xdd, false,
+ 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ 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;
+ int err, fd;
+
+ const char *desc = "Get Intel Marketing Name log and show it.";
+ const char *raw = "dump output in binary format";
+ struct config {
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, 0xc5, false,
+ 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+}
+
+struct intel_lat_stats {
+ __u16 maj;
+ __u16 min;
+ __u32 data[1216];
+};
+
+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 const 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 const 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)
+{
+ if (bound_type != NOINF) {
+ snprintf(buffer, 5, "%s", bound_type ? "+INF" : "-INF");
+ return;
+ }
+ char *string;
+
+ switch (unit) {
+ case US:
+ string = "us";
+ break;
+ case MS:
+ string = "ms";
+ break;
+ case S:
+ string = "s";
+ break;
+ default:
+ string = "_s";
+ break;
+ }
+ snprintf(buffer, 11, "%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_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.
+ */
+static int lat_stats_log_scale(int i)
+{
+ static const int LATENCY_STATS_V4_BASE_BITS = 6;
+ static const int LATENCY_STATS_V4_BASE_VAL = (
+ 1 << LATENCY_STATS_V4_BASE_BITS);
+
+ // 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_add_value_object(bucket_list,
+ "bucket", bucket);
+ json_object_add_value_int(bucket, "id", id);
+
+ set_unit_string(buffer, lower_us,
+ get_seconds_magnitude(lower_us), start_type);
+ json_object_add_value_string(bucket, "start", buffer);
+
+ set_unit_string(buffer, upper_us,
+ get_seconds_magnitude(upper_us), end_type);
+ json_object_add_value_string(bucket, "end", buffer);
+
+ json_object_add_value_int(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_create_object();
+
+ 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_create_object();
+
+ 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(struct intel_lat_stats *stats, int write)
+{
+ switch (stats->maj) {
+ case 3:
+ json_lat_stats_3_0(stats, write);
+ break;
+ case 4:
+ switch (stats->min) {
+ 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"
+ "Defaulting to format for rev4.0"),
+ 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(struct intel_lat_stats *stats, int write)
+{
+ static const int separator_length = 50;
+
+ printf("Intel IO %s Command Latency Statistics\n",
+ write ? "Write" : "Read");
+ printf("Major Revision : %u\nMinor Revision : %u\n",
+ stats->maj, stats->min);
+ print_dash_separator(separator_length);
+ printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
+ print_dash_separator(separator_length);
+
+ switch (stats->maj) {
+ case 3:
+ show_lat_stats_3_0(stats);
+ break;
+ case 4:
+ switch (stats->min) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ show_lat_stats_4_0(stats);
+ break;
+ default:
+ printf(("Unsupported minor revision (%u.%u)\n"
+ "Defaulting to format for rev4.0"),
+ stats->maj, stats->min);
+ 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)
+{
+ struct intel_lat_stats stats;
+ enum nvme_print_flags flags;
+ int err, fd;
+
+ const char *desc = "Get Intel Latency Statistics log and show it.";
+ const char *raw = "dump output in binary format";
+ const char *write = "Get write statistics (read default)";
+ struct config {
+ char *output_format;
+ int raw_binary;
+ int write;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output format: normal|json|binary"),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = flags = validate_output_format(cfg.output_format);
+ if (flags < 0)
+ goto close_fd;
+
+ if (cfg.raw_binary)
+ flags = BINARY;
+
+ err = nvme_get_log(fd, NVME_NSID_ALL, cfg.write ? 0xc2 : 0xc1,
+ false, sizeof(stats), &stats);
+ if (!err) {
+ if (flags & JSON)
+ json_lat_stats(&stats, cfg.write);
+ else if (flags & BINARY)
+ d_raw((unsigned char *)&stats, sizeof(stats));
+ else
+ show_lat_stats(&stats, cfg.write);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+close_fd:
+ close(fd);
+ 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);
+ 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, fd, 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;
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ free(intel);
+ return fd;
+ }
+
+ if (cfg.log > 2 || cfg.core > 4 || cfg.lnum > 255) {
+ free(intel);
+ return EINVAL;
+ }
+
+ if (!cfg.file) {
+ err = setup_file(f, cfg.file, fd, cfg.log);
+ if (err)
+ goto out;
+ 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);
+
+ err = read_header(&cmd, buf, fd, 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, fd, &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, fd, 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, fd, 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, fd, 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, fd, buf);
+ if (err)
+ goto out;
+ }
+ }
+ }
+ err = 0;
+ out:
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else if (err < 0) {
+ perror("intel log");
+ err = EIO;
+ } else
+ printf("Successfully wrote log to %s\n", cfg.file);
+ free(intel);
+ return err;
+}
+
+static int enable_lat_stats_tracking(int argc, char **argv,
+ struct command *command, struct plugin *plugin)
+{
+ int err, fd;
+ 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;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ bool enable, disable;
+ };
+
+ struct config cfg = {
+ .enable = false,
+ .disable = false,
+ };
+
+ const struct argconfig_commandline_options command_line_options[] = {
+ {"enable", 'e', "", CFG_NONE, &cfg.enable, no_argument, enable_desc},
+ {"disable", 'd', "", CFG_NONE, &cfg.disable, no_argument, disable_desc},
+ {NULL}
+ };
+
+ fd = parse_and_open(argc, argv, desc, command_line_options);
+
+ enum Option {
+ None = -1,
+ True = 1,
+ False = 0,
+ };
+
+ enum Option option = None;
+
+ if (cfg.enable && cfg.disable)
+ printf("Cannot enable and disable simultaneously.");
+ else if (cfg.enable || cfg.disable)
+ option = cfg.enable;
+
+ if (fd < 0)
+ return fd;
+ switch (option) {
+ case None:
+ err = nvme_get_feature(fd, nsid, fid, sel, cdw11, data_len, buf,
+ &result);
+ if (!err) {
+ printf(
+ "Latency Statistics Tracking (FID 0x%X) is currently (%i).\n",
+ fid, result);
+ } else {
+ printf("Could not read feature id 0xE2.\n");
+ return err;
+ }
+ break;
+ case True:
+ case False:
+ err = nvme_set_feature(fd, nsid, fid, option, cdw12, save,
+ data_len, buf, &result);
+ if (err > 0) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else if (err < 0) {
+ perror("Enable latency tracking");
+ fprintf(stderr, "Command failed while parsing.\n");
+ } else {
+ printf("Successfully set enable bit for FID (0x%X) to %i.\n",
+ fid, option);
+ }
+ break;
+ default:
+ printf("%d not supported.\n", option);
+ return EINVAL;
+ }
+ return fd;
+}
diff --git a/plugins/intel/intel-nvme.h b/plugins/intel/intel-nvme.h
new file mode 100644
index 0000000..335e901
--- /dev/null
+++ b/plugins/intel/intel-nvme.h
@@ -0,0 +1,23 @@
+#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"),
+ 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("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/lnvm/lnvm-nvme.c b/plugins/lnvm/lnvm-nvme.c
new file mode 100644
index 0000000..3678176
--- /dev/null
+++ b/plugins/lnvm/lnvm-nvme.c
@@ -0,0 +1,436 @@
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "nvme-lightnvm.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "lnvm-nvme.h"
+
+static int lnvm_init(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Initialize LightNVM device. A LightNVM/Open-Channel SSD"\
+ " must have a media manager associated before it can"\
+ " be exposed to the user. The default is to initialize"
+ " the general media manager on top of the device.\n\n"
+ "Example:"
+ " lnvm-init -d nvme0n1";
+ const char *devname = "identifier of desired device. e.g. nvme0n1.";
+ const char *mmtype = "media manager to initialize on top of device. Default: gennvm.";
+ int ret;
+
+ struct config {
+ char *devname;
+ char *mmtype;
+ };
+
+ struct config cfg = {
+ .devname = "",
+ .mmtype = "gennvm",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname),
+ OPT_STRING("mediamgr-name", 'm', "MM", &cfg.mmtype, mmtype),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ if (!strlen(cfg.devname)) {
+ fprintf(stderr, "device name missing\n");
+ return -EINVAL;
+ }
+
+ return lnvm_do_init(cfg.devname, cfg.mmtype);
+}
+
+static int lnvm_list(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "List all devices registered with LightNVM.";
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ return lnvm_do_list_devices();
+}
+
+static int lnvm_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Show general information and registered target types with LightNVM";
+ int ret;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ return lnvm_do_info();
+}
+
+static int lnvm_id_ns(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Send an Identify Geometry command to the "\
+ "given LightNVM device, returns properties of the specified "\
+ "namespace in either human-readable or binary format.";
+ const char *raw_binary = "show infos in binary format";
+ const char *human_readable = "show infos in readable format";
+ const char *namespace_id = "identifier of desired namespace. default: 1";
+ unsigned int flags = 0;
+ int fd;
+
+ struct config {
+ __u32 namespace_id;
+ int raw_binary;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (cfg.human_readable)
+ flags |= VERBOSE;
+ else if (cfg.raw_binary)
+ flags |= BINARY;
+
+ return lnvm_do_id_ns(fd, cfg.namespace_id, flags);
+}
+
+static int lnvm_chunk_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Retrieve the chunk information log for the "\
+ "specified given LightNVM device, returns in either "\
+ "human-readable or binary format.\n"\
+ "This will request Geometry first to get the "\
+ "num_grp,num_pu,num_chk first to figure out the total size "\
+ "of the log pages."\
+ ;
+ const char *output_format = "Output format: normal|binary";
+ const char *human_readable = "Print normal in readable format";
+ int err, fmt, fd;
+ struct nvme_nvm_id20 geo;
+ struct nvme_nvm_chunk_desc *chunk_log;
+ __u32 nsid;
+ __u32 data_len;
+ unsigned int flags = 0;
+
+ struct config {
+ char *output_format;
+ int human_readable;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ fmt = validate_output_format(cfg.output_format);
+ if (fmt < 0) {
+ err = fmt;
+ goto close;
+ }
+
+ if (fmt == BINARY)
+ flags |= BINARY;
+ else if (cfg.human_readable)
+ flags |= VERBOSE;
+
+ nsid = nvme_get_nsid(fd);
+
+ /*
+ * It needs to figure out how many bytes will be requested by this
+ * subcommand by the (num_grp * num_pu * num_chk) from the Geometry.
+ */
+ err = lnvm_get_identity(fd, nsid, (struct nvme_nvm_id *) &geo);
+ if (err)
+ goto close;
+
+ data_len = (geo.num_grp * geo.num_pu * geo.num_chk) *
+ sizeof(struct nvme_nvm_chunk_desc);
+ chunk_log = malloc(data_len);
+ if (!chunk_log) {
+ fprintf(stderr, "cound not alloc for chunk log %dbytes\n",
+ data_len);
+ err = -ENOMEM;
+ goto close;
+ }
+
+ err = lnvm_do_chunk_log(fd, nsid, data_len, chunk_log, flags);
+ if (err)
+ fprintf(stderr, "get log page for chunk information failed\n");
+
+ free(chunk_log);
+close:
+ close(fd);
+ return err;
+}
+
+static int lnvm_create_tgt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Instantiate a target on top of a LightNVM enabled device.";
+ const char *devname = "identifier of desired device. e.g. nvme0n1.";
+ const char *tgtname = "target name of the device to initialize. e.g. target0.";
+ const char *tgttype = "identifier of target type. e.g. pblk.";
+ const char *lun_begin = "Define begin of luns to use for target.";
+ const char *lun_end = "Define set of luns to use for target.";
+ const char *over_prov = "Define over-provision percentage for target.";
+ const char *flag_factory = "Create target in factory mode";
+ int flags;
+ int ret;
+
+ struct config {
+ char *devname;
+ char *tgtname;
+ char *tgttype;
+ __u32 lun_begin;
+ __u32 lun_end;
+ __u32 over_prov;
+
+ /* flags */
+ __u32 factory;
+ };
+
+ struct config cfg = {
+ .devname = "",
+ .tgtname = "",
+ .tgttype = "",
+ .lun_begin = -1,
+ .lun_end = -1,
+ .over_prov = -1,
+ .factory = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname),
+ OPT_STRING("target-name", 'n', "TARGET", &cfg.tgtname, tgtname),
+ OPT_STRING("target-type", 't', "TARGETTYPE", &cfg.tgttype, tgttype),
+ OPT_UINT("lun-begin", 'b', &cfg.lun_begin, lun_begin),
+ OPT_UINT("lun-end", 'e', &cfg.lun_end, lun_end),
+ OPT_UINT("over-prov", 'o', &cfg.over_prov, over_prov),
+ OPT_FLAG("factory", 'f', &cfg.factory, flag_factory),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ if (!strlen(cfg.devname)) {
+ fprintf(stderr, "device name missing\n");
+ return -EINVAL;
+ }
+ if (!strlen(cfg.tgtname)) {
+ fprintf(stderr, "target name missing\n");
+ return -EINVAL;
+ }
+ if (!strlen(cfg.tgttype)) {
+ fprintf(stderr, "target type missing\n");
+ return -EINVAL;
+ }
+
+ flags = 0;
+ if (cfg.factory)
+ flags |= NVM_TARGET_FACTORY;
+
+ return lnvm_do_create_tgt(cfg.devname, cfg.tgtname, cfg.tgttype, cfg.lun_begin, cfg.lun_end, cfg.over_prov, flags);
+}
+
+static int lnvm_remove_tgt(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Remove an initialized LightNVM target.";
+ const char *tgtname = "target name of the device to remove. e.g. target0.";
+ int ret;
+
+ struct config {
+ char *tgtname;
+ };
+
+ struct config cfg = {
+ .tgtname = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("target-name", 'n', "TARGET", &cfg.tgtname, tgtname),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ if (!strlen(cfg.tgtname)) {
+ fprintf(stderr, "target name missing\n");
+ return -EINVAL;
+ }
+
+ return lnvm_do_remove_tgt(cfg.tgtname);
+}
+
+static int lnvm_factory_init(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Factory initialize a LightNVM enabled device.";
+ const char *devname = "identifier of desired device. e.g. nvme0n1.";
+ const char *erase_only_marked = "only erase marked blocks. default: all blocks.";
+ const char *host_marks = "remove host side blocks list. default: keep.";
+ const char *bb_marks = "remove grown bad blocks list. default: keep";
+ int ret;
+
+ struct config {
+ char *devname;
+ int erase_only_marked;
+ int clear_host_marks;
+ int clear_bb_marks;
+ };
+
+ struct config cfg = {
+ .devname = "",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("device-name", 'd', "DEVICE", &cfg.devname, devname),
+ OPT_FLAG("erase-only-marked", 'e', &cfg.erase_only_marked, erase_only_marked),
+ OPT_FLAG("clear-host-side-blks", 's', &cfg.clear_host_marks, host_marks),
+ OPT_FLAG("clear-bb-blks", 'b', &cfg.clear_bb_marks, bb_marks),
+ OPT_END()
+ };
+
+ ret = argconfig_parse(argc, argv, desc, opts);
+ if (ret < 0)
+ return ret;
+
+ if (!strlen(cfg.devname)) {
+ fprintf(stderr, "device name missing\n");
+ return -EINVAL;
+ }
+
+ return lnvm_do_factory_init(cfg.devname, cfg.erase_only_marked,
+ cfg.clear_host_marks, cfg.clear_bb_marks);
+}
+
+static int lnvm_get_bbtbl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Receive bad block table from a LightNVM compatible"\
+ " device.";
+ const char *namespace = "(optional) desired namespace";
+ const char *ch = "channel identifier";
+ const char *lun = "lun identifier (within a channel)";
+ const char *raw_binary = "show infos in binary format";
+ unsigned int fd, flags = 0;
+
+ struct config {
+ __u32 namespace_id;
+ __u16 lunid;
+ __u16 chid;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .lunid = 0,
+ .chid = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_SHRT("channel-id", 'c', &cfg.chid, ch),
+ OPT_SHRT("lun-id", 'l', &cfg.lunid, lun),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw_binary),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (cfg.raw_binary)
+ flags |= BINARY;
+
+ return lnvm_do_get_bbtbl(fd, cfg.namespace_id, cfg.lunid, cfg.chid, flags);
+}
+
+static int lnvm_set_bbtbl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc = "Update bad block table on a LightNVM compatible"\
+ " device.";
+ const char *namespace = "(optional) desired namespace";
+ const char *ch = "channel identifier";
+ const char *lun = "lun identifier (within a channel)";
+ const char *pln = "plane identifier (within a lun)";
+ const char *blk = "block identifier (within a plane)";
+ const char *value = "value to update the specific block to.";
+ int fd;
+
+ struct config {
+ __u32 namespace_id;
+ __u16 lunid;
+ __u16 chid;
+ __u16 plnid;
+ __u16 blkid;
+ __u16 value;
+ };
+
+ struct config cfg = {
+ .namespace_id = 1,
+ .lunid = 0,
+ .chid = 0,
+ .plnid = 0,
+ .blkid = 0,
+ .value = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_SHRT("channel-id", 'c', &cfg.chid, ch),
+ OPT_SHRT("lun-id", 'l', &cfg.lunid, lun),
+ OPT_SHRT("plane-id", 'p', &cfg.plnid, pln),
+ OPT_SHRT("block-id", 'b', &cfg.blkid, blk),
+ OPT_SHRT("value", 'v', &cfg.value, value),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ printf("Updating: Ch.: %u LUN: %u Plane: %u Block: %u -> %u\n",
+ cfg.chid, cfg.lunid, cfg.plnid, cfg.blkid, cfg.value);
+ return lnvm_do_set_bbtbl(fd, cfg.namespace_id, cfg.chid, cfg.lunid,
+ cfg.plnid, cfg.blkid, cfg.value);
+}
diff --git a/plugins/lnvm/lnvm-nvme.h b/plugins/lnvm/lnvm-nvme.h
new file mode 100644
index 0000000..45b3cf0
--- /dev/null
+++ b/plugins/lnvm/lnvm-nvme.h
@@ -0,0 +1,27 @@
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/lnvm/lnvm-nvme
+
+#if !defined(LNVM_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define LNVM_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("lnvm", "LightNVM specific extensions"),
+ COMMAND_LIST(
+ ENTRY("list", "List available LightNVM devices", lnvm_list)
+ ENTRY("info", "List general information and available target engines", lnvm_info)
+ ENTRY("id-ns", "List geometry for LightNVM device", lnvm_id_ns, "geometry")
+ ENTRY("chunk-log", "Chunk Information Log Page", lnvm_chunk_log)
+ ENTRY("init", "Initialize media manager on LightNVM device", lnvm_init)
+ ENTRY("create", "Create target on top of a LightNVM device", lnvm_create_tgt)
+ ENTRY("remove", "Remove target from device", lnvm_remove_tgt)
+ ENTRY("factory", "Reset device to factory state", lnvm_factory_init)
+ ENTRY("diag-bbtbl", "Diagnose bad block table", lnvm_get_bbtbl)
+ ENTRY("diag-set-bbtbl", "Update bad block table", lnvm_set_bbtbl)
+ )
+);
+
+#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..c75f49c
--- /dev/null
+++ b/plugins/memblaze/memblaze-nvme.c
@@ -0,0 +1,759 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "memblaze-nvme.h"
+#include "memblaze-utils.h"
+
+enum {
+ MB_FEAT_POWER_MGMT = 0xc6,
+};
+
+/*
+ * 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.83 = raisin
+#define IS_RAISIN(str) (!strcmp(str, "2.83"))
+// 2.13 = papaya
+#define IS_PAPAYA(str) (!strcmp(str, "2.13"))
+#define STR_VER_SIZE 5
+
+int getlogpage_format_type(char *fw_ver)
+{
+ char fw_ver_local[STR_VER_SIZE];
+ strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
+ *(fw_ver_local + STR_VER_SIZE - 1) = '\0';
+ if ( IS_RAISIN(fw_ver_local) )
+ {
+ return INTEL_FORMAT;
+ }
+ else
+ {
+ return MEMBLAZE_FORMAT;
+ }
+}
+
+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);
+}
+
+#define STRN2_01 "Additional Smart Log for NVME device"
+#define STRN2_02 "namespace-id"
+#define STRN1_01 "key"
+#define STRN1_02 "normalized"
+#define STRN1_03 "raw"
+#define STR00_01 "program_fail_count"
+#define STR01_01 "erase_fail_count"
+#define STR02_01 "wear_leveling"
+#define STR02_03 "min: "
+#define STR02_04 ", max: "
+#define STR02_05 ", avg: "
+#define STR03_01 "end_to_end_error_detection_count"
+#define STR04_01 "crc_error_count"
+#define STR05_01 "timed_workload_media_wear"
+#define STR06_01 "timed_workload_host_reads"
+#define STR07_01 "timed_workload_timer"
+#define STR07_02 " min"
+#define STR08_01 "thermal_throttle_status"
+#define STR08_02 ", cnt: "
+#define STR09_01 "retry_buffer_overflow_count"
+#define STR10_01 "pll_lock_loss_count"
+#define STR11_01 "nand_bytes_written"
+#define STR11_03 "sectors: "
+#define STR12_01 "host_bytes_written"
+#define STR12_03 "sectors: "
+#define STR13_01 "system_area_life_left"
+#define STR14_01 "total_read"
+#define STR15_01 "tempt_since_born"
+#define STR15_03 "max: "
+#define STR15_04 ", min: "
+#define STR15_05 ", curr: "
+#define STR16_01 "power_consumption"
+#define STR16_03 "max: "
+#define STR16_04 ", min: "
+#define STR16_05 ", curr: "
+#define STR17_01 "tempt_since_bootup"
+#define STR17_03 "max: "
+#define STR17_04 ", min: "
+#define STR17_05 ", curr: "
+#define STR18_01 "power_loss_protection"
+#define STR19_01 "read_fail"
+#define STR20_01 "thermal_throttle_time"
+#define STR21_01 "flash_media_error"
+
+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));
+
+ /* Table Title */
+ printf("%s:%s %s:%x\n", STRN2_01, devname, STRN2_02, nsid);
+ /* Clumn Name*/
+ printf("%-34s%-11s%s\n", STRN1_01, STRN1_02, STRN1_03);
+ /* 00 RAISIN_SI_VD_PROGRAM_FAIL */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PROGRAM_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR00_01, *nm, int48_to_long(raw));
+ /* 01 RAISIN_SI_VD_ERASE_FAIL */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_ERASE_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR01_01, *nm, int48_to_long(raw));
+ /* 02 RAISIN_SI_VD_WEARLEVELING_COUNT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_WEARLEVELING_COUNT, nm, raw);
+ printf("%-31s : %3d%% %s%u%s%u%s%u\n", STR02_01, *nm,
+ STR02_03, *raw, STR02_04, *(raw+2), STR02_05, *(raw+4));
+ /* 03 RAISIN_SI_VD_E2E_DECTECTION_COUNT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_E2E_DECTECTION_COUNT, nm, raw);
+ printf("%-31s: %3d%% %"PRIu64"\n", STR03_01, *nm, int48_to_long(raw));
+ /* 04 RAISIN_SI_VD_PCIE_CRC_ERR_COUNT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PCIE_CRC_ERR_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR04_01, *nm, int48_to_long(raw));
+ /* 05 RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_MEDIA_WEAR, nm, raw);
+ printf("%-32s: %3d%% %.3f%%\n", STR05_01, *nm, ((float)int48_to_long(raw))/1000);
+ /* 06 RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_HOST_READ, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"%%\n", STR06_01, *nm, int48_to_long(raw));
+ /* 07 RAISIN_SI_VD_TIMED_WORKLOAD_TIMER */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TIMED_WORKLOAD_TIMER, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"%s\n", STR07_01, *nm, int48_to_long(raw), STR07_02);
+ /* 08 RAISIN_SI_VD_THERMAL_THROTTLE_STATUS */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_STATUS, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"%%%s%"PRIu64"\n", STR08_01, *nm,
+ int48_to_long(raw), STR08_02, int48_to_long(raw+1));
+ /* 09 RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_RETRY_BUFF_OVERFLOW_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR09_01, *nm, int48_to_long(raw));
+ /* 10 RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_PLL_LOCK_LOSS_COUNT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR10_01, *nm, int48_to_long(raw));
+ /* 11 RAISIN_SI_VD_TOTAL_WRITE */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_WRITE, nm, raw);
+ printf("%-32s: %3d%% %s%"PRIu64"\n", STR11_01, *nm, STR11_03, int48_to_long(raw));
+ /* 12 RAISIN_SI_VD_HOST_WRITE */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_HOST_WRITE, nm, raw);
+ printf("%-32s: %3d%% %s%"PRIu64"\n", STR12_01, *nm, STR12_03, int48_to_long(raw));
+ /* 13 RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_SYSTEM_AREA_LIFE_LEFT, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR13_01, *nm, int48_to_long(raw));
+ /* 14 RAISIN_SI_VD_TOTAL_READ */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TOTAL_READ, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR14_01, *nm, int48_to_long(raw));
+ /* 15 RAISIN_SI_VD_TEMPT_SINCE_BORN */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BORN, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", STR15_01, *nm,
+ STR15_03, *raw, STR15_04, *(raw+2), STR15_05, *(raw+4));
+ /* 16 RAISIN_SI_VD_POWER_CONSUMPTION */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_POWER_CONSUMPTION, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", STR16_01, *nm,
+ STR16_03, *raw, STR16_04, *(raw+2), STR16_05, *(raw+4));
+ /* 17 RAISIN_SI_VD_TEMPT_SINCE_BOOTUP */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_TEMPT_SINCE_BOOTUP, nm, raw);
+ printf("%-32s: %3d%% %s%u%s%u%s%u\n", STR17_01, *nm, STR17_03, *raw,
+ STR17_04, *(raw+2), STR17_05, *(raw+4));
+ /* 18 RAISIN_SI_VD_POWER_LOSS_PROTECTION */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_POWER_LOSS_PROTECTION, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR18_01, *nm, int48_to_long(raw));
+ /* 19 RAISIN_SI_VD_READ_FAIL */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_READ_FAIL, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR19_01, *nm, int48_to_long(raw));
+ /* 20 RAISIN_SI_VD_THERMAL_THROTTLE_TIME */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_THERMAL_THROTTLE_TIME, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR20_01, *nm, int48_to_long(raw));
+ /* 21 RAISIN_SI_VD_FLASH_MEDIA_ERROR */
+ get_memblaze_new_smart_info(smart, RAISIN_SI_VD_FLASH_MEDIA_ERROR, nm, raw);
+ printf("%-32s: %3d%% %"PRIu64"\n", STR21_01, *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];
+ struct nvme_memblaze_smart_log_item *item;
+
+ strncpy(fw_ver_local, fw_ver, STR_VER_SIZE);
+ *(fw_ver_local + STR_VER_SIZE - 1) = '\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 Kelvin since last factory reset : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_RESET].temperature.max));
+ printf("Minimum temperature in Kelvin 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 Kelvin since power on : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.max));
+ printf("Minimum temperature in Kelvin since power on : %u\n",
+ le16_to_cpu(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.min));
+ }
+ printf("Current temperature in Kelvin : %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));
+
+ /* 00 RAISIN_SI_VD_PROGRAM_FAIL */
+ get_memblaze_new_smart_info(s, PROGRAM_FAIL, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ STR00_01, *nm, int48_to_long(raw));
+ /* 01 RAISIN_SI_VD_ERASE_FAIL */
+ get_memblaze_new_smart_info(s, ERASE_FAIL, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ STR01_01, *nm, int48_to_long(raw));
+ /* 02 RAISIN_SI_VD_WEARLEVELING_COUNT */
+ get_memblaze_new_smart_info(s, WEARLEVELING_COUNT, nm, raw);
+ printf("%-31s : %3d%% %s%u%s%u%s%u\n",
+ STR02_01, *nm, STR02_03, *raw, STR02_04, *(raw+2), STR02_05, *(raw+4));
+ /* 11 RAISIN_SI_VD_TOTAL_WRITE */
+ get_memblaze_new_smart_info(s, TOTAL_WRITE, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ STR11_01, *nm, 32*int48_to_long(raw));
+ /* 12 RAISIN_SI_VD_HOST_WRITE */
+ get_memblaze_new_smart_info(s, HOST_WRITE, nm, raw);
+ printf("%-32s : %3d%% %"PRIu64"\n",
+ STR12_01, *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(fw_ver)) // 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;
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_memblaze_smart_log smart_log;
+ int err, fd;
+ 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 config {
+ __u32 namespace_id;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+ return err;
+}
+
+static char *mb_feature_to_string(int feature)
+{
+ switch (feature) {
+ case MB_FEAT_POWER_MGMT: return "Memblaze power management";
+ default: return "Unknown";
+ }
+}
+
+static int get_additional_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 "\
+ "behaviour of the feature. Each Feature has three possible "\
+ "settings: default, saveable, and current. If a Feature is "\
+ "saveable, it may be modified by set-feature. Default values "\
+ "are vendor-specific and not changeable. Use set-feature to "\
+ "change saveable Features.\n\n"\
+ "Available additional feature id:\n"\
+ "0xc6: Memblaze power management\n"\
+ " (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ const char *raw = "show feature in binary format";
+ const char *namespace_id = "identifier of desired namespace";
+ const char *feature_id = "hexadecimal feature name";
+ const char *sel = "[0-3]: curr./default/saved/supp.";
+ const char *data_len = "buffer len (if) data is returned";
+ const char *cdw11 = "dword 11 for interrupt vector config";
+ const char *human_readable = "show infos in readable format";
+ int err, fd;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u8 sel;
+ __u32 cdw11;
+ __u32 data_len;
+ int raw_binary;
+ int human_readable;
+ };
+
+ 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_UINT("cdw11", 'c', &cfg.cdw11, cdw11),
+ OPT_FLAG("human-readable", 'H', &cfg.human_readable, human_readable),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (cfg.sel > 7) {
+ fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
+ return EINVAL;
+ }
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ return EINVAL;
+ }
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len))
+ exit(ENOMEM);
+ memset(buf, 0, cfg.data_len);
+ }
+
+ err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
+ cfg.data_len, buf, &result);
+ if (!err) {
+ printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id),
+ nvme_select_to_string(cfg.sel), result);
+ if (cfg.human_readable)
+ nvme_feature_show_fields(cfg.feature_id, result, buf);
+ else {
+ if (buf) {
+ if (!cfg.raw_binary)
+ d(buf, cfg.data_len, 16, 1);
+ else
+ d_raw(buf, cfg.data_len);
+ }
+ }
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static int set_additional_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.\n\n"\
+ "Available additional feature id:\n"\
+ "0xc6: Memblaze power management\n"\
+ " (value 0 - 25w, 1 - 20w, 2 - 15w)";
+ const char *namespace_id = "desired namespace";
+ const char *feature_id = "hex feature name (required)";
+ const char *data_len = "buffer length if data required";
+ const char *data = "optional file for feature data (default stdin)";
+ const char *value = "new value of feature (required)";
+ const char *save = "specifies that the controller shall save the attribute";
+ int err, fd;
+ __u32 result;
+ void *buf = NULL;
+ int ffd = STDIN_FILENO;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ __u32 data_len;
+ int 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ return EINVAL;
+ }
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len))
+ exit(ENOMEM);
+ memset(buf, 0, cfg.data_len);
+ }
+
+ if (buf) {
+ if (strlen(cfg.file)) {
+ ffd = open(cfg.file, O_RDONLY);
+ if (ffd <= 0) {
+ fprintf(stderr, "no firmware file provided\n");
+ err = EINVAL;
+ goto free;
+ }
+ }
+ if (read(ffd, (void *)buf, cfg.data_len) < 0) {
+ fprintf(stderr, "failed to read data buffer from input file\n");
+ err = EINVAL;
+ goto free;
+ }
+ }
+
+ err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
+ 0, cfg.save, cfg.data_len, buf, &result);
+ if (err < 0) {
+ perror("set-feature");
+ goto free;
+ }
+ if (!err) {
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ mb_feature_to_string(cfg.feature_id), cfg.value);
+ if (buf)
+ d(buf, cfg.data_len, 16, 1);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+free:
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static int memblaze_fw_commit(int fd, int select)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_activate_fw,
+ .cdw10 = 8,
+ .cdw12 = select,
+ };
+
+ return nvme_submit_admin_passthru(fd, &cmd);
+}
+
+static int memblaze_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "This performs a selective firmware download, which allows the user to "
+ "select which firmware binary to update for 9200 devices. This requires a power cycle once the "
+ "update completes. The options available are: \n\n"
+ "OOB - This updates the OOB and main firmware\n"
+ "EEP - This updates the eeprom and main firmware\n"
+ "ALL - This updates the eeprom, OOB, and main firmware";
+ const char *fw = "firmware file (required)";
+ const char *select = "FW Select (e.g., --select=OOB, EEP, ALL)";
+ int xfer = 4096;
+ void *fw_buf;
+ int fd, selectNo,fw_fd,fw_size,err,offset = 0;
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (strlen(cfg.select) != 3) {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < 3; i++) {
+ cfg.select[i] = toupper(cfg.select[i]);
+ }
+
+ if (strncmp(cfg.select,"OOB", 3) == 0) {
+ selectNo = 18;
+ } else if (strncmp(cfg.select,"EEP", 3) == 0) {
+ selectNo = 10;
+ } else if (strncmp(cfg.select,"ALL", 3) == 0) {
+ selectNo = 26;
+ } else {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ if (fw_fd < 0) {
+ fprintf(stderr, "no firmware file provided\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ err = errno;
+ }
+
+ fw_size = sb.st_size;
+ if (fw_size & 0x3) {
+ fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
+ fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ err = ENOMEM;
+ goto out;
+ }
+
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t)(fw_size)))
+ return EIO;
+
+ while (fw_size > 0) {
+ xfer = min(xfer, fw_size);
+
+ err = nvme_fw_download(fd, offset, xfer, fw_buf);
+ if (err < 0) {
+ perror("fw-download");
+ goto out;
+ } else if (err != 0) {
+ fprintf(stderr, "NVME Admin command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ goto out;
+ }
+ fw_buf += xfer;
+ fw_size -= xfer;
+ offset += xfer;
+ }
+
+ err = memblaze_fw_commit(fd,selectNo);
+
+ if(err == 0x10B || err == 0x20B) {
+ err = 0;
+ fprintf(stderr, "Update successful! Please power cycle for changes to take effect\n");
+ }
+
+out:
+ return err;
+}
+
diff --git a/plugins/memblaze/memblaze-nvme.h b/plugins/memblaze/memblaze-nvme.h
new file mode 100644
index 0000000..8f7024d
--- /dev/null
+++ b/plugins/memblaze/memblaze-nvme.h
@@ -0,0 +1,27 @@
+#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"
+#include "common.h"
+
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", get_additional_smart_log)
+ ENTRY("get-feature-add", "Get Memblaze feature and show the resulting value", get_additional_feature)
+ ENTRY("set-feature-add", "Set a Memblaze feature and show the resulting value", set_additional_feature)
+ ENTRY("select-download", "Selective Firmware Download", memblaze_selective_download)
+ )
+);
+
+#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..a67ee5e
--- /dev/null
+++ b/plugins/memblaze/memblaze-utils.h
@@ -0,0 +1,164 @@
+#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
+
+typedef unsigned char u8;
+
+// 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 Addtional 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 momery are dirty.
+ */
+ u8 resv[SMART_INFO_NEW_SIZE - sizeof(struct nvme_p4_smart_log_item) * NR_SMART_ITEMS];
+};
+
+#endif // __MEMBLAZE_UTILS_H__
+
diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c
new file mode 100644
index 0000000..165fcf0
--- /dev/null
+++ b/plugins/micron/micron-nvme.c
@@ -0,0 +1,1180 @@
+#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 "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include <sys/ioctl.h>
+#include <limits.h>
+
+#define CREATE_CMD
+#include "micron-nvme.h"
+#define min(x, y) ((x) > (y) ? (y) : (x))
+#define SensorCount 2
+#define C5_log_size (((452 + 16 * 1024) / 4) * 4096)
+#define D0_log_size 256
+#define MaxLogChunk 16 * 1024
+#define CommonChunkSize 16 * 4096
+
+typedef struct _LogPageHeader_t {
+ unsigned char numDwordsInLogPageHeaderLo;
+ unsigned char logPageHeaderFormatVersion;
+ unsigned char logPageId;
+ unsigned char numDwordsInLogPageHeaderHi;
+ unsigned int numValidDwordsInPayload;
+ unsigned int numDwordsInEntireLogPage;
+} LogPageHeader_t;
+
+/*
+ * Useful Helper functions
+ */
+
+static int micron_fw_commit(int fd, int select)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_activate_fw,
+ .cdw10 = 8,
+ .cdw12 = select,
+ };
+ return ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
+
+}
+
+static int ZipAndRemoveDir(char *strDirName, char *strFileName)
+{
+ int err = 0;
+ char strBuffer[PATH_MAX];
+ int nRet;
+
+ sprintf(strBuffer, "zip -r \"%s\" \"%s\" >temp.txt 2>&1", strFileName,
+ strDirName);
+
+ nRet = system(strBuffer);
+
+ if (nRet < 0) {
+ printf("Unable to create zip package!\n");
+ err = EINVAL;
+ goto exit_status;
+ }
+
+ sprintf(strBuffer, "rm -f -R \"%s\" >temp.txt 2>&1", strDirName);
+ nRet = system(strBuffer);
+ if (nRet < 0) {
+ printf("Unable to remove temporary files!\n");
+ err = EINVAL;
+ goto exit_status;
+ }
+
+ exit_status:
+ err = system("rm -f temp.txt");
+ return err;
+}
+
+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, '/') != NULL) {
+ fileName = strrchr(strFilePath, '\\');
+ if (fileName == NULL) {
+ fileName = strrchr(strFilePath, '/');
+ }
+
+ if (fileName != NULL) {
+ if (!strcmp(fileName, "/")) {
+ goto exit_status;
+ }
+
+ while (strFilePath[nIndex] != '\0') {
+ if ('\\' == strFilePath[nIndex] && '\\' == strFilePath[nIndex + 1]) {
+ goto exit_status;
+ }
+ nIndex++;
+ }
+
+ length = (int)strlen(strFilePath) - (int)strlen(fileName);
+
+ if (fileName == strFilePath) {
+ length = 1;
+ }
+
+ fileLocation = (char *)malloc(length + 1);
+ strncpy(fileLocation, strFilePath, length);
+ fileLocation[length] = '\0';
+
+ while (fileLocation[k] != '\0') {
+ if (fileLocation[k] == '\\') {
+ fileLocation[k] = '/';
+ }
+ }
+
+ length = (int)strlen(fileLocation);
+
+ if (':' == fileLocation[length - 1]) {
+ strTemp = (char *)malloc(length + 2);
+ strcpy(strTemp, fileLocation);
+ strcat(strTemp, "/");
+ free(fileLocation);
+
+ length = (int)strlen(strTemp);
+ fileLocation = (char *)malloc(length + 1);
+ memcpy(fileLocation, strTemp, length + 1);
+ free(strTemp);
+ }
+
+ if (stat(fileLocation, &st) != 0) {
+ free(fileLocation);
+ goto exit_status;
+ }
+ free(fileLocation);
+ } else {
+ goto exit_status;
+ }
+ }
+
+ nIndex = 0;
+ for (i = 0; i < (int)strlen(strSN); i++) {
+ if (strSN[i] != ' ' && strSN[i] != '\n' && strSN[i] != '\t' && strSN[i] != '\r') {
+ strMainDirName[nIndex++] = strSN[i];
+ }
+ }
+ strMainDirName[nIndex] = '\0';
+
+ j = 1;
+ while (stat(strMainDirName, &dirStat) == 0) {
+ strMainDirName[nIndex] = '\0';
+ sprintf(strAppend, "-%d", j);
+ strcat(strMainDirName, strAppend);
+ j++;
+ }
+
+ mkdir(strMainDirName, 0777);
+
+ if (strOSDirName != NULL) {
+ sprintf(strOSDirName, "%s/%s", strMainDirName, "OS");
+ mkdir(strOSDirName, 0777);
+
+ }
+ if (strCtrlDirName != NULL) {
+ sprintf(strCtrlDirName, "%s/%s", strMainDirName, "Controller");
+ mkdir(strCtrlDirName, 0777);
+
+ }
+
+ exit_status:
+ return err;
+}
+
+static int GetLogPageSize(int nFD, unsigned char ucLogID, int *nLogSize)
+{
+ int err = 0;
+ struct nvme_admin_cmd cmd;
+ unsigned int uiXferDwords = 0;
+ unsigned char pTmpBuf[CommonChunkSize] = { 0 };
+ LogPageHeader_t *pLogHeader = NULL;
+
+ if (ucLogID == 0xC1 || ucLogID == 0xC2 || ucLogID == 0xC4) {
+ cmd.opcode = 0x02;
+ cmd.cdw10 = ucLogID;
+ uiXferDwords = (unsigned int)(CommonChunkSize / 4);
+ cmd.nsid = 0xFFFFFFFF;
+ cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
+ cmd.data_len = CommonChunkSize;
+ cmd.addr = (__u64) (uintptr_t) & pTmpBuf;
+ err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
+ if (err == 0) {
+ pLogHeader = (LogPageHeader_t *) pTmpBuf;
+ LogPageHeader_t *pLogHeader1 = (LogPageHeader_t *) pLogHeader;
+ *nLogSize = (int)(pLogHeader1->numDwordsInEntireLogPage) * 4;
+ } else {
+ printf ("Getting size of log page : 0x%X failed with %d\n", ucLogID, err);
+ *nLogSize = 0;
+ }
+ }
+ return err;
+}
+
+static int NVMEGetLogPage(int nFD, unsigned char ucLogID, unsigned char *pBuffer, int nBuffSize)
+{
+ int err = 0;
+ struct nvme_admin_cmd cmd = { 0 };
+ unsigned int uiNumDwords = (unsigned int)nBuffSize / sizeof(unsigned int);
+ unsigned int uiMaxChunk = uiNumDwords;
+ unsigned int uiNumChunks = 1;
+ unsigned int uiXferDwords = 0;
+ unsigned long long ullBytesRead = 0;
+ unsigned char *pTempPtr = pBuffer;
+ unsigned char ucOpCode = 0x02;
+
+ if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ uiMaxChunk = 4096;
+ } else if (uiMaxChunk > 16 * 1024) {
+ uiMaxChunk = 16 * 1024;
+ }
+
+ uiNumChunks = uiNumDwords / uiMaxChunk;
+ if (uiNumDwords % uiMaxChunk > 0) {
+ uiNumChunks += 1;
+ }
+
+ for (unsigned int i = 0; i < uiNumChunks; i++) {
+ memset(&cmd, 0, sizeof(cmd));
+ uiXferDwords = uiMaxChunk;
+ if (i == uiNumChunks - 1 && uiNumDwords % uiMaxChunk > 0) {
+ uiXferDwords = uiNumDwords % uiMaxChunk;
+ }
+
+ cmd.opcode = ucOpCode;
+ cmd.cdw10 |= ucLogID;
+ cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
+
+ if (ucLogID == 0x7) {
+ cmd.cdw10 |= 0x80;
+ }
+ if (ullBytesRead == 0 && (ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ cmd.cdw11 = 1;
+ }
+ if (ullBytesRead > 0 && !(ucLogID == 0xE6 || ucLogID == 0xE7)) {
+ unsigned long long ullOffset = ullBytesRead;
+ cmd.cdw12 = ullOffset & 0xFFFFFFFF;
+ cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
+ }
+
+ cmd.addr = (__u64) (uintptr_t) pTempPtr;
+ cmd.nsid = 0xFFFFFFFF;
+ cmd.data_len = uiXferDwords * 4;
+ err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
+ ullBytesRead += uiXferDwords * 4;
+ pTempPtr = pBuffer + ullBytesRead;
+ }
+
+ return err;
+}
+
+static int NVMEResetLog(int nFD, unsigned char ucLogID, int nBufferSize,
+ long long llMaxSize)
+{
+ unsigned int *pBuffer = NULL;
+ int err = 0;
+
+ if ((pBuffer = (unsigned int *)calloc(1, nBufferSize)) == NULL)
+ return err;
+
+ while (err == 0 && llMaxSize > 0) {
+ err = NVMEGetLogPage(nFD, ucLogID, (unsigned char *)pBuffer, nBufferSize);
+ if (err)
+ return err;
+
+ 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)
+{
+ struct nvme_admin_cmd cmd;
+ int err = 0;
+ unsigned char pTmpBuf[CommonChunkSize] = { 0 };
+ unsigned int uiMaxChunk = 0;
+ unsigned int uiXferDwords = 0;
+ int nBytesRead = 0;
+ unsigned char *pTempPtr = NULL;
+
+ uiMaxChunk = CommonChunkSize / 4;
+ pTempPtr = (unsigned char *)malloc(nBuffSize);
+ if (!pTempPtr) {
+ goto exit_status;
+ }
+ memset(pTempPtr, 0, nBuffSize);
+
+ while (nBytesRead < nBuffSize) {
+ int nBytesRemaining = nBuffSize - nBytesRead;
+
+ memset(pTmpBuf, 0, CommonChunkSize);
+
+ uiXferDwords = uiMaxChunk;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = 0x02;
+ cmd.cdw10 |= ucLogID;
+ cmd.cdw10 |= ((uiXferDwords - 1) & 0x0000FFFF) << 16;
+
+ if (nBytesRead > 0) {
+ unsigned long long ullOffset = (unsigned long long)nBytesRead;
+ cmd.cdw12 = ullOffset & 0xFFFFFFFF;
+ cmd.cdw13 = (ullOffset >> 32) & 0xFFFFFFFF;
+ }
+ cmd.nsid = 0xFFFFFFFF;
+ cmd.data_len = uiXferDwords * 4;
+ cmd.addr = (__u64) (uintptr_t) pTmpBuf;
+
+ err = nvme_submit_passthru(nFD, NVME_IOCTL_ADMIN_CMD, &cmd);
+
+ if (nBytesRemaining >= (int)(uiMaxChunk * 4)) {
+ memcpy(&pTempPtr[nBytesRead], pTmpBuf, uiMaxChunk * 4);
+ } else {
+ memcpy(&pTempPtr[nBytesRead], pTmpBuf, nBytesRemaining);
+ }
+
+ nBytesRead += (int)uiXferDwords *4;
+ }
+ *pBuffer = pTempPtr;
+
+ exit_status:
+ return err;
+}
+
+/*
+ * Plugin Commands
+ */
+
+static int micron_selective_download(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ const char *desc =
+ "This performs a selective firmware download, which allows the user to "
+ "select which firmware binary to update for 9200 devices. This requires a power cycle once the "
+ "update completes. The options available are: \n\n"
+ "OOB - This updates the OOB and main firmware\n"
+ "EEP - This updates the eeprom and main firmware\n"
+ "ALL - This updates the eeprom, OOB, and main firmware";
+ const char *fw = "firmware file (required)";
+ const char *select = "FW Select (e.g., --select=ALL)";
+ int xfer = 4096;
+ void *fw_buf;
+ int fd, selectNo, fw_fd, fw_size, err, offset = 0;
+ struct stat sb;
+
+ struct config {
+ char *fw;
+ char *select;
+ };
+
+ struct config cfg = {
+ .fw = "",
+ .select = "\0",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("fw", 'f', "FILE", &cfg.fw, fw),
+ OPT_STRING("select", 's', "flag", &cfg.select, select),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ return fd;
+
+ if (strlen(cfg.select) != 3) {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ cfg.select[i] = toupper(cfg.select[i]);
+ }
+
+ if (strncmp(cfg.select, "OOB", 3) == 0) {
+ selectNo = 18;
+ } else if (strncmp(cfg.select, "EEP", 3) == 0) {
+ selectNo = 10;
+ } else if (strncmp(cfg.select, "ALL", 3) == 0) {
+ selectNo = 26;
+ } else {
+ fprintf(stderr, "Invalid select flag\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ fw_fd = open(cfg.fw, O_RDONLY);
+ if (fw_fd < 0) {
+ fprintf(stderr, "no firmware file provided\n");
+ err = EINVAL;
+ goto out;
+ }
+
+ err = fstat(fw_fd, &sb);
+ if (err < 0) {
+ perror("fstat");
+ err = errno;
+ }
+
+ fw_size = sb.st_size;
+ if (fw_size & 0x3) {
+ fprintf(stderr, "Invalid size:%d for f/w image\n", fw_size);
+ err = EINVAL;
+ goto out;
+ }
+
+ if (posix_memalign(&fw_buf, getpagesize(), fw_size)) {
+ fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
+ err = ENOMEM;
+ goto out;
+ }
+
+ if (read(fw_fd, fw_buf, fw_size) != ((ssize_t) (fw_size)))
+ return EIO;
+
+ while (fw_size > 0) {
+ xfer = min(xfer, fw_size);
+
+ err = nvme_fw_download(fd, offset, xfer, fw_buf);
+ if (err < 0) {
+ perror("fw-download");
+ goto out;
+ } else if (err != 0) {
+ fprintf(stderr, "NVME Admin command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ goto out;
+ }
+ fw_buf += xfer;
+ fw_size -= xfer;
+ offset += xfer;
+ }
+
+ err = micron_fw_commit(fd, selectNo);
+
+ if (err == 0x10B || err == 0x20B) {
+ err = 0;
+ fprintf(stderr,
+ "Update successful! Please power cycle for changes to take effect\n");
+ }
+
+ out:
+ 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, fd = 0, err = 0;
+ unsigned int tempSensors[SensorCount] = { 0 };
+ const char *desc = "Retrieve Micron temperature info for the given device ";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ err = nvme_smart_log(fd, 0xffffffff, &smart_log);
+ if (!err) {
+ printf("Micron temperature information:\n");
+ temperature = ((smart_log.temperature[1] << 8) | smart_log.temperature[0]);
+ temperature = temperature ? temperature - 273 : 0;
+ for (i = 0; i < SensorCount; i++) {
+ tempSensors[i] = le16_to_cpu(smart_log.temp_sensor[i]);
+ tempSensors[i] = tempSensors[i] ? tempSensors[i] - 273 : 0;
+ }
+ printf("%-10s : %u C\n", "Current Composite Temperature", temperature);
+ for (i = 0; i < SensorCount; i++) {
+ printf("%-10s%d : %u C\n", "Temperature Sensor #", i + 1, tempSensors[i]);
+ }
+ }
+ return err;
+}
+
+static int micron_pcie_stats(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0, bus = 0, domain = 0, device = 0, function = 0;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ char *businfo = NULL;
+ char *devicename = NULL;
+ char tdevice[NAME_MAX] = { 0 };
+ ssize_t sLinkSize = 0;
+ FILE *fp;
+ char correctable[8] = { 0 };
+ char uncorrectable[8] = { 0 };
+ char *res;
+
+ if (argc != 2) {
+ printf("vs-pcie-stats: Invalid argument\n");
+ printf("Usage: nvme micron vs-pcie-stats <device>\n\n");
+ goto out;
+ }
+ if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
+ devicename = strrchr(argv[optind], '/');
+ } else if (strstr(argv[optind], "/dev/nvme")) {
+ devicename = strrchr(argv[optind], '/');
+ sprintf(tdevice, "%s%s", devicename, "n1");
+ devicename = tdevice;
+ } else {
+ printf("Invalid device specified!\n");
+ goto out;
+ }
+ sprintf(strTempFile, "/sys/block/%s/device", devicename);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ printf("Unable to read device\n");
+ goto out;
+ }
+ if (strstr(strTempFile2, "../../nvme")) {
+ sprintf(strTempFile, "/sys/block/%s/device/device", devicename);
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ printf("Unable to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+10.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (res == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x4.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(uncorrectable, sizeof(uncorrectable), fp);
+ if (res == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+ printf("PCIE Stats:\n");
+ printf("Device correctable errors detected: %s\n", correctable);
+ printf("Device uncorrectable errors detected: %s\n", uncorrectable);
+
+ out:
+ return err;
+}
+
+static int micron_clear_pcie_correctable_errors(int argc, char **argv,
+ struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0, bus = 0, domain = 0, device = 0, function = 0;
+ char strTempFile[1024], strTempFile2[1024], command[1024];
+ char *businfo = NULL;
+ char *devicename = NULL;
+ char tdevice[PATH_MAX] = { 0 };
+ ssize_t sLinkSize = 0;
+ FILE *fp;
+ char correctable[8] = { 0 };
+ char *res;
+
+ if (argc != 2) {
+ printf("clear-pcie-correctable-errors: Invalid argument\n");
+ printf ("Usage: nvme micron clear-pcie-correctable-errors <device>\n\n");
+ goto out;
+ }
+ if (strstr(argv[optind], "/dev/nvme") && strstr(argv[optind], "n1")) {
+ devicename = strrchr(argv[optind], '/');
+ } else if (strstr(argv[optind], "/dev/nvme")) {
+ devicename = strrchr(argv[optind], '/');
+ sprintf(tdevice, "%s%s", devicename, "n1");
+ devicename = tdevice;
+ } else {
+ printf("Invalid device specified!\n");
+ goto out;
+ }
+ err = snprintf(strTempFile, sizeof(strTempFile),
+ "/sys/block/%s/device", devicename);
+ if (err < 0)
+ goto out;
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ printf("Unable to read device\n");
+ goto out;
+ }
+ if (strstr(strTempFile2, "../../nvme")) {
+ err = snprintf(strTempFile, sizeof(strTempFile),
+ "/sys/block/%s/device/device", devicename);
+ if (err < 0)
+ goto out;
+ sLinkSize = readlink(strTempFile, strTempFile2, 1024);
+ if (sLinkSize < 0) {
+ printf("Unable to read device\n");
+ goto out;
+ }
+ }
+ businfo = strrchr(strTempFile2, '/');
+ sscanf(businfo, "/%x:%x:%x.%x", &domain, &bus, &device, &function);
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L=0xffffffff", bus,
+ device, function);
+
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Unable to clear error count\n");
+ goto out;
+ }
+ pclose(fp);
+
+ sprintf(command, "setpci -s %x:%x.%x ECAP_AER+0x10.L", bus, device,
+ function);
+ fp = popen(command, "r");
+ if (fp == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ res = fgets(correctable, sizeof(correctable), fp);
+ if (res == NULL) {
+ printf("Unable to retrieve error count\n");
+ goto out;
+ }
+ pclose(fp);
+ printf("Device correctable errors cleared!\n");
+ printf("Device correctable errors detected: %s\n", correctable);
+
+ out:
+ return err;
+}
+
+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[64] = { 0 };
+ struct nvme_id_ctrl ctrl;
+ int fd, err;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ goto out;
+
+ err = NVMEGetLogPage(fd, 0xD0, (unsigned char *)extSmartLog, D0_log_size);
+ if (err)
+ goto out;
+
+ unsigned long long count = ((unsigned long long)extSmartLog[45] << 32) | extSmartLog[44];
+ printf("%-40s : 0x%llx\n", "NAND Writes (Bytes Written)", count);
+ printf("%-40s : ", "Program Failure Count");
+
+ unsigned long long count_hi = ((unsigned long long)extSmartLog[39] << 32) | extSmartLog[38];
+ unsigned long long count_lo = ((unsigned long long)extSmartLog[37] << 32) | extSmartLog[36];
+ if (count_hi != 0)
+ printf("0x%llx%016llx", count_hi, count_lo);
+ else
+ printf("0x%llx\n", count_lo);
+
+ count = ((unsigned long long)extSmartLog[25] << 32) | extSmartLog[24];
+ printf("%-40s : 0x%llx\n", "Erase Failures", count);
+ printf("%-40s : 0x%x\n", "Bad Block Count", extSmartLog[3]);
+
+ count = (unsigned long long)extSmartLog[3] - (count_lo + count);
+ printf("%-40s : 0x%llx\n", "NAND XOR/RAID Recovery Trigger Events", count);
+ printf("%-40s : 0x%x\n", "NSZE Change Supported", (ctrl.oacs >> 3) & 0x1);
+ printf("%-40s : 0x%x\n", "Number of NSZE Modifications", extSmartLog[1]);
+ out:
+ close(fd);
+ return err;
+}
+
+typedef enum { M5410 = 0, M51AX, M51BX, UNKNOWN_MODEL } eDriveModel;
+
+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;
+
+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) {
+ ret = read(fd, idstr, sizeof(idstr));
+ close(fd);
+ }
+
+ if (fd < 0 || ret < 0)
+ perror(file);
+ else
+ *id = strtol(idstr, NULL, 16);
+
+ return ret;
+}
+
+static eDriveModel GetDriveModel(int idx)
+{
+ eDriveModel eModel = UNKNOWN_MODEL;
+ char path[512];
+
+ sprintf(path, fvendorid1, idx);
+ if (ReadSysFile(path, &vendor_id) < 0) {
+ sprintf(path, fvendorid2, idx);
+ ReadSysFile(path, &vendor_id);
+ }
+ sprintf(path, fdeviceid1, idx);
+ if (ReadSysFile(path, &device_id) < 0) {
+ sprintf(path, fdeviceid2, idx);
+ ReadSysFile(path, &device_id);
+ }
+
+ if (vendor_id == 0x1344) {
+ switch (device_id) {
+ case 0x5410:
+ eModel = M5410;
+ break;
+ case 0x51A0:
+ case 0x51A1:
+ case 0x51A2:
+ eModel = M51AX;
+ break;
+ case 0x51B0:
+ case 0x51B1:
+ case 0x51B2:
+ eModel = M51BX;
+ break;
+ default:
+ break;
+ }
+ }
+ return eModel;
+}
+
+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("Unable to create %s\n", tempFile);
+ free(strPDir);
+ return;
+ }
+
+ strncpy(model, ctrlp->mn, 40);
+ strncpy(serial, ctrlp->sn, 20);
+ strncpy(fwrev, ctrlp->fr, 8);
+
+ sprintf(strBuffer,
+ "********************\nDrive Info\n********************\n");
+
+ fprintf(fpOutFile, "%s", strBuffer);
+ sprintf(strBuffer,
+ "%-20s : /dev/nvme%d\n%-20s : %s\n%-20s : %-20s\n%-20s : %-20s\n",
+ "Device Name", nFD,
+ "Model No", (char *)model,
+ "Serial No", (char *)serial, "FW-Rev", (char *)fwrev);
+
+ fprintf(fpOutFile, "%s", strBuffer);
+
+ sprintf(strBuffer,
+ "\n********************\nPCI Info\n********************\n");
+
+ fprintf(fpOutFile, "%s", strBuffer);
+
+ sprintf(strBuffer,
+ "%-22s : %04X\n%-22s : %04X\n",
+ "VendorId", vendor_id, "DeviceId", device_id);
+ fprintf(fpOutFile, "%s", strBuffer);
+ fclose(fpOutFile);
+ free(strPDir);
+}
+
+static void GetTimestampInfo(const char *strOSDirName)
+{
+ char outstr[200];
+ time_t t;
+ struct tm *tmp;
+ FILE *fpOutFile = NULL;
+ size_t num;
+ char tempFolder[256] = { 0 };
+ char *strPDir;
+ char *strDest;
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (tmp == NULL)
+ return;
+
+ num = strftime(outstr, sizeof(outstr), "Timestamp (UTC): %a, %d %b %Y %T %z", tmp);
+ if (num) {
+ strPDir = strdup(strOSDirName);
+ strDest = dirname(strPDir);
+ sprintf(tempFolder, "%s/%s", strDest, "timestamp_info.txt");
+ fpOutFile = fopen(tempFolder, "wb");
+ if (fwrite(outstr, 1, num, fpOutFile) != num)
+ printf("Unable to write to %s file!", tempFolder);
+ if (fpOutFile)
+ fclose(fpOutFile);
+ free(strPDir);
+ }
+}
+
+static void GetCtrlIDDInfo(const char *strCtrlDirName, struct nvme_id_ctrl *ctrlp)
+{
+ char tempFolder[PATH_MAX] = { 0 };
+ FILE *fpOutFile;
+ sprintf(tempFolder, "%s/%s", strCtrlDirName,
+ "nvme_controller_identify_data.bin");
+ fpOutFile = fopen(tempFolder, "wb");
+ if (fwrite(ctrlp, 1, sizeof(*ctrlp), fpOutFile) != sizeof(*ctrlp))
+ printf("Unable to write controller data to %s file!", tempFolder);
+ if (fpOutFile)
+ fclose(fpOutFile);
+}
+
+static void GetSmartlogData(int fd, const char *strCtrlDirName)
+{
+ char tempFolder[PATH_MAX] = { 0 };
+ FILE *fpOutFile = NULL;
+ struct nvme_smart_log smart_log;
+ if (nvme_smart_log(fd, -1, &smart_log) == 0) {
+ sprintf(tempFolder, "%s/%s", strCtrlDirName, "smart_data.bin");
+ fpOutFile = fopen(tempFolder, "wb");
+ if (fwrite(&smart_log, 1, sizeof(smart_log), fpOutFile) != sizeof(smart_log))
+ printf("Unable to write smart log data to %s file!", tempFolder);
+ if (fpOutFile)
+ fclose(fpOutFile);
+ }
+}
+
+static void GetErrorlogData(int fd, int entries, const char *strCtrlDirName)
+{
+ char tempFolder[PATH_MAX] = { 0 };
+ FILE *fpOutFile = NULL;
+ int logSize = entries * sizeof(struct nvme_error_log_page);
+ struct nvme_error_log_page *error_log = (struct nvme_error_log_page *)calloc(1, logSize);
+
+ if (error_log == NULL)
+ return;
+
+ if (nvme_error_log(fd, entries, error_log) == 0) {
+ sprintf(tempFolder, "%s/%s", strCtrlDirName,
+ "error_information_log.bin");
+ fpOutFile = fopen(tempFolder, "wb");
+ if (fwrite(error_log, 1, logSize, fpOutFile) != logSize)
+ printf("Unable to write error log to %s file!", tempFolder);
+ if (fpOutFile)
+ fclose(fpOutFile);
+ }
+ free(error_log);
+}
+
+static void GetNSIDDInfo(int fd, const char *strCtrlDirName, int nsid)
+{
+ char tempFolder[256] = { 0 };
+ char strFileName[PATH_MAX] = { 0 };
+ FILE *fpOutFile = NULL;
+ struct nvme_id_ns ns;
+ if (nvme_identify_ns(fd, nsid, 0, &ns) == 0) {
+ sprintf(tempFolder, "identify_namespace_%d_data.bin.bin", nsid);
+ sprintf(strFileName, "%s/%s", strCtrlDirName, tempFolder);
+ fpOutFile = fopen(strFileName, "wb");
+ if (fwrite(&ns, 1, sizeof(ns), fpOutFile) != sizeof(ns))
+ printf("Unable to write controller data to %s file!", tempFolder);
+ if (fpOutFile)
+ fclose(fpOutFile);
+ }
+}
+
+static void GetOSConfig(const char *strOSDirName)
+{
+ FILE *fpOSConfig = NULL;
+ char strBuffer[1024], strTemp[1024];
+ char strFileName[PATH_MAX];
+ int i;
+
+ struct {
+ char *strcmdHeader;
+ char *strCommand;
+ } cmdArray[] = {
+ { (char *)"SYSTEM INFORMATION", (char *)"uname -a >> %s" },
+ { (char *)"LINUX KERNEL MODULE INFORMATION", (char *)"lsmod >> %s" },
+ { (char *)"LINUX SYSTEM MEMORY INFORMATION", (char *)"cat /proc/meminfo >> %s" },
+ { (char *)"SYSTEM INTERRUPT INFORMATION", (char *)"cat /proc/interrupts >> %s" },
+ { (char *)"CPU INFORMATION", (char *)"cat /proc/cpuinfo >> %s" },
+ { (char *)"IO MEMORY MAP INFORMATION", (char *)"cat /proc/iomem >> %s" },
+ { (char *)"MAJOR NUMBER AND DEVICE GROUP", (char *)"cat /proc/devices >> %s" },
+ { (char *)"KERNEL DMESG", (char *)"dmesg >> %s" },
+ { (char *)"/VAR/LOG/MESSAGES", (char *)"cat /var/log/messages >> %s" }
+ };
+
+ sprintf(strFileName, "%s/%s", strOSDirName, "os_config.txt");
+
+ for (i = 0; i < 7; i++) {
+ fpOSConfig = fopen(strFileName, "a+");
+ fprintf(fpOSConfig,
+ "\n\n\n\n%s\n-----------------------------------------------\n",
+ cmdArray[i].strcmdHeader);
+ if (NULL != fpOSConfig) {
+ fclose(fpOSConfig);
+ fpOSConfig = NULL;
+ }
+ strcpy(strTemp, cmdArray[i].strCommand);
+ sprintf(strBuffer, strTemp, strFileName);
+ if (system(strBuffer))
+ fprintf(stderr, "Failed to send \"%s\"\n", strBuffer);
+ }
+}
+
+static int micron_internal_logs(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+
+ int err = 0;
+ int fd;
+ int ctrlIdx;
+ FILE *fpOutFile = NULL;
+ char strOSDirName[1024];
+ char strCtrlDirName[1024];
+ char strMainDirName[256];
+ char tempFolder[PATH_MAX] = { 0 };
+ unsigned int *puiIDDBuf;
+ unsigned int uiMask;
+ struct nvme_id_ctrl ctrl;
+ char sn[20] = { 0 };
+
+ struct {
+ unsigned char ucLogPage;
+ const char *strFileName;
+ int nLogSize;
+ int nMaxSize;
+ } aVendorLogs[32] = {
+ { 0xC1, "nvmelog_C1.bin", 0, 0 },
+ { 0xC2, "nvmelog_C2.bin", 0, 0 },
+ { 0xC4, "nvmelog_C4.bin", 0, 0 },
+ { 0xC5, "nvmelog_C5.bin", C5_log_size, 0 },
+ { 0xD0, "nvmelog_D0.bin", D0_log_size, 0 },
+ { 0xE6, "nvmelog_E6.bin", 0, 0 },
+ { 0xE7, "nvmelog_E7.bin", 0, 0 }
+ },
+ aM51XXLogs[] = {
+ { 0xFB, "nvmelog_FB.bin", 4096, 0 }, /* this should be collected first for M51AX */
+ { 0xF7, "nvmelog_F7.bin", 4096, 512 * 1024 },
+ { 0xF8, "nvmelog_F8.bin", 4096, 512 * 1024 },
+ { 0xF9, "nvmelog_F9.bin", 4096, 200 * 1024 * 1024 },
+ { 0xFC, "nvmelog_FC.bin", 4096, 200 * 1024 * 1024 },
+ { 0xFD, "nvmelog_FD.bin", 4096, 80 * 1024 * 1024 }
+ },
+ aM51AXLogs[] = {
+ { 0xD0, "nvmelog_D0.bin", 512, 0 },
+ { 0xCA, "nvmelog_CA.bin", 512, 0 },
+ { 0xFA, "nvmelog_FA.bin", 4096, 15232 },
+ { 0xFE, "nvmelog_FE.bin", 4096, 512 * 1024 },
+ { 0xFF, "nvmelog_FF.bin", 4096, 162 * 1024 },
+ { 0x04, "changed_namespace_log.bin", 4096, 0 },
+ { 0x05, "command_effects_log.bin", 4096, 0 },
+ { 0x06, "drive_self_test.bin", 4096, 0 }
+ },
+ aM51BXLogs[] = {
+ { 0xFA, "nvmelog_FA.bin", 4096, 16376 },
+ { 0xFE, "nvmelog_FE.bin", 4096, 256 * 1024 },
+ { 0xFF, "nvmelog_FF.bin", 4096, 64 * 1024 },
+ { 0xCA, "nvmelog_CA.bin", 512, 1024 }
+ };
+
+ eDriveModel eModel;
+
+ const char *desc = "This retrieves the micron debug log package";
+ const char *package = "Log output package name (required)";
+ unsigned char *dataBuffer = NULL;
+ int bSize = 0;
+ int maxSize = 0;
+
+ struct config {
+ char *package;
+ };
+
+ struct config cfg = {
+ .package = ""
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("package", 'p', "FILE", &cfg.package, package),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (strlen(cfg.package) == 0) {
+ printf ("You must specify an output name for the log package. ie --p=logfiles.zip\n");
+ goto out;
+ }
+
+ if (fd < 0)
+ goto out;
+
+ /* pull log details based on the model name */
+ sscanf(argv[optind], "/dev/nvme%d", &ctrlIdx);
+ if ((eModel = GetDriveModel(ctrlIdx)) == UNKNOWN_MODEL) {
+ printf ("Unsupported drive model for vs-internal-log collection\n");
+ close(fd);
+ goto out;
+ }
+
+ printf("Preparing log package. This will take a few seconds...\n");
+ err = nvme_identify_ctrl(fd, &ctrl);
+ if (err)
+ goto out;
+
+ // trim spaces out of serial number string */
+ int i, j = 0;
+ for (i = 0; i < sizeof(ctrl.sn); i++) {
+ if (isblank(ctrl.sn[i]))
+ continue;
+ sn[j++] = ctrl.sn[i];
+ }
+ sn[j] = '\0';
+ strcpy(ctrl.sn, sn);
+
+ SetupDebugDataDirectories(ctrl.sn, cfg.package, strMainDirName, strOSDirName, strCtrlDirName);
+
+ GetTimestampInfo(strOSDirName);
+ GetCtrlIDDInfo(strCtrlDirName, &ctrl);
+ GetOSConfig(strOSDirName);
+ GetDriveInfo(strOSDirName, ctrlIdx, &ctrl);
+
+ for (int i = 1; i <= ctrl.nn; i++)
+ GetNSIDDInfo(fd, strCtrlDirName, i);
+
+ GetSmartlogData(fd, strCtrlDirName);
+ GetErrorlogData(fd, ctrl.elpe, strCtrlDirName);
+
+ if (eModel != M5410) {
+ memcpy(aVendorLogs, aM51XXLogs, sizeof(aM51XXLogs));
+ if (eModel == M51AX)
+ memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51AXLogs, sizeof(aM51AXLogs));
+ else
+ memcpy((char *)aVendorLogs + sizeof(aM51XXLogs), aM51BXLogs, sizeof(aM51BXLogs));
+ }
+
+ for (int i = 0; i < (int)(sizeof(aVendorLogs) / sizeof(aVendorLogs[0])) && aVendorLogs[i].ucLogPage != 0; i++) {
+ err = -1;
+ switch (aVendorLogs[i].ucLogPage) {
+ case 0xC1:
+ case 0xC2:
+ case 0xC4:
+ err = GetLogPageSize(fd, aVendorLogs[i].ucLogPage, &bSize);
+ if (err == 0 && bSize > 0)
+ err = GetCommonLogPage(fd, aVendorLogs[i].ucLogPage, &dataBuffer, bSize);
+ break;
+
+ case 0xE6:
+ case 0xE7:
+ puiIDDBuf = (unsigned int *)&ctrl;
+ uiMask = puiIDDBuf[1015];
+ if (uiMask == 0 || (aVendorLogs[i].ucLogPage == 0xE6 && uiMask == 2) || (aVendorLogs[i].ucLogPage == 0xE7
+ && uiMask == 1)) {
+ bSize = 0;
+ } else {
+ bSize = (int)puiIDDBuf[1015];
+ if (bSize % (16 * 1024)) {
+ bSize += (16 * 1024) - (bSize % (16 * 1024));
+ }
+ }
+ if (bSize != 0) {
+ dataBuffer = (unsigned char *)malloc(bSize);
+ memset(dataBuffer, 0, bSize);
+ err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
+ }
+ break;
+
+ case 0xF7:
+ case 0xF9:
+ case 0xFC:
+ case 0xFD:
+ if (eModel == M51BX)
+ (void)NVMEResetLog(fd, aVendorLogs[i].ucLogPage, aVendorLogs[i].nLogSize, aVendorLogs[i].nMaxSize);
+ default:
+ bSize = aVendorLogs[i].nLogSize;
+ dataBuffer = (unsigned char *)malloc(bSize);
+ memset(dataBuffer, 0, bSize);
+ err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
+ maxSize = aVendorLogs[i].nMaxSize - bSize;
+ while (err == 0 && maxSize > 0 && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
+ sprintf(tempFolder, "%s/%s", strCtrlDirName,
+ aVendorLogs[i].strFileName);
+ fpOutFile = fopen(tempFolder, "ab+");
+ if (fwrite(dataBuffer, 1, bSize, fpOutFile) != bSize) {
+ printf ("Unable to write log to file %s\n!", aVendorLogs[i].strFileName);
+ }
+ if (fpOutFile)
+ fclose(fpOutFile);
+ err = NVMEGetLogPage(fd, aVendorLogs[i].ucLogPage, dataBuffer, bSize);
+ if (err || (((unsigned int *)dataBuffer)[0] == 0xdeadbeef))
+ break;
+ maxSize -= bSize;
+ }
+ break;
+ }
+
+ if (err == 0 && dataBuffer != NULL && ((unsigned int *)dataBuffer)[0] != 0xdeadbeef) {
+ sprintf(tempFolder, "%s/%s", strCtrlDirName,
+ aVendorLogs[i].strFileName);
+ fpOutFile = fopen(tempFolder, "ab+");
+ if (fwrite(dataBuffer, 1, bSize, fpOutFile) != bSize) {
+ printf("Unable to write log to file %s\n!", aVendorLogs[i].strFileName);
+ }
+ if (fpOutFile)
+ fclose(fpOutFile);
+ }
+
+ if (dataBuffer != NULL) {
+ free(dataBuffer);
+ dataBuffer = NULL;
+ }
+ }
+
+ ZipAndRemoveDir(strMainDirName, cfg.package);
+ out:
+ return err;
+}
diff --git a/plugins/micron/micron-nvme.h b/plugins/micron/micron-nvme.h
new file mode 100644
index 0000000..add36e4
--- /dev/null
+++ b/plugins/micron/micron-nvme.h
@@ -0,0 +1,21 @@
+#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"),
+ 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-nand-stats", "Retrieve NAND Stats", micron_nand_stats)
+ )
+);
+
+#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..a942f57
--- /dev/null
+++ b/plugins/netapp/netapp-nvme.c
@@ -0,0 +1,639 @@
+/*
+* 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 <sys/ioctl.h>
+
+#include "nvme.h"
+#include "nvme-ioctl.h"
+#include "json.h"
+
+#include "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 {
+ int nsid;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_id_ns ns;
+ char dev[265];
+};
+
+struct ontapdevice_info {
+ int nsid;
+ struct nvme_id_ctrl ctrl;
+ struct nvme_id_ns ns;
+ char nsdesc[4096];
+ 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, long long *lba,
+ struct nvme_id_ns *ns)
+{
+ *lba = 1 << ns->lbaf[(ns->flbas & 0x0F)].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 netapp_uuid_to_str(char *str, void *data)
+{
+#ifdef LIBUUID
+ uuid_t uuid;
+ struct nvme_ns_id_desc *desc = data;
+
+ memcpy(uuid, data + sizeof(*desc), 16);
+ uuid_unparse_lower(uuid, str);
+#endif
+}
+
+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_array *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_array *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_array *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 */
+
+ 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++) {
+ long long int lba = 1 << devices[i].ns.lbaf[(devices[i].ns.flbas & 0x0F)].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);
+ }
+}
+
+static void netapp_ontapdevices_print(struct ontapdevice_info *devices,
+ int count, int format)
+{
+ struct json_object *root = NULL;
+ struct json_array *json_devices = NULL;
+ char vsname[ONTAP_LABEL_LEN] = " ";
+ char nspath[ONTAP_NS_PATHLEN] = " ";
+ 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);
+ netapp_uuid_to_str(uuid_str, devices[i].nsdesc);
+ 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);
+ }
+}
+
+static int nvme_get_ontap_c2_log(int fd, __u32 nsid, void *buf, __u32 buflen)
+{
+ struct nvme_admin_cmd get_log;
+ int err;
+
+ memset(buf, 0, buflen);
+ memset(&get_log, 0, sizeof(struct nvme_admin_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);
+ 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,
+ strerror(err));
+ return 0;
+ }
+
+ if (strncmp("NetApp E-Series", item->ctrl.mn, 15) != 0)
+ return 0; /* not the right model of controller */
+
+ item->nsid = nvme_get_nsid(fd);
+ err = nvme_identify_ns(fd, item->nsid, 0, &item->ns);
+ if (err) {
+ fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
+ dev, strerror(err));
+ return 0;
+ }
+ strncpy(item->dev, dev, sizeof(item->dev));
+
+ return 1;
+}
+
+static int netapp_ontapdevices_get_info(int fd, struct ontapdevice_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, strerror(err));
+ return 0;
+ }
+
+ if (strncmp("NetApp ONTAP Controller", item->ctrl.mn, 23) != 0)
+ /* not the right controller model */
+ return 0;
+
+ item->nsid = nvme_get_nsid(fd);
+
+ err = nvme_identify_ns(fd, item->nsid, 0, &item->ns);
+ if (err) {
+ fprintf(stderr, "Unable to identify namespace for %s (%s)\n",
+ dev, strerror(err));
+ return 0;
+ }
+
+ err = nvme_identify_ns_descs(fd, item->nsid, item->nsdesc);
+ if (err) {
+ fprintf(stderr, "Unable to identify namespace descriptor for %s (%s)\n",
+ dev, strerror(err));
+ return 0;
+ }
+
+ 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, strerror(err));
+ return 0;
+ }
+
+ strncpy(item->dev, dev, sizeof(item->dev));
+
+ 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..d4eebd6
--- /dev/null
+++ b/plugins/netapp/netapp-nvme.h
@@ -0,0 +1,18 @@
+#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"),
+ COMMAND_LIST(
+ ENTRY("smdevices", "NetApp SMdevices", netapp_smdevices)
+ ENTRY("ontapdevices", "NetApp ONTAPdevices", netapp_ontapdevices)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/scaleflux/sfx-nvme.c b/plugins/scaleflux/sfx-nvme.c
new file mode 100644
index 0000000..846ca77
--- /dev/null
+++ b/plugins/scaleflux/sfx-nvme.c
@@ -0,0 +1,873 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/fs.h>
+#include <inttypes.h>
+#include <asm/byteorder.h>
+#include <sys/ioctl.h>
+#include <sys/sysinfo.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "nvme-status.h"
+#include "json.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.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 IDEMA_CAP(exp_GB) (((__u64)exp_GB - 50ULL) * 1953504ULL + 97696368ULL)
+
+
+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,
+};
+
+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 */
+};
+
+struct nvme_capacity_info {
+ __u64 lba_sec_sz;
+ __u64 phy_sec_sz;
+ __u64 used_space;
+ __u64 free_space;
+};
+struct __attribute__((packed)) nvme_additional_smart_log_item {
+ uint8_t key;
+ uint8_t _kp[2];
+ uint8_t norm;
+ uint8_t _np;
+ union {
+ uint8_t raw[6];
+ struct wear_level {
+ uint16_t min;
+ uint16_t max;
+ uint16_t avg;
+ } wear_level ;
+ struct thermal_throttle {
+ uint8_t pct;
+ uint32_t count;
+ } thermal_throttle;
+ };
+ uint8_t _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
+};
+
+int nvme_change_cap(int fd, __u32 nsid, __u64 capacity)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_change_cap,
+ .nsid = nsid,
+ .cdw10 = (capacity & 0xffffffff),
+ .cdw11 = (capacity >> 32),
+ };
+
+
+ return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd);
+}
+
+int nvme_sfx_set_features(int fd, __u32 nsid, __u32 fid, __u32 value)
+{
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_sfx_set_features,
+ .nsid = nsid,
+ .cdw10 = fid,
+ .cdw11 = value,
+ };
+
+ return nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd);
+}
+
+int nvme_sfx_get_features(int fd, __u32 nsid, __u32 fid, __u32 *result)
+{
+ int err = 0;
+ struct nvme_admin_cmd cmd = {
+ .opcode = nvme_admin_sfx_get_features,
+ .nsid = nsid,
+ .cdw10 = fid,
+ };
+
+ err = nvme_submit_passthru(fd, NVME_IOCTL_ADMIN_CMD,&cmd);
+ 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);
+
+ 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));
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct nvme_additional_smart_log smart_log;
+ int err, fd;
+ 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 config {
+ __u32 namespace_id;
+ int raw_binary;
+ int json;
+ };
+
+ 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()
+ };
+
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false, sizeof(smart_log),
+ (void *)&smart_log);
+ if (!err) {
+ if (cfg.json)
+ show_sfx_smart_log_jsn(&smart_log, cfg.namespace_id, devicename);
+ else if (!cfg.raw_binary)
+ show_sfx_smart_log(&smart_log, cfg.namespace_id, devicename);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+}
+
+
+struct sfx_lat_stats {
+ __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+ */
+};
+
+static void show_lat_stats(struct sfx_lat_stats *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 int get_lat_stats_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct sfx_lat_stats stats;
+ int err, fd;
+
+ 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 config {
+ int raw_binary;
+ int write;
+ };
+
+ struct config cfg = {
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("write", 'w', &cfg.write, write),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ err = nvme_get_log(fd, 0xffffffff, cfg.write ? 0xc3 : 0xc1, false, sizeof(stats), (void *)&stats);
+ if (!err) {
+ if (!cfg.raw_binary)
+ show_lat_stats(&stats, cfg.write);
+ else
+ d_raw((unsigned char *)&stats, sizeof(stats));
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ return err;
+}
+
+int sfx_nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
+{
+ struct nvme_admin_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);
+}
+
+/**
+ * @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%llx", *(bb_elem++));
+ i++;
+ }
+ printf(" ]\n");
+
+ printf("REMAP_GBB_TABLE [");
+ i = 0;
+ while (bb_elem < elem_end && i < remap_gbb_count) {
+ printf(" 0x%llx",*(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)
+{
+ int fd;
+ unsigned char *data_buf;
+ const __u64 buf_size = 256*4096*sizeof(unsigned char);
+ int err = 0;
+
+ char *desc = "Get bad block table of sfx block device.";
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0) {
+ return fd;
+ }
+
+ data_buf = malloc(buf_size);
+ if (!data_buf) {
+ fprintf(stderr, "malloc fail, errno %d\r\n", errno);
+ return -1;
+ }
+
+ err = get_bb_table(fd, 0xffffffff, data_buf, buf_size);
+ if (err < 0) {
+ perror("get-bad-block");
+ } else if (err != 0) {
+ fprintf(stderr, "NVMe IO command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ } else {
+ bd_table_show(data_buf, buf_size);
+ printf("ScaleFlux get bad block table: success\n");
+ }
+
+ free(data_buf);
+ return 0;
+}
+
+static void show_cap_info(struct sfx_freespace_ctx *ctx)
+{
+ printf("user sectors: %#llx\n", ctx->user_space);
+ printf("totl physical sectors: %#llx\n", ctx->phy_space);
+ printf("free physical sectors: %#llx\n", ctx->free_space);
+ printf("used physical sectors: %#llx\n", ctx->phy_space - ctx->free_space);
+}
+
+static int query_cap_info(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ struct sfx_freespace_ctx ctx = { 0 };
+ int err = 0, fd;
+ char *desc = "query current capacity info of vanda";
+ const char *raw = "dump output in binary format";
+ const char *json= "Dump output in json format";
+ struct config {
+ int raw_binary;
+ int json;
+ };
+ struct config cfg;
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("json", 'j', &cfg.json, json),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
+
+ if (ioctl(fd, SFX_GET_FREESPACE, &ctx)) {
+ fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno);
+ return -1;
+ }
+
+ show_cap_info(&ctx);
+ return err;
+}
+
+static int change_cap_mem_check(int fd, __u64 trg_in_4k)
+{
+ struct sfx_freespace_ctx freespace_ctx = { 0 };
+ struct sysinfo s_info;
+ __u64 mem_need = 0;
+ __u64 cur_in_4k = 0;
+ __u32 cnt_ms = 0;
+
+ while (ioctl(fd, SFX_GET_FREESPACE, &freespace_ctx)) {
+ if (cnt_ms++ > 600) {//1min
+ fprintf(stderr, "vu ioctl fail, errno %d\r\n", errno);
+ return -1;
+ }
+ usleep(100000);
+ }
+
+ cur_in_4k = freespace_ctx.user_space >> (SFX_PAGE_SHIFT - SECTOR_SHIFT);
+ if (cur_in_4k > trg_in_4k) {
+ return 0;
+ }
+
+ 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: mem needed is %llu, free mem is %lu\n"
+ "Insufficient memory, please drop cache or add free memory and retry\n",
+ mem_need, s_info.freeram);
+ return -1;
+ }
+ return 0;
+}
+
+static int change_cap(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = -1, fd;
+ char *desc = "query current capacity info of vanda";
+ const char *raw = "dump output in binary format";
+ const char *json= "Dump output in json format";
+ 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";
+ __u64 cap_in_4k = 0;
+ __u64 cap_in_sec = 0;
+ struct config {
+ __u64 cap_in_byte;
+ __u32 capacity_in_gb;
+ int raw_binary;
+ int json;
+ int 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_UINT("cap-byte", 'z', &cfg.cap_in_byte, cap_byte),
+ OPT_FLAG("force", 'f', &cfg.force, force),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_FLAG("json", 'j', &cfg.json, json),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
+
+ if (!cfg.force) {
+ fprintf(stderr, "WARNING: Changing capacity may irrevocably delete user data.\n"
+ "You have 10 seconds to press Ctrl-C to cancel this operation.\n\n"
+ "Use the force [--force|-f] option to suppress this warning.\n");
+ sleep(10);
+ fprintf(stderr, "Sending operation ... \n");
+ }
+
+ cap_in_sec = IDEMA_CAP(cfg.capacity_in_gb);
+ cap_in_4k = cap_in_sec >> 3;
+ if (cfg.cap_in_byte)
+ cap_in_4k = cfg.cap_in_byte >> 12;
+ printf("%dG %lluB %llu 4K\n",
+ cfg.capacity_in_gb, cfg.cap_in_byte, cap_in_4k);
+ if (change_cap_mem_check(fd, cap_in_4k))
+ return err;
+
+ err = nvme_change_cap(fd, 0xffffffff, cap_in_4k);
+ if (err < 0)
+ perror("sfx-change-cap");
+ else if (err != 0)
+ fprintf(stderr, "NVMe IO command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else {
+ printf("ScaleFlux change-capacity: success\n");
+ if(ioctl(fd, BLKRRPART) < 0) {
+ fprintf(stderr, "failed to re-read partition table\n");
+ err = EFAULT;
+ }
+ }
+ return err;
+}
+
+char *sfx_feature_to_string(int feature)
+{
+ switch (feature) {
+ case SFX_FEAT_ATOMIC: return "ATOMIC";
+
+ default: return "Unknown";
+ }
+}
+
+static int sfx_set_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0, fd;
+ char *desc = "ScaleFlux internal set features\n"
+ "feature id 1: ATOMIC";
+ const char *value = "new value of feature (required)";
+ const char *feature_id = "hex feature name (required)";
+ const char *namespace_id = "desired namespace";
+ struct nvme_id_ns ns;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ };
+ struct config cfg = {
+ .namespace_id = 1,
+ .feature_id = 0,
+ .value = 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_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ return fd;
+ }
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ return EINVAL;
+ }
+
+ if (cfg.feature_id == SFX_FEAT_ATOMIC) {
+ if (cfg.namespace_id != 0xffffffff) {
+ err = nvme_identify_ns(fd, cfg.namespace_id, 0, &ns);
+ if (err) {
+ if (err < 0)
+ perror("identify-namespace");
+ else
+ fprintf(stderr,
+ "NVMe Admin command error:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ 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");
+ return EFAULT;
+ }
+ }
+ }
+
+ err = nvme_sfx_set_features(fd, cfg.namespace_id, cfg.feature_id, cfg.value);
+ if (err < 0) {
+ perror("ScaleFlux-set-feature");
+ return errno;
+ } else if (!err) {
+ printf("ScaleFlux set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ sfx_feature_to_string(cfg.feature_id), cfg.value);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+ return err;
+}
+
+static int sfx_get_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0, fd;
+ 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";
+ __u32 result = 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0) {
+ return fd;
+ }
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ return EINVAL;
+ }
+
+ err = nvme_sfx_get_features(fd, cfg.namespace_id, cfg.feature_id, &result);
+ if (err < 0) {
+ perror("ScaleFlux-get-feature");
+ 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+ return err;
+
+}
diff --git a/plugins/scaleflux/sfx-nvme.h b/plugins/scaleflux/sfx-nvme.h
new file mode 100644
index 0000000..daf9c33
--- /dev/null
+++ b/plugins/scaleflux/sfx-nvme.h
@@ -0,0 +1,25 @@
+#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"),
+ 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)
+ )
+);
+
+#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..3dc2df7
--- /dev/null
+++ b/plugins/seagate/seagate-diag.h
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+
+#ifndef SEAGATE_NVME_H
+#define SEAGATE_NVME_H
+
+#define SEAGATE_PLUGIN_VERSION_MAJOR 1
+#define SEAGATE_PLUGIN_VERSION_MINOR 1
+
+#define PERSIST_FILE_SIZE (2764800)
+#define ONE_MB (1048576) /* (1024 * 1024) */
+#define PERSIST_CHUNK (65536) /* (1024 * 64) */
+#define FOUR_KB (4096)
+
+
+/***************************
+*Supported Log-Pages from FW
+***************************/
+
+typedef struct 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 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
+***************************/
+#pragma pack(1)
+#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 _SmartVendorSpecific
+{
+ __u8 AttributeNumber;
+ __u16 SmartStatus;
+ __u8 NominalValue;
+ __u8 LifetimeWorstValue;
+ __u32 Raw0_3;
+ __u8 RawHigh[3];
+} SmartVendorSpecific;
+
+typedef struct _EXTENDED_SMART_INFO_T
+{
+ __u16 Version;
+ SmartVendorSpecific vendorData[NUMBER_EXTENDED_SMART_ATTRIBUTES];
+ __u8 vendor_specific_reserved[6];
+} EXTENDED_SMART_INFO_T;
+
+typedef struct vendor_smart_attribute_data
+{
+ __u8 AttributeNumber; /* 00 */
+ __u8 Rsvd[3]; /* 01 -03 */
+ __u32 LSDword; /* 04-07 */
+ __u32 MSDword; /* 08 - 11 */
+} vendor_smart_attribute_data;
+
+struct 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 _U128
+{
+ __u64 LS__u64;
+ __u64 MS__u64;
+} U128;
+
+typedef struct _vendor_log_page_CF_Attr
+{
+ __u16 SuperCapCurrentTemperature; /* 00-01 */
+ __u16 SuperCapMaximumTemperature; /* 02-03 */
+ __u8 SuperCapStatus; /* 04 */
+ __u8 Reserved5to7[3]; /* 05-07 */
+ U128 DataUnitsReadToDramNamespace; /* 08-23 */
+ U128 DataUnitsWrittenToDramNamespace; /* 24-39 */
+ __u64 DramCorrectableErrorCount; /* 40-47 */
+ __u64 DramUncorrectableErrorCount; /* 48-55 */
+}vendor_log_page_CF_Attr;
+
+typedef struct _vendor_log_page_CF
+{
+ vendor_log_page_CF_Attr AttrCF;
+ __u8 Vendor_Specific_Reserved[ 456 ]; /* 56-511 */
+}vendor_log_page_CF;
+
+#pragma pack()
+/* EOF Extended-SMART Information*/
+
+
+/**************************
+* PCIE ERROR INFORMATION
+**************************/
+typedef struct 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 */
+
+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 362-372 */
+ VS_ATTR_LIFETIME_WRITES1_TO_FLASH, /* 31 374-385 */
+ VS_ATTR_LIFETIME_WRITES0_FROM_HOST, /* 32 386-397 */
+ VS_ATTR_LIFETIME_WRITES1_FROM_HOST, /* 33 398-409 */
+ VS_ATTR_LIFETIME_READ0_FROM_HOST, /* 34 410-421 */
+ VS_ATTR_LIFETIME_READ1_FROM_HOST, /* 35 422-433 */
+ VS_ATTR_PCIE_PHY_CRC_ERROR, /* 36 434-445 */
+ VS_ATTR_BAD_BLOCK_COUNT_SYSTEM, /* 37 446-457 */
+ VS_ATTR_BAD_BLOCK_COUNT_USER, /* 38 458-469 */
+ VS_ATTR_THERMAL_THROTTLING_STATUS, /* 39 470-481 */
+ VS_ATTR_POWER_CONSUMPTION, /* 40 482-493 */
+ VS_ATTR_MAX_SOC_LIFE_TEMPERATURE, /* 41 494-505 */
+
+ 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..7ba14f8
--- /dev/null
+++ b/plugins/seagate/seagate-nvme.c
@@ -0,0 +1,1397 @@
+/*
+ * 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.
+ */
+
+
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include "linux/nvme_ioctl.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "argconfig.h"
+#include "suffix.h"
+#include "json.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";
+ break;
+ case 0x02:
+ return "SMART_INFORMATION";
+ break;
+ case 0x03:
+ return "FW_SLOT_INFORMATION";
+ break;
+ case 0x04:
+ return "CHANGED_NAMESPACE_LIST";
+ break;
+ case 0x05:
+ return "COMMANDS_SUPPORTED_AND_EFFECTS";
+ break;
+ case 0x06:
+ return "DEVICE_SELF_TEST";
+ break;
+ case 0x07:
+ return "TELEMETRY_HOST_INITIATED";
+ break;
+ case 0x08:
+ return "TELEMETRY_CONTROLLER_INITIATED";
+ break;
+ case 0xC0:
+ return "VS_MEDIA_SMART_LOG";
+ break;
+ case 0xC1:
+ return "VS_DEBUG_LOG1";
+ break;
+ case 0xC2:
+ return "VS_SEC_ERROR_LOG_PAGE";
+ break;
+ case 0xC3:
+ return "VS_LIFE_TIME_DRIVE_HISTORY";
+ break;
+ case 0xC4:
+ return "VS_EXTENDED_SMART_INFO";
+ break;
+ case 0xC5:
+ return "VS_LIST_SUPPORTED_LOG_PAGE";
+ break;
+ case 0xC6:
+ return "VS_POWER_MONITOR_LOG_PAGE";
+ break;
+ case 0xC7:
+ return "VS_CRITICAL_EVENT_LOG_PAGE";
+ break;
+ case 0xC8:
+ return "VS_RECENT_DRIVE_HISTORY";
+ break;
+ case 0xC9:
+ return "VS_SEC_ERROR_LOG_PAGE";
+ break;
+ case 0xCA:
+ return "VS_LIFE_TIME_DRIVE_HISTORY";
+ break;
+ case 0xCB:
+ return "VS_PCIE_ERROR_LOG_PAGE";
+ break;
+ case 0xCF:
+ return "DRAM Supercap SMART Attributes";
+ break;
+ case 0xD6:
+ return "VS_OEM2_WORK_LOAD";
+ break;
+ case 0xD7:
+ return "VS_OEM2_FW_SECURITY";
+ break;
+ case 0xD8:
+ return "VS_OEM2_REVISION";
+ break;
+ default:
+ return "UNKNOWN";
+ break;
+ }
+}
+
+
+static void json_log_pages_supp(log_page_map *logPageMap)
+{
+ struct json_object *root;
+ struct json_array *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);
+ printf("\n");
+}
+
+static int log_pages_supp(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err = 0;
+ int fd = 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";
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ err = nvme_get_log(fd, 1, 0xc5, false, 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ 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";
+ break;
+ case VS_ATTR_ID_REALLOCATED_SECTOR_COUNT:
+ return "Bad NAND block count";
+ break;
+ case VS_ATTR_ID_POWER_ON_HOURS:
+ return "Power On Hours";
+ break;
+ case VS_ATTR_ID_POWER_FAIL_EVENT_COUNT:
+ return "Power Fail Event Count";
+ break;
+ case VS_ATTR_ID_DEVICE_POWER_CYCLE_COUNT:
+ return "Device Power Cycle Count";
+ break;
+ case VS_ATTR_ID_RAW_READ_ERROR_RATE:
+ return "Raw Read Error Count";
+ break;
+ case VS_ATTR_ID_GROWN_BAD_BLOCK_COUNT:
+ return "Bad NAND block count";
+ break;
+ case VS_ATTR_ID_END_2_END_CORRECTION_COUNT:
+ return "SSD End to end correction counts";
+ break;
+ case VS_ATTR_ID_MIN_MAX_WEAR_RANGE_COUNT:
+ return "User data erase counts";
+ break;
+ case VS_ATTR_ID_REFRESH_COUNT:
+ return "Refresh count";
+ break;
+ case VS_ATTR_ID_BAD_BLOCK_COUNT_USER:
+ return "User data erase fail count";
+ break;
+ case VS_ATTR_ID_BAD_BLOCK_COUNT_SYSTEM:
+ return "System area erase fail count";
+ break;
+ case VS_ATTR_ID_THERMAL_THROTTLING_STATUS:
+ return "Thermal throttling status and count";
+ break;
+ case VS_ATTR_ID_ALL_PCIE_CORRECTABLE_ERROR_COUNT:
+ return "PCIe Correctable Error count";
+ break;
+ case VS_ATTR_ID_ALL_PCIE_UNCORRECTABLE_ERROR_COUNT:
+ return "PCIe Uncorrectable Error count";
+ break;
+ case VS_ATTR_ID_INCOMPLETE_SHUTDOWN_COUNT:
+ return "Incomplete shutdowns";
+ break;
+ case VS_ATTR_ID_GB_ERASED_LSB:
+ return "LSB of Flash GB erased";
+ break;
+ case VS_ATTR_ID_GB_ERASED_MSB:
+ return "MSB of Flash GB erased";
+ break;
+ case VS_ATTR_ID_LIFETIME_DEVSLEEP_EXIT_COUNT:
+ return "LIFETIME_DEV_SLEEP_EXIT_COUNT";
+ break;
+ case VS_ATTR_ID_LIFETIME_ENTERING_PS4_COUNT:
+ return "LIFETIME_ENTERING_PS4_COUNT";
+ break;
+ case VS_ATTR_ID_LIFETIME_ENTERING_PS3_COUNT:
+ return "LIFETIME_ENTERING_PS3_COUNT";
+ break;
+ case VS_ATTR_ID_RETIRED_BLOCK_COUNT:
+ return "Retired block count"; /*VS_ATTR_ID_RETIRED_BLOCK_COUNT*/
+ break;
+ case VS_ATTR_ID_PROGRAM_FAILURE_COUNT:
+ return "Program fail count";
+ break;
+ case VS_ATTR_ID_ERASE_FAIL_COUNT:
+ return "Erase Fail Count";
+ break;
+ case VS_ATTR_ID_AVG_ERASE_COUNT:
+ return "System data % used";
+ break;
+ case VS_ATTR_ID_UNEXPECTED_POWER_LOSS_COUNT:
+ return "Unexpected power loss count";
+ break;
+ case VS_ATTR_ID_WEAR_RANGE_DELTA:
+ return "Wear range delta";
+ break;
+ case VS_ATTR_ID_SATA_INTERFACE_DOWNSHIFT_COUNT:
+ return "PCIE_INTF_DOWNSHIFT_COUNT";
+ break;
+ case VS_ATTR_ID_END_TO_END_CRC_ERROR_COUNT:
+ return "E2E_CRC_ERROR_COUNT";
+ break;
+ case VS_ATTR_ID_UNCORRECTABLE_READ_ERRORS:
+ return "Uncorrectable Read Error Count";
+ break;
+ case VS_ATTR_ID_MAX_LIFE_TEMPERATURE:
+ return "Max lifetime temperature";/*VS_ATTR_ID_MAX_LIFE_TEMPERATURE for extended*/
+ break;
+ case VS_ATTR_ID_RAISE_ECC_CORRECTABLE_ERROR_COUNT:
+ return "RAIS_ECC_CORRECT_ERR_COUNT";
+ break;
+ case VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS:
+ return "Uncorrectable read error count";/*VS_ATTR_ID_UNCORRECTABLE_RAISE_ERRORS*/
+ break;
+ case VS_ATTR_ID_DRIVE_LIFE_PROTECTION_STATUS:
+ return "DRIVE_LIFE_PROTECTION_STATUS";
+ break;
+ case VS_ATTR_ID_REMAINING_SSD_LIFE:
+ return "Remaining SSD life";
+ break;
+ case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_LSB:
+ return "LSB of Physical (NAND) bytes written";
+ break;
+ case VS_ATTR_ID_LIFETIME_WRITES_TO_FLASH_MSB:
+ return "MSB of Physical (NAND) bytes written";
+ break;
+ case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_LSB:
+ return "LSB of Physical (HOST) bytes written";
+ break;
+ case VS_ATTR_ID_LIFETIME_WRITES_FROM_HOST_MSB:
+ return "MSB of Physical (HOST) bytes written";
+ break;
+ case VS_ATTR_ID_LIFETIME_READS_TO_HOST_LSB:
+ return "LSB of Physical (NAND) bytes read";
+ break;
+ case VS_ATTR_ID_LIFETIME_READS_TO_HOST_MSB:
+ return "MSB of Physical (NAND) bytes read";
+ break;
+ case VS_ATTR_ID_FREE_SPACE:
+ return "Free Space";
+ break;
+ case VS_ATTR_ID_TRIM_COUNT_LSB:
+ return "LSB of Trim count";
+ break;
+ case VS_ATTR_ID_TRIM_COUNT_MSB:
+ return "MSB of Trim count";
+ break;
+ case VS_ATTR_ID_OP_PERCENTAGE:
+ return "OP percentage";
+ break;
+ case VS_ATTR_ID_MAX_SOC_LIFE_TEMPERATURE:
+ return "Max lifetime SOC temperature";
+ break;
+ 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 != 0) && (hideAttr != 1)) {
+ printf("%-40s", print_ext_smart_id(attr.AttributeNumber));
+ printf("%-15d", attr.AttributeNumber );
+ printf(" 0x%016"PRIx64"", (uint64_t)smart_attribute_vs(verNo, attr));
+ printf("\n");
+ }
+
+ 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", buf);
+ printf("\n");
+
+ 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", buf);
+ printf("\n");
+
+ 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", buf);
+ printf("\n");
+
+ 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", buf);
+ printf("\n");
+
+ 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", buf);
+ printf("\n");
+
+ }
+}
+
+static void json_print_smart_log(struct json_object *root,
+ EXTENDED_SMART_INFO_T *ExtdSMARTInfo )
+{
+ /*struct json_object *root; */
+ struct json_array *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};
+
+ /*root = json_create_object();*/
+ 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 != 0) {
+ 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);
+
+ /*
+ json_print_object(root, NULL);
+ printf("\n");
+ */
+}
+
+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;
+ /*currentTemp = currentTemp ? currentTemp - 273 : 0;*/
+ printf(" 0x%016"PRIx64"", le64_to_cpu(currentTemp));
+ printf("\n");
+
+ maxTemp = pLogPageCF->AttrCF.SuperCapMaximumTemperature;
+ /*maxTemp = maxTemp ? maxTemp - 273 : 0;*/
+ printf("%-40s", "Super-cap maximum temperature");
+ printf(" 0x%016"PRIx64"", le64_to_cpu(maxTemp));
+ printf("\n");
+
+ printf("%-40s", "Super-cap status");
+ printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.SuperCapStatus));
+ printf("\n");
+
+ printf("%-40s", "Data units read to DRAM namespace");
+ printf(" 0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsReadToDramNamespace.LS__u64));
+ printf("\n");
+
+ printf("%-40s", "Data units written to DRAM namespace");
+ printf(" 0x%016"PRIx64"%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.MS__u64),
+ le64_to_cpu(pLogPageCF->AttrCF.DataUnitsWrittenToDramNamespace.LS__u64));
+ printf("\n");
+
+ printf("%-40s", "DRAM correctable error count");
+ printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DramCorrectableErrorCount));
+ printf("\n");
+
+ printf("%-40s", "DRAM uncorrectable error count");
+ printf(" 0x%016"PRIx64"", le64_to_cpu(pLogPageCF->AttrCF.DramUncorrectableErrorCount));
+ printf("\n");
+
+}
+
+static void json_print_smart_log_CF(struct json_object *root,
+ vendor_log_page_CF *pLogPageCF)
+{
+ /*struct json_object *root;*/
+ struct json_array *logPages;
+ unsigned int currentTemp, maxTemp;
+ char buf[40];
+
+ /*root = json_create_object(); */
+
+ 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;
+ /*currentTemp = currentTemp ? currentTemp - 273 : 0;*/
+ 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;
+ /*maxTemp = maxTemp ? maxTemp - 273 : 0;*/
+ 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);
+
+ /*
+ json_print_object(root, NULL);
+ printf("\n");
+ */
+}
+
+static int vs_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ EXTENDED_SMART_INFO_T ExtdSMARTInfo;
+ vendor_log_page_CF logPageCF;
+ int fd;
+ struct json_object *root;
+ struct json_array *lbafs;
+ struct json_object *lbafs_ExtSmart, *lbafs_DramSmart;
+ root = json_create_object();
+ lbafs = json_create_array();
+
+ const char *desc = "Retrieve Seagate Extended SMART information for the given device ";
+ const char *output_format = "output in binary format";
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (strcmp(cfg.output_format,"json"))
+ printf("Seagate Extended SMART Information :\n");
+
+ err = nvme_get_log(fd, 1, 0xC4, false, 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(fd, 1, 0xCF, false, sizeof(logPageCF), &logPageCF);
+ if (!err) {
+ if(strcmp(cfg.output_format,"json")) {
+ /*printf("Seagate DRAM Supercap SMART Attributes :\n");*/
+
+ 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+ 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;
+ 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);
+ printf("\n");
+
+}
+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 fd;
+ 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 config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, output_format),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ 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_smart_log(fd, 0xffffffff, &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(fd, 1, 0xC4, false, 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+ cf_err = nvme_get_log(fd, 1, 0xCF, false, sizeof(ExtdSMARTInfo), &logPageCF);
+
+ 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);
+
+ return err;
+}
+/* EOF Temperature Stats information */
+
+/***************************************
+ * PCIe error-log information
+ ***************************************/
+static void print_vs_pcie_error_log(pcie_error_log_page pcieErrorLog)
+{
+ __u32 correctPcieEc = 0;
+ __u32 uncorrectPcieEc = 0;
+ correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
+ + pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
+ + pcieErrorLog.ReplayNumRolloverErrCnt;
+
+ 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;
+ root = json_create_object();
+ __u32 correctPcieEc = 0;
+ __u32 uncorrectPcieEc = 0;
+ correctPcieEc = pcieErrorLog.BadDllpErrCnt + pcieErrorLog.BadTlpErrCnt
+ + pcieErrorLog.RcvrErrCnt + pcieErrorLog.ReplayTOErrCnt
+ + pcieErrorLog.ReplayNumRolloverErrCnt;
+
+ 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);
+ printf("\n");
+}
+
+static int vs_pcie_error_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ pcie_error_log_page pcieErrorLog;
+ int fd;
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if(strcmp(cfg.output_format,"json"))
+ printf("Seagate PCIe error counters Information :\n");
+
+ err = nvme_get_log(fd, 1, 0xCB, false, 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+ return err;
+}
+/* EOF PCIE error-log information */
+
+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";
+ int err, fd;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ int save;
+ };
+
+ struct config cfg = {
+ .save = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FLAG("save", 's', &cfg.save, save),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ err = nvme_set_feature(fd, 0, 0xE1, 0xCB, 0, cfg.save, 0, buf, &result);
+
+ if (err < 0) {
+ perror("set-feature");
+ return errno;
+ }
+
+ 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 " \
+ "state of the controller at the time the command is processed. " \
+ "0 - controller shall not update the Telemetry Host Initiated Data.";
+ const char *raw = "output in raw format";
+ int err, fd, dump_fd;
+ struct nvme_temetry_log_hdr tele_log;
+ __le64 offset = 0;
+ int blkCnt, maxBlk = 0, blksToGet;
+ unsigned char *log;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 log_id;
+ int 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ dump_fd = STDOUT_FILENO;
+ cfg.log_id = (cfg.log_id << 8) | 0x07;
+ err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ 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",
+ devicename, 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt = 0;
+
+ while(blkCnt < maxBlk) {
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if(blksToGet == 0)
+ return err;
+
+ log = malloc(blksToGet * 512);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ return EINVAL;
+ }
+
+ memset(log, 0, blksToGet * 512);
+
+ err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ blksToGet * 512, (void *)log);
+ if (!err) {
+ offset += blksToGet * 512;
+
+ if (!cfg.raw_binary) {
+ printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
+
+ d((unsigned char *)log, blksToGet * 512, 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+
+ 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";
+ int err, fd, 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;
+ int 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ dump_fd = STDOUT_FILENO;
+
+ log_id = 0x08;
+ err = nvme_get_log13(fd, cfg.namespace_id, log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ 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",
+ devicename, 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)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt = 0;
+
+ while(blkCnt < maxBlk) {
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if(blksToGet == 0)
+ return err;
+
+ log = malloc(blksToGet * 512);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ return EINVAL;
+ }
+
+ memset(log, 0, blksToGet * 512);
+
+ err = nvme_get_log13(fd, cfg.namespace_id, log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ blksToGet * 512, (void *)log);
+ if (!err) {
+ offset += blksToGet * 512;
+
+ if (!cfg.raw_binary) {
+ printf("\nBlock # :%d to %d\n", blkCnt + 1, blkCnt + blksToGet);
+
+ d((unsigned char *)log, blksToGet * 512, 16, 1);
+ } else
+ seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+ return err;
+
+}
+
+void seaget_d_raw(unsigned char *buf, int len, int fd)
+{
+ /*********************
+ int i;
+ fflush(stdout);
+ for (i = 0; i < len; i++)
+ putchar(*(buf+i));
+ *********************/
+
+ if (write(fd, (void *)buf, len) <= 0)
+ printf("%s: Write Failed\n",__FUNCTION__);
+}
+
+
+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";
+ int err, fd, dump_fd;
+ int flags = O_WRONLY | O_CREAT;
+ int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH;
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ dump_fd = STDOUT_FILENO;
+ if(strlen(cfg.file)) {
+ dump_fd = open(cfg.file, flags, mode);
+ if (dump_fd < 0) {
+ perror(cfg.file);
+ return EINVAL;
+ }
+ }
+
+ log_id = 0x08;
+ err = nvme_get_log13(fd, cfg.namespace_id, log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ sizeof(tele_log), (void *)(&tele_log));
+ if (!err) {
+ maxBlk = tele_log.tele_data_area3;
+ offset += 512;
+
+ /*
+ 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);
+ */
+ seaget_d_raw((unsigned char *)(&tele_log), sizeof(tele_log), dump_fd);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt = 0;
+
+ while(blkCnt < maxBlk) {
+ blksToGet = ((maxBlk - blkCnt) >= TELEMETRY_BLOCKS_TO_READ) ? TELEMETRY_BLOCKS_TO_READ : (maxBlk - blkCnt);
+
+ if(blksToGet == 0) {
+ return err;
+ }
+
+ log = malloc(blksToGet * 512);
+
+ if (!log) {
+ fprintf(stderr, "could not alloc buffer for log\n");
+ return EINVAL;
+ }
+
+ memset(log, 0, blksToGet * 512);
+
+ err = nvme_get_log13(fd, cfg.namespace_id, log_id,
+ NVME_NO_LOG_LSP, offset, 0, false,
+ blksToGet * 512, (void *)log);
+ if (!err) {
+ offset += blksToGet * 512;
+
+ seaget_d_raw((unsigned char *)log, blksToGet * 512, dump_fd);
+
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ else
+ perror("log page");
+
+ blkCnt += blksToGet;
+
+ free(log);
+ }
+
+ if(strlen(cfg.file))
+ close(dump_fd);
+
+ 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 */
diff --git a/plugins/seagate/seagate-nvme.h b/plugins/seagate/seagate-nvme.h
new file mode 100644
index 0000000..f570697
--- /dev/null
+++ b/plugins/seagate/seagate-nvme.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#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"),
+ 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("plugin-version", "Shows Seagate plugin's version information ", seagate_plugin_version)
+ )
+);
+
+#endif
+#include "define_cmd.h"
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
new file mode 100644
index 0000000..3aa6f8a
--- /dev/null
+++ b/plugins/shannon/shannon-nvme.c
@@ -0,0 +1,374 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "json.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "shannon-nvme.h"
+
+typedef 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,
+}addtional_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;
+ int err, fd;
+ 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 config {
+ __u32 namespace_id;
+ int raw_binary;
+ };
+
+ struct config cfg = {
+ .namespace_id = NVME_NSID_ALL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace),
+ OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
+ sizeof(smart_log), &smart_log);
+ if (!err) {
+ if (!cfg.raw_binary)
+ show_shannon_smart_log(&smart_log, cfg.namespace_id, devicename);
+ else
+ d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+ }
+ else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ 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 "\
+ "specified controller. Operating parameters are grouped "\
+ "and identified by Feature Identifiers; each Feature "\
+ "Identifier contains one or more attributes that may affect "\
+ "behaviour of the feature. Each Feature has three possible "\
+ "settings: default, saveable, and current. If a Feature is "\
+ "saveable, it may be modified by set-feature. Default values "\
+ "are vendor-specific and not changeable. Use set-feature to "\
+ "change saveable Features.\n\n"\
+ "Available additional feature id:\n"\
+ "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";
+ int err, fd;
+ __u32 result;
+ void *buf = NULL;
+
+ struct config {
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u8 sel;
+ __u32 cdw11;
+ __u32 data_len;
+ int raw_binary;
+ int human_readable;
+ };
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (cfg.sel > 7) {
+ fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
+ close(fd);
+ return EINVAL;
+ }
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ close(fd);
+ return EINVAL;
+ }
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len))
+ {
+ close(fd);
+ exit(ENOMEM);
+ }
+ memset(buf, 0, cfg.data_len);
+ }
+
+ err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
+ cfg.data_len, buf, &result);
+ if (!err) {
+ printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id),
+ nvme_select_to_string(cfg.sel), result);
+ if (cfg.human_readable)
+ nvme_feature_show_fields(cfg.feature_id, result, buf);
+ else {
+ if (buf) {
+ if (!cfg.raw_binary)
+ d(buf, cfg.data_len, 16, 1);
+ else
+ d_raw(buf, cfg.data_len);
+ }
+ }
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ if (buf)
+ free(buf);
+ return err;
+}
+
+static int set_additional_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.\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 err, fd;
+ __u32 result;
+ void *buf = NULL;
+ int ffd = STDIN_FILENO;
+
+ struct config {
+ char *file;
+ __u32 namespace_id;
+ __u32 feature_id;
+ __u32 value;
+ __u32 data_len;
+ int 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!cfg.feature_id) {
+ fprintf(stderr, "feature-id required param\n");
+ close(fd);
+ return EINVAL;
+ }
+
+ if (cfg.data_len) {
+ if (posix_memalign(&buf, getpagesize(), cfg.data_len)){
+ fprintf(stderr, "can not allocate feature payload\n");
+ close(fd);
+ 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;
+ }
+ }
+
+ err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
+ 0, cfg.save, cfg.data_len, buf, &result);
+ if (err < 0) {
+ perror("set-feature");
+ goto free;
+ }
+ if (!err) {
+ printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+ nvme_feature_to_string(cfg.feature_id), cfg.value);
+ if (buf)
+ d(buf, cfg.data_len, 16, 1);
+ } else if (err > 0)
+ fprintf(stderr, "NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+
+free:
+ if (buf)
+ free(buf);
+ return err;
+}
+
+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..d40732e
--- /dev/null
+++ b/plugins/shannon/shannon-nvme.h
@@ -0,0 +1,20 @@
+#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"),
+ COMMAND_LIST(
+ ENTRY("smart-log-add", "Retrieve Shannon SMART Log, show it", get_additional_smart_log)
+ ENTRY("get-feature-add", "Get Shannon feature and show the resulting value", get_additional_feature)
+ ENTRY("set-feature-add", "Set a Shannon feature and show the resulting value", set_additional_feature)
+ ENTRY("id-ctrl", "Shannon NVMe Identify Controller", shannon_id_ctrl)
+ )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/toshiba/toshiba-nvme.c b/plugins/toshiba/toshiba-nvme.c
new file mode 100644
index 0000000..c067ce8
--- /dev/null
+++ b/plugins/toshiba/toshiba-nvme.c
@@ -0,0 +1,563 @@
+#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 "linux/nvme_ioctl.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "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 = 0x0;
+static const __u32 DW10_SCT_COMMAND_TRANSFER = 0x1;
+
+static const __u32 DW11_SCT_STATUS_COMMAND = 0x0;
+static const __u32 DW11_SCT_COMMAND_TRANSFER = 0x0;
+
+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 */
+typedef 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
+} DeviceMask;
+
+/* Internal device codes */
+typedef enum {
+ CODE_0 = 0x0D,
+ CODE_1 = 0x10
+} DeviceCode;
+
+
+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;
+ int err = 0;
+
+ __u32 result;
+ err = nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd,
+ namespace_id, cdw2, cdw3, cdw10,
+ cdw11, cdw12, cdw13, cdw14, cdw15,
+ data_len, data, metadata_len, metadata,
+ timeout, &result);
+ return err;
+}
+
+static int nvme_get_sct_status(int fd, __u32 device_mask)
+{
+ int err;
+ void* data = NULL;
+ size_t data_len = 512;
+ unsigned char *status;
+
+ 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) {
+ __u32 supported = 0;
+ switch (status[1]) {
+ case CODE_0:
+ supported = (device_mask & MASK_0);
+ break;
+
+ case CODE_1:
+ supported = (device_mask & MASK_1);
+ break;
+
+ default:
+ break;
+ };
+
+ if (0 == 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);
+ 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 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;
+
+ /*
+ * 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;) {
+ __u32 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(int fd, __u32 nsid, const char *devname,
+ struct nvme_xdn_smart_log_c0 *smart)
+{
+ printf("Vendor Log Page Directory 0xC0 for NVME device:%s namespace-id:%x\n",
+ devname, 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(int fd, __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(fd, MASK_0 | MASK_1);
+ if (err) {
+ goto end;
+ }
+ err = nvme_get_log(fd, namespace_id, log_page, false,
+ 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(fd, namespace_id, devicename,
+ (struct nvme_xdn_smart_log_c0 *)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)
+{
+ int err, fd;
+ 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 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ 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(fd, 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)
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(err), err);
+ return err;
+}
+
+static int internal_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err, fd;
+ 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 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ 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(fd, cfg.output_file, !cfg.prev_log);
+ if (err < 0)
+ fprintf(stderr, "%s: couldn't get fw log \n", __func__);
+ if (err > 0)
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__,
+ nvme_status_to_string(err), err);
+ return err;
+}
+
+static int clear_correctable_errors(int argc, char **argv, struct command *cmd,
+ struct plugin *plugin)
+{
+ int err, fd;
+ 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;
+ __u32 result;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ fprintf(stderr,"%s: failed to parse arguments\n", __func__);
+ return EINVAL;
+ }
+
+ /* Check device supported */
+ err = nvme_get_sct_status(fd, MASK_0 | MASK_1);
+ if (err)
+ goto end;
+
+ err = nvme_set_feature(fd, namespace_id, feature_id, value, cdw12, save,
+ 0, NULL, &result);
+ if (err)
+ fprintf(stderr, "%s: couldn't clear PCIe correctable errors \n",
+ __func__);
+end:
+ if (err > 0)
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__,
+ nvme_status_to_string(err), err);
+ return err;
+}
diff --git a/plugins/toshiba/toshiba-nvme.h b/plugins/toshiba/toshiba-nvme.h
new file mode 100644
index 0000000..c405e78
--- /dev/null
+++ b/plugins/toshiba/toshiba-nvme.h
@@ -0,0 +1,20 @@
+#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"),
+ 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..dbb56be
--- /dev/null
+++ b/plugins/transcend/transcend-nvme.c
@@ -0,0 +1,92 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "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 result=0, fd;
+ int percent_used = 0, healthvalue=0;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0) {
+ printf("\nDevice not found \n");;
+ return -1;
+ }
+ result = nvme_smart_log(fd, 0xffffffff, &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);
+ }
+
+ }
+
+ return result;
+}
+
+
+static int getBadblock(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+
+ char *desc = "Get nvme bad block number.";
+ int result=0, fd;
+
+ OPT_ARGS(opts) = {
+
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ 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(fd,&nvmecmd);
+ if(!result) {
+ int badblock = data[0];
+ printf("Transcend NVME badblock count: %d\n",badblock);
+ }
+
+ return result;
+}
diff --git a/plugins/transcend/transcend-nvme.h b/plugins/transcend/transcend-nvme.h
new file mode 100644
index 0000000..14d62ec
--- /dev/null
+++ b/plugins/transcend/transcend-nvme.h
@@ -0,0 +1,20 @@
+#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"),
+ 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..47b0fdc
--- /dev/null
+++ b/plugins/virtium/virtium-nvme.c
@@ -0,0 +1,1044 @@
+#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 "linux/nvme_ioctl.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "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 int time_stamp;
+ struct nvme_id_ctrl raw_ctrl;
+ struct nvme_firmware_log_page raw_fw;
+};
+
+struct vtview_smart_log_entry {
+ char path[256];
+ long int 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 long double int128_to_double(__u8 *data)
+{
+ int i;
+ long double result = 0;
+
+ for (i = 0; i < 16; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+ return result;
+}
+
+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;
+
+ curlocale = setlocale(LC_ALL, NULL);
+ templocale = strdup(curlocale);
+
+ if (NULL == templocale)
+ printf("Cannot malloc buffer\n");
+
+ setlocale(LC_ALL, "C");
+
+ long long int lba = 1 << smart->raw_ns.lbaf[(smart->raw_ns.flbas & 0x0f)].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;%0.Lf;", int128_to_double(smart->raw_smart.data_units_read));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Data_Units_Written;%0.Lf;", int128_to_double(smart->raw_smart.data_units_written));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Host_Read_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_reads));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Host_Write_Commands;%0.Lf;", int128_to_double(smart->raw_smart.host_writes));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Controller_Busy_Time;%0.Lf;", int128_to_double(smart->raw_smart.ctrl_busy_time));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Power_Cycles;%0.Lf;", int128_to_double(smart->raw_smart.power_cycles));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Power_On_Hours;%0.Lf;", int128_to_double(smart->raw_smart.power_on_hours));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Unsafe_Shutdowns;%0.Lf;", int128_to_double(smart->raw_smart.unsafe_shutdowns));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Media_Errors;%0.Lf;", int128_to_double(smart->raw_smart.media_errors));
+ strcat(text, tempbuff);
+ snprintf(tempbuff, sizeof(tempbuff), "Num_Err_Log_Entries;%0.Lf;", int128_to_double(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 (0 == 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(NULL == 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 == 0)
+ return;
+
+ i = size - 1;
+ while ((0 != 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;
+ char filename[256] = "";
+ int ret = 0;
+ int nsid = 0;
+
+ memset(smart.path, 0, sizeof(smart.path));
+ strcpy(smart.path, path);
+ if(NULL == cfg->output_file)
+ strcpy(filename, vt_default_log_file_name);
+ else
+ strcpy(filename, cfg->output_file);
+
+ smart.time_stamp = time(NULL);
+ nsid = nvme_get_nsid(fd);
+
+ if (nsid <= 0) {
+ printf("Cannot read namespace-id\n");
+ return -1;
+ }
+
+ ret = nvme_identify_ns(fd, nsid, 0, &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_smart_log(fd, NVME_NSID_ALL, &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;
+ char filename[256] = "";
+ int ret = 0;
+
+ vt_initialize_header_buffer(&header);
+ strcpy(header.path, path);
+
+ if (NULL == cfg->test_name)
+ strcpy(header.test_name, DEFAULT_TEST_NAME);
+ else
+ strcpy(header.test_name, cfg->test_name);
+
+ if(NULL == cfg->output_file)
+ strcpy(filename, vt_default_log_file_name);
+ else
+ strcpy(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_fw_log(fd, &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].idle_scale;
+ 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].active_work_scale;
+ 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 int 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) == 0) || ((i + 1) == pbuffsize)) {
+ printf(" ");
+ if ((i + 1) % 32 == 0) {
+ 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) == 0)
+ printf(" ");
+
+ for (j = ((i + 1) % 32); j < 32; j++) {
+ printf(" ");
+ if(((j + 1) % 8) == 0)
+ 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 *NVSCCtable[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->nvscc;
+ printf(" \"NVM Vendor Specific Command Configuration\":{\n");
+ vt_convert_data_buffer_to_hex_string(&buf[530], 1, true, s);
+ printf(" \"Value\":\"%sh\",\n", s);
+ vt_build_identify_lv2(temp, 0, 1, NVSCCtable, true);
+
+ vt_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 err = 0;
+ int fd, ret;
+ long int total_time = 0;
+ long int freq_time = 0;
+ long int cur_time = 0;
+ long int remain_time = 0;
+ long int start_time = 0;
+ long int 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 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)
+ strcpy(path, argv[1]);
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("Error parse and open (fd = %d)\n", fd);
+ return (fd);
+ }
+
+ 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(fd, path, &cfg);
+ if (ret) {
+ err = EINVAL;
+ close(fd);
+ 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 == 0)
+ 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(fd, 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);
+ }
+
+ close (fd);
+ return (err);
+}
+
+static int vt_show_identify(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+ int err = 0;
+ int fd ,ret;
+ struct nvme_id_ctrl ctrl;
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0) {
+ printf("Error parse and open (fd = %d)\n", fd);
+ return (fd);
+ }
+
+ ret = nvme_identify_ctrl(fd, &ctrl);
+ if (ret) {
+ printf("Cannot read identify device\n");
+ close (fd);
+ return (-1);
+ }
+
+ vt_process_string(ctrl.sn, sizeof(ctrl.sn));
+ vt_process_string(ctrl.mn, sizeof(ctrl.mn));
+ vt_parse_detail_identify(&ctrl);
+
+ close(fd);
+ return (err);
+}
diff --git a/plugins/virtium/virtium-nvme.h b/plugins/virtium/virtium-nvme.h
new file mode 100644
index 0000000..b95c910
--- /dev/null
+++ b/plugins/virtium/virtium-nvme.h
@@ -0,0 +1,21 @@
+#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"),
+ 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..0cebe3f
--- /dev/null
+++ b/plugins/wdc/wdc-nvme.c
@@ -0,0 +1,5663 @@
+/*
+ * 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>
+ */
+#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 "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+#include "json.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+#include <sys/ioctl.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
+
+/* 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_ZN440_DEV_ID 0x2600
+#define WDC_NVME_SN440_DEV_ID 0x2610
+#define WDC_NVME_SN7GC_DEV_ID 0x2700
+#define WDC_NVME_SN7GC_DEV_ID_1 0x2701
+#define WDC_NVME_SN7GC_DEV_ID_2 0x2702
+#define WDC_NVME_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_SN720_DEV_ID 0x5002
+#define WDC_NVME_SN730A_DEV_ID 0x5006
+#define WDC_NVME_SN730B_DEV_ID 0x3714
+#define WDC_NVME_SN730B_DEV_ID_1 0x3734
+#define WDC_NVME_SN340_DEV_ID 0x500d
+
+#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_DRIVE_ESSENTIALS 0x0000000100000000
+#define WDC_DRIVE_CAP_DUI_DATA 0x0000000200000000
+#define WDC_SN730B_CAP_VUC_LOG 0x0000000400000000
+#define WDC_DRIVE_CAP_SN340_DUI 0x0000000800000000
+#define WDC_DRIVE_CAP_SMART_LOG_MASK (WDC_DRIVE_CAP_C1_LOG_PAGE | WDC_DRIVE_CAP_CA_LOG_PAGE | \
+ WDC_DRIVE_CAP_D0_LOG_PAGE)
+
+/* 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_0x1004 0x1004
+#define WDC_CUSTOMER_ID_0x1005 0x1005
+
+/* 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
+
+/* 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
+
+/* 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
+
+/* 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_OPCODE 0xC2
+#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
+#define WDC_BD_CA_LOG_BUF_LEN 0x9C
+
+/* C0 EOL Status Log Page */
+#define WDC_NVME_GET_EOL_STATUS_LOG_OPCODE 0xC0
+#define WDC_NVME_EOL_STATUS_LOG_LEN 0x200
+
+/* 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
+
+/* 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_C2 WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE
+#define WDC_LOG_ID_C4 0xC4
+#define WDC_LOG_ID_C5 0xC5
+#define WDC_LOG_ID_C6 0xC6
+#define WDC_LOG_ID_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_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
+
+/* 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_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
+
+typedef enum _NVME_FEATURES_SELECT
+{
+ FS_CURRENT = 0,
+ FS_DEFAULT = 1,
+ FS_SAVED = 2,
+ FS_SUPPORTED_CAPBILITIES = 3
+} NVME_FEATURES_SELECT;
+
+typedef 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
+} NVME_FEATURE_IDENTIFIERS;
+
+typedef enum
+{
+ 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,
+} WDC_DRIVE_ESSENTIAL_TYPE;
+
+typedef struct __attribute__((__packed__)) _WDC_DE_VU_FILE_META_DATA
+{
+ __u8 fileName[WDC_DE_FILE_NAME_SIZE];
+ __u16 fileID;
+ __u64 fileSize;
+} WDC_DE_VU_FILE_META_DATA, *PWDC_DE_VU_FILE_META_DATA;
+
+typedef struct _WDC_DRIVE_ESSENTIALS
+{
+ WDC_DE_VU_FILE_META_DATA metaData;
+ WDC_DRIVE_ESSENTIAL_TYPE essentialType;
+} WDC_DRIVE_ESSENTIALS;
+
+typedef struct _WDC_DE_VU_LOG_DIRECTORY
+{
+ WDC_DRIVE_ESSENTIALS *logEntry; /* Caller to allocate memory */
+ __u32 maxNumLogEntries; /* Caller to input memory allocated */
+ __u32 numOfValidLogEntries; /* API will output this value */
+} WDC_DE_VU_LOG_DIRECTORY,*PWDC_DE_VU_LOG_DIRECTORY;
+
+typedef struct _WDC_DE_CSA_FEATURE_ID_LIST
+{
+ NVME_FEATURE_IDENTIFIERS featureId;
+ __u8 featureName[WDC_DE_GENERIC_BUFFER_SIZE];
+} WDC_DE_CSA_FEATURE_ID_LIST;
+
+typedef 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];
+} tarfile_metadata;
+
+static 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"},
+};
+
+typedef enum _NVME_VU_DE_LOGPAGE_NAMES
+{
+ NVME_DE_LOGPAGE_E3 = 0x01,
+ NVME_DE_LOGPAGE_C0 = 0x02
+} NVME_VU_DE_LOGPAGE_NAMES;
+typedef struct _NVME_VU_DE_LOGPAGE_LIST
+{
+ NVME_VU_DE_LOGPAGE_NAMES logPageName;
+ __u32 logPageId;
+ __u32 logPageLen;
+ char logPageIdStr[5];
+} NVME_VU_DE_LOGPAGE_LIST, *PNVME_VU_DE_LOGPAGE_LIST;
+
+typedef struct _WDC_NVME_DE_VU_LOGPAGES
+{
+ NVME_VU_DE_LOGPAGE_NAMES vuLogPageReqd;
+ __u32 numOfVULogPages;
+} WDC_NVME_DE_VU_LOGPAGES, *PWDC_NVME_DE_VU_LOGPAGES;
+
+static NVME_VU_DE_LOGPAGE_LIST deVULogPagesList[] =
+{
+ { NVME_DE_LOGPAGE_E3, 0xE3, 1072, "0xe3"},
+ { NVME_DE_LOGPAGE_C0, 0xC0, 512, "0xc0"}
+};
+
+static int wdc_get_serial_name(int fd, 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(int fd, __u8 opcode, __u32 cdw12);
+static int wdc_do_dump(int fd, __u32 opcode,__u32 data_len,
+ __u32 cdw12, char *file, __u32 xfer_size);
+static int wdc_do_crash_dump(int fd, char *file, int type);
+static int wdc_crash_dump(int fd, 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(int fd, 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(int fd, __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(int fd, 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(int fd, 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(int fd, __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(int fd, char *file, int log_id);
+static int wdc_save_reason_id(int fd, __u8 *rsn_ident, int size);
+static int wdc_clear_reason_id(int fd);
+static int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log_page_hdr *log_hdr);
+static int wdc_log_page_directory(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+static int wdc_do_drive_info(int fd, __u32 *result);
+static int wdc_vs_drive_info(int argc, char **argv, struct command *command,
+ struct plugin *plugin);
+
+/* 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 data_area_id;
+ __le32 section_size;
+};
+
+/* DUI log header V2 */
+struct __attribute__((__packed__)) wdc_dui_log_section_v2 {
+ __le16 section_type;
+ __le16 data_area_id;
+ __le64 section_size;
+};
+
+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 __attribute__((__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 __attribute__((__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];
+};
+
+/* 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 wdc_bd_ca_log_format {
+ __u8 field_id;
+ __u8 reserved1[2];
+ __u8 normalized_value;
+ __u8 reserved2;
+ __u8 raw_value[7];
+};
+
+struct __attribute__((__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 __attribute__((__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 */
+};
+
+/* NAND Stats */
+struct __attribute__((__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[444];
+};
+
+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];
+};
+
+#define WDC_REASON_INDEX_MAX 16
+#define WDC_REASON_ID_ENTRY_LEN 128
+#define WDC_REASON_ID_PATH_NAME "/usr/local/nvmecli"
+
+
+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 long double int128_to_double(__u8 *data)
+{
+ int i;
+ long double result = 0;
+
+ for (i = 0; i < 16; i++) {
+ result *= 256;
+ result += data[15 - i];
+ }
+ return result;
+}
+
+static int wdc_get_pci_ids(uint32_t *device_id, uint32_t *vendor_id)
+{
+ int fd, ret = -1;
+ char *block, path[512], *id;
+
+ id = calloc(1, 32);
+ if (!id) {
+ fprintf(stderr, "ERROR : WDC : %s : calloc failed\n", __func__);
+ return -1;
+ }
+
+ block = nvme_char_from_block((char *)devicename);
+
+ /* read the vendor ID from sys fs */
+ sprintf(path, "/sys/class/nvme/%s/device/vendor", block);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ sprintf(path, "/sys/class/misc/%s/device/vendor", block);
+ fd = open(path, O_RDONLY);
+ }
+ if (fd < 0) {
+ fprintf(stderr, "ERROR : WDC : %s : Open vendor file failed\n", __func__);
+ ret = -1;
+ goto free_id;
+ }
+
+ ret = read(fd, id, 32);
+ if (ret < 0) {
+ fprintf(stderr, "%s: Read of pci vendor id failed\n", __func__);
+ ret = -1;
+ goto close_fd;
+ } else {
+ if (id[strlen(id) - 1] == '\n')
+ id[strlen(id) - 1] = '\0';
+
+ /* convert the device id string to an int */
+ *vendor_id = (int)strtol(&id[2], NULL, 16);
+ ret = 0;
+ }
+
+ /* read the device ID from sys fs */
+ sprintf(path, "/sys/class/nvme/%s/device/device", block);
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ sprintf(path, "/sys/class/misc/%s/device/device", block);
+ fd = open(path, O_RDONLY);
+ }
+ if (fd < 0) {
+ fprintf(stderr, "ERROR : WDC : %s : Open device file failed\n", __func__);
+ ret = -1;
+ goto close_fd;
+ }
+
+ ret = read(fd, id, 32);
+ if (ret < 0) {
+ fprintf(stderr, "%s: Read of pci device id failed\n", __func__);
+ ret = -1;
+ } else {
+ if (id[strlen(id) - 1] == '\n')
+ id[strlen(id) - 1] = '\0';
+
+ /* convert the device id string to an int */
+ *device_id = strtol(&id[2], NULL, 16);
+ ret = 0;
+ }
+
+close_fd:
+ close(fd);
+free_id:
+ free(block);
+ free(id);
+ return ret;
+}
+
+static bool wdc_check_device(int fd)
+{
+ int ret;
+ bool supported;
+ uint32_t read_device_id, read_vendor_id;
+
+ ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
+ if (ret < 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 __u64 wdc_get_drive_capabilities(int fd) {
+ int ret;
+ uint32_t read_device_id, read_vendor_id;
+ __u64 capabilities = 0;
+
+ ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
+ if (ret < 0)
+ 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);
+ 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);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xC1 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_ADD_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_C1_LOG_PAGE;
+ break;
+ default:
+ capabilities = 0;
+ }
+ break;
+ case WDC_NVME_VID_2:
+ switch (read_device_id) {
+ case WDC_NVME_SN630_DEV_ID:
+ /* FALLTHRU */
+ 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(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+ break;
+ case WDC_NVME_SN640_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_SN640_DEV_ID_1:
+ /* FALLTHRU */
+ case WDC_NVME_SN640_DEV_ID_2:
+ /* FALLTHRU */
+ case WDC_NVME_SN640_DEV_ID_3:
+ /* FALLTHRU */
+ case WDC_NVME_SN840_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_SN840_DEV_ID_1:
+ /* FALLTHRU */
+ case WDC_NVME_ZN440_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_SN440_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_SN7GC_DEV_ID:
+ case WDC_NVME_SN7GC_DEV_ID_1:
+ case WDC_NVME_SN7GC_DEV_ID_2:
+ capabilities = (WDC_DRIVE_CAP_CAP_DIAG | WDC_DRIVE_CAP_INTERNAL_LOG |
+ WDC_DRIVE_CAP_DRIVE_STATUS | WDC_DRIVE_CAP_CLEAR_ASSERT |
+ WDC_DRIVE_CAP_RESIZE | WDC_DRIVE_CAP_CLEAR_PCIE |
+ WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY | WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY |
+ WDC_DRVIE_CAP_DISABLE_CTLR_TELE_LOG | WDC_DRIVE_CAP_REASON_ID |
+ WDC_DRIVE_CAP_LOG_PAGE_DIR | WDC_DRIVE_CAP_INFO);
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_CA_LOG_PAGE;
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == true)
+ capabilities |= WDC_DRIVE_CAP_D0_LOG_PAGE;
+ break;
+ case WDC_NVME_SN730B_DEV_ID:
+ /* FALLTHRU */
+ case WDC_NVME_SN730B_DEV_ID_1:
+ capabilities = WDC_SN730B_CAP_VUC_LOG;
+ 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:
+ /* FALLTHRU */
+ case WDC_NVME_SN520_DEV_ID_1:
+ /* FALLTHRU */
+ case WDC_NVME_SN520_DEV_ID_2:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA;
+ 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_SN730A_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_DUI_DATA | WDC_DRIVE_CAP_NAND_STATS;
+ break;
+ case WDC_NVME_SN340_DEV_ID:
+ capabilities = WDC_DRIVE_CAP_SN340_DUI;
+ break;
+ default:
+ capabilities = 0;
+ }
+ break;
+ default:
+ capabilities = 0;
+ }
+
+ return capabilities;
+}
+
+static int wdc_get_serial_name(int fd, 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(fd, &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 == 0) {
+ 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));
+ 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));
+ return -1;
+ }
+
+ if (fsync(fd) < 0) {
+ fprintf(stderr, "ERROR : WDC : fsync : %s\n", strerror(errno));
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+static bool get_dev_mgment_cbs_data(int fd, __u8 log_id, void **cbs_data)
+{
+ int ret = -1;
+ __u8* data;
+ struct wdc_c2_log_page_header *hdr_ptr;
+ struct wdc_c2_log_subpage_header *sph;
+ __u32 length = 0;
+ bool found = false;
+
+ *cbs_data = NULL;
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_C2_LOG_BUF_LEN)) == NULL) {
+ 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 */
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE,
+ false, WDC_C2_LOG_BUF_LEN, data);
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : Unable to get C2 Log Page length, ret = 0x%x\n", ret);
+ goto end;
+ }
+
+ hdr_ptr = (struct wdc_c2_log_page_header *)data;
+
+ if (le32_to_cpu(hdr_ptr->length) > WDC_C2_LOG_BUF_LEN) {
+ /* Log Page buffer too small, free and reallocate the necessary size */
+ free(data);
+ data = calloc(le32_to_cpu(hdr_ptr->length), sizeof(__u8));
+ if (data == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return false;
+ }
+ }
+
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE,
+ false, le32_to_cpu(hdr_ptr->length), data);
+ /* parse the data until the List of log page ID's is found */
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : Unable to read C2 Log Page data, ret = 0x%x\n", ret);
+ goto end;
+ }
+
+ length = sizeof(struct wdc_c2_log_page_header);
+ hdr_ptr = (struct wdc_c2_log_page_header *)data;
+
+ while (length < le32_to_cpu(hdr_ptr->length)) {
+ sph = (struct wdc_c2_log_subpage_header *)(data + length);
+
+ if (le32_to_cpu(sph->entry_id) == log_id) {
+ *cbs_data = (void *)&sph->data;
+ found = true;
+ break;
+ }
+ length += le32_to_cpu(sph->length);
+ }
+
+end:
+ free(data);
+ return found;
+}
+
+static bool wdc_nvme_check_supported_log_page(int fd, __u8 log_id)
+{
+ int i;
+ bool found = false;
+ struct wdc_c2_cbs_data *cbs_data = NULL;
+
+ if (get_dev_mgment_cbs_data(fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) {
+ if (cbs_data != NULL) {
+ 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
+ } 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(int fd, __le32 *ret_data,
+ __u8 log_id)
+{
+ __u32 *cbs_data = NULL;
+
+ if (get_dev_mgment_cbs_data(fd, log_id, (void *)&cbs_data)) {
+ if (cbs_data != NULL) {
+ memcpy((void *)ret_data, (void *)cbs_data, 4);
+ return true;
+ }
+ }
+
+ *ret_data = 0;
+ return false;
+}
+
+static int wdc_do_clear_dump(int fd, __u8 opcode, __u32 cdw12)
+{
+ int ret;
+ struct nvme_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ admin_cmd.opcode = opcode;
+ admin_cmd.cdw12 = cdw12;
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ if (ret != 0) {
+ fprintf(stdout, "ERROR : WDC : Crash dump erase failed\n");
+ }
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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_admin_cmd admin_cmd;
+
+ l = (struct wdc_log_size *) buf;
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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);
+ if (ret != 0) {
+ l->log_size = 0;
+ ret = -1;
+ fprintf(stderr, "ERROR : WDC : reading dump length failed\n");
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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);
+ if (ret != 0) {
+ fprintf(stderr, "ERROR : WDC : reading dump length failed\n");
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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);
+ if (ret != 0) {
+ fprintf(stderr, "ERROR : WDC : reading DUI data failed\n");
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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 = (__u32)(offset & 0x00000000FFFFFFFF);
+ admin_cmd.cdw13 = (__u32)(offset >> 32);
+ 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);
+ if (ret != 0) {
+ fprintf(stderr, "ERROR : WDC : reading DUI data V2 failed\n");
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ }
+
+ return ret;
+}
+
+static int wdc_do_dump(int fd, __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_admin_cmd admin_cmd;
+ __u32 dump_length = data_len;
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * dump_length);
+ if (dump_data == NULL) {
+ fprintf(stderr, "%s: ERROR : malloc : %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ memset(dump_data, 0, sizeof (__u8) * dump_length);
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ curr_data_offset = 0;
+ curr_data_len = xfer_size;
+ i = 0;
+
+ 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(fd, &admin_cmd);
+ if (ret != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n",
+ __func__, nvme_status_to_string(ret), ret);
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n",
+ __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr);
+ break;
+ }
+
+ if ((curr_data_offset + xfer_size) <= data_len)
+ curr_data_len = xfer_size;
+ else
+ curr_data_len = data_len - curr_data_offset; /* last transfer */
+
+ curr_data_offset += curr_data_len;
+ 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 == 0) {
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), 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_admin_cmd admin_cmd;
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * data_len);
+
+ if (dump_data == NULL) {
+ 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_admin_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;
+
+ log_size = data_len;
+ 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);
+ if (ret != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n",
+ __func__, i, admin_cmd.data_len, curr_data_offset, (long unsigned int)admin_cmd.addr);
+ break;
+ }
+
+ log_size -= xfer_size;
+ curr_data_offset += xfer_size;
+ i++;
+ }
+
+ if (ret == 0) {
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ } else {
+ fprintf(stderr, "%s: FAILURE: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), 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(int fd, char *file, __u32 bs, int type, int data_area)
+{
+ struct nvme_telemetry_log_page_hdr *hdr;
+ size_t full_size, offset = WDC_TELEMETRY_HEADER_LENGTH;
+ int err = 0, output;
+ void *page_log;
+ __u32 host_gen = 1;
+ int ctrl_init = 0;
+ __u32 result;
+ void *buf = NULL;
+
+
+ if (type == WDC_TELEMETRY_TYPE_HOST) {
+ host_gen = 1;
+ ctrl_init = 0;
+ } else if (type == WDC_TELEMETRY_TYPE_CONTROLLER) {
+ /* Verify the Controller Initiated Option is enabled */
+ err = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0,
+ 4, buf, &result);
+ if (err == 0) {
+ if (result == 0) {
+ /* enabled */
+ host_gen = 0;
+ ctrl_init = 1;
+ }
+ else {
+ fprintf(stderr, "%s: Controller initiated option telemetry log page disabled\n", __func__);
+ err = -EINVAL;
+ goto close_fd;
+ }
+ } else {
+ fprintf(stderr, "ERROR : WDC: Get telemetry option feature failed. NVMe Status:%s(%x)\n",
+ nvme_status_to_string(err), err);
+ err = -EPERM;
+ goto close_fd;
+ }
+ } else {
+ fprintf(stderr, "%s: Invalid type parameter; type = %d\n", __func__, type);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ if (!file) {
+ fprintf(stderr, "%s: Please provide an output file!\n", __func__);
+ err = -EINVAL;
+ goto close_fd;
+ }
+
+ hdr = malloc(bs);
+ page_log = malloc(bs);
+ if (!hdr || !page_log) {
+ fprintf(stderr, "%s: Failed to allocate 0x%x bytes for log: %s\n",
+ __func__, bs, strerror(errno));
+ err = -ENOMEM;
+ goto free_mem;
+ }
+ memset(hdr, 0, bs);
+
+ 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));
+ err = output;
+ goto free_mem;
+ }
+
+ err = nvme_get_telemetry_log(fd, hdr, host_gen, ctrl_init, WDC_TELEMETRY_HEADER_LENGTH, 0);
+ if (err < 0)
+ perror("get-telemetry-log");
+ else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "%s: Failed to acquire telemetry header!\n", __func__);
+ goto close_output;
+ }
+
+ err = write(output, (void *) hdr, WDC_TELEMETRY_HEADER_LENGTH);
+ if (err != WDC_TELEMETRY_HEADER_LENGTH) {
+ fprintf(stderr, "%s: Failed to flush header data to file!, err = %d\n", __func__, err);
+ goto close_output;
+ }
+
+ switch (data_area) {
+ case 1:
+ full_size = (le16_to_cpu(hdr->dalb1) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH;
+ break;
+ case 2:
+ full_size = (le16_to_cpu(hdr->dalb2) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH;
+ break;
+ case 3:
+ full_size = (le16_to_cpu(hdr->dalb3) * WDC_TELEMETRY_BLOCK_SIZE) + WDC_TELEMETRY_HEADER_LENGTH;
+ break;
+ default:
+ fprintf(stderr, "%s: Invalid data area requested, data area = %d\n", __func__, data_area);
+ err = -EINVAL;
+ goto close_output;
+ }
+
+ /*
+ * Continuously pull data until the offset hits the end of the last
+ * block.
+ */
+ while (offset < full_size) {
+ if ((full_size - offset) < bs)
+ bs = (full_size - offset);
+
+
+ err = nvme_get_telemetry_log(fd, page_log, 0, ctrl_init, bs, offset);
+ if (err < 0) {
+ perror("get-telemetry-log");
+ break;
+ } else if (err > 0) {
+ nvme_show_status(err);
+ fprintf(stderr, "%s: Failed to acquire full telemetry log!\n", __func__);
+ nvme_show_status(err);
+ break;
+ }
+
+ err = write(output, (void *) page_log, bs);
+ if (err != bs) {
+ fprintf(stderr, "%s: Failed to flush telemetry data to file!, err = %d\n", __func__, err);
+ break;
+ }
+ err = 0;
+ offset += bs;
+ }
+
+close_output:
+ close(output);
+free_mem:
+ free(hdr);
+ free(page_log);
+close_fd:
+ close(fd);
+
+ return err;
+
+}
+
+static int wdc_do_cap_diag(int fd, 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 == NULL) {
+ 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(fd, 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 == 0) {
+ fprintf(stderr, "INFO : WDC : Capture Diagnostics log is empty\n");
+ } else {
+ ret = wdc_do_dump_e6(fd, 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(fd, 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(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;
+ struct wdc_dui_log_hdr_v3 *log_hdr_v3;
+ __u32 cap_dui_length;
+ __u64 cap_dui_length_v3;
+ __u8 *dump_data = NULL;
+ __u8 *buffer_addr;
+ __s64 total_size = 0;
+ int i;
+ int j;
+ bool last_xfer = false;
+ int err = 0, output = 0;
+
+ log_hdr = (struct wdc_dui_log_hdr *) malloc(dui_log_hdr_size);
+ if (log_hdr == NULL) {
+ 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 != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : Get DUI headers failed\n", __func__);
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ goto out;
+ }
+
+ /* Check the Log Header version */
+ if (((log_hdr->hdr_version & 0xFF) == 0x02) ||
+ ((log_hdr->hdr_version & 0xFF) == 0x03)) { /* Process Version 2 or 3 header */
+ __s64 log_size = 0;
+ __u64 curr_data_offset = 0;
+ __u64 xfer_size_long = (__u64)xfer_size;
+
+ 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_v3->hdr_version >= 0x03)
+ fprintf(stderr, "INFO : WDC : DUI Product ID = %c\n", log_hdr_v3->product_id);
+ }
+
+ if (cap_dui_length_v3 == 0) {
+ fprintf(stderr, "INFO : WDC : Capture V2 or V3 Device Unit Info log is empty\n");
+ } else {
+ /* parse log header for all sections up to specified data area inclusively */
+ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) {
+ for(j = 0; j < WDC_NVME_DUI_MAX_SECTION_V3; j++) {
+ if (log_hdr_v3->log_section[j].data_area_id <= data_area &&
+ log_hdr_v3->log_section[j].data_area_id != 0) {
+ log_size += log_hdr_v3->log_section[j].section_size;
+ if (verbose)
+ fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%lx\n",
+ __func__, log_hdr_v3->log_section[j].data_area_id, (unsigned int)log_hdr_v3->log_section[j].section_size, (long unsigned int)log_size);
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, "%s: break, total size = 0x%lx\n", __func__, (long unsigned int)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);
+ goto out;
+ }
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size_long);
+ if (dump_data == NULL) {
+ fprintf(stderr, "%s: ERROR : dump data v3 malloc failed : status %s, size = 0x%lx\n",
+ __func__, strerror(errno), (long unsigned int)xfer_size_long);
+ ret = -1;
+ goto out;
+ }
+ 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));
+ ret = output;
+ goto free_mem;
+ }
+
+ curr_data_offset = 0;
+
+ if (file_size != 0) {
+ /* Write the DUI data based on the passed in file size */
+ if ((offset + file_size) > total_size)
+ log_size = min((total_size - offset), file_size);
+ else
+ log_size = min(total_size, file_size);
+
+ if (verbose)
+ fprintf(stderr, "%s: INFO : WDC : Offset 0x%"PRIx64", file size 0x%"PRIx64", total size 0x%"PRIx64", log size 0x%"PRIx64"\n",
+ __func__, (uint64_t)offset, (uint64_t)file_size, (uint64_t)total_size, (uint64_t)log_size);
+
+ curr_data_offset = offset;
+
+ }
+
+ 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 != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%lx, addr = 0x%lx\n",
+ __func__, i, (long unsigned int)total_size, (long unsigned int)curr_data_offset, (long unsigned int)buffer_addr);
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ break;
+ }
+
+ /* write the dump data into the file */
+ err = write(output, (void *)buffer_addr, xfer_size_long);
+ if (err != xfer_size_long) {
+ fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%lx\n",
+ __func__, i, err, (long unsigned int)xfer_size_long);
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size_long;
+ i++;
+ }
+ }
+ } else {
+ __s32 log_size = 0;
+ __u32 curr_data_offset = 0;
+
+ cap_dui_length = le32_to_cpu(log_hdr->log_size);
+
+ if (verbose) {
+ fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log, data area = %d\n", data_area);
+ fprintf(stderr, "INFO : WDC : DUI Header Version = 0x%x\n", log_hdr->hdr_version);
+ }
+
+ if (cap_dui_length == 0) {
+ fprintf(stderr, "INFO : WDC : Capture V1 Device Unit Info log is empty\n");
+ } else {
+ /* parse log header for all sections up to specified data area inclusively */
+ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA) {
+ for(j = 0; j < WDC_NVME_DUI_MAX_SECTION; j++) {
+ if (log_hdr->log_section[j].data_area_id <= data_area &&
+ log_hdr->log_section[j].data_area_id != 0) {
+ log_size += log_hdr->log_section[j].section_size;
+ if (verbose)
+ fprintf(stderr, "%s: Data area ID %d : section size 0x%x, total size = 0x%x\n",
+ __func__, log_hdr->log_section[j].data_area_id, (unsigned int)log_hdr->log_section[j].section_size, (unsigned int)log_size);
+
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, "%s: break, total size = 0x%x\n", __func__, (unsigned int)log_size);
+ break;
+ }
+ }
+ } else
+ log_size = cap_dui_length;
+
+ total_size = log_size;
+
+ dump_data = (__u8 *) malloc(sizeof (__u8) * xfer_size);
+ if (dump_data == NULL) {
+ fprintf(stderr, "%s: ERROR : dump data V1 malloc failed : status %s, size = 0x%x\n",
+ __func__, strerror(errno), (unsigned int)xfer_size);
+ ret = -1;
+ goto out;
+ }
+ memset(dump_data, 0, sizeof (__u8) * xfer_size);
+
+ output = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (output < 0) {
+ fprintf(stderr, "%s: Failed to open output file %s: %s!\n",
+ __func__, file, strerror(errno));
+ ret = output;
+ goto free_mem;
+ }
+
+ /* write the telemetry and log headers into the dump_file */
+ err = write(output, (void *)log_hdr, WDC_NVME_CAP_DUI_HEADER_SIZE);
+ if (err != WDC_NVME_CAP_DUI_HEADER_SIZE) {
+ fprintf(stderr, "%s: Failed to flush header data to file!\n", __func__);
+ goto free_mem;
+ }
+
+ log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE;
+ curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE;
+ i = 0;
+ buffer_addr = dump_data;
+
+ for(; log_size > 0; log_size -= xfer_size) {
+ xfer_size = min(xfer_size, log_size);
+
+ if (log_size <= xfer_size)
+ last_xfer = true;
+
+ ret = wdc_dump_dui_data(fd, xfer_size, curr_data_offset, buffer_addr, last_xfer);
+ if (ret != 0) {
+ fprintf(stderr, "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%x, addr = %p\n",
+ __func__, i, (long unsigned int)log_size, curr_data_offset, buffer_addr);
+ fprintf(stderr, "%s: ERROR : WDC : NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ break;
+ }
+
+ /* write the dump data into the file */
+ err = write(output, (void *)buffer_addr, xfer_size);
+ if (err != xfer_size) {
+ fprintf(stderr, "%s: ERROR : WDC : Failed to flush DUI data to file! chunk %d, err = 0x%x, xfer_size = 0x%x\n",
+ __func__, i, err, xfer_size);
+ goto free_mem;
+ }
+
+ curr_data_offset += xfer_size;
+ i++;
+ }
+ }
+ }
+
+ fprintf(stderr, "%s: NVMe Status:%s(%x)\n", __func__, nvme_status_to_string(ret), ret);
+ if (verbose)
+ fprintf(stderr, "INFO : WDC : Capture Device Unit Info log, length = 0x%lx\n", (long unsigned int)total_size);
+
+ free_mem:
+ close(output);
+ free(dump_data);
+
+ out:
+ free(log_hdr);
+ return ret;
+}
+
+static int wdc_cap_diag(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Capture Diagnostics Log.";
+ char *file = "Output file pathname.";
+ char *size = "Data retrieval transfer size.";
+ char f[PATH_MAX] = {0};
+ __u32 xfer_size = 0;
+ int fd;
+ __u64 capabilities = 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (cfg.file != NULL)
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ if (cfg.xfer_size != 0)
+ xfer_size = cfg.xfer_size;
+ if (wdc_get_serial_name(fd, f, PATH_MAX, "cap_diag") == -1) {
+ fprintf(stderr, "ERROR : WDC: failed to generate file name\n");
+ return -1;
+ }
+ if (cfg.file == NULL)
+ snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_CAP_DIAG) == WDC_DRIVE_CAP_CAP_DIAG)
+ return wdc_do_cap_diag(fd, f, xfer_size, 0, 0);
+
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ return 0;
+}
+
+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_admin_cmd admin_cmd;
+
+ if ((output = (uint32_t*)malloc(sizeof(uint32_t))) == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(output, 0, sizeof (uint32_t));
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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);
+ if (ret == 0)
+ *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_admin_cmd admin_cmd;
+
+ if ((output = (uint8_t*)calloc(SN730_LOG_CHUNK_SIZE, sizeof(uint8_t))) == NULL) {
+ fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno));
+ return -1;
+ }
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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);
+ 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;
+
+ if ((chunk_buf = (uint8_t*) malloc(sizeof (uint8_t) * SN730_LOG_CHUNK_SIZE)) == NULL) {
+ 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;
+ tarfile_metadata* tarInfo = NULL;
+
+ tarInfo = (struct tarfile_metadata*) malloc(sizeof(tarfile_metadata));
+ if (tarInfo == NULL) {
+ fprintf(stderr, "ERROR : WDC : malloc : %s\n", strerror(errno));
+ ret = -1;
+ goto free_buf;
+ }
+ memset(tarInfo, 0, sizeof(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 != NULL)
+ 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) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &key_log_len, SN730_GET_KEY_LOG_LENGTH);
+ if (ret) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &core_dump_log_len, SN730_GET_COREDUMP_LOG_LENGTH);
+ if (ret) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ goto free_buf;
+ }
+ ret = wdc_do_get_sn730_log_len(fd, &extended_log_len, SN730_GET_EXTENDED_LOG_LENGTH);
+ if (ret) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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) {
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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 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, and SN840 devices.";
+ char *file_size = "Output file size. Currently only supported on the SN340 device.";
+ char *offset = "Output file data offset. Currently only supported on the SN340 device.";
+ char *type = "Telemetry type - NONE, HOST, or CONTROLLER. Currently only supported on the SN640 and SN840 devices.";
+ char *verbose = "Display more debug messages.";
+ char f[PATH_MAX] = {0};
+ char fileSuffix[PATH_MAX] = {0};
+ __u32 xfer_size = 0;
+ int fd;
+ int telemetry_type = 0, telemetry_data_area = 0;
+ UtilsTimeInfo timeInfo;
+ __u8 timeStamp[MAX_PATH_LEN];
+ __u64 capabilities = 0;
+
+ struct config {
+ char *file;
+ __u32 xfer_size;
+ int data_area;
+ __u64 file_size;
+ __u64 offset;
+ char *type;
+ int verbose;
+ };
+
+ struct config cfg = {
+ .file = NULL,
+ .xfer_size = 0x10000,
+ .data_area = 3,
+ .file_size = 0,
+ .offset = 0,
+ .type = NULL,
+ .verbose = 0,
+ };
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ if (cfg.xfer_size != 0)
+ xfer_size = cfg.xfer_size;
+ else {
+ fprintf(stderr, "ERROR : WDC : Invalid length\n");
+ return -1;
+ }
+
+ if (cfg.file != NULL) {
+ 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));
+ return -1;
+ }
+ 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);
+
+ if (wdc_get_serial_name(fd, f, PATH_MAX, fileSuffix) == -1) {
+ fprintf(stderr, "ERROR : WDC: failed to generate file name\n");
+ return -1;
+ }
+ }
+
+ if (cfg.file == NULL)
+ snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
+ fprintf(stderr, "%s: filename = %s\n", __func__, f);
+
+ if (cfg.data_area > 5 || cfg.data_area == 0) {
+ fprintf(stderr, "ERROR : WDC: Data area must be 1-5\n");
+ return -1;
+ }
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_INTERNAL_LOG) == WDC_DRIVE_CAP_INTERNAL_LOG) {
+ if ((cfg.type == NULL) ||
+ (!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");
+ return -1;
+ }
+
+ return wdc_do_cap_diag(fd, f, xfer_size, telemetry_type, telemetry_data_area);
+ }
+ if ((capabilities & WDC_DRIVE_CAP_SN340_DUI) == WDC_DRIVE_CAP_SN340_DUI) {
+ /* FW requirement - xfer size must be 256k for data area 4 */
+ if (cfg.data_area >= 4)
+ xfer_size = 0x40000;
+ return wdc_do_cap_dui(fd, f, xfer_size, cfg.data_area, cfg.verbose, cfg.file_size, cfg.offset);
+ }
+ if ((capabilities & WDC_DRIVE_CAP_DUI_DATA) == WDC_DRIVE_CAP_DUI_DATA)
+ return wdc_do_cap_dui(fd, f, xfer_size, WDC_NVME_DUI_MAX_DATA_AREA, cfg.verbose, 0, 0);
+ if ((capabilities & WDC_SN730B_CAP_VUC_LOG) == WDC_SN730B_CAP_VUC_LOG)
+ return wdc_do_sn730_get_and_tar(fd, f);
+
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ return -1;
+}
+
+static int wdc_do_crash_dump(int fd, 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(fd,
+ 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 == 0) {
+ 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(fd,
+ opcode,
+ crash_dump_length,
+ cdw12,
+ file,
+ crash_dump_length);
+
+ if (ret == 0)
+ ret = wdc_do_clear_dump(fd, WDC_NVME_CLEAR_DUMP_OPCODE, cdw12_clear);
+ }
+ return ret;
+}
+
+static int wdc_crash_dump(int fd, char *file, int type)
+{
+ char f[PATH_MAX] = {0};
+ const char *dump_type;
+
+ if (file != NULL) {
+ strncpy(f, file, PATH_MAX - 1);
+ }
+
+ if (type == WDC_NVME_PFAIL_DUMP_TYPE)
+ dump_type = "_pfail_dump";
+ else
+ dump_type = "_crash_dump";
+
+ if (wdc_get_serial_name(fd, f, PATH_MAX, dump_type) == -1) {
+ fprintf(stderr, "ERROR : WDC : failed to generate file name\n");
+ return -1;
+ }
+ return wdc_do_crash_dump(fd, f, type);
+}
+
+static int wdc_do_drive_log(int fd, char *file)
+{
+ int ret;
+ __u8 *drive_log_data;
+ __u32 drive_log_length;
+ struct nvme_admin_cmd admin_cmd;
+
+ ret = wdc_dump_length(fd, 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 == NULL) {
+ 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_admin_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(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret),
+ ret);
+ if (ret == 0) {
+ 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};
+ int fd;
+ int ret;
+ __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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_DRIVE_LOG) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ if (cfg.file != NULL) {
+ strncpy(f, cfg.file, PATH_MAX - 1);
+ }
+ if (wdc_get_serial_name(fd, f, PATH_MAX, "drive_log") == -1) {
+ fprintf(stderr, "ERROR : WDC : failed to generate file name\n");
+ return -1;
+ }
+ ret = wdc_do_drive_log(fd, f);
+ }
+ 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.";
+ int fd, ret;
+ __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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_CRASH_DUMP) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_crash_dump(fd, cfg.file, WDC_NVME_CRASH_DUMP_TYPE);
+ if (ret != 0) {
+ fprintf(stderr, "ERROR : WDC : failed to read crash dump\n");
+ }
+ }
+ 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.";
+ int fd;
+ int ret;
+ __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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_PFAIL_DUMP) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_crash_dump(fd, cfg.file, WDC_NVME_PFAIL_DUMP_TYPE);
+ if (ret != 0) {
+ fprintf(stderr, "ERROR : WDC : failed to read pfail crash dump\n");
+ }
+ }
+
+ 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\nor reset interruption. Other commands may be "
+ "rejected until\nPurge 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.";
+ char *err_str;
+ int fd, ret;
+ struct nvme_passthru_cmd admin_cmd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ err_str = "";
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_PURGE_CMD_OPCODE;
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ if (ret > 0) {
+ switch (ret) {
+ case WDC_NVME_PURGE_CMD_SEQ_ERR:
+ err_str = "ERROR : WDC : Cannot execute purge, "
+ "Purge operation is in progress.\n";
+ break;
+ case WDC_NVME_PURGE_INT_DEV_ERR:
+ err_str = "ERROR : WDC : Internal Device Error.\n";
+ break;
+ default:
+ err_str = "ERROR : WDC\n";
+ }
+ }
+
+ fprintf(stderr, "%s", err_str);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ 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.";
+ int fd, ret;
+ __u8 output[WDC_NVME_PURGE_MONITOR_DATA_LEN];
+ double progress_percent;
+ struct nvme_passthru_cmd admin_cmd;
+ struct wdc_nvme_purge_monitor_data *mon;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ memset(output, 0, sizeof (output));
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ admin_cmd.opcode = WDC_NVME_PURGE_MONITOR_OPCODE;
+ admin_cmd.addr = (__u64)(uintptr_t)output;
+ admin_cmd.data_len = WDC_NVME_PURGE_MONITOR_DATA_LEN;
+ admin_cmd.cdw10 = WDC_NVME_PURGE_MONITOR_CMD_CDW10;
+ admin_cmd.timeout_ms = WDC_NVME_PURGE_MONITOR_TIMEOUT;
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ if (ret == 0) {
+ mon = (struct wdc_nvme_purge_monitor_data *) output;
+ printf("Purge state = 0x%0x\n", admin_cmd.result);
+ printf("%s\n", wdc_purge_mon_status_to_string(admin_cmd.result));
+ if (admin_cmd.result == WDC_NVME_PURGE_STATE_BUSY) {
+ progress_percent =
+ ((double)le32_to_cpu(mon->entire_progress_current) * 100) /
+ le32_to_cpu(mon->entire_progress_total);
+ printf("Purge Progress = %f%%\n", progress_percent);
+ }
+ }
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ 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;
+
+ 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 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;
+ uint64_t converted = 0;
+
+ root = json_create_object();
+ 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(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;
+
+ if (bd_data->field_id == 0x00) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" CA Log Page values :- \n");
+ printf(" Program fail counts %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf(" %% Remaining of allowable program fails %3"PRIu8"\n",
+ bd_data->normalized_value);
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x01) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Erase fail count %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ printf(" %% Remaining of allowable erase fails %3"PRIu8"\n",
+ bd_data->normalized_value);
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x02) {
+ word_raw = (__u16*)bd_data->raw_value;
+ printf(" Min erase cycles %10"PRIu16"\n",
+ le16_to_cpu(*word_raw));
+ word_raw = (__u16*)&bd_data->raw_value[2];
+ printf(" Max erase cycles %10"PRIu16"\n",
+ le16_to_cpu(*word_raw));
+ word_raw = (__u16*)&bd_data->raw_value[4];
+ printf(" Ave erase cycles %10"PRIu16"\n",
+ le16_to_cpu(*word_raw));
+ printf(" Wear Leveling Normalized %3"PRIu8"\n",
+ bd_data->normalized_value);
+
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x03) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" End to end error detection count %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x04) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Crc error count %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x05) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Timed workload media error %20.3f\n",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 1024.0));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x06) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Timed workload host reads %% %3"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00000000000000FF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x07) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Timed workload timer %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x08) {
+ byte_raw = (__u8*)bd_data->raw_value;
+ printf(" Throttle status %% %10"PRIu16"\n",
+ *byte_raw);
+ dword_raw = (__u32*)&bd_data->raw_value[1];
+ printf(" Throttling event counter %10"PRIu16"\n",
+ le32_to_cpu(*dword_raw));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x09) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Retry buffer overflow count %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0A) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Pll lock loss count %20"PRIu64"\n",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0B) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Nand bytes written (32mb) %20.0f\n",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ raw = (__u64*)bd_data->raw_value;
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0C) {
+ raw = (__u64*)bd_data->raw_value;
+ printf(" Host bytes written (32mb) %20.0f\n",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ raw = (__u64*)bd_data->raw_value;
+ } 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;
+
+ root = json_create_object();
+ if (bd_data->field_id == 0x00) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "Program fail counts",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ json_object_add_value_int(root, "% Remaining of allowable program fails",
+ bd_data->normalized_value);
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x01) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "Erase fail count",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ json_object_add_value_int(root, "% Remaining of allowable erase fails",
+ bd_data->normalized_value);
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x02) {
+ word_raw = (__u16*)bd_data->raw_value;
+ json_object_add_value_int(root, "Min erase cycles", le16_to_cpu(*word_raw));
+ word_raw = (__u16*)&bd_data->raw_value[2];
+ json_object_add_value_int(root, "Max erase cycles", le16_to_cpu(*word_raw));
+ word_raw = (__u16*)&bd_data->raw_value[4];
+ json_object_add_value_int(root, "Ave erase cycles", le16_to_cpu(*word_raw));
+ json_object_add_value_int(root, "Wear Leveling Normalized", bd_data->normalized_value);
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x03) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "End to end error detection count",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x04) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "Crc error count",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x05) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_float(root, "Timed workload media error",
+ 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;
+ json_object_add_value_int(root, "Timed workload host reads %",
+ le64_to_cpu(*raw & 0x00000000000000FF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x07) {
+ raw = (__u64*)bd_data->raw_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;
+ json_object_add_value_int(root, "Throttle status %", *byte_raw);
+ dword_raw = (__u32*)&bd_data->raw_value[1];
+ json_object_add_value_int(root, "Throttling event counter", le32_to_cpu(*dword_raw));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x09) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "Retry buffer overflow count",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0A) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_int(root, "Pll lock loss count",
+ le64_to_cpu(*raw & 0x00FFFFFFFFFFFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0B) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_float(root, "Nand bytes written (32mb)",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ } else {
+ goto invalid_id;
+ }
+ bd_data++;
+ if (bd_data->field_id == 0x0C) {
+ raw = (__u64*)bd_data->raw_value;
+ json_object_add_value_float(root, "Host bytes written (32mb)",
+ safe_div_fp((*raw & 0x00FFFFFFFFFFFFFF), 0xFFFF));
+ raw = (__u64*)bd_data->raw_value;
+ } else {
+ goto invalid_id;
+ }
+
+ goto done;
+
+ invalid_id:
+ printf(" Invalid Field ID = %d\n", bd_data->field_id);
+
+ done:
+ 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;
+
+ 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(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
+ int num_entries)
+{
+ int i;
+ char previous_fw[9];
+ char new_fw[9];
+ char commit_action_bin[8];
+ memset((void *)previous_fw, 0, 9);
+ memset((void *)new_fw, 0, 9);
+ memset((void *)commit_action_bin, 0, 8);
+ char *null_fw = "--------";
+
+
+ printf(" Firmware Activate History Log \n");
+ printf(" Power on Hour Power Cycle Previous New \n");
+ printf(" Entry hh:mm:ss Count Firmware Firmware Slot Action Result \n");
+ printf(" ----- -------------- ------------ ---------- ---------- ----- ------ -------\n");
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ printf("%5"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->entry_num));
+ printf(" ");
+ printf("%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
+ printf(" ");
+ printf("%8"PRIu32"", (uint32_t)le32_to_cpu(fw_act_history_entry->power_cycle_count));
+ printf(" ");
+ printf("%s", (char *)previous_fw);
+ printf(" ");
+ printf("%s", (char *)new_fw);
+ printf(" ");
+ printf("%2"PRIu8"", (uint8_t)fw_act_history_entry->slot_number);
+ printf(" ");
+ wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
+ printf(" %s", (char *)commit_action_bin);
+ printf(" ");
+ if (le16_to_cpu(fw_act_history_entry->result) == 0)
+ printf("pass");
+ else
+ printf("fail #%d", (uint16_t)le16_to_cpu(fw_act_history_entry->result));
+
+ printf("\n");
+
+ fw_act_history_entry++;
+ }
+}
+
+static void wdc_print_fw_act_history_log_json(struct wdc_fw_act_history_log_entry *fw_act_history_entry,
+ int num_entries)
+{
+ struct json_object *root;
+ int i;
+ char previous_fw[9];
+ char new_fw[9];
+ char commit_action_bin[8];
+ char fail_str[32];
+ char time_str[9];
+ memset((void *)previous_fw, 0, 9);
+ memset((void *)new_fw, 0, 9);
+ memset((void *)commit_action_bin, 0, 8);
+ memset((void *)time_str, 0, 9);
+ memset((void *)fail_str, 0, 11);
+ char *null_fw = "--------";
+
+ root = json_create_object();
+
+ for (i = 0; i < num_entries; i++) {
+ memcpy(previous_fw, (char *)&(fw_act_history_entry->previous_fw_version), 8);
+ if (strlen((char *)&(fw_act_history_entry->new_fw_version)) > 1)
+ memcpy(new_fw, (char *)&(fw_act_history_entry->new_fw_version), 8);
+ else
+ memcpy(new_fw, null_fw, 8);
+
+ json_object_add_value_int(root, "Entry",
+ le32_to_cpu(fw_act_history_entry->entry_num));
+
+ sprintf((char *)time_str, "%02d:%02d:%02d", (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)/3600),
+ (int)((le64_to_cpu(fw_act_history_entry->power_on_seconds)%3600)/60),
+ (int)(le64_to_cpu(fw_act_history_entry->power_on_seconds)%60));
+ json_object_add_value_string(root, "Power on Hour", time_str);
+
+ json_object_add_value_int(root, "Power Cycle Count",
+ le32_to_cpu(fw_act_history_entry->power_cycle_count));
+ json_object_add_value_string(root, "Previous Firmware",
+ previous_fw);
+ json_object_add_value_string(root, "New Firmware",
+ new_fw);
+ json_object_add_value_int(root, "Slot",
+ fw_act_history_entry->slot_number);
+
+ wdc_get_commit_action_bin(fw_act_history_entry->commit_action_type,(char *)&commit_action_bin);
+ json_object_add_value_string(root, "Action", commit_action_bin);
+
+ if (le16_to_cpu(fw_act_history_entry->result) == 0)
+ json_object_add_value_string(root, "Result", "pass");
+ else {
+ sprintf((char *)fail_str, "fail #%d", (int)(le16_to_cpu(fw_act_history_entry->result)));
+ json_object_add_value_string(root, "Result", fail_str);
+ }
+
+ fw_act_history_entry++;
+ }
+
+ json_print_object(root, NULL);
+ printf("\n");
+
+ json_free_object(root);
+}
+
+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(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(bd_data);
+ break;
+ case JSON:
+ wdc_print_bd_ca_log_json(bd_data);
+ break;
+ }
+ 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(struct wdc_fw_act_history_log_entry *fw_act_history_entries,
+ int num_entries,
+ int fmt)
+{
+ if (!fw_act_history_entries) {
+ fprintf(stderr, "ERROR : WDC : Invalid buffer to read fw activate history entries\n");
+ return -1;
+ }
+
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_fw_act_history_log_normal(fw_act_history_entries, num_entries);
+ break;
+ case JSON:
+ wdc_print_fw_act_history_log_json(fw_act_history_entries, num_entries);
+ break;
+ }
+ return 0;
+}
+
+static int wdc_get_ca_log_page(int fd, char *format)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ __u32 *cust_id;
+ struct wdc_ssd_ca_perf_stats *perf;
+ uint32_t read_device_id, read_vendor_id;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ /* verify the 0xCA log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE) == false) {
+ fprintf(stderr, "ERROR : WDC : 0xCA Log Page not supported\n");
+ return -1;
+ }
+
+ if (!get_dev_mgment_cbs_data(fd, WDC_C2_CUSTOMER_ID_ID, (void*)&data)) {
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_CUSTOMER_ID_ID);
+ return -1;
+ }
+
+ ret = wdc_get_pci_ids(&read_device_id, &read_vendor_id);
+
+ cust_id = (__u32*)data;
+
+ switch (read_device_id) {
+
+ case WDC_NVME_SN200_DEV_ID:
+
+ if (*cust_id == WDC_CUSTOMER_ID_0x1005) {
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) {
+ 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(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ false, WDC_FB_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ 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 = %d\n", *cust_id);
+ return -1;
+ }
+ break;
+
+ case WDC_NVME_SN640_DEV_ID:
+ case WDC_NVME_SN640_DEV_ID_1:
+ case WDC_NVME_SN640_DEV_ID_2:
+ case WDC_NVME_SN640_DEV_ID_3:
+ case WDC_NVME_SN840_DEV_ID:
+ case WDC_NVME_SN840_DEV_ID_1:
+
+ if (*cust_id == WDC_CUSTOMER_ID_0x1005) {
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FB_CA_LOG_BUF_LEN)) == NULL) {
+ 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(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ false, WDC_FB_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ 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)) {
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_BD_CA_LOG_BUF_LEN)) == NULL) {
+ 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(fd, 0xFFFFFFFF, WDC_NVME_GET_DEVICE_INFO_LOG_OPCODE,
+ false, WDC_BD_CA_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ ret = wdc_print_bd_ca_log(data, fmt);
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read CA Log Page data\n");
+ ret = -1;
+ }
+
+ break;
+ } else {
+
+ fprintf(stderr, "ERROR : WDC : Unsupported Customer id, id = %d\n", *cust_id);
+ return -1;
+ }
+ break;
+
+ default:
+
+ fprintf(stderr, "ERROR : WDC : Log page 0xCA not supported for this device\n");
+ return -1;
+ break;
+ }
+
+ free(data);
+ return ret;
+}
+
+static int wdc_get_c1_log_page(int fd, char *format, uint8_t interval)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ __u8 *p;
+ int i;
+ int skip_cnt = 4;
+ int total_subpages;
+ struct wdc_log_page_header *l;
+ struct wdc_log_page_subpage_header *sph;
+ struct wdc_ssd_perf_stats *perf;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ if (interval < 1 || interval > 15) {
+ fprintf(stderr, "ERROR : WDC : interval out of range [1-15]\n");
+ return -1;
+ }
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_ADD_LOG_BUF_LEN)) == NULL) {
+ 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(fd, 0x01, WDC_NVME_ADD_LOG_OPCODE, false,
+ WDC_ADD_LOG_BUF_LEN, data);
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ if (ret == 0) {
+ 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_d0_log_page(int fd, char *format)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ struct wdc_ssd_d0_smart_log *perf;
+
+ if (!wdc_check_device(fd))
+ return -1;
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ /* verify the 0xD0 log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_VU_SMART_LOG_OPCODE) == false) {
+ fprintf(stderr, "ERROR : WDC : 0xD0 Log Page not supported\n");
+ return -1;
+ }
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_NVME_VU_SMART_LOG_LEN)) == NULL) {
+ 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(fd, 0xFFFFFFFF, WDC_NVME_GET_VU_SMART_LOG_OPCODE,
+ false, WDC_NVME_VU_SMART_LOG_LEN, data);
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ 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 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].";
+ int fd;
+ int ret = 0;
+ __u64 capabilities = 0;
+
+ struct config {
+ uint8_t interval;
+ int vendor_specific;
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .interval = 14,
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("interval", 'i', &cfg.interval, interval),
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_SMART_LOG_MASK) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ if ((capabilities & (WDC_DRIVE_CAP_CA_LOG_PAGE)) == (WDC_DRIVE_CAP_CA_LOG_PAGE)) {
+ /* Get the CA Log Page */
+ ret = wdc_get_ca_log_page(fd, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the CA Log Page, ret = %d\n", ret);
+ }
+ if ((capabilities & WDC_DRIVE_CAP_C1_LOG_PAGE) == WDC_DRIVE_CAP_C1_LOG_PAGE) {
+ /* Get the C1 Log Page */
+ ret = wdc_get_c1_log_page(fd, cfg.output_format, cfg.interval);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the C1 Log Page, ret = %d\n", ret);
+ }
+ if ((capabilities & WDC_DRIVE_CAP_D0_LOG_PAGE) == WDC_DRIVE_CAP_D0_LOG_PAGE) {
+ /* Get the D0 Log Page */
+ ret = wdc_get_d0_log_page(fd, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the D0 Log Page, ret = %d\n", ret);
+ }
+out:
+ return ret;
+}
+
+static int wdc_clear_pcie_correctable_errors(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Clear PCIE Correctable Errors.";
+ int fd, ret;
+ __u64 capabilities = 0;
+ struct nvme_passthru_cmd admin_cmd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ if (!wdc_check_device(fd)) {
+ ret = -1;
+ goto out;
+ }
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_CLEAR_PCIE) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_PCIE_CORR_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_PCIE_CORR_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_PCIE_CORR_CMD);
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+out:
+ return ret;
+}
+static int wdc_drive_status(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ char *desc = "Get Drive Status.";
+ int fd;
+ int ret = -1;
+ __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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ 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(fd, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == 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(fd, &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(fd, &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(fd, &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(fd, &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(fd, &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(fd, &format_corrupt_reason,
+ WDC_C2_FORMAT_CORRUPT_REASON_ID))
+ fprintf(stderr, "ERROR : WDC : Get Format Corrupt Reason Failed\n");
+
+ printf(" Drive Status :- \n");
+ if (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:
+ 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.";
+ int fd;
+ int ret = -1;
+ __le32 assert_status = cpu_to_le32(0xFFFFFFFF);
+ __u64 capabilities = 0;
+ struct nvme_passthru_cmd admin_cmd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ 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(fd, &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(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ } else
+ fprintf(stderr, "INFO : WDC : No Assert Dump Present\n");
+
+out:
+ return ret;
+}
+
+static int wdc_get_fw_act_history(int fd, char *format)
+{
+ int ret = 0;
+ int fmt = -1;
+ __u8 *data;
+ struct wdc_fw_act_history_log_hdr *fw_act_history_hdr;
+ struct wdc_fw_act_history_log_entry *fw_act_history_entry;
+
+ if (!wdc_check_device(fd))
+ return -1;
+
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ return fmt;
+ }
+
+ /* verify the FW Activate History log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID) == false) {
+ fprintf(stderr, "ERROR : WDC : %d Log Page not supported\n", WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID);
+ return -1;
+ }
+
+ if ((data = (__u8*) malloc(sizeof (__u8) * WDC_FW_ACT_HISTORY_LOG_BUF_LEN)) == NULL) {
+ 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(fd, 0xFFFFFFFF, WDC_NVME_GET_FW_ACT_HISTORY_LOG_ID,
+ false, WDC_FW_ACT_HISTORY_LOG_BUF_LEN, data);
+
+ if (strcmp(format, "json"))
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ if (ret == 0) {
+ /* parse the data */
+ fw_act_history_hdr = (struct wdc_fw_act_history_log_hdr *)(data);
+ fw_act_history_entry = (struct wdc_fw_act_history_log_entry *)(data + sizeof(struct wdc_fw_act_history_log_hdr));
+
+ if (fw_act_history_hdr->num_entries > 0)
+ ret = wdc_print_fw_act_history_log(fw_act_history_entry, fw_act_history_hdr->num_entries, fmt);
+ else
+ fprintf(stderr, "INFO : WDC : No entries found in FW Activate History Log Page\n");
+ } else {
+ fprintf(stderr, "ERROR : WDC : Unable to read FW Activate History Log Page data\n");
+ ret = -1;
+ }
+
+ free(data);
+ return ret;
+}
+
+static int wdc_vs_fw_activate_history(int argc, char **argv, struct command *command,
+ struct plugin *plugin)
+{
+ int fd;
+ int ret = 0;
+ __u64 capabilities = 0;
+ const char *desc = "Retrieve FW activate history table.";
+
+
+ struct config {
+ char *output_format;
+ };
+
+ struct config cfg = {
+ .output_format = "normal",
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_FMT("output-format", 'o', &cfg.output_format, "Output Format: normal|json"),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) == WDC_DRIVE_CAP_FW_ACTIVATE_HISTORY) {
+ ret = wdc_get_fw_act_history(fd, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading the FW Activate History, ret = %d\n", ret);
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+
+ 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.";
+ int fd;
+ int ret = -1;
+ __u64 capabilities = 0;
+ struct nvme_passthru_cmd admin_cmd;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) != WDC_DRIVE_CAP_CLEAR_FW_ACT_HISTORY) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ goto out;
+ }
+
+ memset(&admin_cmd, 0, sizeof (admin_cmd));
+ admin_cmd.opcode = WDC_NVME_CLEAR_FW_ACT_HIST_OPCODE;
+ admin_cmd.cdw12 = ((WDC_NVME_CLEAR_FW_ACT_HIST_SUBCMD << WDC_NVME_SUBCMD_SHIFT) |
+ WDC_NVME_CLEAR_FW_ACT_HIST_CMD);
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+out:
+ 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.";
+ int fd;
+ int ret = -1;
+ __u64 capabilities = 0;
+ __u32 result;
+ void *buf = NULL;
+
+
+ struct config {
+ int disable;
+ int enable;
+ int status;
+ };
+
+ struct config cfg = {
+ .disable = 0,
+ .enable = 0,
+ .status = 0,
+ };
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ 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_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 1,
+ 0, 0, 0, buf, &result);
+
+ wdc_clear_reason_id(fd);
+ }
+ else {
+ if (cfg.enable) {
+ ret = nvme_set_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0,
+ 0, 0, 0, buf, &result);
+ }
+ else if (cfg.status) {
+ ret = nvme_get_feature(fd, 0, WDC_VU_DISABLE_CNTLR_TELEMETRY_OPTION_FEATURE_ID, 0, 0,
+ 4, buf, &result);
+ if (ret == 0) {
+ if (result)
+ fprintf(stderr, "Controller Option Telemetry Log Page State: Disabled\n");
+ else
+ fprintf(stderr, "Controller Option Telemetry Log Page State: Enabled\n");
+ } else {
+ fprintf(stderr, "ERROR : WDC: NVMe Status:%s(%x)\n", nvme_status_to_string(ret), 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:
+ return ret;
+}
+
+
+static int wdc_get_serial_and_fw_rev(int fd, 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(fd, &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(int fd, __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(fd, &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(int fd, __u32 fileId, __u16 spiDestn, __u32* logSize)
+{
+ int ret = WDC_STATUS_FAILURE;
+ struct nvme_admin_cmd cmd;
+
+ if(!fd || !logSize )
+ {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ memset(&cmd,0,sizeof(struct nvme_admin_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(fd, &cmd);
+
+ if (!ret && logSize)
+ *logSize = cmd.result;
+ if( ret != WDC_STATUS_SUCCESS)
+ fprintf(stderr, "ERROR : WDC : VUReadSize() failed, status:%s(0x%x)\n", nvme_status_to_string(ret), ret);
+
+ end:
+ return ret;
+}
+
+static int wdc_de_VU_read_buffer(int fd, __u32 fileId, __u16 spiDestn, __u32 offsetInDwords, __u8* dataBuffer, __u32* bufferSize)
+{
+ int ret = WDC_STATUS_FAILURE;
+ struct nvme_admin_cmd cmd;
+ __u32 noOfDwordExpected = 0;
+
+ if(!fd || !dataBuffer || !bufferSize)
+ {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ memset(&cmd,0,sizeof(struct nvme_admin_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(fd, &cmd);
+
+ if( ret != WDC_STATUS_SUCCESS)
+ fprintf(stderr, "ERROR : WDC : VUReadBuffer() failed, status:%s(0x%x)\n", nvme_status_to_string(ret), ret);
+
+ end:
+ return ret;
+}
+
+static int wdc_get_log_dir_max_entries(int fd, __u32* maxNumOfEntries)
+{
+ int ret = WDC_STATUS_FAILURE;
+ __u32 headerPayloadSize = 0;
+ __u8* fileIdOffsetsBuffer = NULL;
+ __u32 fileIdOffsetsBufferSize = 0;
+ __u32 fileNum = 0;
+ __u16 fileOffset = 0;
+
+
+ if (!fd || !maxNumOfEntries)
+ {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+ /* 1.Get log directory first four bytes */
+ if (WDC_STATUS_SUCCESS != (ret = wdc_de_VU_read_size(fd, 0, 5, (__u32*)&headerPayloadSize)))
+ {
+ fprintf(stderr, "ERROR : WDC : %s: Failed to get headerPayloadSize from file directory 0x%x\n",
+ __func__, ret);
+ goto end;
+ }
+
+ fileIdOffsetsBufferSize = WDC_DE_FILE_HEADER_SIZE + (headerPayloadSize * WDC_DE_FILE_OFFSET_SIZE);
+ fileIdOffsetsBuffer = (__u8*)calloc(1, fileIdOffsetsBufferSize);
+
+ /* 2.Read to get file offsets */
+ if (WDC_STATUS_SUCCESS != (ret = wdc_de_VU_read_buffer(fd, 0, 5, 0, fileIdOffsetsBuffer, &fileIdOffsetsBufferSize)))
+ {
+ 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:
+ if (!fileIdOffsetsBuffer)
+ free(fileIdOffsetsBuffer);
+ return ret;
+}
+
+static WDC_DRIVE_ESSENTIAL_TYPE wdc_get_essential_type(__u8 fileName[])
+{
+ WDC_DRIVE_ESSENTIAL_TYPE essentialType = WDC_DE_TYPE_NONE;
+
+ if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_CORE_DUMP_FILE_NAME) == 0)
+ {
+ essentialType = WDC_DE_TYPE_DUMPSNAPSHOT;
+ }
+ else if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_EVENT_LOG_FILE_NAME) == 0)
+ {
+ essentialType = WDC_DE_TYPE_EVENTLOG;
+ }
+ else if (wdc_UtilsStrCompare((char*)fileName, WDC_DE_MANUFACTURING_INFO_PAGE_FILE_NAME) == 0)
+ {
+ essentialType = WDC_DE_TYPE_NVME_MANF_INFO;
+ }
+
+ return essentialType;
+}
+
+static int wdc_fetch_log_directory(int fd, PWDC_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 (!fd || !directory) {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ ret = wdc_de_VU_read_size(fd, 0, 5, &fileDirectorySize);
+ if (WDC_STATUS_SUCCESS != ret) {
+ 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(fd, 0, 5, 0, fileDirectory, &fileDirectorySize);
+ if (WDC_STATUS_SUCCESS != ret) {
+ 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 == 0) {
+ 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 (0 == fileOffsetTemp)
+ continue;
+
+ memset(&directory->logEntry[entryId], 0, sizeof(WDC_DRIVE_ESSENTIALS));
+ memcpy(&directory->logEntry[entryId].metaData, fileOffset, sizeof(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 (0 == directory->logEntry[entryId].metaData.fileID)
+ continue;
+
+ directory->logEntry[entryId].essentialType = wdc_get_essential_type(directory->logEntry[entryId].metaData.fileName);
+ /*fprintf(stderr, "WDC : %s: NVMe VU Log Entry %d, fileName = %s, fileSize = 0x%lx, fileId = 0x%x\n",
+ __func__, entryId, directory->logEntry[entryId].metaData.fileName,
+ (long unsigned int)directory->logEntry[entryId].metaData.fileSize, directory->logEntry[entryId].metaData.fileID);
+ */
+ entryId++;
+ }
+
+ directory->numOfValidLogEntries = entryId;
+end:
+ if (fileDirectory != NULL)
+ free(fileDirectory);
+ return ret;
+}
+
+static int wdc_fetch_log_file_from_device(int fd, __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 (!fd || !dataBuffer || !fileSize)
+ {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ goto end;
+ }
+
+ wdc_get_max_transfer_len(fd, &maximumTransferLength);
+
+ /* 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(fd, 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, (long unsigned int)fileSize);
+ break;
+ }
+ }
+ } else {
+ buffSize = (__u32)fileSize;
+ ret = wdc_de_VU_read_buffer(fd, 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, (long unsigned int)fileSize);
+ }
+ }
+
+ end:
+ return ret;
+}
+
+static int wdc_de_get_dump_trace(int fd, 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 (!fd || !binFileName || !filePath)
+ {
+ ret = WDC_STATUS_INVALID_PARAMETER;
+ return ret;
+ }
+
+ wdc_get_max_transfer_len(fd, &maximumTransferLength);
+
+ do
+ {
+ /* Get dumptrace size */
+ ret = wdc_de_VU_read_size(fd, 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 == NULL)
+ {
+ 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(fd, 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;
+}
+
+static int wdc_do_drive_essentials(int fd, 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;
+ __u32 maxNumOfVUFiles = 0;
+ 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_log_page fw_log;
+ PWDC_NVME_DE_VU_LOGPAGES vuLogInput = NULL;
+ WDC_DE_VU_LOG_DIRECTORY deEssentialsList;
+
+ 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));
+ memset(&vuLogInput, 0, sizeof(vuLogInput));
+
+ if (wdc_get_serial_and_fw_rev(fd, (char *)idSerialNo, (char *)idFwRev))
+ {
+ fprintf(stderr, "ERROR : WDC : get serial # and fw revision failed\n");
+ return -1;
+ } else {
+ 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 != NULL) {
+ 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 != NULL)
+ 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 != 0)
+ {
+ fprintf(stderr, "ERROR : WDC : create directory failed, ret = %d, dir = %s\n", ret, bufferFolderPath);
+ return -1;
+ } else {
+ 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(fd, &ctrl);
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : nvme_identify_ctrl() failed, ret = %d\n", ret);
+ return -1;
+ } else {
+ 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(fd, 1, 0, &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_error_log(fd, elogNumEntries, 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_smart_log(fd, NVME_NSID_ALL, &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_log_page));
+ ret = nvme_fw_log(fd, &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_log_page));
+ }
+
+ /* Get VU log pages */
+ /* define inputs for vendor unique log pages */
+ vuLogInput = (PWDC_NVME_DE_VU_LOGPAGES)calloc(1, sizeof(WDC_NVME_DE_VU_LOGPAGES));
+ vuLogInput->numOfVULogPages = sizeof(deVULogPagesList) / sizeof(deVULogPagesList[0]);
+
+ for (vuLogIdx = 0; vuLogIdx < vuLogInput->numOfVULogPages; vuLogIdx++)
+ {
+ dataBufferSize = deVULogPagesList[vuLogIdx].logPageLen;
+ dataBuffer = calloc(1, dataBufferSize);
+ memset(dataBuffer, 0, dataBufferSize);
+
+ ret = nvme_get_log(fd, WDC_DE_GLOBAL_NSID, deVULogPagesList[vuLogIdx].logPageId,
+ false, 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 < (sizeof(deFeatureIdList) / sizeof(deFeatureIdList[0])); 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_feature(fd, WDC_DE_GLOBAL_NSID, deFeatureIdList[listIdx].featureId, FS_CURRENT, 0,
+ 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));
+ }
+ }
+
+ /* Read Debug Directory */
+ ret = wdc_get_log_dir_max_entries(fd, &maxNumOfVUFiles);
+ if (ret == WDC_STATUS_SUCCESS)
+ {
+ memset(&deEssentialsList, 0, sizeof(deEssentialsList));
+ deEssentialsList.logEntry = (WDC_DRIVE_ESSENTIALS*)calloc(1, sizeof(WDC_DRIVE_ESSENTIALS)*maxNumOfVUFiles);
+ deEssentialsList.maxNumLogEntries = maxNumOfVUFiles;
+
+ /* Fetch VU File Directory */
+ ret = wdc_fetch_log_directory(fd, &deEssentialsList);
+ if (ret == WDC_STATUS_SUCCESS)
+ {
+ /* Get Debug Data Files */
+ for (listIdx = 0; listIdx < deEssentialsList.numOfValidLogEntries; listIdx++)
+ {
+ if (0 == 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(fd, 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);
+ dataBuffer = NULL;
+ }
+ }
+ } else {
+ fprintf(stderr, "WDC : wdc_fetch_log_directory failed, ret = %d\n", ret);
+ }
+
+ free(deEssentialsList.logEntry);
+ deEssentialsList.logEntry = NULL;
+ } else {
+ fprintf(stderr, "WDC : wdc_get_log_dir_max_entries failed, ret = %d\n", ret);
+ }
+
+ /* 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);
+ if (WDC_STATUS_SUCCESS != (ret = wdc_de_get_dump_trace(fd, (char*)bufferFolderPath, 0, fileName)))
+ {
+ 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 != NULL) {
+ 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");
+ 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};
+ char *d_ptr;
+ int fd;
+ __u64 capabilities = 0;
+
+ struct config {
+ char *dirName;
+ };
+
+ struct config cfg = {
+ .dirName = NULL,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_STRING("dir-name", 'd', "DIRECTORY", &cfg.dirName, dirName),
+ OPT_END()
+ };
+
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_DRIVE_ESSENTIALS) != WDC_DRIVE_CAP_DRIVE_ESSENTIALS) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ return -1;
+ }
+
+ if (cfg.dirName != NULL) {
+ strncpy(d, cfg.dirName, PATH_MAX - 1);
+ d_ptr = d;
+ } else {
+ d_ptr = NULL;
+ }
+
+ return wdc_do_drive_essentials(fd, d_ptr, k);
+}
+
+static int wdc_do_drive_resize(int fd, uint64_t new_size)
+{
+ int ret;
+ struct nvme_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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(fd, &admin_cmd);
+ return ret;
+}
+
+static int wdc_do_namespace_resize(int fd, __u32 nsid, __u32 op_option)
+{
+ int ret;
+ struct nvme_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_cmd));
+ admin_cmd.opcode = WDC_NVME_NAMESPACE_RESIZE_OPCODE;
+ admin_cmd.nsid = nsid;
+ admin_cmd.cdw10 = op_option;
+
+ ret = nvme_submit_admin_passthru(fd, &admin_cmd);
+ return ret;
+}
+
+static int wdc_do_drive_info(int fd, __u32 *result)
+{
+ int ret;
+ struct nvme_admin_cmd admin_cmd;
+
+ memset(&admin_cmd, 0, sizeof (struct nvme_admin_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(fd, &admin_cmd);
+
+ 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;
+ int fd, ret;
+
+ struct config {
+ uint64_t size;
+ };
+
+ struct config cfg = {
+ .size = 0,
+ };
+
+ OPT_ARGS(opts) = {
+ OPT_UINT("size", 's', &cfg.size, size),
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_RESIZE) == WDC_DRIVE_CAP_RESIZE) {
+ ret = wdc_do_drive_resize(fd, 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);
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ 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;
+ int fd, 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ 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");
+ return -1;
+ }
+
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_NS_RESIZE) == WDC_DRIVE_CAP_NS_RESIZE) {
+ ret = wdc_do_namespace_resize(fd, cfg.namespace_id, cfg.op_option);
+
+ if (ret != 0)
+ 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;
+ }
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ 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";
+ int fd;
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+
+ if (fd < 0)
+ return fd;
+
+ if (cfg.log_id != NVME_LOG_TELEMETRY_HOST && cfg.log_id != NVME_LOG_TELEMETRY_CTRL) {
+ fprintf(stderr, "ERROR : WDC: Invalid Log ID. It must be 7 (Host) or 8 (Controller)\n");
+ ret = -1;
+ goto close_fd;
+ }
+
+ if (cfg.file != NULL) {
+ 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_fd;
+ }
+ 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_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(fd, f, PATH_MAX, fileSuffix) == -1) {
+ fprintf(stderr, "ERROR : WDC: failed to generate file name\n");
+ ret = -1;
+ goto close_fd;
+ }
+
+ snprintf(f + strlen(f), PATH_MAX, "%s", ".bin");
+ }
+
+ fprintf(stderr, "%s: filename = %s\n", __func__, f);
+
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_REASON_ID) == WDC_DRIVE_CAP_REASON_ID) {
+ ret = wdc_do_get_reason_id(fd, f, cfg.log_id);
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+
+ close_fd:
+ close(fd);
+ return ret;
+}
+
+static const char *nvme_log_id_to_string(__u8 log_id)
+{
+ switch (log_id) {
+ case NVME_LOG_ERROR: return "Error Information Log ID";
+ case NVME_LOG_SMART: return "Smart/Health Information Log ID";
+ case NVME_LOG_FW_SLOT: return "Firmware Slot Information Log ID";
+ case NVME_LOG_CHANGED_NS: return "Namespace Changed Log ID";
+ case NVME_LOG_CMD_EFFECTS: return "Commamds Supported and Effects Log ID";
+ case NVME_LOG_DEVICE_SELF_TEST: return "Device Self Test Log ID";
+ case NVME_LOG_TELEMETRY_HOST: return "Telemetry Host Initiated Log ID";
+ case NVME_LOG_TELEMETRY_CTRL: return "Telemetry Controller Generated Log ID";
+ case NVME_LOG_ENDURANCE_GROUP: return "Endurance Group Log ID";
+ case NVME_LOG_ANA: return "ANA Log ID";
+ case NVME_LOG_PERSISTENT_EVENT: return "Persistent Event Log ID";
+ case NVME_LOG_DISC: return "Discovery Log ID";
+ case NVME_LOG_RESERVATION: return "Reservation Notification Log ID";
+ case NVME_LOG_SANITIZE: return "Sanitize Status Log ID";
+
+ case WDC_LOG_ID_C0: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C2: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C4: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C5: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_C6: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_CA: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_CB: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_D0: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_D6: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_D7: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_D8: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_DE: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_F0: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_F1: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_F2: return "WDC Vendor Unique Log ID";
+ case WDC_LOG_ID_FA: return "WDC Vendor Unique Log ID";
+
+ default: return "Unknown 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.";
+ int fd;
+ int ret = 0;
+ __u64 capabilities = 0;
+ struct wdc_c2_cbs_data *cbs_data = NULL;
+ int i;
+
+ 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ ret = validate_output_format(cfg.output_format);
+ if (ret < 0) {
+ fprintf(stderr, "%s: ERROR : WDC : invalid output format\n", __func__);
+ return ret;
+ }
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_LOG_PAGE_DIR) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ /* verify the 0xC2 Device Manageability log page is supported */
+ if (wdc_nvme_check_supported_log_page(fd, WDC_NVME_GET_DEV_MGMNT_LOG_PAGE_OPCODE) == false) {
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page not supported\n", __func__);
+ ret = -1;
+ goto out;
+ }
+
+ if (get_dev_mgment_cbs_data(fd, WDC_C2_LOG_PAGES_SUPPORTED_ID, (void *)&cbs_data)) {
+ if (cbs_data != NULL) {
+ 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;
+ 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);
+ } else
+ fprintf(stderr, "%s: ERROR : WDC : NULL_data ptr\n", __func__);
+ } else
+ fprintf(stderr, "%s: ERROR : WDC : 0xC2 Log Page entry ID 0x%x not found\n", __func__, WDC_C2_LOG_PAGES_SUPPORTED_ID);
+
+
+ }
+
+ out:
+ return ret;
+}
+
+static int wdc_get_drive_reason_id(int fd, 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(fd, &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(int fd, __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(fd, 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) {
+ mkdir(reason_id_path, 0700);
+ }
+
+ 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(int fd)
+{
+ int ret = -1;
+ int verify_file;
+ char *reason_id_file;
+ char drive_reason_id[PATH_MAX] = {0};
+
+ if (wdc_get_drive_reason_id(fd, 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_do_get_reason_id(int fd, char *file, int log_id)
+{
+ int ret;
+ struct nvme_telemetry_log_page_hdr *log_hdr;
+ __u32 log_hdr_size = sizeof(struct nvme_telemetry_log_page_hdr);
+ __u32 reason_id_size = 0;
+
+ log_hdr = (struct nvme_telemetry_log_page_hdr *) malloc(log_hdr_size);
+ if (log_hdr == NULL) {
+ 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(fd, log_id, log_hdr);
+ if (ret != 0) {
+ 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_TELEMETRY_CTRL)
+ wdc_save_reason_id(fd, 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 int wdc_dump_telemetry_hdr(int fd, int log_id, struct nvme_telemetry_log_page_hdr *log_hdr)
+{
+ int ret = 0;
+ int host_gen = 0, ctrl_init = 0;
+
+ if (log_id == NVME_LOG_TELEMETRY_HOST)
+ host_gen = 1;
+ else
+ ctrl_init = 1;
+
+ ret = nvme_get_telemetry_log(fd, log_hdr, host_gen, ctrl_init, 512, 0);
+ 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 void wdc_print_nand_stats_normal(struct wdc_nand_stats *data)
+{
+ printf(" NAND Statistics :- \n");
+ printf(" NAND Writes TLC (Bytes) %.0Lf\n",
+ int128_to_double(data->nand_write_tlc));
+ printf(" NAND Writes SLC (Bytes) %.0Lf\n",
+ int128_to_double(data->nand_write_slc));
+ printf(" NAND Program Failures %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(data->nand_prog_failure));
+ printf(" NAND Erase Failures %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(data->nand_erase_failure));
+ printf(" Bad Block Count %"PRIu32"\n",
+ (uint32_t)le32_to_cpu(data->bad_block_count));
+ printf(" NAND XOR/RAID Recovery Trigger Events %"PRIu64"\n",
+ le64_to_cpu(data->nand_rec_trigger_event));
+ printf(" E2E Error Counter %"PRIu64"\n",
+ le64_to_cpu(data->e2e_error_counter));
+ printf(" Number Successful NS Resizing Events %"PRIu64"\n",
+ le64_to_cpu(data->successful_ns_resize_event));
+}
+
+static void wdc_print_nand_stats_json(struct wdc_nand_stats *data)
+{
+ struct json_object *root;
+
+ root = json_create_object();
+ json_object_add_value_float(root, "NAND Writes TLC (Bytes)",
+ int128_to_double(data->nand_write_tlc));
+ json_object_add_value_float(root, "NAND Writes SLC (Bytes)",
+ int128_to_double(data->nand_write_slc));
+ json_object_add_value_uint(root, "NAND Program Failures",
+ le32_to_cpu(data->nand_prog_failure));
+ json_object_add_value_uint(root, "NAND Erase Failures",
+ le32_to_cpu(data->nand_erase_failure));
+ json_object_add_value_uint(root, "Bad Block Count",
+ le32_to_cpu(data->bad_block_count));
+ json_object_add_value_uint(root, "NAND XOR/RAID Recovery Trigger Events",
+ le64_to_cpu(data->nand_rec_trigger_event));
+ json_object_add_value_uint(root, "E2E Error Counter",
+ le64_to_cpu(data->e2e_error_counter));
+ json_object_add_value_uint(root, "Number Successful NS Resizing Events",
+ le64_to_cpu(data->successful_ns_resize_event));
+
+ json_print_object(root, NULL);
+ printf("\n");
+ json_free_object(root);
+}
+
+static int wdc_do_vs_nand_stats(int fd, char *format)
+{
+ int ret;
+ int fmt = -1;
+ uint8_t *output = NULL;
+ struct wdc_nand_stats *nand_stats;
+
+ if ((output = (uint8_t*)calloc(WDC_NVME_NAND_STATS_SIZE, sizeof(uint8_t))) == NULL) {
+ fprintf(stderr, "ERROR : WDC : calloc : %s\n", strerror(errno));
+ ret = -1;
+ goto out;
+ }
+
+ ret = nvme_get_log(fd, 0xFFFFFFFF, WDC_NVME_NAND_STATS_LOG_ID,
+ false, WDC_NVME_NAND_STATS_SIZE, (void*)output);
+ if (ret) {
+ fprintf(stderr, "ERROR : WDC : %s : Failed to retreive NAND stats\n", __func__);
+ goto out;
+ } else {
+ fmt = validate_output_format(format);
+ if (fmt < 0) {
+ fprintf(stderr, "ERROR : WDC : invalid output format\n");
+ ret = fmt;
+ goto out;
+ }
+
+ /* parse the data */
+ nand_stats = (struct wdc_nand_stats *)(output);
+ switch (fmt) {
+ case NORMAL:
+ wdc_print_nand_stats_normal(nand_stats);
+ break;
+ case JSON:
+ wdc_print_nand_stats_json(nand_stats);
+ 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.";
+ int fd;
+ int ret = 0;
+ __u64 capabilities = 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()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ capabilities = wdc_get_drive_capabilities(fd);
+
+ if ((capabilities & WDC_DRIVE_CAP_NAND_STATS) == 0) {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ } else {
+ ret = wdc_do_vs_nand_stats(fd, cfg.output_format);
+ if (ret)
+ fprintf(stderr, "ERROR : WDC : Failure reading NAND statistics, ret = %d\n", ret);
+ }
+
+ 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.";
+ uint64_t capabilities = 0;
+ int fd, ret;
+ __le32 result;
+ __u16 size;
+ double rev;
+
+ OPT_ARGS(opts) = {
+ OPT_END()
+ };
+
+ fd = parse_and_open(argc, argv, desc, opts);
+ if (fd < 0)
+ return fd;
+
+ wdc_check_device(fd);
+ capabilities = wdc_get_drive_capabilities(fd);
+ if ((capabilities & WDC_DRIVE_CAP_INFO) == WDC_DRIVE_CAP_INFO) {
+ ret = wdc_do_drive_info(fd, &result);
+ } else {
+ fprintf(stderr, "ERROR : WDC: unsupported device for this command\n");
+ ret = -1;
+ }
+
+ if (!ret) {
+ size = (__u16)((cpu_to_le32(result) & 0xffff0000) >> 16);
+ rev = (double)(cpu_to_le32(result) & 0x0000ffff);
+
+ printf("Drive HW Revison: %4.1f\n", (.1 * rev));
+ printf("FTL Unit Size: 0x%x KB\n", size);
+ }
+
+ fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(ret), ret);
+ return ret;
+}
+
+
diff --git a/plugins/wdc/wdc-nvme.h b/plugins/wdc/wdc-nvme.h
new file mode 100644
index 0000000..c6b2d3f
--- /dev/null
+++ b/plugins/wdc/wdc-nvme.h
@@ -0,0 +1,38 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/wdc/wdc-nvme
+
+#if !defined(WDC_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define WDC_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("wdc", "Western Digital vendor specific extensions"),
+ 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("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)
+ )
+);
+
+#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..80d9955
--- /dev/null
+++ b/plugins/wdc/wdc-utils.c
@@ -0,0 +1,146 @@
+/*
+ * 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 "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;
+ timeInfo->zone = -currTimeInfo.tm_gmtoff / 60;
+
+ 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 comapring.
+ * @param pcDst Points to a null terminated string for comapring.
+ *
+ * @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;
+}
+
diff --git a/plugins/wdc/wdc-utils.h b/plugins/wdc/wdc-utils.h
new file mode 100644
index 0000000..251339f
--- /dev/null
+++ b/plugins/wdc/wdc-utils.h
@@ -0,0 +1,77 @@
+/*
+ * 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 <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);
+
diff --git a/regress b/regress
new file mode 100755
index 0000000..aa7820c
--- /dev/null
+++ b/regress
@@ -0,0 +1,112 @@
+#!/bin/bash
+#
+# 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/gen-hostnqn.sh b/scripts/gen-hostnqn.sh
new file mode 100644
index 0000000..d8783cf
--- /dev/null
+++ b/scripts/gen-hostnqn.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+LC_ALL=C
+
+UUID=$(dmidecode -s system-uuid | tr -d '[:space:]')
+
+if [ -z "$UUID" ] ; then
+ >&2 echo "No UUID found, can't determine hostnqn."
+ exit 1
+fi
+
+# convert UUID to lower-case only:
+UUID=$(echo $UUID | tr '[:upper:]' '[:lower:]')
+
+# check UUID format, e.g.: 4c4c4544-0156-4a10-8134-b7d04f383232, so: 8-4-4-4-12
+if ! [[ $UUID =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]] ; then
+ >&2 echo "UUID has invalid format."
+ >&2 echo "Invalid UUID: ${UUID}"
+ exit 2
+fi
+
+# HEURISTIC:
+# (1) if any one given character occurs more than 50% of the time, it is likely
+# that the UUID is fake.
+# (2) if the first or the last group consists of mostly the same character, it
+# is likely that the UUID is fake.
+FIRST_GROUP="$(echo $UUID | cut -d'-' -f1)"
+LAST_GROUP="$(echo $UUID | cut -d'-' -f5)"
+for i in {{0..9},{a..f}} ; do
+ COUNT_TOTAL="${UUID//[^$i]}"
+ COUNT_FIRST="${FIRST_GROUP//[^$i]}"
+ COUNT_LAST="${LAST_GROUP//[^$i]}"
+ if [ ${#COUNT_TOTAL} -ge 16 ] || [ ${#COUNT_FIRST} -ge 7 ] || [ ${#COUNT_LAST} -ge 11 ] ; then
+ >&2 echo "UUID is too repetitive. This may be a false alert."
+ >&2 echo "Repetitive UUID: ${UUID}"
+ exit 3
+ fi
+done
+
+HOSTNQN="nqn.2014-08.org.nvmexpress:uuid:${UUID}"
+
+echo $HOSTNQN
diff --git a/scripts/latency b/scripts/latency
new file mode 100755
index 0000000..908ae4a
--- /dev/null
+++ b/scripts/latency
@@ -0,0 +1,114 @@
+#!/bin/bash
+#
+# 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/tests/Makefile b/tests/Makefile
new file mode 100644
index 0000000..c0f9f31
--- /dev/null
+++ b/tests/Makefile
@@ -0,0 +1,48 @@
+###############################################################################
+#
+# Makefile : Allows user to run testcases, generate documentation, and
+# perform static code analysis.
+#
+###############################################################################
+
+NOSE2_OPTIONS="--verbose"
+
+help: all
+
+all:
+ @echo "Usage:"
+ @echo
+ @echo " make run - Run all testcases."
+ @echo " make doc - Generate Documentation."
+ @echo " make cleanall - removes *pyc, documentation."
+ @echo " make static_check- runs pep8, flake8, pylint on code."
+
+doc:
+ @epydoc -v --output=Documentation *.py
+
+run:
+ @for i in `ls *.py`; \
+ do \
+ echo "Running $${i}"; \
+ TESTCASE_NAME=`echo $${i} | cut -f 1 -d '.'`; \
+ nose2 ${NOSE2_OPTIONS} $${TESTCASE_NAME}; \
+ done
+
+static_check:
+ @for i in `ls *.py`; \
+ do \
+ echo "Pylint :- " ; \
+ printf "%10s " $${i}; \
+ pylint $${i} 2>&1 | grep "^Your code" | awk '{print $$7}';\
+ echo "--------------------------------------------";\
+ pep8 $${i}; \
+ echo "pep8 :- "; \
+ echo "flake8 :- "; \
+ flake8 $${i}; \
+ done
+
+cleanall: clean
+ @rm -fr *.pyc Documentation
+
+clean:
+ @rm -fr *.pyc
diff --git a/tests/README b/tests/README
new file mode 100644
index 0000000..686bd04
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,93 @@
+nvmetests
+=========
+
+ This contains NVMe unit 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.
+
+1. Common Package Dependencies
+------------------------------
+
+ 1. Python(>= 2.7.5 or >= 3.3)
+ 2. nose(http://nose.readthedocs.io/en/latest/)
+ 3. nose2(Installation guide http://nose2.readthedocs.io/)
+ 4. pep8(https://pypi.python.org/pypi/setuptools-pep8)
+ 5. flake8(https://pypi.python.org/pypi/flake8)
+ 6. pylint(https://www.pylint.org/)
+ 7. Epydoc(http://epydoc.sourceforge.net/)
+ 8. nvme-cli(https://github.com/linux-nvme/nvme-cli.git)
+
+ Python package management system pip can be used to install most of the
+ listed packages(https://pip.pypa.io/en/stable/installing/) :-
+ $ pip install nose nose2 pep8 flake8 pylint epydoc
+
+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 __init__. Make sure you are calling
+ super class __init__.
+ 5. Write test post condition code into __del__. Make sure you are calling
+ super class __del__.
+ 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 pep8, flake8, pylint on the testcase and fix errors/warnings.
+ -Example "$ make static_check" will run pep8, flake8 and pylint on
+ all the python files in current directory.
+ b. Execute make doc to generate the documentation.
+ -Example "$ make doc" will create and update existing
+ documentation.
+
+4. Running testcases with framework
+-----------------------------------
+ 1. Running single testcase with nose2 :-
+ $ nose2 --verbose nvme_writezeros_test
+ $ nose2 --verbose nvme_read_write_test
+
+ 2. Running all the testcases with Makefile :-
+ $ make run
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/nvme_attach_detach_ns_test.py b/tests/nvme_attach_detach_ns_test.py
new file mode 100644
index 0000000..92a82dd
--- /dev/null
+++ b/tests/nvme_attach_detach_ns_test.py
@@ -0,0 +1,90 @@
+# 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 nose.tools import assert_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeAttachDetachNSCmd """
+ TestNVMe.__init__(self)
+ 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 __del__(self):
+ """
+ Post Section for TestNVMeAttachDetachNSCmd
+
+ - Create primary namespace.
+ - Atttach it to controller.
+ - Call super class's destructor.
+ """
+ assert_equal(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)
+ TestNVMe.__del__(self)
+
+ 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)
+ assert_equal(err, 0)
+ assert_equal(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
+
+ self.run_ns_io(self.default_nsid, 0)
+
+ assert_equal(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ assert_equal(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..c919c07
--- /dev/null
+++ b/tests/nvme_compare_test.py
@@ -0,0 +1,79 @@
+# 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 nose.tools import assert_equal, assert_not_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeCompareCmd """
+ TestNVMeIO.__init__(self)
+ 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 __del__(self):
+ """ Post Section for TestNVMeCompareCmd """
+ TestNVMeIO.__del__(self)
+
+ 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 """
+ assert_equal(self.nvme_write(), 0)
+ assert_not_equal(self.nvme_compare(self.compare_file), 0)
+ assert_equal(self.nvme_compare(self.write_file), 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..33a66b7
--- /dev/null
+++ b/tests/nvme_create_max_ns_test.py
@@ -0,0 +1,97 @@
+# 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 nose.tools import assert_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeAttachDetachNSCmd """
+ TestNVMe.__init__(self)
+ 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 __del__(self):
+ """
+ Post Section for TestNVMeAttachDetachNSCmd
+
+ - Create primary namespace.
+ - Atttach it to controller.
+ - Call super class's destructor.
+ """
+ assert_equal(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)
+ TestNVMe.__del__(self)
+
+ 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)
+ assert_equal(err, 0)
+ print("##### Attaching " + str(nsid))
+ assert_equal(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))
+ assert_equal(self.detach_ns(self.ctrl_id, nsid), 0)
+ print("#### Deleting " + str(nsid))
+ assert_equal(self.delete_and_validate_ns(nsid), 0)
+ self.nvme_reset_ctrl()
diff --git a/tests/nvme_error_log_test.py b/tests/nvme_error_log_test.py
new file mode 100644
index 0000000..a6a451d
--- /dev/null
+++ b/tests/nvme_error_log_test.py
@@ -0,0 +1,63 @@
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeErrorLogCmd(TestNVMe):
+
+ """
+ Represents Smart Log testcae.
+
+ - Attributes:
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeErrorLogCmd """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+
+ def __del__(self):
+ """
+ Post Section for TestNVMeErrorLogCmd
+
+ - Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ 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 """
+ assert_equal(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..f3a68b3
--- /dev/null
+++ b/tests/nvme_flush_test.py
@@ -0,0 +1,61 @@
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeFlushCmd(TestNVMe):
+
+ """
+ Represents Flush Testcase. Inherits TestNVMe class.
+
+ - Attributes:
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeFlushCmd """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+
+ def __del__(self):
+ """ Post Section for TestNVMeFlushCmd """
+ TestNVMe.__del__(self)
+
+ 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 """
+ assert_equal(self.nvme_flush(), 0)
diff --git a/tests/nvme_format_test.py b/tests/nvme_format_test.py
new file mode 100644
index 0000000..55092fa
--- /dev/null
+++ b/tests/nvme_format_test.py
@@ -0,0 +1,148 @@
+# 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 time
+import subprocess
+from nose.tools import assert_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeFormatCmd """
+ TestNVMe.__init__(self)
+ 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 __del__(self):
+ """
+ Post Section for TestNVMeFormatCmd
+
+ - Create primary namespace.
+ - Atttach it to controller.
+ - Call super class's destructor.
+ """
+ assert_equal(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)
+ TestNVMe.__del__(self)
+
+ def attach_detach_primary_ns(self):
+ """ Extract supported format information using default namespace """
+ assert_equal(self.create_and_validate_ns(self.default_nsid,
+ self.nsze,
+ self.ncap,
+ self.flbas,
+ self.dps), 0)
+ assert_equal(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(" ")
+ assert_equal(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ assert_equal(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)
+ assert_equal(err, 0)
+ assert_equal(self.attach_ns(self.ctrl_id, self.default_nsid), 0)
+ self.run_ns_io(self.default_nsid, self.lbads_list[i])
+ time.sleep(5)
+ assert_equal(self.detach_ns(self.ctrl_id, self.default_nsid), 0)
+ assert_equal(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..adb6386
--- /dev/null
+++ b/tests/nvme_fw_log_test.py
@@ -0,0 +1,71 @@
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeFwLogCmd(TestNVMe):
+
+ """
+ Represents NVMe Firmware Log test.
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeFwLogCmd. """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+
+ def __del__(self):
+ """
+ Post Section for TestNVMeSimpleTestTemplate.
+
+ - Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ 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(fw_log_output + "\n")
+ err = proc.wait()
+ return err
+
+ def test_fw_log(self):
+ """ Testcase main """
+ assert_equal(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..94ed865
--- /dev/null
+++ b/tests/nvme_get_features_test.py
@@ -0,0 +1,105 @@
+# 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 nose.tools import assert_equal
+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 : numer of the interrupt vectors.
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeGetMandatoryFeatures """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+ self.feature_id_list = ["0x01", "0x02", "0x04", "0x05", "0x07",
+ "0x08", "0x09", "0x0A", "0x0B"]
+ get_vector_list_cmd = "cat /proc/interrupts | grep nvme |" \
+ " 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 __del__(self):
+ """ Post Section for TestNVMeGetMandatoryFeatures
+
+ Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ 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)
+ proc = subprocess.Popen(get_feat_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ feature_output = proc.communicate()[0]
+ print(feature_output)
+ assert_equal(proc.wait(), 0)
+ else:
+ get_feat_cmd = "nvme get-feature " + self.ctrl + \
+ " --feature-id=" + str(feature_id)
+ proc = subprocess.Popen(get_feat_cmd,
+ shell=True,
+ stdout=subprocess.PIPE,
+ encoding='utf-8')
+ feature_output = proc.communicate()[0]
+ print(feature_output)
+ assert_equal(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_id_ctrl_test.py b/tests/nvme_id_ctrl_test.py
new file mode 100644
index 0000000..0caf7b2
--- /dev/null
+++ b/tests/nvme_id_ctrl_test.py
@@ -0,0 +1,56 @@
+
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeIdctrlCmd(TestNVMe):
+
+ """
+ Represents Id ctrl testcase
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeIdctrlCmd. """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+
+ def __del__(self):
+ """ Post Section for TestNVMeIdctrlCmd
+
+ Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ def test_id_ctrl(self):
+ """ Testcase main """
+ vendor = True
+ assert_equal(self.get_id_ctrl(), 0)
+ assert_equal(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..cf56187
--- /dev/null
+++ b/tests/nvme_id_ns_test.py
@@ -0,0 +1,88 @@
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeIdentifyNamespace(TestNVMe):
+
+ """
+ Represents Identify Namesepace testcase
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeIdentifyNamespace. """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+ self.ns_list = self.get_ns_list()
+
+ def __del__(self):
+ """
+ Post Section for TestNVMeIdentifyNamespace
+
+ - Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ 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 """
+ assert_equal(self.get_id_ns(1), 0)
+ assert_equal(self.get_id_ns_all(), 0)
diff --git a/tests/nvme_read_write_test.py b/tests/nvme_read_write_test.py
new file mode 100644
index 0000000..4a04f8a
--- /dev/null
+++ b/tests/nvme_read_write_test.py
@@ -0,0 +1,72 @@
+# 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 nose.tools import assert_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeReadWriteTest """
+ TestNVMeIO.__init__(self)
+ 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 __del__(self):
+ """ Post Section for TestNVMeReadWriteTest """
+ TestNVMeIO.__del__(self)
+
+ 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 """
+ assert_equal(self.nvme_write(), 0)
+ assert_equal(self.nvme_read(), 0)
+ assert_equal(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..b6736da
--- /dev/null
+++ b/tests/nvme_simple_template_test.py
@@ -0,0 +1,55 @@
+# 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 __init__(self):
+ """ Pre Section for TestNVMeSimpleTestTemplate. """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+ # Add this test specific variables here
+
+ def __del__(self):
+ """ Post Section for TestNVMeSimpleTestTemplate
+
+ Call super class's destructor.
+ """
+ # Add this test specific cleanup code here
+ TestNVMe.__del__(self)
+
+ 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..e1eb6e5
--- /dev/null
+++ b/tests/nvme_smart_log_test.py
@@ -0,0 +1,86 @@
+# 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 nose.tools import assert_equal
+from nvme_test import TestNVMe
+
+
+class TestNVMeSmartLogCmd(TestNVMe):
+
+ """
+ Represents Smart Log testcae.
+
+ - Attributes:
+ """
+
+ def __init__(self):
+ """ Pre Section for TestNVMeSmartLogCmd """
+ TestNVMe.__init__(self)
+ self.setup_log_dir(self.__class__.__name__)
+
+ def __del__(self):
+ """
+ Post Section for TestNVMeSmartLogCmd
+
+ - Call super class's destructor.
+ """
+ TestNVMe.__del__(self)
+
+ 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 """
+ assert_equal(self.get_smart_log_ctrl(), 0)
+ assert_equal(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..b49c12f
--- /dev/null
+++ b/tests/nvme_test.py
@@ -0,0 +1,479 @@
+# 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 re
+import os
+import sys
+import json
+import mmap
+import stat
+import time
+import shutil
+import subprocess
+from nose import tools
+from nose.tools import assert_equal
+from nvme_test_logger import TestNVMeLogger
+
+
+class TestNVMe(object):
+
+ """
+ Represents a testcase, each testcase shuold 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 __init__(self):
+ """ Pre Section for TestNVMe. """
+ # common code used in various testcases.
+ self.ctrl = "XXX"
+ self.ns1 = "XXX"
+ self.test_log_dir = "XXX"
+ self.default_nsid = 0x1
+ self.config_file = 'config.json'
+
+ self.load_config()
+ self.validate_pci_device()
+
+ def __del__(self):
+ """ Post Section for TestNVMe. """
+ if self.clear_log_dir is True:
+ shutil.rmtree(self.log_dir, ignore_errors=True)
+
+ @tools.nottest
+ def validate_pci_device(self):
+ """ Validate underlaying device belogs 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)
+ assert_equal(err, 0, "ERROR : Only NVMe PCI subsystem is supported")
+
+ @tools.nottest
+ 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.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)
+
+ @tools.nottest
+ 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")
+
+ @tools.nottest
+ 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()
+
+ @tools.nottest
+ 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')
+ assert_equal(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)
+ assert_equal(proc.wait(), 0, "ERROR : pci rescan failed")
+
+ @tools.nottest
+ 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()
+ assert_equal(err, 0, "ERROR : nvme list-ctrl failed")
+ line = proc.stdout.readline()
+ ctrl_id = line.split(":")[1].strip()
+ return ctrl_id
+
+ @tools.nottest
+ def get_ns_list(self):
+ """ Wrapper for extrating 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')
+ assert_equal(proc.wait(), 0, "ERROR : nvme list namespace failed")
+ for line in proc.stdout:
+ ns_list.append(line.split('x')[-1])
+
+ return ns_list
+
+ @tools.nottest
+ def get_max_ns(self):
+ """ Wrapper for extracting maximum number of namspaces 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()
+ assert_equal(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)
+
+ @tools.nottest
+ 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()
+ assert_equal(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)
+
+ @tools.nottest
+ 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()
+ assert_equal(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)
+
+ @tools.nottest
+ 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"
+ assert_equal(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()
+ assert_equal(output, '0', "ERROR : deleting all namespace failed")
+
+ @tools.nottest
+ 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)
+
+ @tools.nottest
+ 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
+
+ @tools.nottest
+ 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
+
+ @tools.nottest
+ 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')
+
+ @tools.nottest
+ 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')
+ assert_equal(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()
+ assert_equal(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()
+ assert_equal(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()
+ assert_equal(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]
+ assert_equal(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]
+ assert_equal(run_io_result, None)
diff --git a/tests/nvme_test_io.py b/tests/nvme_test_io.py
new file mode 100644
index 0000000..0c5c6bb
--- /dev/null
+++ b/tests/nvme_test_io.py
@@ -0,0 +1,99 @@
+# 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 nose import tools
+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 __init__(self):
+ """ Pre Section for TestNVMeIO """
+ TestNVMe.__init__(self)
+ # 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 __del__(self):
+ """ Post Section for TestNVMeIO """
+ TestNVMe.__del__(self)
+
+ @tools.nottest
+ 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()
+
+ @tools.nottest
+ 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)
+
+ @tools.nottest
+ 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..c59fa18
--- /dev/null
+++ b/tests/nvme_test_logger.py
@@ -0,0 +1,52 @@
+# 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(object):
+ """ 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_writeuncor_test.py b/tests/nvme_writeuncor_test.py
new file mode 100644
index 0000000..9f96f63
--- /dev/null
+++ b/tests/nvme_writeuncor_test.py
@@ -0,0 +1,76 @@
+# 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 nose.tools import assert_equal, assert_not_equal
+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 __init__(self):
+ """ Constructor TestNVMeUncor """
+ TestNVMeIO.__init__(self)
+ 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 __del__(self):
+ """ Post Section for TestNVMeUncor """
+ TestNVMeIO.__del__(self)
+
+ 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 """
+ assert_equal(self.nvme_read(), 0)
+ assert_equal(self.write_uncor(), 0)
+ assert_not_equal(self.nvme_read(), 0)
+ assert_equal(self.nvme_write(), 0)
+ assert_equal(self.nvme_read(), 0)
diff --git a/tests/nvme_writezeros_test.py b/tests/nvme_writezeros_test.py
new file mode 100644
index 0000000..157fd78
--- /dev/null
+++ b/tests/nvme_writezeros_test.py
@@ -0,0 +1,102 @@
+# 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 nose.tools import assert_equal
+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 __init__(self):
+ """ Pre Section for TestNVMeWriteZeros """
+ TestNVMeIO.__init__(self)
+ 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 __del__(self):
+ """ Post Section for TestNVMeWriteZeros """
+ TestNVMeIO.__del__(self)
+
+ 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 """
+ assert_equal(self.nvme_write(), 0)
+ assert_equal(self.nvme_read(), 0)
+ assert_equal(self.validate_write_read(), 0)
+ assert_equal(self.write_zeroes(), 0)
+ assert_equal(self.nvme_read(), 0)
+ assert_equal(self.validate_zeroes(), 0)
diff --git a/util/argconfig.c b/util/argconfig.c
new file mode 100644
index 0000000..f647448
--- /dev/null
+++ b/util/argconfig.c
@@ -0,0 +1,534 @@
+/*
+ * 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 <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL };
+
+static char END_DEFAULT[] = "__end_default__";
+
+static const char *append_usage_str = "";
+
+void argconfig_append_usage(const char *str)
+{
+ append_usage_str = str;
+}
+
+void print_word_wrapped(const char *s, int indent, int start)
+{
+ const int width = 76;
+ const char *c, *t;
+ int next_space = -1;
+ int last_line = indent;
+
+ while (start < indent) {
+ putc(' ', stderr);
+ 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', stderr);
+ for (i = 0; i < indent; i++)
+ putc(' ', stderr);
+ start = indent;
+ continue;
+ }
+ }
+ putc(*c, stderr);
+ }
+}
+
+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);
+ print_word_wrapped(option->help, 44, 44);
+ }
+ fprintf(stderr, "\n");
+}
+
+void argconfig_print_help(const char *program_desc,
+ const struct argconfig_commandline_options *options)
+{
+ const struct argconfig_commandline_options *s;
+
+ printf("\033[1mUsage: %s\033[0m\n\n",
+ append_usage_str);
+
+ print_word_wrapped(program_desc, 0, 0);
+ printf("\n");
+
+ if (!options || !options->option)
+ return;
+
+ printf("\n\033[1mOptions:\033[0m\n");
+ for (s = options; (s->option != NULL) && (s != NULL); s++)
+ show_option(s);
+}
+
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+ const struct argconfig_commandline_options *options)
+{
+ char *short_opts;
+ char *endptr;
+ struct option *long_opts;
+ const struct argconfig_commandline_options *s;
+ int c, option_index = 0, short_index = 0, options_count = 0;
+ void *value_addr;
+ int ret = -EINVAL;
+
+ errno = 0;
+ for (s = options; s->option != NULL; s++)
+ options_count++;
+
+ long_opts = malloc(sizeof(struct option) * (options_count + 2));
+ short_opts = malloc(sizeof(*short_opts) * (options_count * 3 + 4));
+
+ 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 != NULL) && (option_index < options_count);
+ s++) {
+ if (s->short_option != 0) {
+ 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;
+
+ if (s->argument_type == no_argument
+ && s->default_value != NULL) {
+ value_addr = (void *)(char *)s->default_value;
+
+ long_opts[option_index].flag = value_addr;
+ long_opts[option_index].val = 1;
+ } else {
+ long_opts[option_index].flag = NULL;
+ long_opts[option_index].val = 0;
+ }
+ }
+ option_index++;
+ }
+
+ long_opts[option_index].name = "help";
+ long_opts[option_index].flag = NULL;
+ long_opts[option_index].val = 'h';
+ option_index++;
+
+ long_opts[option_index].name = NULL;
+ long_opts[option_index].flag = NULL;
+ long_opts[option_index].val = 0;
+
+ short_opts[short_index++] = '?';
+ short_opts[short_index++] = 'h';
+ short_opts[short_index] = 0;
+
+ optind = 0;
+ while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
+ &option_index)) != -1) {
+ if (c != 0) {
+ if (c == '?' || c == 'h') {
+ argconfig_print_help(program_desc, options);
+ goto out;
+ }
+ for (option_index = 0; option_index < options_count;
+ option_index++) {
+ if (c == options[option_index].short_option)
+ break;
+ }
+ if (option_index == options_count)
+ continue;
+ if (long_opts[option_index].flag) {
+ *(uint8_t *)(long_opts[option_index].flag) = 1;
+ continue;
+ }
+ }
+
+ s = &options[option_index];
+ value_addr = (void *)(char *)s->default_value;
+ if (s->config_type == CFG_STRING) {
+ *((char **)value_addr) = optarg;
+ } else if (s->config_type == CFG_SIZE) {
+ *((size_t *) value_addr) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_INT) {
+ *((int *)value_addr) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_BOOL) {
+ int tmp = strtol(optarg, &endptr, 0);
+ if (errno || tmp < 0 || tmp > 1 || optarg == endptr) {
+ fprintf(stderr,
+ "Expected 0 or 1 argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((int *)value_addr) = tmp;
+ } else if (s->config_type == CFG_BYTE) {
+ unsigned long tmp = strtoul(optarg, &endptr, 0);
+ if (errno || tmp >= (1 << 8) || optarg == endptr) {
+ fprintf(stderr,
+ "Expected byte argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint8_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_SHORT) {
+ unsigned long tmp = strtoul(optarg, &endptr, 0);
+ if (errno || tmp >= (1 << 16) || optarg == endptr) {
+ fprintf(stderr,
+ "Expected short argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint16_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_POSITIVE) {
+ uint32_t tmp = strtoul(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected word argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint32_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_INCREMENT) {
+ (*((int *)value_addr))++;
+ } else if (s->config_type == CFG_LONG) {
+ *((unsigned long *)value_addr) = strtoul(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected long integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_LONG_SUFFIX) {
+ *((uint64_t *)value_addr) = suffix_binary_parse(optarg);
+ if (errno) {
+ fprintf(stderr,
+ "Expected long suffixed integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_DOUBLE) {
+ *((double *)value_addr) = strtod(optarg, &endptr);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected float argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_SUBOPTS) {
+ char **opts = ((char **)value_addr);
+ int remaining_space = CFG_MAX_SUBOPTS;
+ int enddefault = 0;
+ int r;
+ while (0 && *opts != NULL) {
+ if (*opts == END_DEFAULT)
+ enddefault = 1;
+ remaining_space--;
+ opts++;
+ }
+
+ if (!enddefault) {
+ *opts = END_DEFAULT;
+ remaining_space -= 2;
+ opts += 2;
+ }
+
+ r = argconfig_parse_subopt_string(optarg, opts,
+ remaining_space);
+ if (r == 2) {
+ fprintf(stderr,
+ "Error Parsing Sub-Options: Too many options!\n");
+ goto out;
+ } else if (r) {
+ fprintf(stderr, "Error Parsing Sub-Options\n");
+ goto out;
+ }
+ } else if (s->config_type == CFG_FILE_A ||
+ s->config_type == CFG_FILE_R ||
+ s->config_type == CFG_FILE_W ||
+ s->config_type == CFG_FILE_AP ||
+ s->config_type == CFG_FILE_RP ||
+ s->config_type == CFG_FILE_WP) {
+ const char *fopts = "";
+ FILE *f;
+ if (s->config_type == CFG_FILE_A)
+ fopts = "a";
+ else if (s->config_type == CFG_FILE_R)
+ fopts = "r";
+ else if (s->config_type == CFG_FILE_W)
+ fopts = "w";
+ else if (s->config_type == CFG_FILE_AP)
+ fopts = "a+";
+ else if (s->config_type == CFG_FILE_RP)
+ fopts = "r+";
+ else if (s->config_type == CFG_FILE_WP)
+ fopts = "w+";
+
+ f = fopen(optarg, fopts);
+ if (f == NULL) {
+ fprintf(stderr, "Unable to open %s file: %s\n",
+ s->option, optarg);
+ goto out;
+ }
+ *((FILE **) value_addr) = f;
+ }
+ }
+ free(short_opts);
+ free(long_opts);
+
+ return 0;
+ out:
+ free(short_opts);
+ free(long_opts);
+ return ret;
+}
+
+int argconfig_parse_subopt_string(char *string, char **options,
+ size_t max_options)
+{
+ char **o = options;
+ char *tmp;
+ size_t toklen;
+
+ if (!string || !strlen(string)) {
+ *(o++) = NULL;
+ *(o++) = NULL;
+ return 0;
+ }
+
+ tmp = calloc(strlen(string) + 2, 1);
+ if (!tmp)
+ return 1;
+ strcpy(tmp, string);
+
+ toklen = strcspn(tmp, "=");
+
+ if (!toklen) {
+ free(tmp);
+ return 1;
+ }
+
+ *(o++) = tmp;
+ tmp[toklen] = 0;
+ tmp += toklen + 1;
+
+ while (1) {
+ if (*tmp == '"' || *tmp == '\'' || *tmp == '[' || *tmp == '(' ||
+ *tmp == '{') {
+
+ tmp++;
+ toklen = strcspn(tmp, "\"'])}");
+
+ if (!toklen)
+ return 1;
+
+ *(o++) = tmp;
+ tmp[toklen] = 0;
+ tmp += toklen + 1;
+
+ toklen = strcspn(tmp, ";:,");
+ tmp[toklen] = 0;
+ tmp += toklen + 1;
+ } else {
+ toklen = strcspn(tmp, ";:,");
+
+ if (!toklen)
+ return 1;
+
+ *(o++) = tmp;
+ tmp[toklen] = 0;
+ tmp += toklen + 1;
+ }
+
+ toklen = strcspn(tmp, "=");
+
+ if (!toklen)
+ break;
+
+ *(o++) = tmp;
+ tmp[toklen] = 0;
+ tmp += toklen + 1;
+
+ if ((o - options) > (max_options - 2))
+ return 2;
+ }
+
+ *(o++) = NULL;
+ *(o++) = NULL;
+
+ return 0;
+}
+
+unsigned argconfig_parse_comma_sep_array(char *string, int *val,
+ unsigned max_length)
+{
+ unsigned ret = 0;
+ char *tmp;
+ char *p;
+
+ if (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (!tmp)
+ return 0;
+
+ val[ret] = strtol(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] = strtol(tmp, &p, 0);
+
+ if (*p != 0)
+ return -1;
+ ret++;
+ }
+}
+
+unsigned argconfig_parse_comma_sep_array_long(char *string,
+ unsigned long long *val,
+ unsigned max_length)
+{
+ unsigned 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++;
+ }
+}
+
+void argconfig_register_help_func(argconfig_help_func * f)
+{
+ int i;
+ for (i = 0; i < MAX_HELP_FUNC; i++) {
+ if (help_funcs[i] == NULL) {
+ help_funcs[i] = f;
+ help_funcs[i + 1] = NULL;
+ break;
+ }
+ }
+}
diff --git a/util/argconfig.h b/util/argconfig.h
new file mode 100644
index 0000000..623b832
--- /dev/null
+++ b/util/argconfig.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * 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>
+
+enum argconfig_types {
+ CFG_NONE,
+ CFG_STRING,
+ CFG_INT,
+ CFG_SIZE,
+ CFG_LONG,
+ CFG_LONG_SUFFIX,
+ CFG_DOUBLE,
+ CFG_BOOL,
+ CFG_BYTE,
+ CFG_SHORT,
+ CFG_POSITIVE,
+ CFG_INCREMENT,
+ CFG_SUBOPTS,
+ CFG_FILE_A,
+ CFG_FILE_W,
+ CFG_FILE_R,
+ CFG_FILE_AP,
+ CFG_FILE_WP,
+ CFG_FILE_RP,
+};
+
+#define OPT_ARGS(n) \
+ const struct argconfig_commandline_options n[]
+
+#define OPT_END() { NULL }
+
+#define OPT_FLAG(l, s, v, d) \
+ {l, s, NULL, CFG_NONE, v, no_argument, d}
+
+#define OPT_SUFFIX(l, s, v, d) \
+ {l, s, "IONUM", CFG_LONG_SUFFIX, v, required_argument, d}
+
+#define OPT_LONG(l, s, v, d) \
+ {l, s, "NUM", CFG_LONG, v, required_argument, d}
+
+#define OPT_UINT(l, s, v, d) \
+ {l, s, "NUM", CFG_POSITIVE, v, required_argument, d}
+
+#define OPT_INT(l, s, v, d) \
+ {l, s, "NUM", CFG_INT, v, required_argument, d}
+
+#define OPT_LONG(l, s, v, d) \
+ {l, s, "NUM", CFG_LONG, v, required_argument, d}
+
+#define OPT_DOUBLE(l, s, v, d) \
+ {l, s, "NUM", CFG_DOUBLE, v, required_argument, d}
+
+#define OPT_BYTE(l, s, v, d) \
+ {l, s, "NUM", CFG_BYTE, v, required_argument, d}
+
+#define OPT_SHRT(l, s, v, d) \
+ {l, s, "NUM", CFG_SHORT, v, required_argument, d}
+
+#define OPT_STRING(l, s, m, v, d) \
+ {l, s, m, CFG_STRING, v, required_argument, d}
+
+#define OPT_FMT(l, s, v, d) OPT_STRING(l, s, "FMT", v, d)
+#define OPT_FILE(l, s, v, d) OPT_STRING(l, s, "FILE", v, d)
+#define OPT_LIST(l, s, v, d) OPT_STRING(l, s, "LIST", v, d)
+
+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;
+};
+
+#define CFG_MAX_SUBOPTS 500
+#define MAX_HELP_FUNC 20
+
+typedef void argconfig_help_func();
+void argconfig_append_usage(const char *str);
+void argconfig_print_help(const char *program_desc,
+ const struct argconfig_commandline_options *options);
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+ const struct argconfig_commandline_options *options);
+int argconfig_parse_subopt_string(char *string, char **options,
+ size_t max_options);
+unsigned argconfig_parse_comma_sep_array(char *string, int *ret,
+ unsigned max_length);
+unsigned argconfig_parse_comma_sep_array_long(char *string,
+ unsigned long long *ret,
+ unsigned max_length);
+void argconfig_register_help_func(argconfig_help_func * f);
+
+void print_word_wrapped(const char *s, int indent, int start);
+#endif
diff --git a/util/json.c b/util/json.c
new file mode 100644
index 0000000..2978410
--- /dev/null
+++ b/util/json.c
@@ -0,0 +1,407 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "json.h"
+
+static inline void fail_and_notify(void)
+{
+ fprintf(stderr, "Allocation of memory for json object failed, aborting.\n");
+ abort();
+}
+
+struct json_object *json_create_object(void)
+{
+ void *test = calloc(1, sizeof(struct json_object));
+ if (!test)
+ fail_and_notify();
+ return test;
+}
+
+struct json_array *json_create_array(void)
+{
+ void *test = calloc(1, sizeof(struct json_array));
+ if (!test)
+ fail_and_notify();
+ return test;
+}
+
+static struct json_pair *json_create_pair(const char *name, struct json_value *value)
+{
+ struct json_pair *pair = malloc(sizeof(struct json_pair));
+ if (pair) {
+ pair->name = strdup(name);
+ pair->value = value;
+
+ value->parent_type = JSON_PARENT_TYPE_PAIR;
+ value->parent_pair = pair;
+ } else
+ fail_and_notify();
+
+ return pair;
+}
+
+static struct json_value *json_create_value_int(long long number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_INTEGER;
+ value->integer_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_uint(unsigned long long number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_UINT;
+ value->uint_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_float(long double number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_FLOAT;
+ value->float_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static char *strdup_escape(const char *str)
+{
+ const char *input = str;
+ char *p, *ret;
+ int escapes;
+
+ if (!strlen(str))
+ return NULL;
+
+ escapes = 0;
+ while ((input = strpbrk(input, "\\\"")) != NULL) {
+ escapes++;
+ input++;
+ }
+
+ p = ret = malloc(strlen(str) + escapes + 1);
+ if (!ret)
+ fail_and_notify();
+
+ while (*str) {
+ if (*str == '\\' || *str == '\"')
+ *p++ = '\\';
+ *p++ = *str++;
+ }
+ *p = '\0';
+
+ return ret;
+}
+
+/*
+ * Valid JSON strings must escape '"' and '/' with a preceding '/'
+ */
+static struct json_value *json_create_value_string(const char *str)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_STRING;
+ value->string = strdup_escape(str ? str : "(null)");
+ if (!value->string) {
+ free(value);
+ value = NULL;
+ return value;
+ }
+ }
+ if (!value)
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_object(struct json_object *obj)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_OBJECT;
+ value->object = obj;
+ obj->parent = value;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_array(struct json_array *array)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_ARRAY;
+ value->array = array;
+ array->parent = value;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static void json_free_pair(struct json_pair *pair);
+static void json_free_value(struct json_value *value);
+
+void json_free_object(struct json_object *obj)
+{
+ int i;
+
+ for (i = 0; i < obj->pair_cnt; i++)
+ json_free_pair(obj->pairs[i]);
+ free(obj->pairs);
+ free(obj);
+}
+
+void json_free_array(struct json_array *array)
+{
+ int i;
+
+ for (i = 0; i < array->value_cnt; i++)
+ json_free_value(array->values[i]);
+ free(array->values);
+ free(array);
+}
+
+static void json_free_pair(struct json_pair *pair)
+{
+ json_free_value(pair->value);
+ free(pair->name);
+ free(pair);
+}
+
+static void json_free_value(struct json_value *value)
+{
+ switch (value->type) {
+ case JSON_TYPE_STRING:
+ free(value->string);
+ break;
+ case JSON_TYPE_OBJECT:
+ json_free_object(value->object);
+ break;
+ case JSON_TYPE_ARRAY:
+ json_free_array(value->array);
+ break;
+ }
+ free(value);
+}
+
+static int json_array_add_value(struct json_array *array, struct json_value *value)
+{
+ struct json_value **values = realloc(array->values,
+ sizeof(struct json_value *) * (array->value_cnt + 1));
+
+ if (!values)
+ return ENOMEM;
+ values[array->value_cnt] = value;
+ array->value_cnt++;
+ array->values = values;
+
+ value->parent_type = JSON_PARENT_TYPE_ARRAY;
+ value->parent_array = array;
+ return 0;
+}
+
+static int json_object_add_pair(struct json_object *obj, struct json_pair *pair)
+{
+ struct json_pair **pairs = realloc(obj->pairs,
+ sizeof(struct json_pair *) * (obj->pair_cnt + 1));
+ if (!pairs)
+ return ENOMEM;
+ pairs[obj->pair_cnt] = pair;
+ obj->pair_cnt++;
+ obj->pairs = pairs;
+
+ pair->parent = obj;
+ return 0;
+}
+
+int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...)
+{
+ struct json_value *value;
+ struct json_pair *pair;
+ va_list args;
+ int ret;
+
+ va_start(args, type);
+ if (type == JSON_TYPE_STRING)
+ value = json_create_value_string(va_arg(args, char *));
+ else if (type == JSON_TYPE_INTEGER)
+ value = json_create_value_int(va_arg(args, long long));
+ else if (type == JSON_TYPE_UINT)
+ value = json_create_value_uint(va_arg(args, unsigned long long));
+ else if (type == JSON_TYPE_FLOAT)
+ value = json_create_value_float(va_arg(args, long double));
+ else if (type == JSON_TYPE_OBJECT)
+ value = json_create_value_object(va_arg(args, struct json_object *));
+ else
+ value = json_create_value_array(va_arg(args, struct json_array *));
+ va_end(args);
+
+ if (!value)
+ return ENOMEM;
+
+ pair = json_create_pair(name, value);
+ if (!pair) {
+ json_free_value(value);
+ return ENOMEM;
+ }
+ ret = json_object_add_pair(obj, pair);
+ if (ret) {
+ json_free_pair(pair);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static void json_print_array(struct json_array *array, void *);
+int json_array_add_value_type(struct json_array *array, int type, ...)
+{
+ struct json_value *value;
+ va_list args;
+ int ret;
+
+ va_start(args, type);
+ if (type == JSON_TYPE_STRING)
+ value = json_create_value_string(va_arg(args, char *));
+ else if (type == JSON_TYPE_INTEGER)
+ value = json_create_value_int(va_arg(args, long long));
+ else if (type == JSON_TYPE_UINT)
+ value = json_create_value_uint(va_arg(args, unsigned long long));
+ else if (type == JSON_TYPE_FLOAT)
+ value = json_create_value_float(va_arg(args, double));
+ else if (type == JSON_TYPE_OBJECT)
+ value = json_create_value_object(va_arg(args, struct json_object *));
+ else
+ value = json_create_value_array(va_arg(args, struct json_array *));
+ va_end(args);
+
+ if (!value)
+ return ENOMEM;
+
+ ret = json_array_add_value(array, value);
+ if (ret) {
+ json_free_value(value);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static int json_value_level(struct json_value *value);
+static int json_pair_level(struct json_pair *pair);
+static int json_array_level(struct json_array *array);
+static int json_object_level(struct json_object *object)
+{
+ if (object->parent == NULL)
+ return 0;
+ return json_value_level(object->parent);
+}
+
+static int json_pair_level(struct json_pair *pair)
+{
+ return json_object_level(pair->parent) + 1;
+}
+
+static int json_array_level(struct json_array *array)
+{
+ return json_value_level(array->parent);
+}
+
+static int json_value_level(struct json_value *value)
+{
+ if (value->parent_type == JSON_PARENT_TYPE_PAIR)
+ return json_pair_level(value->parent_pair);
+ else
+ return json_array_level(value->parent_array) + 1;
+}
+
+static void json_print_level(int level, void *out)
+{
+ while (level-- > 0)
+ printf(" ");
+}
+
+static void json_print_pair(struct json_pair *pair, void *);
+static void json_print_array(struct json_array *array, void *);
+static void json_print_value(struct json_value *value, void *);
+void json_print_object(struct json_object *obj, void *out)
+{
+ int i;
+
+ printf("{\n");
+ for (i = 0; i < obj->pair_cnt; i++) {
+ if (i > 0)
+ printf(",\n");
+ json_print_pair(obj->pairs[i], out);
+ }
+ printf("\n");
+ json_print_level(json_object_level(obj), out);
+ printf("}");
+}
+
+static void json_print_pair(struct json_pair *pair, void *out)
+{
+ json_print_level(json_pair_level(pair), out);
+ printf("\"%s\" : ", pair->name);
+ json_print_value(pair->value, out);
+}
+
+static void json_print_array(struct json_array *array, void *out)
+{
+ int i;
+
+ printf("[\n");
+ for (i = 0; i < array->value_cnt; i++) {
+ if (i > 0)
+ printf(",\n");
+ json_print_level(json_value_level(array->values[i]), out);
+ json_print_value(array->values[i], out);
+ }
+ printf("\n");
+ json_print_level(json_array_level(array), out);
+ printf("]");
+}
+
+static void json_print_value(struct json_value *value, void *out)
+{
+ switch (value->type) {
+ case JSON_TYPE_STRING:
+ printf( "\"%s\"", value->string);
+ break;
+ case JSON_TYPE_INTEGER:
+ printf( "%lld", value->integer_number);
+ break;
+ case JSON_TYPE_UINT:
+ printf( "%llu", value->uint_number);
+ break;
+ case JSON_TYPE_FLOAT:
+ printf( "%.0Lf", value->float_number);
+ break;
+ case JSON_TYPE_OBJECT:
+ json_print_object(value->object, out);
+ break;
+ case JSON_TYPE_ARRAY:
+ json_print_array(value->array, out);
+ break;
+ }
+}
diff --git a/util/json.h b/util/json.h
new file mode 100644
index 0000000..d78d3db
--- /dev/null
+++ b/util/json.h
@@ -0,0 +1,88 @@
+#ifndef __JSON__H
+#define __JSON__H
+
+struct json_object;
+struct json_array;
+struct json_pair;
+
+#define JSON_TYPE_STRING 0
+#define JSON_TYPE_INTEGER 1
+#define JSON_TYPE_FLOAT 2
+#define JSON_TYPE_OBJECT 3
+#define JSON_TYPE_ARRAY 4
+#define JSON_TYPE_UINT 5
+#define JSON_PARENT_TYPE_PAIR 0
+#define JSON_PARENT_TYPE_ARRAY 1
+struct json_value {
+ int type;
+ union {
+ long long integer_number;
+ unsigned long long uint_number;
+ long double float_number;
+ char *string;
+ struct json_object *object;
+ struct json_array *array;
+ };
+ int parent_type;
+ union {
+ struct json_pair *parent_pair;
+ struct json_array *parent_array;
+ };
+};
+
+struct json_array {
+ struct json_value **values;
+ int value_cnt;
+ struct json_value *parent;
+};
+
+struct json_object {
+ struct json_pair **pairs;
+ int pair_cnt;
+ struct json_value *parent;
+};
+
+struct json_pair {
+ char *name;
+ struct json_value *value;
+ struct json_object *parent;
+};
+
+struct json_object *json_create_object(void);
+struct json_array *json_create_array(void);
+
+void json_free_object(struct json_object *obj);
+void json_free_array(struct json_array *array);
+
+int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...);
+#define json_object_add_value_int(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val))
+#define json_object_add_value_uint(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val))
+#define json_object_add_value_float(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val))
+#define json_object_add_value_string(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val))
+#define json_object_add_value_object(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val))
+#define json_object_add_value_array(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val))
+int json_array_add_value_type(struct json_array *array, int type, ...);
+#define json_array_add_value_int(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val))
+#define json_array_add_value_uint(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_UINT, (val))
+#define json_array_add_value_float(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val))
+#define json_array_add_value_string(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_STRING, (val))
+#define json_array_add_value_object(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val))
+#define json_array_add_value_array(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val))
+
+#define json_array_last_value_object(obj) \
+ (obj->values[obj->value_cnt - 1]->object)
+
+void json_print_object(struct json_object *obj, void *);
+#endif
diff --git a/util/parser.c b/util/parser.c
new file mode 100644
index 0000000..2dd0922
--- /dev/null
+++ b/util/parser.c
@@ -0,0 +1,284 @@
+/*
+ * lib/parser.c - simple parser for mount, etc. options.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "parser.h"
+
+/**
+ * match_one: - Determines if a string matches a simple pattern
+ * @s: the string to examine for presence of the pattern
+ * @p: the string containing the pattern
+ * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
+ * locations.
+ *
+ * Description: Determines if the pattern @p is present in string @s. Can only
+ * match extremely simple token=arg style patterns. If the pattern is found,
+ * the location(s) of the arguments will be returned in the @args array.
+ */
+static int match_one(char *s, const char *p, substring_t args[])
+{
+ char *meta;
+ int argc = 0;
+
+ if (!p)
+ return 1;
+
+ while(1) {
+ int len = -1;
+ meta = strchr(p, '%');
+ if (!meta)
+ return strcmp(p, s) == 0;
+
+ if (strncmp(p, s, meta-p))
+ return 0;
+
+ s += meta - p;
+ p = meta + 1;
+
+ if (isdigit(*p))
+ len = strtoul(p, (char **) &p, 10);
+ else if (*p == '%') {
+ if (*s++ != '%')
+ return 0;
+ p++;
+ continue;
+ }
+
+ if (argc >= MAX_OPT_ARGS)
+ return 0;
+
+ args[argc].from = s;
+ switch (*p++) {
+ case 's': {
+ size_t str_len = strlen(s);
+
+ if (str_len == 0)
+ return 0;
+ if (len == -1 || len > str_len)
+ len = str_len;
+ args[argc].to = s + len;
+ break;
+ }
+ case 'd':
+ strtol(s, &args[argc].to, 0);
+ goto num;
+ case 'u':
+ strtoul(s, &args[argc].to, 0);
+ goto num;
+ case 'o':
+ strtoul(s, &args[argc].to, 8);
+ goto num;
+ case 'x':
+ strtoul(s, &args[argc].to, 16);
+ num:
+ if (args[argc].to == args[argc].from)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ s = args[argc].to;
+ argc++;
+ }
+}
+
+/**
+ * match_token: - Find a token (and optional args) in a string
+ * @s: the string to examine for token/argument pairs
+ * @table: match_table_t describing the set of allowed option tokens and the
+ * arguments that may be associated with them. Must be terminated with a
+ * &struct match_token whose pattern is set to the NULL pointer.
+ * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
+ * locations.
+ *
+ * Description: Detects which if any of a set of token strings has been passed
+ * to it. Tokens can include up to MAX_OPT_ARGS instances of basic c-style
+ * format identifiers which will be taken into account when matching the
+ * tokens, and whose locations will be returned in the @args array.
+ */
+int match_token(char *s, const match_table_t table, substring_t args[])
+{
+ const struct match_token *p;
+
+ for (p = table; !match_one(s, p->pattern, args) ; p++)
+ ;
+
+ return p->token;
+}
+
+/**
+ * match_number: scan a number in the given base from a substring_t
+ * @s: substring to be scanned
+ * @result: resulting integer on success
+ * @base: base to use when converting string
+ *
+ * Description: Given a &substring_t and a base, attempts to parse the substring
+ * as a number in that base. On success, sets @result to the integer represented
+ * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+static int match_number(substring_t *s, int *result, int base)
+{
+ char *endp;
+ char *buf;
+ int ret;
+ long val;
+ size_t len = s->to - s->from;
+
+ buf = malloc(len + 1);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, s->from, len);
+ buf[len] = '\0';
+
+ ret = 0;
+ val = strtol(buf, &endp, base);
+ if (endp == buf)
+ ret = -EINVAL;
+ else if (val < (long)INT_MIN || val > (long)INT_MAX)
+ ret = -ERANGE;
+ else
+ *result = (int) val;
+ free(buf);
+ return ret;
+}
+
+/**
+ * match_int: - scan a decimal representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as a decimal integer. On
+ * success, sets @result to the integer represented by the string and returns 0.
+ * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_int(substring_t *s, int *result)
+{
+ return match_number(s, result, 0);
+}
+
+/**
+ * match_octal: - scan an octal representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as an octal integer. On
+ * success, sets @result to the integer represented by the string and returns
+ * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_octal(substring_t *s, int *result)
+{
+ return match_number(s, result, 8);
+}
+
+/**
+ * match_hex: - scan a hex representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
+ * On success, sets @result to the integer represented by the string and
+ * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_hex(substring_t *s, int *result)
+{
+ return match_number(s, result, 16);
+}
+
+/**
+ * match_wildcard: - parse if a string matches given wildcard pattern
+ * @pattern: wildcard pattern
+ * @str: the string to be parsed
+ *
+ * Description: Parse the string @str to check if matches wildcard
+ * pattern @pattern. The pattern may contain two type wildcardes:
+ * '*' - matches zero or more characters
+ * '?' - matches one character
+ * If it's matched, return true, else return false.
+ */
+bool match_wildcard(const char *pattern, const char *str)
+{
+ const char *s = str;
+ const char *p = pattern;
+ bool star = false;
+
+ while (*s) {
+ switch (*p) {
+ case '?':
+ s++;
+ p++;
+ break;
+ case '*':
+ star = true;
+ str = s;
+ if (!*++p)
+ return true;
+ pattern = p;
+ break;
+ default:
+ if (*s == *p) {
+ s++;
+ p++;
+ } else {
+ if (!star)
+ return false;
+ str++;
+ s = str;
+ p = pattern;
+ }
+ break;
+ }
+ }
+
+ if (*p == '*')
+ ++p;
+ return !*p;
+}
+
+/**
+ * match_strlcpy: - Copy the characters from a substring_t to a sized buffer
+ * @dest: where to copy to
+ * @src: &substring_t to copy
+ * @size: size of destination buffer
+ *
+ * Description: Copy the characters in &substring_t @src to the
+ * c-style string @dest. Copy no more than @size - 1 characters, plus
+ * the terminating NUL. Return length of @src.
+ */
+size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
+{
+ size_t ret = src->to - src->from;
+
+ if (size) {
+ size_t len = ret >= size ? size - 1 : ret;
+ memcpy(dest, src->from, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}
+
+/**
+ * match_strdup: - allocate a new string with the contents of a substring_t
+ * @s: &substring_t to copy
+ *
+ * Description: Allocates and returns a string filled with the contents of
+ * the &substring_t @s. The caller is responsible for freeing the returned
+ * string with free().
+ */
+char *match_strdup(const substring_t *s)
+{
+ size_t sz = s->to - s->from + 1;
+ char *p = malloc(sz);
+ if (p)
+ match_strlcpy(p, s, sz);
+ return p;
+}
diff --git a/util/parser.h b/util/parser.h
new file mode 100644
index 0000000..39d5b79
--- /dev/null
+++ b/util/parser.h
@@ -0,0 +1,34 @@
+/*
+ * linux/include/linux/parser.h
+ *
+ * Header for lib/parser.c
+ * Intended use of these functions is parsing filesystem argument lists,
+ * but could potentially be used anywhere else that simple option=arg
+ * parsing is required.
+ */
+
+
+/* associates an integer enumerator with a pattern string. */
+struct match_token {
+ int token;
+ const char *pattern;
+};
+
+typedef struct match_token match_table_t[];
+
+/* Maximum number of arguments that match_token will find in a pattern */
+enum {MAX_OPT_ARGS = 3};
+
+/* Describe the location within a string of a substring */
+typedef struct {
+ char *from;
+ char *to;
+} substring_t;
+
+int match_token(char *, const match_table_t table, substring_t args[]);
+int match_int(substring_t *, int *result);
+int match_octal(substring_t *, int *result);
+int match_hex(substring_t *, int *result);
+bool match_wildcard(const char *pattern, const char *str);
+size_t match_strlcpy(char *, const substring_t *, size_t);
+char *match_strdup(const substring_t *);
diff --git a/util/suffix.c b/util/suffix.c
new file mode 100644
index 0000000..bf1485f
--- /dev/null
+++ b/util/suffix.c
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+
+static struct si_suffix {
+ double magnitude;
+ const char *suffix;
+} si_suffixes[] = {
+ {1e15, "P"},
+ {1e12, "T"},
+ {1e9, "G"},
+ {1e6, "M"},
+ {1e3, "k"},
+ {1e0, ""},
+ {1e-3, "m"},
+ {1e-6, "u"},
+ {1e-9, "n"},
+ {1e-12, "p"},
+ {1e-15, "f"},
+ {0}
+};
+
+const char *suffix_si_get(double *value)
+{
+ struct si_suffix *s;
+
+ for (s = si_suffixes; s->magnitude != 0; s++) {
+ 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"},
+ {0, ""}
+};
+
+const char *suffix_binary_get(long long *value)
+{
+ struct binary_suffix *s;
+
+ for (s = binary_suffixes; s->shift != 0; s++) {
+ 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)
+{
+ struct binary_suffix *s;
+
+ for (s = binary_suffixes; s->shift != 0; s++) {
+ if (fabs(*value) >= (1LL << s->shift)) {
+ *value = *value / (1LL << s->shift);
+ return s->suffix;
+ }
+ }
+
+ return "";
+}
+
+uint64_t suffix_binary_parse(const char *value)
+{
+ char *suffix;
+ errno = 0;
+ uint64_t ret = strtoll(value, &suffix, 0);
+ if (errno)
+ return 0;
+
+ struct binary_suffix *s;
+ for (s = binary_suffixes; s->shift != 0; s++) {
+ if (tolower(suffix[0]) == tolower(s->suffix[0])) {
+ ret <<= s->shift;
+ return ret;
+ }
+ }
+
+ if (suffix[0] != '\0')
+ errno = EINVAL;
+
+ return ret;
+}
diff --git a/util/suffix.h b/util/suffix.h
new file mode 100644
index 0000000..278f472
--- /dev/null
+++ b/util/suffix.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * 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>
+
+const char *suffix_si_get(double *value);
+const char *suffix_binary_get(long long *value);
+const char *suffix_dbinary_get(double *value);
+uint64_t suffix_binary_parse(const char *value);
+
+#endif